diff --git a/.hgtags b/.hgtags index 989f02b425a..a99bb065cfc 100644 --- a/.hgtags +++ b/.hgtags @@ -351,3 +351,5 @@ db483b34fa7148d257a429acddbde9c13687dcae jdk-9+105 6c644cca3f3fc2763e2ff7d669849a75d34543ba jdk-9+106 1c076468bf7dad5b8f2ee5dcf66e2279caa3e208 jdk-9+107 257b579d813201682931d6b42f0445ffe5b4210d jdk-9+108 +c870cb782aca71093d2584376f27f0cfbfec0e3a jdk-9+109 +4a95f4b1bd8bfce85dc02a593896749feab96c34 jdk-9+110 diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 528a64a3e8c..623af343bef 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -351,3 +351,5 @@ be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105 54575d8783b3a39a2d710c28cda675d44261f9d9 jdk-9+106 4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107 c7be2a78c31b3b6132f2f5e9e4b3d3bb1c20245c jdk-9+108 +1787bdaabb2b6f4193406e25a50cb0419ea8e8f3 jdk-9+109 +925be13b3740d07a5958ccb5ab3c0ae1baba7055 jdk-9+110 diff --git a/common/autoconf/basics.m4 b/common/autoconf/basics.m4 index d748c4f89a1..753d170beb2 100644 --- a/common/autoconf/basics.m4 +++ b/common/autoconf/basics.m4 @@ -843,6 +843,8 @@ AC_DEFUN_ONCE([BASIC_SETUP_OUTPUT_DIR], AC_CONFIG_FILES([$OUTPUT_ROOT/hotspot-spec.gmk:$AUTOCONF_DIR/hotspot-spec.gmk.in]) # The bootcycle-spec.gmk file contains support for boot cycle builds. AC_CONFIG_FILES([$OUTPUT_ROOT/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in]) + # The buildjdk-spec.gmk file contains support for building a buildjdk when cross compiling. + AC_CONFIG_FILES([$OUTPUT_ROOT/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in]) # The compare.sh is used to compare the build output to other builds. AC_CONFIG_FILES([$OUTPUT_ROOT/compare.sh:$AUTOCONF_DIR/compare.sh.in]) # The generated Makefile knows where the spec.gmk is and where the source is. diff --git a/common/autoconf/boot-jdk.m4 b/common/autoconf/boot-jdk.m4 index 7864ea956d4..91bf548fbf8 100644 --- a/common/autoconf/boot-jdk.m4 +++ b/common/autoconf/boot-jdk.m4 @@ -304,6 +304,18 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK], # When compiling code to be executed by the Boot JDK, force jdk8 compatibility. BOOT_JDK_SOURCETARGET="-source 8 -target 8" AC_SUBST(BOOT_JDK_SOURCETARGET) + + ADD_JVM_ARG_IF_OK([-Xpatch:], dummy, [$JAVA]) + AC_MSG_CHECKING([if Boot JDK supports modules]) + if test "x$JVM_ARG_OK" = "xtrue"; then + AC_MSG_RESULT([yes]) + BOOT_JDK_MODULAR="true" + else + AC_MSG_RESULT([no]) + BOOT_JDK_MODULAR="false" + fi + AC_SUBST(BOOT_JDK_MODULAR) + AC_SUBST(JAVAC_FLAGS) # Check if the boot jdk is 32 or 64 bit @@ -397,3 +409,100 @@ AC_DEFUN_ONCE([BOOTJDK_SETUP_BOOT_JDK_ARGUMENTS], done AC_SUBST(JAVA_TOOL_FLAGS_SMALL) ]) + +# BUILD_JDK: the location of the latest JDK that can run +# on the host system and supports the target class file version +# generated in this JDK build. This variable should only be +# used after the launchers are built. +# + +# Execute the check given as argument, and verify the result. +# If the JDK was previously found, do nothing. +# $1 A command line (typically autoconf macro) to execute +AC_DEFUN([BOOTJDK_CHECK_BUILD_JDK], +[ + if test "x$BUILD_JDK_FOUND" = xno; then + # Execute the test + $1 + + # If previous step claimed to have found a JDK, check it to see if it seems to be valid. + if test "x$BUILD_JDK_FOUND" = xmaybe; then + # Do we have a bin/java? + if test ! -x "$BUILD_JDK/bin/java"; then + AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK did not contain bin/java; ignoring]) + BUILD_JDK_FOUND=no + elif test ! -x "$BUILD_JDK/bin/jlink"; then + AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK did not contain bin/jlink; ignoring]) + BUILD_JDK_FOUND=no + elif test ! -x "$BUILD_JDK/bin/javac"; then + # Do we have a bin/javac? + AC_MSG_NOTICE([Potential Build JDK found at $BUILD_JDK did not contain bin/javac; ignoring]) + AC_MSG_NOTICE([(This might be a JRE instead of an JDK)]) + BUILD_JDK_FOUND=no + else + # Oh, this is looking good! We probably have found a proper JDK. Is it the correct version? + BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | head -n 1` + + # Extra M4 quote needed to protect [] in grep expression. + [FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | grep '\"1\.[9]\.'`] + if test "x$FOUND_CORRECT_VERSION" = x; then + AC_MSG_NOTICE([Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring]) + AC_MSG_NOTICE([(Your Build JDK must be version 9)]) + BUILD_JDK_FOUND=no + else + # We're done! + BUILD_JDK_FOUND=yes + BASIC_FIXUP_PATH(BUILD_JDK) + AC_MSG_CHECKING([for Build JDK]) + AC_MSG_RESULT([$BUILD_JDK]) + AC_MSG_CHECKING([Build JDK version]) + BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | $TR '\n\r' ' '` + AC_MSG_RESULT([$BUILD_JDK_VERSION]) + fi # end check jdk version + fi # end check java + fi # end check build jdk found + fi +]) + +# By default the BUILD_JDK is the JDK_OUTPUTDIR. If the target architecture +# is different than the host system doing the build (e.g. cross-compilation), +# a special BUILD_JDK is built as part of the build process. An external +# prebuilt BUILD_JDK can also be supplied. +AC_DEFUN([BOOTJDK_SETUP_BUILD_JDK], +[ + AC_ARG_WITH(build-jdk, [AS_HELP_STRING([--with-build-jdk], + [path to JDK of same version as is being built@<:@the newly built JDK@:>@])]) + + CREATE_BUILDJDK_FOR_HOST=false + BUILD_JDK_FOUND="no" + if test "x$with_build_jdk" != "x"; then + BOOTJDK_CHECK_BUILD_JDK([ + if test "x$with_build_jdk" != x; then + BUILD_JDK=$with_build_jdk + BUILD_JDK_FOUND=maybe + AC_MSG_NOTICE([Found potential Build JDK using configure arguments]) + fi]) + else + if test "x$COMPILE_TYPE" = "xcross"; then + BUILD_JDK="\$(BUILDJDK_OUTPUTDIR)/jdk" + BUILD_JDK_FOUND=yes + CREATE_BUILDJDK=true + AC_MSG_CHECKING([for Build JDK]) + AC_MSG_RESULT([yes, will build it for the host platform]) + else + BUILD_JDK="\$(JDK_OUTPUTDIR)" + BUILD_JDK_FOUND=yes + AC_MSG_CHECKING([for Build JDK]) + AC_MSG_RESULT([yes, will use output dir]) + fi + fi + + if test "x$BUILD_JDK_FOUND" != "xyes"; then + AC_MSG_CHECKING([for Build JDK]) + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Could not find a suitable Build JDK]) + fi + + AC_SUBST(CREATE_BUILDJDK) + AC_SUBST(BUILD_JDK) +]) diff --git a/common/autoconf/bootcycle-spec.gmk.in b/common/autoconf/bootcycle-spec.gmk.in index 0335615795f..c37097d1b1d 100644 --- a/common/autoconf/bootcycle-spec.gmk.in +++ b/common/autoconf/bootcycle-spec.gmk.in @@ -25,6 +25,8 @@ # Support for building boot cycle builds +BOOT_JDK_MODULAR := true + # First include the real base spec.gmk file include @SPEC@ diff --git a/common/autoconf/buildjdk-spec.gmk.in b/common/autoconf/buildjdk-spec.gmk.in new file mode 100644 index 00000000000..f92602edc34 --- /dev/null +++ b/common/autoconf/buildjdk-spec.gmk.in @@ -0,0 +1,148 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# This spec file is used to compile a BUILD_JDK while cross compiling. The +# BUILD_JDK runs on the build/host platform and is of the same version as +# the main build. + +# First include the real base spec.gmk file +include @SPEC@ + +CC := @BUILD_CC@ +CXX := @BUILD_CXX@ +LD := @BUILD_LD@ +AS := @BUILD_AS@ +NM := @BUILD_NM@ +AR := @BUILD_AR@ +OBJCOPY := @BUILD_OBJCOPY@ +STRIP := @BUILD_STRIP@ +SYSROOT_CFLAGS := @BUILD_SYSROOT_CFLAGS@ +SYSROOT_LDFLAGS := @BUILD_SYSROOT_LDFLAGS@ + +# These directories should not be moved to BUILDJDK_OUTPUTDIR +HOTSPOT_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(HOTSPOT_OUTPUTDIR)) +HOTSPOT_DIST := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(HOTSPOT_DIST)) +SUPPORT_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(SUPPORT_OUTPUTDIR)) +JDK_OUTPUTDIR := $(patsubst $(BUILD_OUTPUT)%,$(BUILDJDK_OUTPUTDIR)%,$(JDK_OUTPUTDIR)) + +OPENJDK_BUILD_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@ +OPENJDK_BUILD_CPU_LEGACY_LIB := @OPENJDK_BUILD_CPU_LEGACY_LIB@ +OPENJDK_BUILD_CPU_LIBDIR := @OPENJDK_BUILD_CPU_LIBDIR@ +OPENJDK_TARGET_CPU_LIBDIR := @OPENJDK_BUILD_CPU_LIBDIR@ +OPENJDK_TARGET_CPU := @OPENJDK_BUILD_CPU@ +OPENJDK_TARGET_CPU_ARCH := @OPENJDK_BUILD_CPU_ARCH@ +OPENJDK_TARGET_CPU_BITS := @OPENJDK_BUILD_CPU_BITS@ +OPENJDK_TARGET_CPU_ENDIAN := @OPENJDK_BUILD_CPU_ENDIAN@ +OPENJDK_TARGET_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@ + +CFLAGS_JDKLIB := @OPENJDK_BUILD_CFLAGS_JDKLIB@ +CXXFLAGS_JDKLIB := @OPENJDK_BUILD_CXXFLAGS_JDKLIB@ +LDFLAGS_JDKLIB := @OPENJDK_BUILD_LDFLAGS_JDKLIB@ +CFLAGS_JDKEXE := @OPENJDK_BUILD_CFLAGS_JDKEXE@ +CXXFLAGS_JDKEXE := @OPENJDK_BUILD_CXXFLAGS_JDKEXE@ +LDFLAGS_JDKEXE := @OPENJDK_BUILD_LDFLAGS_JDKEXE@ +OPENJDK_TARGET_CPU_JLI_CFLAGS := @OPENJDK_BUILD_CPU_JLI_CFLAGS@ + +# The compiler for the build platform is likely not warning compatible with the official +# compiler. +WARNINGS_AS_ERRORS := false +DISABLE_WARNING_PREFIX := @BUILD_CC_DISABLE_WARNING_PREFIX@ + +# Save speed and disk space by not enabling debug symbols for the buildjdk +ENABLE_DEBUG_SYMBOLS := false + +#################################################### +# +# Legacy Hotspot support + +# Legacy setting: OPT or DBG +VARIANT := OPT +# Legacy setting: true or false +FASTDEBUG := false +# Legacy setting: debugging the class files? +DEBUG_CLASSFILES := false + +# Some users still set EXTRA_*FLAGS on the make command line. Must +# make sure to override that when building buildjdk. +override EXTRA_CFLAGS := +override EXTRA_CXXFLAGS := +override EXTRA_LDFLAGS := + +# The HOSTCC/HOSTCXX is Hotspot terminology for the BUILD_CC/BUILD_CXX, i.e. the +# compiler that produces code that can be run on the build platform. +HOSTCC := $(BUILD_CC) +HOSTCXX := $(BUILD_CXX) + +# Old name for OPENJDK_TARGET_OS (aix,bsd,hpux,linux,macosx,solaris,windows etc) +PLATFORM := $(OPENJDK_BUILD_OS) +# 32 or 64 bit +ARCH_DATA_MODEL := $(OPENJDK_BUILD_CPU_BITS) + +ALT_BOOTDIR := $(BOOT_JDK) +# Yet another name for arch used for an extra subdir below the jvm lib. +# Uses i386 and amd64, instead of x86 and x86_64. +LIBARCH := @OPENJDK_BUILD_CPU_LEGACY_LIB@ +# Set the cpu architecture. Some users still set ARCH on the make command line. Must +# make sure to override that when building buildjdk. +override ARCH := $(OPENJDK_BUILD_CPU_ARCH) +# Legacy setting for building for a 64 bit machine. +# If yes then this expands to _LP64 := 1 +ifeq ($(OPENJDK_BUILD_CPU_BITS), 64) + _LP64 := 1 +endif + +ALT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR) +ALT_EXPORT_PATH := $(HOTSPOT_DIST) + +JVM_INTERPRETER := @JVM_INTERPRETER@ +ifeq ($(JVM_INTERPRETER), cpp) + CC_INTERP=true +endif + +HOTSPOT_MAKE_ARGS := product docs export_product +# Control wether Hotspot runs Queens test after building +TEST_IN_BUILD := false + +USE_PRECOMPILED_HEADER := @USE_PRECOMPILED_HEADER@ + +# Hotspot expects the variable FULL_DEBUG_SYMBOLS=1/0 to control debug symbols +# creation. +FULL_DEBUG_SYMBOLS := 0 +ZIP_DEBUGINFO_FILES := 0 +# Disable stripping +STRIP_POLICY := none + +JVM_VARIANTS := server +JVM_VARIANT_SERVER := true +JVM_VARIANT_CLIENT := false +JVM_VARIANT_MINIMAL1 := false +JVM_VARIANT_KERNEL := false +JVM_VARIANT_ZERO := false +JVM_VARIANT_ZEROSHARK := false +JVM_VARIANT_CORE := false + +# Sneak this in via the spec.gmk file, since we don't want to mess around too much with the Hotspot make files. +# This is needed to get the LOG setting to work properly. +include $(SRC_ROOT)/make/common/MakeBase.gmk diff --git a/common/autoconf/configure.ac b/common/autoconf/configure.ac index 127d9088555..c7bab7c53a8 100644 --- a/common/autoconf/configure.ac +++ b/common/autoconf/configure.ac @@ -134,6 +134,7 @@ BASIC_SETUP_DEFAULT_MAKE_TARGET # We need build & target for this. JDKOPT_SETUP_JDK_OPTIONS +JDKOPT_SETUP_JLINK_OPTIONS HOTSPOT_SETUP_HOTSPOT_OPTIONS JDKVER_SETUP_JDK_VERSION_NUMBERS @@ -144,6 +145,7 @@ JDKVER_SETUP_JDK_VERSION_NUMBERS ############################################################################### BOOTJDK_SETUP_BOOT_JDK +BOOTJDK_SETUP_BUILD_JDK ############################################################################### # @@ -155,6 +157,8 @@ SRCDIRS_SETUP_TOPDIRS SRCDIRS_SETUP_ALTERNATIVE_TOPDIRS SRCDIRS_SETUP_OUTPUT_DIRS +SRCDIRS_SETUP_IMPORT_MODULES + ############################################################################### # # Setup the toolchain (compilers etc), i.e. tools used to compile and process diff --git a/common/autoconf/flags.m4 b/common/autoconf/flags.m4 index 6b08cbb0a4f..9ea5eaa2a9f 100644 --- a/common/autoconf/flags.m4 +++ b/common/autoconf/flags.m4 @@ -689,9 +689,6 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], ;; esac - # Setup LP64 - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK $ADD_LP64" - # Set some common defines. These works for all compilers, but assume # -D is universally accepted. @@ -722,7 +719,12 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D$OPENJDK_TARGET_OS_UPPERCASE" # Setup target CPU - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY" + OPENJDK_TARGET_CCXXFLAGS_JDK="$OPENJDK_TARGET_CCXXFLAGS_JDK \ + $ADD_LP64 \ + -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY" + OPENJDK_BUILD_CCXXFLAGS_JDK="$OPENJDK_BUILD_CCXXFLAGS_JDK \ + $OPENJDK_BUILD_ADD_LP64 \ + -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY" # Setup debug/release defines if test "x$DEBUG_LEVEL" = xrelease; then @@ -766,17 +768,35 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava" # The shared libraries are compiled using the picflag. - CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" - CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" + CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CFLAGS_JDK $EXTRA_CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" + CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" # Executable flags - CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK" - CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK" + CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CFLAGS_JDK $EXTRA_CFLAGS_JDK" + CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK" + + # The corresponding flags for building for the build platform. This is still an + # approximation, we only need something that runs on this machine when cross + # compiling the product. + OPENJDK_BUILD_CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ + $PICFLAG $CFLAGS_JDKLIB_EXTRA" + OPENJDK_BUILD_CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ + $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" + OPENJDK_BUILD_CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" + OPENJDK_BUILD_CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" AC_SUBST(CFLAGS_JDKLIB) AC_SUBST(CFLAGS_JDKEXE) AC_SUBST(CXXFLAGS_JDKLIB) AC_SUBST(CXXFLAGS_JDKEXE) + AC_SUBST(OPENJDK_BUILD_CFLAGS_JDKLIB) + AC_SUBST(OPENJDK_BUILD_CFLAGS_JDKEXE) + AC_SUBST(OPENJDK_BUILD_CXXFLAGS_JDKLIB) + AC_SUBST(OPENJDK_BUILD_CXXFLAGS_JDKEXE) # Flags for compiling test libraries CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" @@ -872,6 +892,9 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined" fi + OPENJDK_BUILD_LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE}" + LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} ${EXTRA_LDFLAGS_JDK}" + # Customize LDFLAGS for libs LDFLAGS_JDKLIB="${LDFLAGS_JDK}" @@ -882,30 +905,39 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK], JDKLIB_LIBS="" else LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \ - -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}" + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)" # On some platforms (mac) the linker warns about non existing -L dirs. # Add server first if available. Linking aginst client does not always produce the same results. # Only add client dir if client is being built. Add minimal (note not minimal1) if only building minimal1. # Default to server for other variants. if test "x$JVM_VARIANT_SERVER" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" elif test "x$JVM_VARIANT_CLIENT" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/client" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client" elif test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/minimal" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal" else - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi JDKLIB_LIBS="-ljava -ljvm" if test "x$TOOLCHAIN_TYPE" = xsolstudio; then JDKLIB_LIBS="$JDKLIB_LIBS -lc" fi + + # When building a buildjdk, it's always only the server variant + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_JDKLIB}" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${EXTRA_LDFLAGS_JDK}" + AC_SUBST(LDFLAGS_JDKLIB) AC_SUBST(LDFLAGS_JDKEXE) + AC_SUBST(OPENJDK_BUILD_LDFLAGS_JDKLIB) + AC_SUBST(OPENJDK_BUILD_LDFLAGS_JDKEXE) AC_SUBST(JDKLIB_LIBS) AC_SUBST(JDKEXE_LIBS) AC_SUBST(LDFLAGS_CXX_JDK) @@ -1075,5 +1107,6 @@ AC_DEFUN_ONCE([FLAGS_SETUP_COMPILER_FLAGS_MISC], ;; esac AC_SUBST(DISABLE_WARNING_PREFIX) + AC_SUBST(BUILD_CC_DISABLE_WARNING_PREFIX) AC_SUBST(CFLAGS_WARNINGS_ARE_ERRORS) ]) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 7a9d7900667..e4ea273f57f 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -694,6 +694,7 @@ ZIP_EXTERNAL_DEBUG_SYMBOLS COPY_DEBUG_SYMBOLS COMPILE_WITH_DEBUG_SYMBOLS CFLAGS_WARNINGS_ARE_ERRORS +BUILD_CC_DISABLE_WARNING_PREFIX DISABLE_WARNING_PREFIX HOTSPOT_SET_WARNINGS_AS_ERRORS WARNINGS_AS_ERRORS @@ -705,12 +706,18 @@ LDFLAGS_HASH_STYLE LDFLAGS_CXX_JDK JDKEXE_LIBS JDKLIB_LIBS +OPENJDK_BUILD_LDFLAGS_JDKEXE +OPENJDK_BUILD_LDFLAGS_JDKLIB LDFLAGS_JDKEXE LDFLAGS_JDKLIB CXXFLAGS_TESTEXE CXXFLAGS_TESTLIB CFLAGS_TESTEXE CFLAGS_TESTLIB +OPENJDK_BUILD_CXXFLAGS_JDKEXE +OPENJDK_BUILD_CXXFLAGS_JDKLIB +OPENJDK_BUILD_CFLAGS_JDKEXE +OPENJDK_BUILD_CFLAGS_JDKLIB CXXFLAGS_JDKEXE CXXFLAGS_JDKLIB CFLAGS_JDKEXE @@ -759,6 +766,8 @@ HOTSPOT_MT BUILD_AS BUILD_LDCXX BUILD_LD +BUILD_STRIP +BUILD_OBJCOPY BUILD_AR BUILD_NM BUILD_CXX @@ -821,6 +830,12 @@ SHARED_LIBRARY_SUFFIX LIBRARY_PREFIX TOOLCHAIN_TYPE STATIC_BUILD +IMPORT_MODULES_MAKE +IMPORT_MODULES_SRC +IMPORT_MODULES_CONF +IMPORT_MODULES_LIBS +IMPORT_MODULES_CMDS +IMPORT_MODULES_CLASSES BUILD_HOTSPOT HOTSPOT_DIST BUILD_OUTPUT @@ -831,8 +846,11 @@ JAXWS_TOPDIR JAXP_TOPDIR CORBA_TOPDIR LANGTOOLS_TOPDIR +BUILD_JDK +CREATE_BUILDJDK BOOT_JDK_BITS JAVAC_FLAGS +BOOT_JDK_MODULAR BOOT_JDK_SOURCETARGET JARSIGNER JAR @@ -862,6 +880,7 @@ PRODUCT_SUFFIX PRODUCT_NAME LAUNCHER_NAME TEST_IN_BUILD +JLINK_KEEP_PACKAGED_MODULES COPYRIGHT_YEAR COMPRESS_JARS INCLUDE_SA @@ -930,9 +949,13 @@ ZERO_ARCHDEF DEFINE_CROSS_COMPILE_ARCH LP64 OPENJDK_TARGET_OS_EXPORT_DIR +OPENJDK_BUILD_CPU_JLI_CFLAGS OPENJDK_TARGET_CPU_JLI_CFLAGS OPENJDK_TARGET_CPU_OSARCH OPENJDK_TARGET_CPU_ISADIR +OPENJDK_BUILD_CPU_LIBDIR +OPENJDK_BUILD_CPU_LEGACY_LIB +OPENJDK_BUILD_CPU_LEGACY OPENJDK_TARGET_CPU_LIBDIR OPENJDK_TARGET_CPU_LEGACY_LIB OPENJDK_TARGET_CPU_LEGACY @@ -1080,6 +1103,7 @@ enable_headful with_cacerts_file enable_unlimited_crypto with_copyright_year +enable_keep_packaged_modules enable_hotspot_test_in_build with_milestone with_update_version @@ -1094,6 +1118,7 @@ with_version_minor with_version_security with_version_patch with_boot_jdk +with_build_jdk with_add_source_root with_override_source_root with_adds_and_overrides @@ -1105,6 +1130,7 @@ with_override_hotspot with_override_nashorn with_override_jdk with_import_hotspot +with_import_modules enable_static_build with_toolchain_type with_extra_cflags @@ -1248,6 +1274,8 @@ BUILD_CC BUILD_CXX BUILD_NM BUILD_AR +BUILD_OBJCOPY +BUILD_STRIP JTREGEXE XMKMF FREETYPE_CFLAGS @@ -1890,6 +1918,8 @@ Optional Features: support) [enabled] --enable-unlimited-crypto Enable unlimited crypto policy [disabled] + --disable-keep-packaged-modules + Do not keep packaged modules in jdk image [enable] --enable-hotspot-test-in-build run the Queens test after Hotspot build [disabled] --enable-static-build enable static library build [disabled] @@ -1973,6 +2003,8 @@ Optional Packages: --with-version-patch Set version 'PATCH' field (fourth number) [not specified] --with-boot-jdk path to Boot JDK (used to bootstrap build) [probed] + --with-build-jdk path to JDK of same version as is being built[the + newly built JDK] --with-add-source-root Deprecated. Option is kept for backwards compatibility and is ignored --with-override-source-root @@ -1999,6 +2031,8 @@ Optional Packages: --with-import-hotspot import hotspot binaries from this jdk image or hotspot build dist dir instead of building from source + --with-import-modules import a set of prebuilt modules either as a zip + file or an exploded directory --with-toolchain-type the toolchain type (or family) to use, use '--help' to show possible values [platform dependent] --with-extra-cflags extra flags to be used when compiling jdk c-files @@ -2167,6 +2201,9 @@ Some influential environment variables: BUILD_CXX Override default value for BUILD_CXX BUILD_NM Override default value for BUILD_NM BUILD_AR Override default value for BUILD_AR + BUILD_OBJCOPY + Override default value for BUILD_OBJCOPY + BUILD_STRIP Override default value for BUILD_STRIP JTREGEXE Override default value for JTREGEXE XMKMF Path to xmkmf, Makefile generator for X Window System FREETYPE_CFLAGS @@ -3777,6 +3814,23 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. +# BUILD_JDK: the location of the latest JDK that can run +# on the host system and supports the target class file version +# generated in this JDK build. This variable should only be +# used after the launchers are built. +# + +# Execute the check given as argument, and verify the result. +# If the JDK was previously found, do nothing. +# $1 A command line (typically autoconf macro) to execute + + +# By default the BUILD_JDK is the JDK_OUTPUTDIR. If the target architecture +# is different than the host system doing the build (e.g. cross-compilation), +# a special BUILD_JDK is built as part of the build process. An external +# prebuilt BUILD_JDK can also be supplied. + + # # Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4005,7 +4059,7 @@ apt_help() { devkit) PKGHANDLER_COMMAND="sudo apt-get install build-essential" ;; openjdk) - PKGHANDLER_COMMAND="sudo apt-get install openjdk-7-jdk" ;; + PKGHANDLER_COMMAND="sudo apt-get install openjdk-8-jdk" ;; alsa) PKGHANDLER_COMMAND="sudo apt-get install libasound2-dev" ;; cups) @@ -4026,7 +4080,7 @@ yum_help() { devkit) PKGHANDLER_COMMAND="sudo yum groupinstall \"Development Tools\"" ;; openjdk) - PKGHANDLER_COMMAND="sudo yum install java-1.7.0-openjdk" ;; + PKGHANDLER_COMMAND="sudo yum install java-1.8.0-openjdk-devel" ;; alsa) PKGHANDLER_COMMAND="sudo yum install alsa-lib-devel" ;; cups) @@ -4192,6 +4246,13 @@ pkgadd_help() { # +################################################################################ +# +# jlink options. +# We always keep packaged modules in JDK image. +# + + # # Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4628,6 +4689,12 @@ pkgadd_help() { +################################################################################ +# Define a mechanism for importing extra prebuilt modules +# + + + # # Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -4862,7 +4929,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=1456136781 +DATE_WHEN_GENERATED=1458008154 ############################################################################### # @@ -15118,6 +15185,10 @@ $as_echo "$COMPILE_TYPE" >&6; } REQUIRED_OS_NAME=Darwin REQUIRED_OS_VERSION=11.2 fi + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + REQUIRED_OS_NAME=AIX + REQUIRED_OS_VERSION=7.1 + fi @@ -15153,6 +15224,37 @@ $as_echo "$COMPILE_TYPE" >&6; } fi + # Now do the same for OPENJDK_BUILD_CPU... + # Also store the legacy naming of the cpu. + # Ie i586 and amd64 instead of x86 and x86_64 + OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_LEGACY="i586" + elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then + # On all platforms except MacOSX replace x86_64 with amd64. + OPENJDK_BUILD_CPU_LEGACY="amd64" + fi + + + # And the second legacy naming of the cpu. + # Ie i386 and amd64 instead of x86 and x86_64. + OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_LEGACY_LIB="i386" + elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then + OPENJDK_BUILD_CPU_LEGACY_LIB="amd64" + fi + + + # This is the name of the cpu (but using i386 and amd64 instead of + # x86 and x86_64, respectively), preceeded by a /, to be used when + # locating libraries. On macosx, it's empty, though. + OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB" + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_CPU_LIBDIR="" + fi + + # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to # /amd64 or /sparcv9. This string is appended to some library paths, like this: # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so @@ -15195,6 +15297,24 @@ $as_echo "$COMPILE_TYPE" >&6; } fi + OPENJDK_BUILD_CPU_JLI="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_JLI="i386" + elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then + # On all platforms except macosx, we replace x86_64 with amd64. + OPENJDK_BUILD_CPU_JLI="amd64" + fi + # Now setup the -D flags for building libjli. + OPENJDK_BUILD_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_BUILD_CPU_JLI\"'" + if test "x$OPENJDK_BUILD_OS" = xsolaris; then + if test "x$OPENJDK_BUILD_CPU_ARCH" = xsparc; then + OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'" + elif test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then + OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'" + fi + fi + + if test "x$OPENJDK_TARGET_OS" = xmacosx; then OPENJDK_TARGET_OS_EXPORT_DIR=macosx else @@ -15212,6 +15332,11 @@ $as_echo "$COMPILE_TYPE" >&6; } fi LP64=$A_LP64 + if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then + if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_ADD_LP64="-D_LP64=1" + fi + fi if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? @@ -16697,6 +16822,9 @@ $as_echo "$as_me: The path of OUTPUT_ROOT, which resolves as \"$path\", is inval # The bootcycle-spec.gmk file contains support for boot cycle builds. ac_config_files="$ac_config_files $OUTPUT_ROOT/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in" + # The buildjdk-spec.gmk file contains support for building a buildjdk when cross compiling. + ac_config_files="$ac_config_files $OUTPUT_ROOT/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in" + # The compare.sh is used to compare the build output to other builds. ac_config_files="$ac_config_files $OUTPUT_ROOT/compare.sh:$AUTOCONF_DIR/compare.sh.in" @@ -23295,6 +23423,35 @@ fi + # Check whether --enable-keep-packaged-modules was given. +if test "${enable_keep_packaged_modules+set}" = set; then : + enableval=$enable_keep_packaged_modules; +fi + + + if test "x$enable_keep_packaged_modules" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5 +$as_echo_n "checking if packaged modules are kept... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + JLINK_KEEP_PACKAGED_MODULES=true + elif test "x$enable_keep_packaged_modules" = "xno"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if packaged modules are kept" >&5 +$as_echo_n "checking if packaged modules are kept... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + JLINK_KEEP_PACKAGED_MODULES=false + elif test "x$enable_keep_packaged_modules" = "x"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (default)" >&5 +$as_echo "yes (default)" >&6; } + JLINK_KEEP_PACKAGED_MODULES=true + else + as_fn_error $? "--enable-keep-packaged-modules accepts no argument" "$LINENO" 5 + fi + + + + # Control wether Hotspot runs Queens test after build. # Check whether --enable-hotspot-test-in-build was given. if test "${enable_hotspot_test_in_build+set}" = set; then : @@ -29592,6 +29749,35 @@ $as_echo "$tool_specified" >&6; } + $ECHO "Check if jvm arg is ok: -Xpatch:" >&5 + $ECHO "Command: $JAVA -Xpatch: -version" >&5 + OUTPUT=`$JAVA -Xpatch: -version 2>&1` + FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn` + FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""` + if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then + dummy="$dummy -Xpatch:" + JVM_ARG_OK=true + else + $ECHO "Arg failed:" >&5 + $ECHO "$OUTPUT" >&5 + JVM_ARG_OK=false + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if Boot JDK supports modules" >&5 +$as_echo_n "checking if Boot JDK supports modules... " >&6; } + if test "x$JVM_ARG_OK" = "xtrue"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + BOOT_JDK_MODULAR="true" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + BOOT_JDK_MODULAR="false" + fi + + + + # Check if the boot jdk is 32 or 64 bit if "$JAVA" -d64 -version > /dev/null 2>&1; then BOOT_JDK_BITS="64" @@ -29605,6 +29791,237 @@ $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; +fi + + + CREATE_BUILDJDK_FOR_HOST=false + BUILD_JDK_FOUND="no" + if test "x$with_build_jdk" != "x"; then + + if test "x$BUILD_JDK_FOUND" = xno; then + # Execute the test + + if test "x$with_build_jdk" != x; then + BUILD_JDK=$with_build_jdk + BUILD_JDK_FOUND=maybe + { $as_echo "$as_me:${as_lineno-$LINENO}: Found potential Build JDK using configure arguments" >&5 +$as_echo "$as_me: Found potential Build JDK using configure arguments" >&6;} + fi + + # If previous step claimed to have found a JDK, check it to see if it seems to be valid. + if test "x$BUILD_JDK_FOUND" = xmaybe; then + # Do we have a bin/java? + if test ! -x "$BUILD_JDK/bin/java"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK did not contain bin/java; ignoring" >&5 +$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK did not contain bin/java; ignoring" >&6;} + BUILD_JDK_FOUND=no + elif test ! -x "$BUILD_JDK/bin/jlink"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK did not contain bin/jlink; ignoring" >&5 +$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK did not contain bin/jlink; ignoring" >&6;} + BUILD_JDK_FOUND=no + elif test ! -x "$BUILD_JDK/bin/javac"; then + # Do we have a bin/javac? + { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Build JDK found at $BUILD_JDK did not contain bin/javac; ignoring" >&5 +$as_echo "$as_me: Potential Build JDK found at $BUILD_JDK did not contain bin/javac; ignoring" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: (This might be a JRE instead of an JDK)" >&5 +$as_echo "$as_me: (This might be a JRE instead of an JDK)" >&6;} + BUILD_JDK_FOUND=no + else + # Oh, this is looking good! We probably have found a proper JDK. Is it the correct version? + BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | head -n 1` + + # Extra M4 quote needed to protect [] in grep expression. + FOUND_CORRECT_VERSION=`echo $BUILD_JDK_VERSION | grep '\"1\.[9]\.'` + if test "x$FOUND_CORRECT_VERSION" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&5 +$as_echo "$as_me: Potential Boot JDK found at $BUILD_JDK is incorrect JDK version ($BUILD_JDK_VERSION); ignoring" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: (Your Build JDK must be version 9)" >&5 +$as_echo "$as_me: (Your Build JDK must be version 9)" >&6;} + BUILD_JDK_FOUND=no + else + # We're done! + BUILD_JDK_FOUND=yes + + # Only process if variable expands to non-empty + + if test "x$BUILD_JDK" != x; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$BUILD_JDK" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of BUILD_JDK" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-style (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + BUILD_JDK="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_JDK to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting BUILD_JDK to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$BUILD_JDK" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + BUILD_JDK="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_JDK to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting BUILD_JDK to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a unix platform. Hooray! :) + path="$BUILD_JDK" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of BUILD_JDK, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of BUILD_JDK, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + if test -d "$path"; then + BUILD_JDK="`cd "$path"; $THEPWDCMD -L`" + else + dir="`$DIRNAME "$path"`" + base="`$BASENAME "$path"`" + BUILD_JDK="`cd "$dir"; $THEPWDCMD -L`/$base" + fi + fi + fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5 +$as_echo_n "checking for Build JDK... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_JDK" >&5 +$as_echo "$BUILD_JDK" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking Build JDK version" >&5 +$as_echo_n "checking Build JDK version... " >&6; } + BUILD_JDK_VERSION=`"$BUILD_JDK/bin/java" -version 2>&1 | $TR '\n\r' ' '` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_JDK_VERSION" >&5 +$as_echo "$BUILD_JDK_VERSION" >&6; } + fi # end check jdk version + fi # end check java + fi # end check build jdk found + fi + + else + if test "x$COMPILE_TYPE" = "xcross"; then + BUILD_JDK="\$(BUILDJDK_OUTPUTDIR)/jdk" + BUILD_JDK_FOUND=yes + CREATE_BUILDJDK=true + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5 +$as_echo_n "checking for Build JDK... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, will build it for the host platform" >&5 +$as_echo "yes, will build it for the host platform" >&6; } + else + BUILD_JDK="\$(JDK_OUTPUTDIR)" + BUILD_JDK_FOUND=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5 +$as_echo_n "checking for Build JDK... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes, will use output dir" >&5 +$as_echo "yes, will use output dir" >&6; } + fi + fi + + if test "x$BUILD_JDK_FOUND" != "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Build JDK" >&5 +$as_echo_n "checking for Build JDK... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "Could not find a suitable Build JDK" "$LINENO" 5 + fi + + + + + ############################################################################### # # Configure the sources to use. We can add or override individual directories. @@ -29754,6 +30171,189 @@ $as_echo "yes from $HOTSPOT_DIST" >&6; } JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk" + + +# Check whether --with-import-modules was given. +if test "${with_import_modules+set}" = set; then : + withval=$with_import_modules; +fi + + + if test "x$with_import_modules" != x \ + && test "x$with_import_modules" != "xno"; then + if test -d "$with_import_modules"; then + IMPORT_MODULES_TOPDIR="$with_import_modules" + + # Only process if variable expands to non-empty + + if test "x$IMPORT_MODULES_TOPDIR" != x; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # Input might be given as Windows format, start by converting to + # unix format. + path="$IMPORT_MODULES_TOPDIR" + new_path=`$CYGPATH -u "$path"` + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file precense. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Cannot locate the the path of IMPORT_MODULES_TOPDIR" "$LINENO" 5 + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-style (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + + if test "x$path" != "x$new_path"; then + IMPORT_MODULES_TOPDIR="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&6;} + fi + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + path="$IMPORT_MODULES_TOPDIR" + has_colon=`$ECHO $path | $GREP ^.:` + new_path="$path" + if test "x$has_colon" = x; then + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $path` + fi + + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + if test "x$path" != "x$new_path"; then + IMPORT_MODULES_TOPDIR="$new_path" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&5 +$as_echo "$as_me: Rewriting IMPORT_MODULES_TOPDIR to \"$new_path\"" >&6;} + fi + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + + else + # We're on a unix platform. Hooray! :) + path="$IMPORT_MODULES_TOPDIR" + has_space=`$ECHO "$path" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&5 +$as_echo "$as_me: The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is invalid." >&6;} + as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5 + fi + + # Use eval to expand a potential ~ + eval path="$path" + if test ! -f "$path" && test ! -d "$path"; then + as_fn_error $? "The path of IMPORT_MODULES_TOPDIR, which resolves as \"$path\", is not found." "$LINENO" 5 + fi + + if test -d "$path"; then + IMPORT_MODULES_TOPDIR="`cd "$path"; $THEPWDCMD -L`" + else + dir="`$DIRNAME "$path"`" + base="`$BASENAME "$path"`" + IMPORT_MODULES_TOPDIR="`cd "$dir"; $THEPWDCMD -L`/$base" + fi + fi + fi + + elif test -e "$with_import_modules"; then + IMPORT_MODULES_TOPDIR="$CONFIGURESUPPORT_OUTPUTDIR/import-modules" + $RM -rf "$IMPORT_MODULES_TOPDIR" + $MKDIR -p "$IMPORT_MODULES_TOPDIR" + if ! $UNZIP -q "$with_import_modules" -d "$IMPORT_MODULES_TOPDIR"; then + as_fn_error $? "--with-import-modules=\"$with_import_modules\" must point to a dir or a zip file" "$LINENO" 5 + fi + else + as_fn_error $? "--with-import-modules=\"$with_import_modules\" must point to a dir or a zip file" "$LINENO" 5 + fi + fi + + if test -d "$IMPORT_MODULES_TOPDIR/modules"; then + IMPORT_MODULES_CLASSES="$IMPORT_MODULES_TOPDIR/modules" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_cmds"; then + IMPORT_MODULES_CMDS="$IMPORT_MODULES_TOPDIR/modules_cmds" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_libs"; then + IMPORT_MODULES_LIBS="$IMPORT_MODULES_TOPDIR/modules_libs" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_conf"; then + IMPORT_MODULES_CONF="$IMPORT_MODULES_TOPDIR/modules_conf" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then + IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src" + fi + if test -d "$IMPORT_MODULES_TOPDIR/make"; then + IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make" + fi + + + + + + + + + ############################################################################### # # Setup the toolchain (compilers etc), i.e. tools used to compile and process @@ -44510,6 +45110,972 @@ $as_echo "$as_me: Rewriting BUILD_AR to \"$new_complete\"" >&6;} fi fi + + + # Publish this variable in the help. + + + if [ -z "${BUILD_OBJCOPY+x}" ]; then + # The variable is not set by user, try to locate tool using the code snippet + for ac_prog in objcopy +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUILD_OBJCOPY+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUILD_OBJCOPY in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUILD_OBJCOPY="$BUILD_OBJCOPY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUILD_OBJCOPY="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUILD_OBJCOPY=$ac_cv_path_BUILD_OBJCOPY +if test -n "$BUILD_OBJCOPY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_OBJCOPY" >&5 +$as_echo "$BUILD_OBJCOPY" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$BUILD_OBJCOPY" && break +done + + else + # The variable is set, but is it from the command line or the environment? + + # Try to remove the string !BUILD_OBJCOPY! from our list. + try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!BUILD_OBJCOPY!/} + if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then + # If it failed, the variable was not from the command line. Ignore it, + # but warn the user (except for BASH, which is always set by the calling BASH). + if test "xBUILD_OBJCOPY" != xBASH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of BUILD_OBJCOPY from the environment. Use command line variables instead." >&5 +$as_echo "$as_me: WARNING: Ignoring value of BUILD_OBJCOPY from the environment. Use command line variables instead." >&2;} + fi + # Try to locate tool using the code snippet + for ac_prog in objcopy +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUILD_OBJCOPY+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUILD_OBJCOPY in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUILD_OBJCOPY="$BUILD_OBJCOPY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUILD_OBJCOPY="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUILD_OBJCOPY=$ac_cv_path_BUILD_OBJCOPY +if test -n "$BUILD_OBJCOPY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_OBJCOPY" >&5 +$as_echo "$BUILD_OBJCOPY" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$BUILD_OBJCOPY" && break +done + + else + # If it succeeded, then it was overridden by the user. We will use it + # for the tool. + + # First remove it from the list of overridden variables, so we can test + # for unknown variables in the end. + CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" + + # Check if we try to supply an empty value + if test "x$BUILD_OBJCOPY" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool BUILD_OBJCOPY= (no value)" >&5 +$as_echo "$as_me: Setting user supplied tool BUILD_OBJCOPY= (no value)" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_OBJCOPY" >&5 +$as_echo_n "checking for BUILD_OBJCOPY... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } + else + # Check if the provided tool contains a complete path. + tool_specified="$BUILD_OBJCOPY" + tool_basename="${tool_specified##*/}" + if test "x$tool_basename" = "x$tool_specified"; then + # A command without a complete path is provided, search $PATH. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool BUILD_OBJCOPY=$tool_basename" >&5 +$as_echo "$as_me: Will search for user supplied tool BUILD_OBJCOPY=$tool_basename" >&6;} + # Extract the first word of "$tool_basename", so it can be a program name with args. +set dummy $tool_basename; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUILD_OBJCOPY+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUILD_OBJCOPY in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUILD_OBJCOPY="$BUILD_OBJCOPY" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUILD_OBJCOPY="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUILD_OBJCOPY=$ac_cv_path_BUILD_OBJCOPY +if test -n "$BUILD_OBJCOPY"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_OBJCOPY" >&5 +$as_echo "$BUILD_OBJCOPY" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$BUILD_OBJCOPY" = x; then + as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 + fi + else + # Otherwise we believe it is a complete path. Use it as it is. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool BUILD_OBJCOPY=$tool_specified" >&5 +$as_echo "$as_me: Will use user supplied tool BUILD_OBJCOPY=$tool_specified" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_OBJCOPY" >&5 +$as_echo_n "checking for BUILD_OBJCOPY... " >&6; } + if test ! -x "$tool_specified"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + as_fn_error $? "User supplied tool BUILD_OBJCOPY=$tool_specified does not exist or is not executable" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 +$as_echo "$tool_specified" >&6; } + fi + fi + fi + + fi + + + + # Only process if variable expands to non-empty + + if test "x$BUILD_OBJCOPY" != x; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # First separate the path from the arguments. This will split at the first + # space. + complete="$BUILD_OBJCOPY" + path="${complete%% *}" + tmp="$complete EOL" + arguments="${tmp#* }" + + # Input might be given as Windows format, start by converting to + # unix format. + new_path=`$CYGPATH -u "$path"` + + # Now try to locate executable using which + new_path=`$WHICH "$new_path" 2> /dev/null` + # bat and cmd files are not always considered executable in cygwin causing which + # to not find them + if test "x$new_path" = x \ + && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ + && test "x`$LS \"$path\" 2>/dev/null`" != x; then + new_path=`$CYGPATH -u "$path"` + fi + if test "x$new_path" = x; then + # Oops. Which didn't find the executable. + # The splitting of arguments from the executable at a space might have been incorrect, + # since paths with space are more likely in Windows. Give it another try with the whole + # argument. + path="$complete" + arguments="EOL" + new_path=`$CYGPATH -u "$path"` + new_path=`$WHICH "$new_path" 2> /dev/null` + # bat and cmd files are not always considered executable in cygwin causing which + # to not find them + if test "x$new_path" = x \ + && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ + && test "x`$LS \"$path\" 2>/dev/null`" != x; then + new_path=`$CYGPATH -u "$path"` + fi + if test "x$new_path" = x; then + # It's still not found. Now this is an unrecoverable error. + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&5 +$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&6;} + has_space=`$ECHO "$complete" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 +$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} + fi + as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5 + fi + fi + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file presence. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + # Short path failed, file does not exist as specified. + # Try adding .exe or .cmd + if test -f "${new_path}.exe"; then + input_to_shortpath="${new_path}.exe" + elif test -f "${new_path}.cmd"; then + input_to_shortpath="${new_path}.cmd" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$new_path\", is invalid." >&5 +$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$new_path\", is invalid." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5 +$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;} + as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5 + fi + else + input_to_shortpath="$new_path" + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + new_path="$input_to_shortpath" + + input_path="$input_to_shortpath" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-style (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + # remove trailing .exe if any + new_path="${new_path/%.exe/}" + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + # First separate the path from the arguments. This will split at the first + # space. + complete="$BUILD_OBJCOPY" + path="${complete%% *}" + tmp="$complete EOL" + arguments="${tmp#* }" + + # Input might be given as Windows format, start by converting to + # unix format. + new_path="$path" + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + + # Now try to locate executable using which + new_path=`$WHICH "$new_path" 2> /dev/null` + + if test "x$new_path" = x; then + # Oops. Which didn't find the executable. + # The splitting of arguments from the executable at a space might have been incorrect, + # since paths with space are more likely in Windows. Give it another try with the whole + # argument. + path="$complete" + arguments="EOL" + new_path="$path" + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + + new_path=`$WHICH "$new_path" 2> /dev/null` + # bat and cmd files are not always considered executable in MSYS causing which + # to not find them + if test "x$new_path" = x \ + && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ + && test "x`$LS \"$path\" 2>/dev/null`" != x; then + new_path="$path" + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + fi + + if test "x$new_path" = x; then + # It's still not found. Now this is an unrecoverable error. + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&5 +$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&6;} + has_space=`$ECHO "$complete" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 +$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} + fi + as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5 + fi + fi + + # Now new_path has a complete unix path to the binary + if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then + # Keep paths in /bin as-is, but remove trailing .exe if any + new_path="${new_path/%.exe/}" + # Do not save /bin paths to all_fixpath_prefixes! + else + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $new_path` + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + # Output is in $new_path + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + # remove trailing .exe if any + new_path="${new_path/%.exe/}" + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + fi + + else + # We're on a unix platform. Hooray! :) + # First separate the path from the arguments. This will split at the first + # space. + complete="$BUILD_OBJCOPY" + path="${complete%% *}" + tmp="$complete EOL" + arguments="${tmp#* }" + + # Cannot rely on the command "which" here since it doesn't always work. + is_absolute_path=`$ECHO "$path" | $GREP ^/` + if test -z "$is_absolute_path"; then + # Path to executable is not absolute. Find it. + IFS_save="$IFS" + IFS=: + for p in $PATH; do + if test -f "$p/$path" && test -x "$p/$path"; then + new_path="$p/$path" + break + fi + done + IFS="$IFS_save" + else + # This is an absolute path, we can use it without further modifications. + new_path="$path" + fi + + if test "x$new_path" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&5 +$as_echo "$as_me: The path of BUILD_OBJCOPY, which resolves as \"$complete\", is not found." >&6;} + has_space=`$ECHO "$complete" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5 +$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;} + fi + as_fn_error $? "Cannot locate the the path of BUILD_OBJCOPY" "$LINENO" 5 + fi + fi + + # Now join together the path and the arguments once again + if test "x$arguments" != xEOL; then + new_complete="$new_path ${arguments% *}" + else + new_complete="$new_path" + fi + + if test "x$complete" != "x$new_complete"; then + BUILD_OBJCOPY="$new_complete" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_OBJCOPY to \"$new_complete\"" >&5 +$as_echo "$as_me: Rewriting BUILD_OBJCOPY to \"$new_complete\"" >&6;} + fi + fi + + + + # Publish this variable in the help. + + + if [ -z "${BUILD_STRIP+x}" ]; then + # The variable is not set by user, try to locate tool using the code snippet + for ac_prog in strip +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUILD_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUILD_STRIP in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUILD_STRIP="$BUILD_STRIP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUILD_STRIP="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUILD_STRIP=$ac_cv_path_BUILD_STRIP +if test -n "$BUILD_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_STRIP" >&5 +$as_echo "$BUILD_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$BUILD_STRIP" && break +done + + else + # The variable is set, but is it from the command line or the environment? + + # Try to remove the string !BUILD_STRIP! from our list. + try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!BUILD_STRIP!/} + if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then + # If it failed, the variable was not from the command line. Ignore it, + # but warn the user (except for BASH, which is always set by the calling BASH). + if test "xBUILD_STRIP" != xBASH; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of BUILD_STRIP from the environment. Use command line variables instead." >&5 +$as_echo "$as_me: WARNING: Ignoring value of BUILD_STRIP from the environment. Use command line variables instead." >&2;} + fi + # Try to locate tool using the code snippet + for ac_prog in strip +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUILD_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUILD_STRIP in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUILD_STRIP="$BUILD_STRIP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUILD_STRIP="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUILD_STRIP=$ac_cv_path_BUILD_STRIP +if test -n "$BUILD_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_STRIP" >&5 +$as_echo "$BUILD_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$BUILD_STRIP" && break +done + + else + # If it succeeded, then it was overridden by the user. We will use it + # for the tool. + + # First remove it from the list of overridden variables, so we can test + # for unknown variables in the end. + CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var" + + # Check if we try to supply an empty value + if test "x$BUILD_STRIP" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool BUILD_STRIP= (no value)" >&5 +$as_echo "$as_me: Setting user supplied tool BUILD_STRIP= (no value)" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_STRIP" >&5 +$as_echo_n "checking for BUILD_STRIP... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5 +$as_echo "disabled" >&6; } + else + # Check if the provided tool contains a complete path. + tool_specified="$BUILD_STRIP" + tool_basename="${tool_specified##*/}" + if test "x$tool_basename" = "x$tool_specified"; then + # A command without a complete path is provided, search $PATH. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool BUILD_STRIP=$tool_basename" >&5 +$as_echo "$as_me: Will search for user supplied tool BUILD_STRIP=$tool_basename" >&6;} + # Extract the first word of "$tool_basename", so it can be a program name with args. +set dummy $tool_basename; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_BUILD_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $BUILD_STRIP in + [\\/]* | ?:[\\/]*) + ac_cv_path_BUILD_STRIP="$BUILD_STRIP" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_BUILD_STRIP="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +BUILD_STRIP=$ac_cv_path_BUILD_STRIP +if test -n "$BUILD_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUILD_STRIP" >&5 +$as_echo "$BUILD_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "x$BUILD_STRIP" = x; then + as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5 + fi + else + # Otherwise we believe it is a complete path. Use it as it is. + { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool BUILD_STRIP=$tool_specified" >&5 +$as_echo "$as_me: Will use user supplied tool BUILD_STRIP=$tool_specified" >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BUILD_STRIP" >&5 +$as_echo_n "checking for BUILD_STRIP... " >&6; } + if test ! -x "$tool_specified"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5 +$as_echo "not found" >&6; } + as_fn_error $? "User supplied tool BUILD_STRIP=$tool_specified does not exist or is not executable" "$LINENO" 5 + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5 +$as_echo "$tool_specified" >&6; } + fi + fi + fi + + fi + + + + # Only process if variable expands to non-empty + + if test "x$BUILD_STRIP" != x; then + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + + # First separate the path from the arguments. This will split at the first + # space. + complete="$BUILD_STRIP" + path="${complete%% *}" + tmp="$complete EOL" + arguments="${tmp#* }" + + # Input might be given as Windows format, start by converting to + # unix format. + new_path=`$CYGPATH -u "$path"` + + # Now try to locate executable using which + new_path=`$WHICH "$new_path" 2> /dev/null` + # bat and cmd files are not always considered executable in cygwin causing which + # to not find them + if test "x$new_path" = x \ + && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ + && test "x`$LS \"$path\" 2>/dev/null`" != x; then + new_path=`$CYGPATH -u "$path"` + fi + if test "x$new_path" = x; then + # Oops. Which didn't find the executable. + # The splitting of arguments from the executable at a space might have been incorrect, + # since paths with space are more likely in Windows. Give it another try with the whole + # argument. + path="$complete" + arguments="EOL" + new_path=`$CYGPATH -u "$path"` + new_path=`$WHICH "$new_path" 2> /dev/null` + # bat and cmd files are not always considered executable in cygwin causing which + # to not find them + if test "x$new_path" = x \ + && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ + && test "x`$LS \"$path\" 2>/dev/null`" != x; then + new_path=`$CYGPATH -u "$path"` + fi + if test "x$new_path" = x; then + # It's still not found. Now this is an unrecoverable error. + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&5 +$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&6;} + has_space=`$ECHO "$complete" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 +$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} + fi + as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5 + fi + fi + + # Cygwin tries to hide some aspects of the Windows file system, such that binaries are + # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered + # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then + # "foo.exe" is OK but "foo" is an error. + # + # This test is therefore slightly more accurate than "test -f" to check for file presence. + # It is also a way to make sure we got the proper file name for the real test later on. + test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null` + if test "x$test_shortpath" = x; then + # Short path failed, file does not exist as specified. + # Try adding .exe or .cmd + if test -f "${new_path}.exe"; then + input_to_shortpath="${new_path}.exe" + elif test -f "${new_path}.cmd"; then + input_to_shortpath="${new_path}.cmd" + else + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$new_path\", is invalid." >&5 +$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$new_path\", is invalid." >&6;} + { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5 +$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;} + as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5 + fi + else + input_to_shortpath="$new_path" + fi + + # Call helper function which possibly converts this using DOS-style short mode. + # If so, the updated path is stored in $new_path. + new_path="$input_to_shortpath" + + input_path="$input_to_shortpath" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + shortmode_path=`$CYGPATH -s -m -a "$input_path"` + path_after_shortmode=`$CYGPATH -u "$shortmode_path"` + if test "x$path_after_shortmode" != "x$input_to_shortpath"; then + # Going to short mode and back again did indeed matter. Since short mode is + # case insensitive, let's make it lowercase to improve readability. + shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Now convert it back to Unix-style (cygpath) + input_path=`$CYGPATH -u "$shortmode_path"` + new_path="$input_path" + fi + fi + + test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/` + if test "x$test_cygdrive_prefix" = x; then + # As a simple fix, exclude /usr/bin since it's not a real path. + if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then + # The path is in a Cygwin special directory (e.g. /home). We need this converted to + # a path prefixed by /cygdrive for fixpath to work. + new_path="$CYGWIN_ROOT_PATH$input_path" + fi + fi + + # remove trailing .exe if any + new_path="${new_path/%.exe/}" + + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + + # First separate the path from the arguments. This will split at the first + # space. + complete="$BUILD_STRIP" + path="${complete%% *}" + tmp="$complete EOL" + arguments="${tmp#* }" + + # Input might be given as Windows format, start by converting to + # unix format. + new_path="$path" + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + + # Now try to locate executable using which + new_path=`$WHICH "$new_path" 2> /dev/null` + + if test "x$new_path" = x; then + # Oops. Which didn't find the executable. + # The splitting of arguments from the executable at a space might have been incorrect, + # since paths with space are more likely in Windows. Give it another try with the whole + # argument. + path="$complete" + arguments="EOL" + new_path="$path" + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + + new_path=`$WHICH "$new_path" 2> /dev/null` + # bat and cmd files are not always considered executable in MSYS causing which + # to not find them + if test "x$new_path" = x \ + && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \ + && test "x`$LS \"$path\" 2>/dev/null`" != x; then + new_path="$path" + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + fi + + if test "x$new_path" = x; then + # It's still not found. Now this is an unrecoverable error. + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&5 +$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&6;} + has_space=`$ECHO "$complete" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5 +$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;} + fi + as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5 + fi + fi + + # Now new_path has a complete unix path to the binary + if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then + # Keep paths in /bin as-is, but remove trailing .exe if any + new_path="${new_path/%.exe/}" + # Do not save /bin paths to all_fixpath_prefixes! + else + # Not in mixed or Windows style, start by that. + new_path=`cmd //c echo $new_path` + + input_path="$new_path" + # Check if we need to convert this using DOS-style short mode. If the path + # contains just simple characters, use it. Otherwise (spaces, weird characters), + # take no chances and rewrite it. + # Note: m4 eats our [], so we need to use [ and ] instead. + has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]` + if test "x$has_forbidden_chars" != x; then + # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \) + new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + fi + + # Output is in $new_path + + windows_path="$new_path" + if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then + unix_path=`$CYGPATH -u "$windows_path"` + new_path="$unix_path" + elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then + unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'` + new_path="$unix_path" + fi + + # remove trailing .exe if any + new_path="${new_path/%.exe/}" + + # Save the first 10 bytes of this path to the storage, so fixpath can work. + all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}") + fi + + else + # We're on a unix platform. Hooray! :) + # First separate the path from the arguments. This will split at the first + # space. + complete="$BUILD_STRIP" + path="${complete%% *}" + tmp="$complete EOL" + arguments="${tmp#* }" + + # Cannot rely on the command "which" here since it doesn't always work. + is_absolute_path=`$ECHO "$path" | $GREP ^/` + if test -z "$is_absolute_path"; then + # Path to executable is not absolute. Find it. + IFS_save="$IFS" + IFS=: + for p in $PATH; do + if test -f "$p/$path" && test -x "$p/$path"; then + new_path="$p/$path" + break + fi + done + IFS="$IFS_save" + else + # This is an absolute path, we can use it without further modifications. + new_path="$path" + fi + + if test "x$new_path" = x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&5 +$as_echo "$as_me: The path of BUILD_STRIP, which resolves as \"$complete\", is not found." >&6;} + has_space=`$ECHO "$complete" | $GREP " "` + if test "x$has_space" != x; then + { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5 +$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;} + fi + as_fn_error $? "Cannot locate the the path of BUILD_STRIP" "$LINENO" 5 + fi + fi + + # Now join together the path and the arguments once again + if test "x$arguments" != xEOL; then + new_complete="$new_path ${arguments% *}" + else + new_complete="$new_path" + fi + + if test "x$complete" != "x$new_complete"; then + BUILD_STRIP="$new_complete" + { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting BUILD_STRIP to \"$new_complete\"" >&5 +$as_echo "$as_me: Rewriting BUILD_STRIP to \"$new_complete\"" >&6;} + fi + fi + # Assume the C compiler is the assembler BUILD_AS="$BUILD_CC -c" # Just like for the target compiler, use the compiler as linker @@ -44526,6 +46092,8 @@ $as_echo "$as_me: Rewriting BUILD_AR to \"$new_complete\"" >&6;} BUILD_LDCXX="$LDCXX" BUILD_NM="$NM" BUILD_AS="$AS" + BUILD_OBJCOPY="$OBJCOPY" + BUILD_STRIP="$STRIP" BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS" BUILD_SYSROOT_LDFLAGS="$SYSROOT_LDFLAGS" BUILD_AR="$AR" @@ -46680,9 +48248,6 @@ $as_echo "$supports" >&6; } ;; esac - # Setup LP64 - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK $ADD_LP64" - # Set some common defines. These works for all compilers, but assume # -D is universally accepted. @@ -46713,7 +48278,12 @@ $as_echo "$supports" >&6; } COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -D$OPENJDK_TARGET_OS_UPPERCASE" # Setup target CPU - COMMON_CCXXFLAGS_JDK="$COMMON_CCXXFLAGS_JDK -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY" + OPENJDK_TARGET_CCXXFLAGS_JDK="$OPENJDK_TARGET_CCXXFLAGS_JDK \ + $ADD_LP64 \ + -DARCH='\"$OPENJDK_TARGET_CPU_LEGACY\"' -D$OPENJDK_TARGET_CPU_LEGACY" + OPENJDK_BUILD_CCXXFLAGS_JDK="$OPENJDK_BUILD_CCXXFLAGS_JDK \ + $OPENJDK_BUILD_ADD_LP64 \ + -DARCH='\"$OPENJDK_BUILD_CPU_LEGACY\"' -D$OPENJDK_BUILD_CPU_LEGACY" # Setup debug/release defines if test "x$DEBUG_LEVEL" = xrelease; then @@ -46757,12 +48327,30 @@ $as_echo "$supports" >&6; } -I${JDK_TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava" # The shared libraries are compiled using the picflag. - CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" - CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" + CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CFLAGS_JDK $EXTRA_CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA" + CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" # Executable flags - CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK" - CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $CXXFLAGS_JDK" + CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CFLAGS_JDK $EXTRA_CFLAGS_JDK" + CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_TARGET_CCXXFLAGS_JDK \ + $CXXFLAGS_JDK $EXTRA_CXXFLAGS_JDK" + + # The corresponding flags for building for the build platform. This is still an + # approximation, we only need something that runs on this machine when cross + # compiling the product. + OPENJDK_BUILD_CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ + $PICFLAG $CFLAGS_JDKLIB_EXTRA" + OPENJDK_BUILD_CXXFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK \ + $PICFLAG $CXXFLAGS_JDKLIB_EXTRA" + OPENJDK_BUILD_CFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" + OPENJDK_BUILD_CXXFLAGS_JDKEXE="$COMMON_CCXXFLAGS_JDK $OPENJDK_BUILD_CCXXFLAGS_JDK" + + + + @@ -46863,6 +48451,9 @@ $as_echo "$supports" >&6; } LDFLAGS_JDKEXE="$LDFLAGS_JDKEXE -Wl,--allow-shlib-undefined" fi + OPENJDK_BUILD_LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE}" + LDFLAGS_JDKEXE="${LDFLAGS_JDKEXE} ${EXTRA_LDFLAGS_JDK}" + # Customize LDFLAGS for libs LDFLAGS_JDKLIB="${LDFLAGS_JDK}" @@ -46873,28 +48464,37 @@ $as_echo "$supports" >&6; } JDKLIB_LIBS="" else LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} \ - -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}" + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)" # On some platforms (mac) the linker warns about non existing -L dirs. # Add server first if available. Linking aginst client does not always produce the same results. # Only add client dir if client is being built. Add minimal (note not minimal1) if only building minimal1. # Default to server for other variants. if test "x$JVM_VARIANT_SERVER" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" elif test "x$JVM_VARIANT_CLIENT" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/client" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/client" elif test "x$JVM_VARIANT_MINIMAL1" = xtrue; then - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/minimal" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/minimal" else - LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L${OUTPUT_ROOT}/support/modules_libs/java.base${OPENJDK_TARGET_CPU_LIBDIR}/server" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi JDKLIB_LIBS="-ljava -ljvm" if test "x$TOOLCHAIN_TYPE" = xsolstudio; then JDKLIB_LIBS="$JDKLIB_LIBS -lc" fi + + # When building a buildjdk, it's always only the server variant + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} \ + -L\$(SUPPORT_OUTPUTDIR)/modules_libs/java.base\$(OPENJDK_TARGET_CPU_LIBDIR)/server" fi + OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_JDKLIB}" + LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${EXTRA_LDFLAGS_JDK}" + + + @@ -47499,6 +49099,7 @@ $as_echo "$supports" >&6; } + # Setup debug symbols (need objcopy from the toolchain for that) # @@ -61201,6 +62802,7 @@ do "$OUTPUT_ROOT/spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/spec.gmk:$AUTOCONF_DIR/spec.gmk.in" ;; "$OUTPUT_ROOT/hotspot-spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/hotspot-spec.gmk:$AUTOCONF_DIR/hotspot-spec.gmk.in" ;; "$OUTPUT_ROOT/bootcycle-spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/bootcycle-spec.gmk:$AUTOCONF_DIR/bootcycle-spec.gmk.in" ;; + "$OUTPUT_ROOT/buildjdk-spec.gmk") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/buildjdk-spec.gmk:$AUTOCONF_DIR/buildjdk-spec.gmk.in" ;; "$OUTPUT_ROOT/compare.sh") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/compare.sh:$AUTOCONF_DIR/compare.sh.in" ;; "$OUTPUT_ROOT/Makefile") CONFIG_FILES="$CONFIG_FILES $OUTPUT_ROOT/Makefile:$AUTOCONF_DIR/Makefile.in" ;; diff --git a/common/autoconf/help.m4 b/common/autoconf/help.m4 index e266dbf414b..d0892c56256 100644 --- a/common/autoconf/help.m4 +++ b/common/autoconf/help.m4 @@ -106,7 +106,7 @@ apt_help() { devkit) PKGHANDLER_COMMAND="sudo apt-get install build-essential" ;; openjdk) - PKGHANDLER_COMMAND="sudo apt-get install openjdk-7-jdk" ;; + PKGHANDLER_COMMAND="sudo apt-get install openjdk-8-jdk" ;; alsa) PKGHANDLER_COMMAND="sudo apt-get install libasound2-dev" ;; cups) @@ -127,7 +127,7 @@ yum_help() { devkit) PKGHANDLER_COMMAND="sudo yum groupinstall \"Development Tools\"" ;; openjdk) - PKGHANDLER_COMMAND="sudo yum install java-1.7.0-openjdk" ;; + PKGHANDLER_COMMAND="sudo yum install java-1.8.0-openjdk-devel" ;; alsa) PKGHANDLER_COMMAND="sudo yum install alsa-lib-devel" ;; cups) diff --git a/common/autoconf/jdk-options.m4 b/common/autoconf/jdk-options.m4 index a5b403b0d30..3c677d8adde 100644 --- a/common/autoconf/jdk-options.m4 +++ b/common/autoconf/jdk-options.m4 @@ -405,3 +405,31 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_STATIC_BUILD], AC_SUBST(STATIC_BUILD) ]) + +################################################################################ +# +# jlink options. +# We always keep packaged modules in JDK image. +# +AC_DEFUN_ONCE([JDKOPT_SETUP_JLINK_OPTIONS], +[ + AC_ARG_ENABLE([keep-packaged-modules], [AS_HELP_STRING([--disable-keep-packaged-modules], + [Do not keep packaged modules in jdk image @<:@enable@:>@])]) + + if test "x$enable_keep_packaged_modules" = "xyes"; then + AC_MSG_CHECKING([if packaged modules are kept]) + AC_MSG_RESULT([yes]) + JLINK_KEEP_PACKAGED_MODULES=true + elif test "x$enable_keep_packaged_modules" = "xno"; then + AC_MSG_CHECKING([if packaged modules are kept]) + AC_MSG_RESULT([no]) + JLINK_KEEP_PACKAGED_MODULES=false + elif test "x$enable_keep_packaged_modules" = "x"; then + AC_MSG_RESULT([yes (default)]) + JLINK_KEEP_PACKAGED_MODULES=true + else + AC_MSG_ERROR([--enable-keep-packaged-modules accepts no argument]) + fi + + AC_SUBST(JLINK_KEEP_PACKAGED_MODULES) +]) diff --git a/common/autoconf/platform.m4 b/common/autoconf/platform.m4 index 3b7e3e33e5d..fe5a201ecd9 100644 --- a/common/autoconf/platform.m4 +++ b/common/autoconf/platform.m4 @@ -304,6 +304,37 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS], fi AC_SUBST(OPENJDK_TARGET_CPU_LIBDIR) + # Now do the same for OPENJDK_BUILD_CPU... + # Also store the legacy naming of the cpu. + # Ie i586 and amd64 instead of x86 and x86_64 + OPENJDK_BUILD_CPU_LEGACY="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_LEGACY="i586" + elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then + # On all platforms except MacOSX replace x86_64 with amd64. + OPENJDK_BUILD_CPU_LEGACY="amd64" + fi + AC_SUBST(OPENJDK_BUILD_CPU_LEGACY) + + # And the second legacy naming of the cpu. + # Ie i386 and amd64 instead of x86 and x86_64. + OPENJDK_BUILD_CPU_LEGACY_LIB="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_LEGACY_LIB="i386" + elif test "x$OPENJDK_BUILD_CPU" = xx86_64; then + OPENJDK_BUILD_CPU_LEGACY_LIB="amd64" + fi + AC_SUBST(OPENJDK_BUILD_CPU_LEGACY_LIB) + + # This is the name of the cpu (but using i386 and amd64 instead of + # x86 and x86_64, respectively), preceeded by a /, to be used when + # locating libraries. On macosx, it's empty, though. + OPENJDK_BUILD_CPU_LIBDIR="/$OPENJDK_BUILD_CPU_LEGACY_LIB" + if test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_CPU_LIBDIR="" + fi + AC_SUBST(OPENJDK_BUILD_CPU_LIBDIR) + # OPENJDK_TARGET_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to # /amd64 or /sparcv9. This string is appended to some library paths, like this: # /usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libexample.so @@ -346,6 +377,24 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS], fi AC_SUBST(OPENJDK_TARGET_CPU_JLI_CFLAGS) + OPENJDK_BUILD_CPU_JLI="$OPENJDK_BUILD_CPU" + if test "x$OPENJDK_BUILD_CPU" = xx86; then + OPENJDK_BUILD_CPU_JLI="i386" + elif test "x$OPENJDK_BUILD_OS" != xmacosx && test "x$OPENJDK_BUILD_CPU" = xx86_64; then + # On all platforms except macosx, we replace x86_64 with amd64. + OPENJDK_BUILD_CPU_JLI="amd64" + fi + # Now setup the -D flags for building libjli. + OPENJDK_BUILD_CPU_JLI_CFLAGS="-DLIBARCHNAME='\"$OPENJDK_BUILD_CPU_JLI\"'" + if test "x$OPENJDK_BUILD_OS" = xsolaris; then + if test "x$OPENJDK_BUILD_CPU_ARCH" = xsparc; then + OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"sparc\"' -DLIBARCH64NAME='\"sparcv9\"'" + elif test "x$OPENJDK_BUILD_CPU_ARCH" = xx86; then + OPENJDK_BUILD_CPU_JLI_CFLAGS="$OPENJDK_BUILD_CPU_JLI_CFLAGS -DLIBARCH32NAME='\"i386\"' -DLIBARCH64NAME='\"amd64\"'" + fi + fi + AC_SUBST(OPENJDK_BUILD_CPU_JLI_CFLAGS) + if test "x$OPENJDK_TARGET_OS" = xmacosx; then OPENJDK_TARGET_OS_EXPORT_DIR=macosx else @@ -362,6 +411,11 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS], fi fi AC_SUBST(LP64,$A_LP64) + if test "x$OPENJDK_BUILD_CPU_BITS" = x64; then + if test "x$OPENJDK_BUILD_OS" = xlinux || test "x$OPENJDK_BUILD_OS" = xmacosx; then + OPENJDK_BUILD_ADD_LP64="-D_LP64=1" + fi + fi if test "x$COMPILE_TYPE" = "xcross"; then # FIXME: ... or should this include reduced builds..? @@ -406,6 +460,10 @@ AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES], REQUIRED_OS_NAME=Darwin REQUIRED_OS_VERSION=11.2 fi + if test "x$OPENJDK_TARGET_OS" = "xaix"; then + REQUIRED_OS_NAME=AIX + REQUIRED_OS_VERSION=7.1 + fi AC_SUBST(REQUIRED_OS_NAME) AC_SUBST(REQUIRED_OS_VERSION) diff --git a/common/autoconf/source-dirs.m4 b/common/autoconf/source-dirs.m4 index 56f95dcba60..fa2f74d2237 100644 --- a/common/autoconf/source-dirs.m4 +++ b/common/autoconf/source-dirs.m4 @@ -84,3 +84,56 @@ AC_DEFUN_ONCE([SRCDIRS_SETUP_OUTPUT_DIRS], JDK_OUTPUTDIR="$OUTPUT_ROOT/jdk" ]) + +################################################################################ +# Define a mechanism for importing extra prebuilt modules +# + +AC_DEFUN_ONCE([SRCDIRS_SETUP_IMPORT_MODULES], +[ + AC_ARG_WITH(import-modules, [AS_HELP_STRING([--with-import-modules], + [import a set of prebuilt modules either as a zip file or an exploded directory])]) + + if test "x$with_import_modules" != x \ + && test "x$with_import_modules" != "xno"; then + if test -d "$with_import_modules"; then + IMPORT_MODULES_TOPDIR="$with_import_modules" + BASIC_FIXUP_PATH([IMPORT_MODULES_TOPDIR]) + elif test -e "$with_import_modules"; then + IMPORT_MODULES_TOPDIR="$CONFIGURESUPPORT_OUTPUTDIR/import-modules" + $RM -rf "$IMPORT_MODULES_TOPDIR" + $MKDIR -p "$IMPORT_MODULES_TOPDIR" + if ! $UNZIP -q "$with_import_modules" -d "$IMPORT_MODULES_TOPDIR"; then + AC_MSG_ERROR([--with-import-modules="$with_import_modules" must point to a dir or a zip file]) + fi + else + AC_MSG_ERROR([--with-import-modules="$with_import_modules" must point to a dir or a zip file]) + fi + fi + + if test -d "$IMPORT_MODULES_TOPDIR/modules"; then + IMPORT_MODULES_CLASSES="$IMPORT_MODULES_TOPDIR/modules" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_cmds"; then + IMPORT_MODULES_CMDS="$IMPORT_MODULES_TOPDIR/modules_cmds" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_libs"; then + IMPORT_MODULES_LIBS="$IMPORT_MODULES_TOPDIR/modules_libs" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_conf"; then + IMPORT_MODULES_CONF="$IMPORT_MODULES_TOPDIR/modules_conf" + fi + if test -d "$IMPORT_MODULES_TOPDIR/modules_src"; then + IMPORT_MODULES_SRC="$IMPORT_MODULES_TOPDIR/modules_src" + fi + if test -d "$IMPORT_MODULES_TOPDIR/make"; then + IMPORT_MODULES_MAKE="$IMPORT_MODULES_TOPDIR/make" + fi + + AC_SUBST(IMPORT_MODULES_CLASSES) + AC_SUBST(IMPORT_MODULES_CMDS) + AC_SUBST(IMPORT_MODULES_LIBS) + AC_SUBST(IMPORT_MODULES_CONF) + AC_SUBST(IMPORT_MODULES_SRC) + AC_SUBST(IMPORT_MODULES_MAKE) +]) diff --git a/common/autoconf/spec.gmk.in b/common/autoconf/spec.gmk.in index d8322ebce9c..66374c8f649 100644 --- a/common/autoconf/spec.gmk.in +++ b/common/autoconf/spec.gmk.in @@ -130,6 +130,14 @@ JAXP_TOPDIR:=@JAXP_TOPDIR@ JAXWS_TOPDIR:=@JAXWS_TOPDIR@ HOTSPOT_TOPDIR:=@HOTSPOT_TOPDIR@ NASHORN_TOPDIR:=@NASHORN_TOPDIR@ + +IMPORT_MODULES_CLASSES:=@IMPORT_MODULES_CLASSES@ +IMPORT_MODULES_CMDS:=@IMPORT_MODULES_CMDS@ +IMPORT_MODULES_LIBS:=@IMPORT_MODULES_LIBS@ +IMPORT_MODULES_CONF:=@IMPORT_MODULES_CONF@ +IMPORT_MODULES_SRC:=@IMPORT_MODULES_SRC@ +IMPORT_MODULES_MAKE:=@IMPORT_MODULES_MAKE@ + COPYRIGHT_YEAR:=@COPYRIGHT_YEAR@ # New (JEP-223) version information @@ -246,6 +254,7 @@ TESTMAKE_OUTPUTDIR=$(BUILD_OUTPUT)/test-make MAKESUPPORT_OUTPUTDIR=$(BUILD_OUTPUT)/make-support # This does not get overridden in a bootcycle build CONFIGURESUPPORT_OUTPUTDIR:=@CONFIGURESUPPORT_OUTPUTDIR@ +BUILDJDK_OUTPUTDIR=$(BUILD_OUTPUT)/buildjdk HOTSPOT_DIST=@HOTSPOT_DIST@ @@ -255,6 +264,9 @@ BUILD_HOTSPOT=@BUILD_HOTSPOT@ # it in sync. BOOT_JDK:=@BOOT_JDK@ +BUILD_JDK:=@BUILD_JDK@ +CREATE_BUILDJDK:=@CREATE_BUILDJDK@ + # When compiling Java source to be run by the boot jdk # use these extra flags, eg -source 6 -target 6 BOOT_JDK_SOURCETARGET:=@BOOT_JDK_SOURCETARGET@ @@ -405,6 +417,8 @@ BUILD_LDCXX:=@FIXPATH@ @BUILD_LDCXX@ BUILD_AS:=@FIXPATH@ @BUILD_AS@ BUILD_AR:=@FIXPATH@ @BUILD_AR@ BUILD_NM:=@FIXPATH@ @BUILD_NM@ +BUILD_OBJCOPY:=@BUILD_OBJCOPY@ +BUILD_STRIP:=@BUILD_STRIP@ BUILD_SYSROOT_CFLAGS:=@BUILD_SYSROOT_CFLAGS@ BUILD_SYSROOT_LDFLAGS:=@BUILD_SYSROOT_LDFLAGS@ @@ -502,12 +516,40 @@ SJAVAC_SERVER_JAVA=@FIXPATH@ @FIXPATH_DETACH_FLAG@ $(SJAVAC_SERVER_JAVA_CMD) \ # overriding that value by using ?=. JAVAC_FLAGS?=@JAVAC_FLAGS@ + +BUILD_JAVA_FLAGS:=-Xms64M -Xmx1100M +BUILD_JAVA=@FIXPATH@ $(BUILD_JDK)/bin/java $(BUILD_JAVA_FLAGS) + +# Use ?= as this can be overridden from bootcycle-spec.gmk +BOOT_JDK_MODULAR ?= @BOOT_JDK_MODULAR@ + +ifeq ($(BOOT_JDK_MODULAR), true) + INTERIM_OVERRIDE_MODULES_ARGS = -Xpatch:$(BUILDTOOLS_OUTPUTDIR)/override_modules + INTERIM_LANGTOOLS_ARGS = $(INTERIM_OVERRIDE_MODULES_ARGS) + JAVAC_MAIN_CLASS = -m jdk.compiler/com.sun.tools.javac.Main + JAVADOC_MAIN_CLASS = -m jdk.javadoc/jdk.javadoc.internal.tool.Main +else + INTERIM_OVERRIDE_MODULES := java.compiler jdk.compiler \ + jdk.jdeps jdk.javadoc jdk.rmic + INTERIM_OVERRIDE_MODULES_ARGS = \ + -Xbootclasspath/p:$(call PathList, \ + $(addprefix $(BUILDTOOLS_OUTPUTDIR)/override_modules/, \ + $(INTERIM_OVERRIDE_MODULES))) + INTERIM_LANGTOOLS_ARGS = $(INTERIM_OVERRIDE_MODULES_ARGS) \ + -cp $(BUILDTOOLS_OUTPUTDIR)/override_modules/jdk.compiler + JAVAC_MAIN_CLASS = com.sun.tools.javac.Main + JAVADOC_MAIN_CLASS = jdk.javadoc.internal.tool.Main +endif # You run the new javac using the boot jdk with $(BOOT_JDK)/bin/java $(NEW_JAVAC) ... # Use = assignment to be able to override in bootcycle-spec.gmk -INTERIM_LANGTOOLS_JAR = $(BUILDTOOLS_OUTPUTDIR)/interim_langtools.jar -INTERIM_LANGTOOLS_ARGS = "-Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR)" -cp $(INTERIM_LANGTOOLS_JAR) -NEW_JAVAC = $(INTERIM_LANGTOOLS_ARGS) com.sun.tools.javac.Main -NEW_JAVADOC = $(INTERIM_LANGTOOLS_ARGS) jdk.javadoc.internal.tool.Main +NEW_JAVAC = $(INTERIM_LANGTOOLS_ARGS) $(JAVAC_MAIN_CLASS) +NEW_JAVADOC = $(INTERIM_LANGTOOLS_ARGS) $(JAVADOC_MAIN_CLASS) + +# JLink/Jmod are run using the BUILD_JDK, which is normally the jdk output dir. +JLINK_KEEP_PACKAGED_MODULES:=@JLINK_KEEP_PACKAGED_MODULES@ + +JLINK = @FIXPATH@ $(BUILD_JDK)/bin/jlink $(JAVA_TOOL_FLAGS_SMALL) +JMOD = @FIXPATH@ $(BUILD_JDK)/bin/jmod $(JAVA_TOOL_FLAGS_SMALL) # Base flags for RC # Guarding this against resetting value. Legacy make files include spec multiple diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index 5e26fd1e3e6..07a6f834bfc 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -797,6 +797,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS], BASIC_FIXUP_EXECUTABLE(BUILD_NM) BASIC_PATH_PROGS(BUILD_AR, ar gcc-ar) BASIC_FIXUP_EXECUTABLE(BUILD_AR) + BASIC_PATH_PROGS(BUILD_OBJCOPY, objcopy) + BASIC_FIXUP_EXECUTABLE(BUILD_OBJCOPY) + BASIC_PATH_PROGS(BUILD_STRIP, strip) + BASIC_FIXUP_EXECUTABLE(BUILD_STRIP) # Assume the C compiler is the assembler BUILD_AS="$BUILD_CC -c" # Just like for the target compiler, use the compiler as linker @@ -813,6 +817,8 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS], BUILD_LDCXX="$LDCXX" BUILD_NM="$NM" BUILD_AS="$AS" + BUILD_OBJCOPY="$OBJCOPY" + BUILD_STRIP="$STRIP" BUILD_SYSROOT_CFLAGS="$SYSROOT_CFLAGS" BUILD_SYSROOT_LDFLAGS="$SYSROOT_LDFLAGS" BUILD_AR="$AR" diff --git a/common/bin/compare.sh b/common/bin/compare.sh index a629ae084eb..d073fbbda32 100644 --- a/common/bin/compare.sh +++ b/common/bin/compare.sh @@ -290,9 +290,9 @@ compare_general_files() { GENERAL_FILES=$(cd $THIS_DIR && $FIND . -type f ! -name "*.so" ! -name "*.jar" \ ! -name "*.zip" ! -name "*.debuginfo" ! -name "*.dylib" ! -name "jexec" \ - ! -name "*.jimage" ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \ + ! -name "modules" ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \ ! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ - ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \ + ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" ! -name "*.jmod" \ ! -name "*.obj" ! -name "*.o" ! -name "JavaControlPanelHelper" \ ! -name "JavaUpdater" ! -name "JavaWSApplicationStub" \ ! -name "jspawnhelper" ! -name "JavawsLauncher" ! -name "*.a" \ @@ -389,13 +389,13 @@ compare_zip_file() { $RM -rf $THIS_UNZIPDIR $OTHER_UNZIPDIR $MKDIR -p $THIS_UNZIPDIR $MKDIR -p $OTHER_UNZIPDIR - if [ "$TYPE" = "jimage" ] + if [ "$TYPE" = "jar" || "$TYPE" = "war" || "$TYPE" = "zip" || "$TYPE" = "jmod"] then - (cd $THIS_UNZIPDIR && $JIMAGE extract $THIS_ZIP) - (cd $OTHER_UNZIPDIR && $JIMAGE extract $OTHER_ZIP) - else (cd $THIS_UNZIPDIR && $UNARCHIVE $THIS_ZIP) (cd $OTHER_UNZIPDIR && $UNARCHIVE $OTHER_ZIP) + else + (cd $THIS_UNZIPDIR && $JIMAGE extract $THIS_ZIP) + (cd $OTHER_UNZIPDIR && $JIMAGE extract $OTHER_ZIP) fi # Find all archives inside and unzip them as well to compare the contents rather than @@ -526,7 +526,7 @@ compare_all_jar_files() { # TODO filter? ZIPS=$(cd $THIS_DIR && $FIND . -type f -name "*.jar" -o -name "*.war" \ - -o -name "*.jimage" | $SORT | $FILTER) + -o -name "modules" -o -name "*.jmod" | $SORT | $FILTER) if [ -n "$ZIPS" ]; then echo Jar files... diff --git a/common/bin/compare_exceptions.sh.incl b/common/bin/compare_exceptions.sh.incl index fb68ede81d4..30ae49c6fc1 100644 --- a/common/bin/compare_exceptions.sh.incl +++ b/common/bin/compare_exceptions.sh.incl @@ -185,7 +185,6 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; ./lib/amd64/libjava.so ./lib/amd64/libjawt.so ./lib/amd64/libjdwp.so - ./lib/amd64/libjfr.so ./lib/amd64/libjpeg.so ./lib/amd64/libjsdt.so ./lib/amd64/libjsound.so @@ -321,7 +320,6 @@ if [ "$OPENJDK_TARGET_OS" = "solaris" ] && [ "$OPENJDK_TARGET_CPU" = "sparcv9" ] ./lib/sparcv9/libjava.so ./lib/sparcv9/libjawt.so ./lib/sparcv9/libjdwp.so - ./lib/sparcv9/libjfr.so ./lib/sparcv9/libjpeg.so ./lib/sparcv9/libjsdt.so ./lib/sparcv9/libjsound.so diff --git a/common/bin/unshuffle_list.txt b/common/bin/unshuffle_list.txt index a419fe43a57..daa919b9444 100644 --- a/common/bin/unshuffle_list.txt +++ b/common/bin/unshuffle_list.txt @@ -1293,12 +1293,8 @@ jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.c : jdk/src/win jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/j2secmod_md.h : jdk/src/windows/native/sun/security/pkcs11/j2secmod_md.h jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.c : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.c jdk/src/jdk.crypto.pkcs11/windows/native/libj2pkcs11/p11_md.h : jdk/src/windows/native/sun/security/pkcs11/wrapper/p11_md.h -jdk/src/jdk.deploy.osx/macosx/classes/com/apple/concurrent/package.html : jdk/src/macosx/classes/com/apple/concurrent/package.html -jdk/src/jdk.deploy.osx/macosx/classes/com/apple/concurrent : jdk/src/macosx/classes/com/apple/concurrent -jdk/src/jdk.deploy.osx/macosx/native/libosx/CFileManager.m : jdk/src/macosx/native/com/apple/eio/CFileManager.m -jdk/src/jdk.deploy.osx/macosx/native/libosx/Dispatch.m : jdk/src/macosx/native/com/apple/concurrent/Dispatch.m -jdk/src/jdk.deploy.osx/macosx/native/libosx/JavaAppLauncher.m : jdk/src/macosx/native/apple/launcher/JavaAppLauncher.m -jdk/src/jdk.deploy.osx/macosx/native/libosx/KeystoreImpl.m : jdk/src/macosx/native/apple/security/KeystoreImpl.m +jdk/src/java.desktop/macosx/native/libosx/CFileManager.m : jdk/src/macosx/native/com/apple/eio/CFileManager.m +jdk/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m : jdk/src/macosx/native/apple/security/KeystoreImpl.m jdk/src/jdk.hprof.agent/share/classes/com/sun/demo/jvmti/hprof : jdk/src/share/classes/com/sun/demo/jvmti/hprof jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver : jdk/src/share/classes/com/sun/net/httpserver jdk/src/jdk.httpserver/share/classes/sun/net/httpserver : jdk/src/share/classes/sun/net/httpserver diff --git a/common/conf/jib-profiles.js b/common/conf/jib-profiles.js index 48519cfbe74..27fbe1f02cf 100644 --- a/common/conf/jib-profiles.js +++ b/common/conf/jib-profiles.js @@ -421,10 +421,10 @@ var getJibProfilesDependencies = function (input, common) { jtreg: { server: "javare", - revision: "4.1", - build_number: "b12", + revision: "4.2", + build_number: "b01", checksum_file: "MD5_VALUES", - file: "jtreg_bin-4.1.zip", + file: "jtreg_bin-4.2.zip", environment_name: "JT_HOME" }, diff --git a/corba/.hgtags b/corba/.hgtags index 43b212133c8..9c059fc2de3 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -351,3 +351,5 @@ e385e95e6101711d5c63e7b1a827e99b6ec7a1cc jdk-9+104 8ec4f97943fe56f93e4621f622b56b7144c0181a jdk-9+106 49202432b69445164a42be7cbdf74ed5fce98157 jdk-9+107 84f2862a25eb3232ff36c376b4e2bf2a83dfced3 jdk-9+108 +b75afa17aefe480c23c616a6a2497063312f7189 jdk-9+109 +9666775734fb6028ee86df9972626b3667b6a318 jdk-9+110 diff --git a/corba/make/gensrc/Gensrc-java.corba.gmk b/corba/make/gensrc/Gensrc-java.corba.gmk index 608267e0df1..2d186902777 100644 --- a/corba/make/gensrc/Gensrc-java.corba.gmk +++ b/corba/make/gensrc/Gensrc-java.corba.gmk @@ -47,7 +47,7 @@ $(eval $(call SetupJavaCompilation,BUILD_IDLJ, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/idlj_classes, \ COPY := .prp, \ INCLUDES := com/sun/tools/corba/se/idl, \ - EXCLUDE_FILES := ResourceBundleUtil.java)) + EXCLUDE_FILES := ResourceBundleUtil.java module-info.java)) # Force the language to english for predictable source code generation. TOOL_IDLJ_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/idlj_classes \ diff --git a/corba/src/java.corba/share/classes/module-info.java b/corba/src/java.corba/share/classes/module-info.java new file mode 100644 index 00000000000..23da4b785a9 --- /dev/null +++ b/corba/src/java.corba/share/classes/module-info.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +module java.corba { + requires public java.desktop; + requires public java.rmi; + requires java.logging; + requires java.naming; + requires java.transaction; + + exports javax.activity; + exports javax.rmi; + exports javax.rmi.CORBA; + exports org.omg.CORBA; + exports org.omg.CORBA.DynAnyPackage; + exports org.omg.CORBA.ORBPackage; + exports org.omg.CORBA.TypeCodePackage; + exports org.omg.CORBA.portable; + exports org.omg.CORBA_2_3; + exports org.omg.CORBA_2_3.portable; + exports org.omg.CosNaming; + exports org.omg.CosNaming.NamingContextExtPackage; + exports org.omg.CosNaming.NamingContextPackage; + exports org.omg.Dynamic; + exports org.omg.DynamicAny; + exports org.omg.DynamicAny.DynAnyFactoryPackage; + exports org.omg.DynamicAny.DynAnyPackage; + exports org.omg.IOP; + exports org.omg.IOP.CodecFactoryPackage; + exports org.omg.IOP.CodecPackage; + exports org.omg.Messaging; + exports org.omg.PortableInterceptor; + exports org.omg.PortableInterceptor.ORBInitInfoPackage; + exports org.omg.PortableServer; + exports org.omg.PortableServer.CurrentPackage; + exports org.omg.PortableServer.POAManagerPackage; + exports org.omg.PortableServer.POAPackage; + exports org.omg.PortableServer.ServantLocatorPackage; + exports org.omg.PortableServer.portable; + exports org.omg.SendingContext; + exports org.omg.stub.java.rmi; + exports com.sun.corba.se.impl.util to + jdk.rmic; + exports com.sun.jndi.cosnaming to + java.naming; + exports com.sun.jndi.url.corbaname to + java.naming; + exports com.sun.jndi.url.iiop to + java.naming; + exports com.sun.jndi.url.iiopname to + java.naming; + + provides javax.naming.spi.InitialContextFactory + with com.sun.jndi.cosnaming.CNCtxFactory; +} diff --git a/hotspot/.hgtags b/hotspot/.hgtags index c77700ff598..e1c8a7dd0a3 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -511,3 +511,5 @@ c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103 7232de4c17c37f60aecec4f3191090bd3d41d334 jdk-9+106 c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107 934f6793f5f7dca44f69b4559d525fa64b31840d jdk-9+108 +7e7e50ac4faf19899fc811569e32cfa478759ebb jdk-9+109 +2f5d1578b24060ea06bd1f340a124db95d1475b2 jdk-9+110 diff --git a/hotspot/make/aix/makefiles/trace.make b/hotspot/make/aix/makefiles/trace.make index c00b0e3383a..549acb21190 100644 --- a/hotspot/make/aix/makefiles/trace.make +++ b/hotspot/make/aix/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,6 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ traceEventControl.hpp - -ifneq ($(INCLUDE_TRACE), false) -TraceGeneratedNames += traceProducer.cpp -endif - endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) @@ -100,9 +95,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/bsd/makefiles/trace.make b/hotspot/make/bsd/makefiles/trace.make index c7ef3d8ea01..88f17a7326e 100644 --- a/hotspot/make/bsd/makefiles/trace.make +++ b/hotspot/make/bsd/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,6 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ traceEventControl.hpp - -ifneq ($(INCLUDE_TRACE), false) -TraceGeneratedNames += traceProducer.cpp -endif - endif @@ -101,9 +96,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/linux/makefiles/trace.make b/hotspot/make/linux/makefiles/trace.make index 7218adc27b3..229b68c434b 100644 --- a/hotspot/make/linux/makefiles/trace.make +++ b/hotspot/make/linux/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -57,11 +57,6 @@ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ traceEventControl.hpp - -ifneq ($(INCLUDE_TRACE), false) -TraceGeneratedNames += traceProducer.cpp -endif - endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) @@ -100,9 +95,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/share/makefiles/mapfile-vers b/hotspot/make/share/makefiles/mapfile-vers index 28338d046f6..120103a04ba 100644 --- a/hotspot/make/share/makefiles/mapfile-vers +++ b/hotspot/make/share/makefiles/mapfile-vers @@ -168,3 +168,15 @@ JVM_TotalMemory; JVM_UnloadLibrary; JVM_Yield; + + # Module related API's + JVM_AddModuleExports; + JVM_AddModuleExportsToAll; + JVM_AddModuleExportsToAllUnnamed; + JVM_AddModulePackage; + JVM_AddReadsModule; + JVM_CanReadModule; + JVM_DefineModule; + JVM_IsExportedToModule; + JVM_SetBootLoaderUnnamedModule; + JVM_GetModuleByPackageName; diff --git a/hotspot/make/solaris/makefiles/amd64.make b/hotspot/make/solaris/makefiles/amd64.make index 7b1bdf3d8b3..3eb6dee9b92 100644 --- a/hotspot/make/solaris/makefiles/amd64.make +++ b/hotspot/make/solaris/makefiles/amd64.make @@ -39,7 +39,7 @@ OPT_CFLAGS/c1_LinearScan.o = -xO2 # of OPT_CFLAGS. Restore it here. ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1) OPT_CFLAGS/generateOptoStub.o += -g0 -xs - OPT_CFLAGS/LinearScan.o += -g0 -xs + OPT_CFLAGS/c1_LinearScan.o += -g0 -xs endif else diff --git a/hotspot/make/solaris/makefiles/trace.make b/hotspot/make/solaris/makefiles/trace.make index ab96c7ffd65..09979558ea7 100644 --- a/hotspot/make/solaris/makefiles/trace.make +++ b/hotspot/make/solaris/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -56,8 +56,7 @@ TraceGeneratedNames = \ ifeq ($(HAS_ALT_SRC), true) TraceGeneratedNames += \ traceRequestables.hpp \ - traceEventControl.hpp \ - traceProducer.cpp + traceEventControl.hpp endif TraceGeneratedFiles = $(TraceGeneratedNames:%=$(TraceOutDir)/%) @@ -96,9 +95,6 @@ else $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceEventClasses.xsl $(XML_DEPS) $(GENERATE_CODE) -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - $(GENERATE_CODE) - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) $(GENERATE_CODE) diff --git a/hotspot/make/test/JtregNative.gmk b/hotspot/make/test/JtregNative.gmk index 109c04d37fb..95c6bf242b7 100644 --- a/hotspot/make/test/JtregNative.gmk +++ b/hotspot/make/test/JtregNative.gmk @@ -45,9 +45,11 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8025979 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/8033445 \ $(HOTSPOT_TOPDIR)/test/runtime/jni/ToStringInInterfaceTest \ + $(HOTSPOT_TOPDIR)/test/runtime/modules/getModuleJNI \ $(HOTSPOT_TOPDIR)/test/runtime/SameObject \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ $(HOTSPOT_TOPDIR)/test/compiler/calls \ + $(HOTSPOT_TOPDIR)/test/compiler/native \ # # Add conditional directories here when needed. diff --git a/hotspot/make/windows/makefiles/trace.make b/hotspot/make/windows/makefiles/trace.make index 58fee24653c..b32646e3310 100644 --- a/hotspot/make/windows/makefiles/trace.make +++ b/hotspot/make/windows/makefiles/trace.make @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -43,8 +43,7 @@ TraceGeneratedNames = \ !if EXISTS($(TraceAltSrcDir)) TraceGeneratedNames = $(TraceGeneratedNames) \ traceRequestables.hpp \ - traceEventControl.hpp \ - traceProducer.cpp + traceEventControl.hpp !endif @@ -58,8 +57,7 @@ TraceGeneratedFiles = \ !if EXISTS($(TraceAltSrcDir)) TraceGeneratedFiles = $(TraceGeneratedFiles) \ $(TraceOutDir)/traceRequestables.hpp \ - $(TraceOutDir)/traceEventControl.hpp \ - $(TraceOutDir)/traceProducer.cpp + $(TraceOutDir)/traceEventControl.hpp !endif XSLT = $(QUIETLY) $(REMOTE) $(RUN_JAVA) -classpath $(JvmtiOutDir) jvmtiGen @@ -98,10 +96,6 @@ $(TraceOutDir)/traceEventClasses.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir) @echo Generating AltSrc $@ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceEventClasses.xsl -OUT $(TraceOutDir)/traceEventClasses.hpp -$(TraceOutDir)/traceProducer.cpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceProducer.xsl $(XML_DEPS) - @echo Generating AltSrc $@ - @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceProducer.xsl -OUT $(TraceOutDir)/traceProducer.cpp - $(TraceOutDir)/traceRequestables.hpp: $(TraceSrcDir)/trace.xml $(TraceAltSrcDir)/traceRequestables.xsl $(XML_DEPS) @echo Generating AltSrc $@ @$(XSLT) -IN $(TraceSrcDir)/trace.xml -XSL $(TraceAltSrcDir)/traceRequestables.xsl -OUT $(TraceOutDir)/traceRequestables.hpp diff --git a/hotspot/src/cpu/aarch64/vm/aarch64.ad b/hotspot/src/cpu/aarch64/vm/aarch64.ad index e94d23c150e..acc65080e2f 100644 --- a/hotspot/src/cpu/aarch64/vm/aarch64.ad +++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad @@ -1041,10 +1041,8 @@ class HandlerImpl { bool is_card_mark_membar(const MemBarNode *barrier); bool is_CAS(int opcode); - 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 *leading_to_trailing(MemBarNode *leading); + MemBarNode *card_mark_to_leading(const MemBarNode *barrier); MemBarNode *trailing_to_leading(const MemBarNode *trailing); // predicates controlling emit of ldr/ldar and associated dmb @@ -1418,23 +1416,28 @@ source %{ // leading MemBarRelease and a trailing MemBarVolatile as follows // // MemBarRelease - // { || } -- optional + // { || } -- optional // {MemBarCPUOrder} - // || \\ - // || StoreX[mo_release] - // | \ / - // | MergeMem - // | / + // || \\ + // || StoreX[mo_release] + // | \ Bot / ??? + // | MergeMem + // | / // MemBarVolatile // // where // || and \\ represent Ctl and Mem feeds via Proj nodes // | \ and / indicate further routing of the Ctl and Mem feeds // - // 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. + // 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. // // with most GC configurations we with see this simple variant which // includes a post-write barrier card mark. @@ -1442,7 +1445,7 @@ source %{ // MemBarRelease______________________________ // || \\ Ctl \ \\ // || StoreN/P[mo_release] CastP2X StoreB/CM - // | \ / . . . / + // | \ Bot / oop . . . / // | MergeMem // | / // || / @@ -1452,152 +1455,142 @@ 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 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 + // 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 // // dmb ishst // stlrb // - // 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 + // 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 // // MemBarRelease____________________________________________ // || \\ Ctl \ Ctl \ \\ Mem \ // || StoreN/P[mo_release] CastP2X If LoadB | - // | \ / \ | + // | \ Bot / oop \ | // | MergeMem . . . StoreB // | / / // || / // MemBarVolatile // - // It is worth noting at this stage that both the above + // It is worth noting at this stage that all the above // configurations can be uniquely identified by checking that the // memory flow includes the following subgraph: // // MemBarRelease // {MemBarCPUOrder} - // | \ . . . - // | StoreX[mo_release] . . . - // | / - // MergeMem - // | + // | \ . . . + // | StoreX[mo_release] . . . + // Bot | / oop + // MergeMem + // | // MemBarVolatile // - // This is referred to as a *normal* subgraph. It can easily be - // detected starting from any candidate MemBarRelease, - // StoreX[mo_release] or 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. // - // A simple variation on this normal case occurs for an unsafe CAS - // operation. The basic graph for a non-object CAS is + // 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 // // MemBarRelease // || // MemBarCPUOrder - // || \\ . . . - // || CompareAndSwapX - // || | - // || SCMemProj - // | \ / - // | MergeMem - // | / + // | \\ . . . + // | CompareAndSwapX + // | | + // Bot | SCMemProj + // \ / Bot + // MergeMem + // / // MemBarCPUOrder // || // MemBarAcquire // // The same basic variations on this arrangement (mutatis mutandis) - // 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. + // 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. // - // So, in the case of a CAS the normal graph has the variant form + // 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. // - // MemBarRelease - // MemBarCPUOrder - // | \ . . . - // | CompareAndSwapX . . . - // | | - // | SCMemProj - // | / . . . - // MergeMem - // | - // MemBarCPUOrder - // MemBarAcquire + // 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. // - // This graph can also easily be detected starting from any - // candidate MemBarRelease, CompareAndSwapX or 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). // - // 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. + // 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. // - // 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 + // 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 // // MemBarVolatile (card mark) // C | \ . . . // | StoreCM . . . // . . . // - // 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? + // 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? // // A CMS GC post-barrier wraps its card write (StoreCM) inside an If // which selects conditonal execution based on the value loaded @@ -1608,91 +1601,117 @@ source %{ // which looks like this // // MemBarRelease - // 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 + // 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 | / / + // | . . . | / / // | MergeMem - // | | + // | | // MemBarVolatile (trailing) // - // 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). + // 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 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. + // 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. // // MemBarRelease - // 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) + // 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) // // This has a slightly different memory subgraph to the one seen - // previously but the core of it is the same as for the CAS normal - // sungraph + // previously but the core of it has a similar memory flow to the + // CAS normal subgraph: // // MemBarRelease // MemBarCPUOrder____ - // || \ . . . - // MemBarVolatile CompareAndSwapX . . . - // | \ | - // . . . SCMemProj - // | / . . . - // MergeMem - // | + // | \ . . . + // | CompareAndSwapX . . . + // | C / M | + // | CmpI | + // | / | + // | . . / + // Bot | IfTrue / + // | / / + // MemBarVolatile / + // | ... / + // StoreCM ... / + // | / + // . . . SCMemProj + // Raw \ / Bot + // MergeMem + // | // MemBarCPUOrder // MemBarAcquire // - // - // 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 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. // // 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 @@ -1730,25 +1749,60 @@ 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. // - // 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 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) // // 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 form the + // the card mark membar is omitted and the memory feeds from 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. @@ -1770,94 +1824,106 @@ source %{ // // (pre-write subtree elided) // . . . . . . . . . . . . - // 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 + // 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 // - // 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. + // 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. // - // 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. + // 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 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. + // 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. // - // 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 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. // // The predicates controlling generation of instructions for store // and barrier nodes employ a few simple helper functions (described @@ -1878,24 +1944,24 @@ source %{ opcode == Op_CompareAndSwapP); } - // leading_to_normal + // leading_to_trailing // //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 - // MemBarCPUOrder {leading} - // | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {trailing or card mark} + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} + // Bot | \ . . . + // | StoreN/P[mo_release] . . . + // | / + // MergeMem + // | + // MemBarVolatile {not card mark} // - // MemBarRelease - // MemBarCPUOrder {leading} + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} // | \ . . . // | CompareAndSwapX . . . // | @@ -1906,6 +1972,23 @@ 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. // @@ -1916,7 +1999,7 @@ source %{ // the returned value may be a card mark or trailing membar // - MemBarNode *leading_to_normal(MemBarNode *leading) + MemBarNode *leading_to_trailing(MemBarNode *leading) { assert((leading->Opcode() == Op_MemBarRelease || leading->Opcode() == Op_MemBarCPUOrder), @@ -1933,15 +2016,21 @@ 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) { - return NULL; + if (mm2 != NULL) { + // should not see more than 2 merge mems + return NULL; + } else { + mm2 = x->as_MergeMem(); + } + } else { + mm = x->as_MergeMem(); } - // 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) { @@ -1961,13 +2050,13 @@ source %{ return NULL; } - // must have a merge if we also have st + // must have at least one 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); @@ -1987,10 +2076,29 @@ 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 { - // ensure the store feeds the existing mergemem; + Node *y = NULL; + // ensure the store feeds the first mergemem; for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) { if (st->fast_out(i) == mm) { y = st; @@ -2000,55 +2108,89 @@ source %{ if (y == NULL) { return NULL; } - } - - 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; + 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; } } - break; + 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(); + } + 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; + } } } - - return mbar; } - // normal_to_leading + // trailing_to_leading // // graph traversal helper which detects the normal case Mem feed - // 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. + // 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. // - // MemBarRelease - // MemBarCPUOrder {leading} - // | \ . . . - // | StoreN/P[mo_release] . . . - // | / - // MergeMem - // | - // MemBarVolatile {card mark or trailing} + // MemBarRelease {leading} + // MemBarCPUOrder {optional} + // | Bot | \ . . . + // | | StoreN/P[mo_release] . . . + // | | / + // | MergeMem + // | | + // MemBarVolatile {not card mark} // - // MemBarRelease - // MemBarCPUOrder {leading} + // MemBarRelease {leading} + // MemBarCPUOrder {optional} // | \ . . . // | CompareAndSwapX . . . // | // . . . SCMemProj // \ | // | MergeMem - // | / + // | | // MemBarCPUOrder // MemBarAcquire {trailing} // @@ -2058,15 +2200,20 @@ 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 but - // need not be a card mark membar. + // 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. - MemBarNode *normal_to_leading(const MemBarNode *barrier) + MemBarNode *trailing_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; @@ -2179,169 +2326,35 @@ source %{ return NULL; } - // card_mark_to_trailing + // card_mark_to_leading // - // 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. + // 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. // - // 1) - // . . . - // | - // MemBarVolatile (card mark) - // | | - // | StoreCM - // | | - // | . . . - // Bot | / - // MergeMem - // | - // | - // MemBarVolatile {trailing} - // - // 2) - // MemBarRelease/CPUOrder (leading) - // | - // | - // |\ . . . - // | \ | - // | \ MemBarVolatile (card mark) - // | \ | | - // \ \ | StoreCM . . . - // \ \ | - // \ Phi - // \ / - // Phi . . . + // MemBarRelease {leading} + // {MemBarCPUOrder} {optional} + // | . . . // Bot | / - // MergeMem + // MergeMem // | - // MemBarVolatile {trailing} + // MemBarVolatile (card mark) + // | \ + // . . . StoreCM // + // if the configuration is present returns the cpuorder member for + // preference or when absent the release membar otherwise NULL. // - // 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 + // n.b. the input membar is expected to be a MemBarVolatile amd must + // be a card mark membar. - MemBarNode *card_mark_to_trailing(const MemBarNode *barrier) + MemBarNode *card_mark_to_leading(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 = trailing->in(TypeFunc::Memory); + Node *x = barrier->in(TypeFunc::Memory); if (!x->is_MergeMem()) { return NULL; } @@ -2349,118 +2362,20 @@ 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 *card_mark_membar = x->as_MemBar(); + MemBarNode *leading = x->as_MemBar(); - 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) { + if (leading_membar(leading)) { return leading; } - // 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); + return NULL; } - // predicates controlling emit of ldr/ldar and associated dmb - bool unnecessary_acquire(const Node *barrier) { assert(barrier->is_MemBar(), "expecting a membar"); @@ -2675,19 +2590,8 @@ bool unnecessary_release(const Node *n) } // must start with a normal feed - MemBarNode *child_barrier = leading_to_normal(barrier); + MemBarNode *trailing = leading_to_trailing(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); } @@ -2709,7 +2613,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 hgraph. + // a trailing membar of a volatile put graph. return (trailing_to_leading(mbvol) != NULL); } @@ -2759,20 +2663,9 @@ bool needs_releasing_store(const Node *n) } // does this lead a normal subgraph? - MemBarNode *mbvol = leading_to_normal(barrier); + MemBarNode *trailing = leading_to_trailing(barrier); - 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); + return (trailing != NULL); } // predicate controlling translation of CAS @@ -2814,7 +2707,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_normal(barrier); + MemBarNode *mbar = leading_to_trailing(barrier); assert(mbar != NULL, "CAS not embedded in normal graph!"); @@ -2835,48 +2728,27 @@ 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 + // 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 if (!UseConcMarkSweepGC || UseCondCardMark) { return true; } - // if we are implementing volatile puts using barriers then the - // object put as an str so we must insert the dmb ishst + // if we are implementing volatile puts using barriers then we must + // insert the dmb ishst if (UseBarriersForVolatile) { return false; } - // 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 + // we must be using CMS with conditional card marking so we ahve to + // generate the StoreStore - 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); + return false; } @@ -13409,7 +13281,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, vRegF src) %{ __ fmovs($dst$$Register, as_FloatRegister($src$$reg)); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_f2i); %} @@ -13427,7 +13299,7 @@ instruct MoveI2F_reg_reg(vRegF dst, iRegI src) %{ __ fmovs(as_FloatRegister($dst$$reg), $src$$Register); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_i2f); %} @@ -13445,7 +13317,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, vRegD src) %{ __ fmovd($dst$$Register, as_FloatRegister($src$$reg)); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_d2l); %} @@ -13463,7 +13335,7 @@ instruct MoveL2D_reg_reg(vRegD dst, iRegL src) %{ __ fmovd(as_FloatRegister($dst$$reg), $src$$Register); %} - ins_pipe(pipe_class_memory); + ins_pipe(fp_l2d); %} @@ -14319,6 +14191,25 @@ instruct cmpP_imm0_branch(cmpOp cmp, iRegP op1, immP0 op2, label labl, rFlagsReg ins_pipe(pipe_cmp_branch); %} +instruct cmpN_imm0_branch(cmpOp cmp, iRegN op1, immN0 op2, label labl, rFlagsReg cr) %{ + match(If cmp (CmpN op1 op2)); + predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne + || n->in(1)->as_Bool()->_test._test == BoolTest::eq); + effect(USE labl); + + ins_cost(BRANCH_COST); + format %{ "cbw$cmp $op1, $labl" %} + ins_encode %{ + Label* L = $labl$$label; + Assembler::Condition cond = (Assembler::Condition)$cmp$$cmpcode; + if (cond == Assembler::EQ) + __ cbzw($op1$$Register, *L); + else + __ cbnzw($op1$$Register, *L); + %} + ins_pipe(pipe_cmp_branch); +%} + instruct cmpP_narrowOop_imm0_branch(cmpOp cmp, iRegN oop, immP0 zero, label labl, rFlagsReg cr) %{ match(If cmp (CmpP (DecodeN oop) zero)); predicate(n->in(1)->as_Bool()->_test._test == BoolTest::ne @@ -14911,19 +14802,19 @@ instruct string_indexof_con(iRegP_R1 str1, iRegI_R4 cnt1, iRegP_R3 str2, %} instruct string_equals(iRegP_R1 str1, iRegP_R3 str2, iRegI_R4 cnt, - iRegI_R0 result, iRegP_R10 tmp, rFlagsReg cr) + iRegI_R0 result, rFlagsReg cr) %{ predicate(!CompactStrings); match(Set result (StrEquals (Binary str1 str2) cnt)); - effect(KILL tmp, USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); - format %{ "String Equals $str1,$str2,$cnt -> $result // KILL $tmp" %} + format %{ "String Equals $str1,$str2,$cnt -> $result" %} ins_encode %{ // Count is in 8-bit bytes; non-Compact chars are 16 bits. __ asrw($cnt$$Register, $cnt$$Register, 1); - __ string_equals($str1$$Register, $str2$$Register, - $cnt$$Register, $result$$Register, - $tmp$$Register); + __ arrays_equals($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, + 2, /*is_string*/true); %} ins_pipe(pipe_class_memory); %} @@ -14937,9 +14828,10 @@ instruct array_equalsB(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ byte_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); - %} + __ arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 1, /*is_string*/false); + %} ins_pipe(pipe_class_memory); %} @@ -14952,12 +14844,14 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, format %{ "Array Equals $ary1,ary2 -> $result // KILL $tmp" %} ins_encode %{ - __ char_arrays_equals($ary1$$Register, $ary2$$Register, - $result$$Register, $tmp$$Register); + __ arrays_equals($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, + 2, /*is_string*/false); %} ins_pipe(pipe_class_memory); %} + // encode char[] to byte[] in ISO_8859_1 instruct encode_iso_array(iRegP_R2 src, iRegP_R1 dst, iRegI_R3 len, vRegD_V0 Vtmp1, vRegD_V1 Vtmp2, @@ -16608,7 +16502,7 @@ instruct vsll2I(vecD dst, vecD src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift64_imm); + ins_pipe(vshift64); %} instruct vsll4I(vecX dst, vecX src, vecX shift) %{ @@ -16622,7 +16516,7 @@ instruct vsll4I(vecX dst, vecX src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift128_imm); + ins_pipe(vshift128); %} instruct vsrl2I(vecD dst, vecD src, vecX shift) %{ @@ -16635,7 +16529,7 @@ instruct vsrl2I(vecD dst, vecD src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift64_imm); + ins_pipe(vshift64); %} instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ @@ -16648,7 +16542,7 @@ instruct vsrl4I(vecX dst, vecX src, vecX shift) %{ as_FloatRegister($src$$reg), as_FloatRegister($shift$$reg)); %} - ins_pipe(vshift128_imm); + ins_pipe(vshift128); %} instruct vsll2I_imm(vecD dst, vecD src, immI shift) %{ @@ -16766,7 +16660,7 @@ instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{ as_FloatRegister($src$$reg), (int)$shift$$constant & 63); %} - ins_pipe(vshift128); + ins_pipe(vshift128_imm); %} instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{ diff --git a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp index 3e65f538de5..b302548557b 100644 --- a/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/jvmciCodeInstaller_aarch64.cpp @@ -74,7 +74,7 @@ void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, T void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset, TRAPS) { address pc = _instructions->start() + pc_offset; NativeInstruction* inst = nativeInstruction_at(pc); - if (inst->is_adr_aligned()) { + if (inst->is_adr_aligned() || inst->is_ldr_literal()) { address dest = _constants->start() + data_offset; _instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS)); TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset); diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index 8c7f9465622..942518b116b 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -4481,225 +4481,126 @@ void MacroAssembler::string_compare(Register str1, Register str2, BLOCK_COMMENT("} string_compare"); } +// Compare Strings or char/byte arrays. -void MacroAssembler::string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1) { - Label SAME_CHARS, DONE, SHORT_LOOP, SHORT_STRING, - NEXT_WORD; +// is_string is true iff this is a string comparison. - const Register tmp2 = rscratch1; - assert_different_registers(str1, str2, cnt, result, tmp1, tmp2, rscratch2); +// For Strings we're passed the address of the first characters in a1 +// and a2 and the length in cnt1. - BLOCK_COMMENT("string_equals {"); +// For byte and char arrays we're passed the arrays themselves and we +// have to extract length fields and do null checks here. - // Start by assuming that the strings are not equal. - mov(result, zr); +// elem_size is the element size in bytes: either 1 or 2. - // A very short string - cmpw(cnt, 4); - br(Assembler::LT, SHORT_STRING); +// There are two implementations. For arrays >= 8 bytes, all +// comparisons (including the final one, which may overlap) are +// performed 8 bytes at a time. For arrays < 8 bytes, we compare a +// halfword, then a short, and then a byte. - // Check if the strings start at the same location. - cmp(str1, str2); - br(Assembler::EQ, SAME_CHARS); +void MacroAssembler::arrays_equals(Register a1, Register a2, + Register result, Register cnt1, + int elem_size, bool is_string) +{ + Label SAME, DONE, SHORT, NEXT_WORD, ONE; + Register tmp1 = rscratch1; + Register tmp2 = rscratch2; + Register cnt2 = tmp2; // cnt2 only used in array length compare + int elem_per_word = wordSize/elem_size; + int log_elem_size = exact_log2(elem_size); + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset + = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); - // Compare longwords - { - subw(cnt, cnt, 4); // The last longword is a special case + assert(elem_size == 1 || elem_size == 2, "must be char or byte"); + assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2); - // Move both string pointers to the last longword of their - // strings, negate the remaining count, and convert it to bytes. - lea(str1, Address(str1, cnt, Address::uxtw(1))); - lea(str2, Address(str2, cnt, Address::uxtw(1))); - sub(cnt, zr, cnt, LSL, 1); + BLOCK_COMMENT(is_string ? "string_equals {" : "array_equals {"); - // Loop, loading longwords and comparing them into rscratch2. - bind(NEXT_WORD); - ldr(tmp1, Address(str1, cnt)); - ldr(tmp2, Address(str2, cnt)); - adds(cnt, cnt, wordSize); - eor(rscratch2, tmp1, tmp2); - cbnz(rscratch2, DONE); - br(Assembler::LT, NEXT_WORD); + mov(result, false); - // Last longword. In the case where length == 4 we compare the - // same longword twice, but that's still faster than another - // conditional branch. + if (!is_string) { + // if (a==a2) + // return true; + eor(rscratch1, a1, a2); + cbz(rscratch1, SAME); + // if (a==null || a2==null) + // return false; + cbz(a1, DONE); + cbz(a2, DONE); + // if (a1.length != a2.length) + // return false; + ldrw(cnt1, Address(a1, length_offset)); + ldrw(cnt2, Address(a2, length_offset)); + eorw(tmp1, cnt1, cnt2); + cbnzw(tmp1, DONE); - ldr(tmp1, Address(str1)); - ldr(tmp2, Address(str2)); - eor(rscratch2, tmp1, tmp2); - cbz(rscratch2, SAME_CHARS); - b(DONE); + lea(a1, Address(a1, base_offset)); + lea(a2, Address(a2, base_offset)); } - bind(SHORT_STRING); - // Is the length zero? - cbz(cnt, SAME_CHARS); - - bind(SHORT_LOOP); - load_unsigned_short(tmp1, Address(post(str1, 2))); - load_unsigned_short(tmp2, Address(post(str2, 2))); - subw(tmp1, tmp1, tmp2); + // Check for short strings, i.e. smaller than wordSize. + subs(cnt1, cnt1, elem_per_word); + br(Assembler::LT, SHORT); + // Main 8 byte comparison loop. + bind(NEXT_WORD); { + ldr(tmp1, Address(post(a1, wordSize))); + ldr(tmp2, Address(post(a2, wordSize))); + subs(cnt1, cnt1, elem_per_word); + eor(tmp1, tmp1, tmp2); + cbnz(tmp1, DONE); + } br(GT, NEXT_WORD); + // Last longword. In the case where length == 4 we compare the + // same longword twice, but that's still faster than another + // conditional branch. + // cnt1 could be 0, -1, -2, -3, -4 for chars; -4 only happens when + // length == 4. + if (log_elem_size > 0) + lsl(cnt1, cnt1, log_elem_size); + ldr(tmp1, Address(a1, cnt1)); + ldr(tmp2, Address(a2, cnt1)); + eor(tmp1, tmp1, tmp2); cbnz(tmp1, DONE); - sub(cnt, cnt, 1); - cbnz(cnt, SHORT_LOOP); + b(SAME); - // Strings are equal. - bind(SAME_CHARS); + bind(SHORT); + Label TAIL03, TAIL01; + + tbz(cnt1, 2 - log_elem_size, TAIL03); // 0-7 bytes left. + { + ldrw(tmp1, Address(post(a1, 4))); + ldrw(tmp2, Address(post(a2, 4))); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + bind(TAIL03); + tbz(cnt1, 1 - log_elem_size, TAIL01); // 0-3 bytes left. + { + ldrh(tmp1, Address(post(a1, 2))); + ldrh(tmp2, Address(post(a2, 2))); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + bind(TAIL01); + if (elem_size == 1) { // Only needed when comparing byte arrays. + tbz(cnt1, 0, SAME); // 0-1 bytes left. + { + ldrb(tmp1, a1); + ldrb(tmp2, a2); + eorw(tmp1, tmp1, tmp2); + cbnzw(tmp1, DONE); + } + } + // Arrays are equal. + bind(SAME); mov(result, true); - // That's it + // That's it. bind(DONE); - - BLOCK_COMMENT("} string_equals"); + BLOCK_COMMENT(is_string ? "} string_equals" : "} array_equals"); } -void MacroAssembler::byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL07, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_BYTE); - - BLOCK_COMMENT("byte_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 8); - br(LT, TAIL07); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 8); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL07); // 0-7 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b100); - br(EQ, TAIL03); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(TAIL03); // 0-3 bytes left, cnt1 = #bytes left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrh(tmp1, Address(post(ary1, 2))); - ldrh(tmp2, Address(post(ary2, 2))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 byte left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrb(tmp1, ary1); - ldrb(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} byte_arrays_equals"); -} - -// Compare char[] arrays aligned to 4 bytes -void MacroAssembler::char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1) -{ - Register cnt1 = rscratch1; - Register cnt2 = rscratch2; - Register tmp2 = rscratch2; - - Label SAME, DIFFER, NEXT, TAIL03, TAIL01; - - int length_offset = arrayOopDesc::length_offset_in_bytes(); - int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR); - - BLOCK_COMMENT("char_arrays_equals {"); - - // different until proven equal - mov(result, false); - - // same array? - cmp(ary1, ary2); - br(Assembler::EQ, SAME); - - // ne if either null - cbz(ary1, DIFFER); - cbz(ary2, DIFFER); - - // lengths ne? - ldrw(cnt1, Address(ary1, length_offset)); - ldrw(cnt2, Address(ary2, length_offset)); - cmp(cnt1, cnt2); - br(Assembler::NE, DIFFER); - - lea(ary1, Address(ary1, base_offset)); - lea(ary2, Address(ary2, base_offset)); - - subs(cnt1, cnt1, 4); - br(LT, TAIL03); - - BIND(NEXT); - ldr(tmp1, Address(post(ary1, 8))); - ldr(tmp2, Address(post(ary2, 8))); - subs(cnt1, cnt1, 4); - eor(tmp1, tmp1, tmp2); - cbnz(tmp1, DIFFER); - br(GE, NEXT); - - BIND(TAIL03); // 0-3 chars left, cnt1 = #chars left - 4 - tst(cnt1, 0b10); - br(EQ, TAIL01); - ldrw(tmp1, Address(post(ary1, 4))); - ldrw(tmp2, Address(post(ary2, 4))); - cmp(tmp1, tmp2); - br(NE, DIFFER); - BIND(TAIL01); // 0-1 chars left - tst(cnt1, 0b01); - br(EQ, SAME); - ldrh(tmp1, ary1); - ldrh(tmp2, ary2); - cmp(tmp1, tmp2); - br(NE, DIFFER); - - BIND(SAME); - mov(result, true); - BIND(DIFFER); // result already set - - BLOCK_COMMENT("} char_arrays_equals"); -} - // encode char[] to byte[] in ISO_8859_1 void MacroAssembler::encode_iso_array(Register src, Register dst, Register len, Register result, diff --git a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp index d22c581bc41..e042b5055eb 100644 --- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp @@ -1186,13 +1186,11 @@ public: void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register result, Register tmp1); - void string_equals(Register str1, Register str2, - Register cnt, Register result, - Register tmp1); - void char_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); - void byte_arrays_equals(Register ary1, Register ary2, - Register result, Register tmp1); + + void arrays_equals(Register a1, Register a2, + Register result, Register cnt1, + int elem_size, bool is_string); + void encode_iso_array(Register src, Register dst, Register len, Register result, FloatRegister Vtmp1, FloatRegister Vtmp2, diff --git a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp index 72c3479659c..d83017c1770 100644 --- a/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp +++ b/hotspot/src/cpu/aarch64/vm/nativeInst_aarch64.hpp @@ -105,13 +105,20 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { inline friend NativeInstruction* nativeInstruction_at(address address); static bool is_adrp_at(address instr); + static bool is_ldr_literal_at(address instr); + + bool is_ldr_literal() { + return is_ldr_literal_at(addr_at(0)); + } + static bool is_ldrw_to_zr(address instr); static bool is_call_at(address instr) { const uint32_t insn = (*(uint32_t*)instr); return (insn >> 26) == 0b100101; } + bool is_call() { return is_call_at(addr_at(0)); } diff --git a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp index 554495da44e..942d7bc5cb7 100644 --- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp +++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp @@ -163,30 +163,20 @@ class StubGenerator: public StubCodeGenerator { sp_after_call_off = -26, d15_off = -26, - d14_off = -25, d13_off = -24, - d12_off = -23, d11_off = -22, - d10_off = -21, d9_off = -20, - d8_off = -19, r28_off = -18, - r27_off = -17, r26_off = -16, - r25_off = -15, r24_off = -14, - r23_off = -13, r22_off = -12, - r21_off = -11, r20_off = -10, - r19_off = -9, call_wrapper_off = -8, result_off = -7, result_type_off = -6, method_off = -5, entry_point_off = -4, - parameters_off = -3, parameter_size_off = -2, thread_off = -1, fp_f = 0, @@ -208,30 +198,20 @@ class StubGenerator: public StubCodeGenerator { const Address result_type (rfp, result_type_off * wordSize); const Address method (rfp, method_off * wordSize); const Address entry_point (rfp, entry_point_off * wordSize); - const Address parameters (rfp, parameters_off * wordSize); const Address parameter_size(rfp, parameter_size_off * wordSize); const Address thread (rfp, thread_off * wordSize); const Address d15_save (rfp, d15_off * wordSize); - const Address d14_save (rfp, d14_off * wordSize); const Address d13_save (rfp, d13_off * wordSize); - const Address d12_save (rfp, d12_off * wordSize); const Address d11_save (rfp, d11_off * wordSize); - const Address d10_save (rfp, d10_off * wordSize); const Address d9_save (rfp, d9_off * wordSize); - const Address d8_save (rfp, d8_off * wordSize); const Address r28_save (rfp, r28_off * wordSize); - const Address r27_save (rfp, r27_off * wordSize); const Address r26_save (rfp, r26_off * wordSize); - const Address r25_save (rfp, r25_off * wordSize); const Address r24_save (rfp, r24_off * wordSize); - const Address r23_save (rfp, r23_off * wordSize); const Address r22_save (rfp, r22_off * wordSize); - const Address r21_save (rfp, r21_off * wordSize); const Address r20_save (rfp, r20_off * wordSize); - const Address r19_save (rfp, r19_off * wordSize); // stub code @@ -254,31 +234,20 @@ class StubGenerator: public StubCodeGenerator { // rthread because we want to sanity check rthread later __ str(c_rarg7, thread); __ strw(c_rarg6, parameter_size); - __ str(c_rarg5, parameters); - __ str(c_rarg4, entry_point); - __ str(c_rarg3, method); - __ str(c_rarg2, result_type); - __ str(c_rarg1, result); - __ str(c_rarg0, call_wrapper); - __ str(r19, r19_save); - __ str(r20, r20_save); - __ str(r21, r21_save); - __ str(r22, r22_save); - __ str(r23, r23_save); - __ str(r24, r24_save); - __ str(r25, r25_save); - __ str(r26, r26_save); - __ str(r27, r27_save); - __ str(r28, r28_save); + __ stp(c_rarg4, c_rarg5, entry_point); + __ stp(c_rarg2, c_rarg3, result_type); + __ stp(c_rarg0, c_rarg1, call_wrapper); - __ strd(v8, d8_save); - __ strd(v9, d9_save); - __ strd(v10, d10_save); - __ strd(v11, d11_save); - __ strd(v12, d12_save); - __ strd(v13, d13_save); - __ strd(v14, d14_save); - __ strd(v15, d15_save); + __ stp(r20, r19, r20_save); + __ stp(r22, r21, r22_save); + __ stp(r24, r23, r24_save); + __ stp(r26, r25, r26_save); + __ stp(r28, r27, r28_save); + + __ stpd(v9, v8, d9_save); + __ stpd(v11, v10, d11_save); + __ stpd(v13, v12, d13_save); + __ stpd(v15, v14, d15_save); // install Java thread in global register now we have saved // whatever value it held @@ -385,33 +354,22 @@ class StubGenerator: public StubCodeGenerator { #endif // restore callee-save registers - __ ldrd(v15, d15_save); - __ ldrd(v14, d14_save); - __ ldrd(v13, d13_save); - __ ldrd(v12, d12_save); - __ ldrd(v11, d11_save); - __ ldrd(v10, d10_save); - __ ldrd(v9, d9_save); - __ ldrd(v8, d8_save); + __ ldpd(v15, v14, d15_save); + __ ldpd(v13, v12, d13_save); + __ ldpd(v11, v10, d11_save); + __ ldpd(v9, v8, d9_save); - __ ldr(r28, r28_save); - __ ldr(r27, r27_save); - __ ldr(r26, r26_save); - __ ldr(r25, r25_save); - __ ldr(r24, r24_save); - __ ldr(r23, r23_save); - __ ldr(r22, r22_save); - __ ldr(r21, r21_save); - __ ldr(r20, r20_save); - __ ldr(r19, r19_save); - __ ldr(c_rarg0, call_wrapper); - __ ldr(c_rarg1, result); + __ ldp(r28, r27, r28_save); + __ ldp(r26, r25, r26_save); + __ ldp(r24, r23, r24_save); + __ ldp(r22, r21, r22_save); + __ ldp(r20, r19, r20_save); + + __ ldp(c_rarg0, c_rarg1, call_wrapper); __ ldrw(c_rarg2, result_type); __ ldr(c_rarg3, method); - __ ldr(c_rarg4, entry_point); - __ ldr(c_rarg5, parameters); - __ ldr(c_rarg6, parameter_size); - __ ldr(c_rarg7, thread); + __ ldp(c_rarg4, c_rarg5, entry_point); + __ ldp(c_rarg6, c_rarg7, parameter_size); #ifndef PRODUCT // tell the simulator we are about to end Java execution @@ -666,7 +624,7 @@ class StubGenerator: public StubCodeGenerator { // count - element count // tmp - scratch register // - // Destroy no registers! + // Destroy no registers except rscratch1 and rscratch2 // void gen_write_ref_array_pre_barrier(Register addr, Register count, bool dest_uninitialized) { BarrierSet* bs = Universe::heap()->barrier_set(); @@ -674,12 +632,13 @@ class StubGenerator: public StubCodeGenerator { case BarrierSet::G1SATBCTLogging: // With G1, don't generate the call if we statically know that the target in uninitialized if (!dest_uninitialized) { - __ push(RegSet::range(r0, r29), sp); // integer registers except lr & sp + __ push_call_clobbered_registers(); if (count == c_rarg0) { if (addr == c_rarg1) { // exactly backwards!! - __ stp(c_rarg0, c_rarg1, __ pre(sp, -2 * wordSize)); - __ ldp(c_rarg1, c_rarg0, __ post(sp, -2 * wordSize)); + __ mov(rscratch1, c_rarg0); + __ mov(c_rarg0, c_rarg1); + __ mov(c_rarg1, rscratch1); } else { __ mov(c_rarg1, count); __ mov(c_rarg0, addr); @@ -689,7 +648,7 @@ class StubGenerator: public StubCodeGenerator { __ mov(c_rarg1, count); } __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_pre), 2); - __ pop(RegSet::range(r0, r29), sp); // integer registers except lr & sp } + __ pop_call_clobbered_registers(); break; case BarrierSet::CardTableForRS: case BarrierSet::CardTableExtension: @@ -719,7 +678,7 @@ class StubGenerator: public StubCodeGenerator { case BarrierSet::G1SATBCTLogging: { - __ push(RegSet::range(r0, r29), sp); // integer registers except lr & sp + __ push_call_clobbered_registers(); // must compute element count unless barrier set interface is changed (other platforms supply count) assert_different_registers(start, end, scratch); __ lea(scratch, Address(end, BytesPerHeapOop)); @@ -728,7 +687,7 @@ class StubGenerator: public StubCodeGenerator { __ mov(c_rarg0, start); __ mov(c_rarg1, scratch); __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2); - __ pop(RegSet::range(r0, r29), sp); // integer registers except lr & sp } + __ pop_call_clobbered_registers(); } break; case BarrierSet::CardTableForRS: @@ -1394,10 +1353,10 @@ class StubGenerator: public StubCodeGenerator { // no-overlap entry point used by generate_conjoint_long_oop_copy(). // address generate_disjoint_oop_copy(bool aligned, address *entry, - const char *name, bool dest_uninitialized = false) { + const char *name, bool dest_uninitialized) { const bool is_oop = true; const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); - return generate_disjoint_copy(size, aligned, is_oop, entry, name); + return generate_disjoint_copy(size, aligned, is_oop, entry, name, dest_uninitialized); } // Arguments: @@ -1412,10 +1371,11 @@ class StubGenerator: public StubCodeGenerator { // address generate_conjoint_oop_copy(bool aligned, address nooverlap_target, address *entry, - const char *name, bool dest_uninitialized = false) { + const char *name, bool dest_uninitialized) { const bool is_oop = true; const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); - return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, name); + return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, + name, dest_uninitialized); } @@ -1522,6 +1482,8 @@ class StubGenerator: public StubCodeGenerator { } #endif //ASSERT + gen_write_ref_array_pre_barrier(to, count, dest_uninitialized); + // save the original count __ mov(count_save, count); @@ -1988,9 +1950,11 @@ class StubGenerator: public StubCodeGenerator { bool aligned = !UseCompressedOops; StubRoutines::_arrayof_oop_disjoint_arraycopy - = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy"); + = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy", + /*dest_uninitialized*/false); StubRoutines::_arrayof_oop_arraycopy - = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy"); + = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy", + /*dest_uninitialized*/false); // Aligned versions without pre-barriers StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy_uninit", diff --git a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp index cb4105de874..4afb89e1ffb 100644 --- a/hotspot/src/cpu/ppc/vm/globals_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/globals_ppc.hpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -74,8 +74,7 @@ define_pd_global(size_t, CMSYoungGenPerWorker, 16*M); // Default max size of CM define_pd_global(uintx, TypeProfileLevel, 111); -// No performance work done here yet. -define_pd_global(bool, CompactStrings, false); +define_pd_global(bool, CompactStrings, true); // Platform dependent flag handling: flags only defined on this platform. #define ARCH_FLAGS(develop, product, diagnostic, experimental, notproduct, range, constraint) \ diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp index e9da9714579..ce9d109dfdd 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.cpp @@ -45,6 +45,9 @@ #include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#ifdef COMPILER2 +#include "opto/intrinsicnode.hpp" +#endif #ifdef PRODUCT #define BLOCK_COMMENT(str) // nothing @@ -3168,6 +3171,553 @@ void MacroAssembler::clear_memory_doubleword(Register base_ptr, Register cnt_dwo /////////////////////////////////////////// String intrinsics //////////////////////////////////////////// +#ifdef COMPILER2 +// Intrinsics for CompactStrings + +// Compress char[] to byte[] by compressing 16 bytes at once. +void MacroAssembler::string_compress_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Label& Lfailure) { + + const Register tmp0 = R0; + assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); + Label Lloop, Lslow; + + // Check if cnt >= 8 (= 16 bytes) + lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF00FF00FF + srwi_(tmp2, cnt, 3); + beq(CCR0, Lslow); + ori(tmp1, tmp1, 0xFF); + rldimi(tmp1, tmp1, 32, 0); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lloop); + ld(tmp2, 0, src); // _0_1_2_3 (Big Endian) + ld(tmp4, 8, src); // _4_5_6_7 + + orr(tmp0, tmp2, tmp4); + rldicl(tmp3, tmp2, 6*8, 64-24); // _____1_2 + rldimi(tmp2, tmp2, 2*8, 2*8); // _0_2_3_3 + rldicl(tmp5, tmp4, 6*8, 64-24); // _____5_6 + rldimi(tmp4, tmp4, 2*8, 2*8); // _4_6_7_7 + + andc_(tmp0, tmp0, tmp1); + bne(CCR0, Lfailure); // Not latin1. + addi(src, src, 16); + + rlwimi(tmp3, tmp2, 0*8, 24, 31);// _____1_3 + srdi(tmp2, tmp2, 3*8); // ____0_2_ + rlwimi(tmp5, tmp4, 0*8, 24, 31);// _____5_7 + srdi(tmp4, tmp4, 3*8); // ____4_6_ + + orr(tmp2, tmp2, tmp3); // ____0123 + orr(tmp4, tmp4, tmp5); // ____4567 + + stw(tmp2, 0, dst); + stw(tmp4, 4, dst); + addi(dst, dst, 8); + bdnz(Lloop); + + bind(Lslow); // Fallback to slow version +} + +// Compress char[] to byte[]. cnt must be positive int. +void MacroAssembler::string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure) { + Label Lloop; + mtctr(cnt); + + bind(Lloop); + lhz(tmp, 0, src); + cmplwi(CCR0, tmp, 0xff); + bgt(CCR0, Lfailure); // Not latin1. + addi(src, src, 2); + stb(tmp, 0, dst); + addi(dst, dst, 1); + bdnz(Lloop); +} + +// Inflate byte[] to char[] by inflating 16 bytes at once. +void MacroAssembler::string_inflate_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { + const Register tmp0 = R0; + assert_different_registers(src, dst, cnt, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5); + Label Lloop, Lslow; + + // Check if cnt >= 8 + srwi_(tmp2, cnt, 3); + beq(CCR0, Lslow); + lis(tmp1, 0xFF); // tmp1 = 0x00FF00FF + ori(tmp1, tmp1, 0xFF); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lloop); + lwz(tmp2, 0, src); // ____0123 (Big Endian) + lwz(tmp4, 4, src); // ____4567 + addi(src, src, 8); + + rldicl(tmp3, tmp2, 7*8, 64-8); // _______2 + rlwimi(tmp2, tmp2, 3*8, 16, 23);// ____0113 + rldicl(tmp5, tmp4, 7*8, 64-8); // _______6 + rlwimi(tmp4, tmp4, 3*8, 16, 23);// ____4557 + + andc(tmp0, tmp2, tmp1); // ____0_1_ + rlwimi(tmp2, tmp3, 2*8, 0, 23); // _____2_3 + andc(tmp3, tmp4, tmp1); // ____4_5_ + rlwimi(tmp4, tmp5, 2*8, 0, 23); // _____6_7 + + rldimi(tmp2, tmp0, 3*8, 0*8); // _0_1_2_3 + rldimi(tmp4, tmp3, 3*8, 0*8); // _4_5_6_7 + + std(tmp2, 0, dst); + std(tmp4, 8, dst); + addi(dst, dst, 16); + bdnz(Lloop); + + bind(Lslow); // Fallback to slow version +} + +// Inflate byte[] to char[]. cnt must be positive int. +void MacroAssembler::string_inflate(Register src, Register dst, Register cnt, Register tmp) { + Label Lloop; + mtctr(cnt); + + bind(Lloop); + lbz(tmp, 0, src); + addi(src, src, 1); + sth(tmp, 0, dst); + addi(dst, dst, 2); + bdnz(Lloop); +} + +void MacroAssembler::string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, + Register tmp1, Register result, int ae) { + const Register tmp0 = R0, + diff = tmp1; + + assert_different_registers(str1, str2, cnt1, cnt2, tmp0, tmp1, result); + Label Ldone, Lslow, Lloop, Lreturn_diff; + + // Note: Making use of the fact that compareTo(a, b) == -compareTo(b, a) + // we interchange str1 and str2 in the UL case and negate the result. + // Like this, str1 is always latin1 encoded, except for the UU case. + // In addition, we need 0 (or sign which is 0) extend. + + if (ae == StrIntrinsicNode::UU) { + srwi(cnt1, cnt1, 1); + } else { + clrldi(cnt1, cnt1, 32); + } + + if (ae != StrIntrinsicNode::LL) { + srwi(cnt2, cnt2, 1); + } else { + clrldi(cnt2, cnt2, 32); + } + + // See if the lengths are different, and calculate min in cnt1. + // Save diff in case we need it for a tie-breaker. + subf_(diff, cnt2, cnt1); // diff = cnt1 - cnt2 + // if (diff > 0) { cnt1 = cnt2; } + if (VM_Version::has_isel()) { + isel(cnt1, CCR0, Assembler::greater, /*invert*/ false, cnt2); + } else { + Label Lskip; + blt(CCR0, Lskip); + mr(cnt1, cnt2); + bind(Lskip); + } + + // Rename registers + Register chr1 = result; + Register chr2 = tmp0; + + // Compare multiple characters in fast loop (only implemented for same encoding). + int stride1 = 8, stride2 = 8; + if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) { + int log2_chars_per_iter = (ae == StrIntrinsicNode::LL) ? 3 : 2; + Label Lfastloop, Lskipfast; + + srwi_(tmp0, cnt1, log2_chars_per_iter); + beq(CCR0, Lskipfast); + rldicl(cnt2, cnt1, 0, 64 - log2_chars_per_iter); // Remaining characters. + li(cnt1, 1 << log2_chars_per_iter); // Initialize for failure case: Rescan characters from current iteration. + mtctr(tmp0); + + bind(Lfastloop); + ld(chr1, 0, str1); + ld(chr2, 0, str2); + cmpd(CCR0, chr1, chr2); + bne(CCR0, Lslow); + addi(str1, str1, stride1); + addi(str2, str2, stride2); + bdnz(Lfastloop); + mr(cnt1, cnt2); // Remaining characters. + bind(Lskipfast); + } + + // Loop which searches the first difference character by character. + cmpwi(CCR0, cnt1, 0); + beq(CCR0, Lreturn_diff); + bind(Lslow); + mtctr(cnt1); + + switch (ae) { + case StrIntrinsicNode::LL: stride1 = 1; stride2 = 1; break; + case StrIntrinsicNode::UL: // fallthru (see comment above) + case StrIntrinsicNode::LU: stride1 = 1; stride2 = 2; break; + case StrIntrinsicNode::UU: stride1 = 2; stride2 = 2; break; + default: ShouldNotReachHere(); break; + } + + bind(Lloop); + if (stride1 == 1) { lbz(chr1, 0, str1); } else { lhz(chr1, 0, str1); } + if (stride2 == 1) { lbz(chr2, 0, str2); } else { lhz(chr2, 0, str2); } + subf_(result, chr2, chr1); // result = chr1 - chr2 + bne(CCR0, Ldone); + addi(str1, str1, stride1); + addi(str2, str2, stride2); + bdnz(Lloop); + + // If strings are equal up to min length, return the length difference. + bind(Lreturn_diff); + mr(result, diff); + + // Otherwise, return the difference between the first mismatched chars. + bind(Ldone); + if (ae == StrIntrinsicNode::UL) { + neg(result, result); // Negate result (see note above). + } +} + +void MacroAssembler::array_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register tmp1, Register result, bool is_byte) { + const Register tmp0 = R0; + assert_different_registers(ary1, ary2, limit, tmp0, tmp1, result); + Label Ldone, Lskiploop, Lloop, Lfastloop, Lskipfast; + bool limit_needs_shift = false; + + if (is_array_equ) { + const int length_offset = arrayOopDesc::length_offset_in_bytes(); + const int base_offset = arrayOopDesc::base_offset_in_bytes(is_byte ? T_BYTE : T_CHAR); + + // Return true if the same array. + cmpd(CCR0, ary1, ary2); + beq(CCR0, Lskiploop); + + // Return false if one of them is NULL. + cmpdi(CCR0, ary1, 0); + cmpdi(CCR1, ary2, 0); + li(result, 0); + cror(CCR0, Assembler::equal, CCR1, Assembler::equal); + beq(CCR0, Ldone); + + // Load the lengths of arrays. + lwz(limit, length_offset, ary1); + lwz(tmp0, length_offset, ary2); + + // Return false if the two arrays are not equal length. + cmpw(CCR0, limit, tmp0); + bne(CCR0, Ldone); + + // Load array addresses. + addi(ary1, ary1, base_offset); + addi(ary2, ary2, base_offset); + } else { + limit_needs_shift = !is_byte; + li(result, 0); // Assume not equal. + } + + // Rename registers + Register chr1 = tmp0; + Register chr2 = tmp1; + + // Compare 8 bytes per iteration in fast loop. + const int log2_chars_per_iter = is_byte ? 3 : 2; + + srwi_(tmp0, limit, log2_chars_per_iter + (limit_needs_shift ? 1 : 0)); + beq(CCR0, Lskipfast); + mtctr(tmp0); + + bind(Lfastloop); + ld(chr1, 0, ary1); + ld(chr2, 0, ary2); + addi(ary1, ary1, 8); + addi(ary2, ary2, 8); + cmpd(CCR0, chr1, chr2); + bne(CCR0, Ldone); + bdnz(Lfastloop); + + bind(Lskipfast); + rldicl_(limit, limit, limit_needs_shift ? 64 - 1 : 0, 64 - log2_chars_per_iter); // Remaining characters. + beq(CCR0, Lskiploop); + mtctr(limit); + + // Character by character. + bind(Lloop); + if (is_byte) { + lbz(chr1, 0, ary1); + lbz(chr2, 0, ary2); + addi(ary1, ary1, 1); + addi(ary2, ary2, 1); + } else { + lhz(chr1, 0, ary1); + lhz(chr2, 0, ary2); + addi(ary1, ary1, 2); + addi(ary2, ary2, 2); + } + cmpw(CCR0, chr1, chr2); + bne(CCR0, Ldone); + bdnz(Lloop); + + bind(Lskiploop); + li(result, 1); // All characters are equal. + bind(Ldone); +} + +void MacroAssembler::string_indexof(Register result, Register haystack, Register haycnt, + Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae) { + + // Ensure 0=2, bail out otherwise. + // ************************************************************************************************** + + // Compute last haystack addr to use if no match gets found. + clrldi(haycnt, haycnt, 32); // Ensure positive int is valid as 64 bit value. + addi(addr, haystack, -h_csize); // Accesses use pre-increment. + if (needlecntval == 0) { // variable needlecnt + cmpwi(CCR6, needlecnt, 2); + clrldi(needlecnt, needlecnt, 32); // Ensure positive int is valid as 64 bit value. + blt(CCR6, L_TooShort); // Variable needlecnt: handle short needle separately. + } + + if (n_csize == 2) { lwz(n_start, 0, needle); } else { lhz(n_start, 0, needle); } // Load first 2 characters of needle. + + if (needlecntval == 0) { // variable needlecnt + subf(ch1, needlecnt, haycnt); // Last character index to compare is haycnt-needlecnt. + addi(needlecnt, needlecnt, -2); // Rest of needle. + } else { // constant needlecnt + guarantee(needlecntval != 1, "IndexOf with single-character needle must be handled separately"); + assert((needlecntval & 0x7fff) == needlecntval, "wrong immediate"); + addi(ch1, haycnt, -needlecntval); // Last character index to compare is haycnt-needlecnt. + if (needlecntval > 3) { li(needlecnt, needlecntval - 2); } // Rest of needle. + } + + if (h_csize == 2) { slwi(ch1, ch1, 1); } // Scale to number of bytes. + + if (ae ==StrIntrinsicNode::UL) { + srwi(tmp4, n_start, 1*8); // ___0 + rlwimi(n_start, tmp4, 2*8, 0, 23); // _0_1 + } + + add(last_addr, haystack, ch1); // Point to last address to compare (haystack+2*(haycnt-needlecnt)). + + // Main Loop (now we have at least 2 characters). + Label L_OuterLoop, L_InnerLoop, L_FinalCheck, L_Comp1, L_Comp2; + bind(L_OuterLoop); // Search for 1st 2 characters. + Register addr_diff = tmp4; + subf(addr_diff, addr, last_addr); // Difference between already checked address and last address to check. + addi(addr, addr, h_csize); // This is the new address we want to use for comparing. + srdi_(ch2, addr_diff, h_csize); + beq(CCR0, L_FinalCheck); // 2 characters left? + mtctr(ch2); // num of characters / 2 + bind(L_InnerLoop); // Main work horse (2x unrolled search loop) + if (h_csize == 2) { // Load 2 characters of haystack (ignore alignment). + lwz(ch1, 0, addr); + lwz(ch2, 2, addr); + } else { + lhz(ch1, 0, addr); + lhz(ch2, 1, addr); + } + cmpw(CCR0, ch1, n_start); // Compare 2 characters (1 would be sufficient but try to reduce branches to CompLoop). + cmpw(CCR1, ch2, n_start); + beq(CCR0, L_Comp1); // Did we find the needle start? + beq(CCR1, L_Comp2); + addi(addr, addr, 2 * h_csize); + bdnz(L_InnerLoop); + bind(L_FinalCheck); + andi_(addr_diff, addr_diff, h_csize); // Remaining characters not covered by InnerLoop: (num of characters) & 1. + beq(CCR0, L_NotFound); + if (h_csize == 2) { lwz(ch1, 0, addr); } else { lhz(ch1, 0, addr); } // One position left at which we have to compare. + cmpw(CCR1, ch1, n_start); + beq(CCR1, L_Comp1); + bind(L_NotFound); + li(result, -1); // not found + b(L_End); + + // ************************************************************************************************** + // Special Case: unfortunately, the variable needle case can be called with needlecnt<2 + // ************************************************************************************************** + if (needlecntval == 0) { // We have to handle these cases separately. + Label L_OneCharLoop; + bind(L_TooShort); + mtctr(haycnt); + if (n_csize == 2) { lhz(n_start, 0, needle); } else { lbz(n_start, 0, needle); } // First character of needle + bind(L_OneCharLoop); + if (h_csize == 2) { lhzu(ch1, 2, addr); } else { lbzu(ch1, 1, addr); } + cmpw(CCR1, ch1, n_start); + beq(CCR1, L_Found); // Did we find the one character needle? + bdnz(L_OneCharLoop); + li(result, -1); // Not found. + b(L_End); + } + + // ************************************************************************************************** + // Regular Case Part II: compare rest of needle (first 2 characters have been compared already) + // ************************************************************************************************** + + // Compare the rest + bind(L_Comp2); + addi(addr, addr, h_csize); // First comparison has failed, 2nd one hit. + bind(L_Comp1); // Addr points to possible needle start. + if (needlecntval != 2) { // Const needlecnt==2? + if (needlecntval != 3) { + if (needlecntval == 0) { beq(CCR6, L_Found); } // Variable needlecnt==2? + Register n_ind = tmp4, + h_ind = n_ind; + li(n_ind, 2 * n_csize); // First 2 characters are already compared, use index 2. + mtctr(needlecnt); // Decremented by 2, still > 0. + Label L_CompLoop; + bind(L_CompLoop); + if (ae ==StrIntrinsicNode::UL) { + h_ind = ch1; + sldi(h_ind, n_ind, 1); + } + if (n_csize == 2) { lhzx(ch2, needle, n_ind); } else { lbzx(ch2, needle, n_ind); } + if (h_csize == 2) { lhzx(ch1, addr, h_ind); } else { lbzx(ch1, addr, h_ind); } + cmpw(CCR1, ch1, ch2); + bne(CCR1, L_OuterLoop); + addi(n_ind, n_ind, n_csize); + bdnz(L_CompLoop); + } else { // No loop required if there's only one needle character left. + if (n_csize == 2) { lhz(ch2, 2 * 2, needle); } else { lbz(ch2, 2 * 1, needle); } + if (h_csize == 2) { lhz(ch1, 2 * 2, addr); } else { lbz(ch1, 2 * 1, addr); } + cmpw(CCR1, ch1, ch2); + bne(CCR1, L_OuterLoop); + } + } + // Return index ... + bind(L_Found); + subf(result, haystack, addr); // relative to haystack, ... + if (h_csize == 2) { srdi(result, result, 1); } // in characters. + bind(L_End); +} // string_indexof + +void MacroAssembler::string_indexof_char(Register result, Register haystack, Register haycnt, + Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte) { + assert_different_registers(haystack, haycnt, needle, tmp1, tmp2); + + Label L_InnerLoop, L_FinalCheck, L_Found1, L_Found2, L_NotFound, L_End; + Register addr = tmp1, + ch1 = tmp2, + ch2 = R0; + + const int h_csize = is_byte ? 1 : 2; + +//4: + srwi_(tmp2, haycnt, 1); // Shift right by exact_log2(UNROLL_FACTOR). + mr(addr, haystack); + beq(CCR0, L_FinalCheck); + mtctr(tmp2); // Move to count register. +//8: + bind(L_InnerLoop); // Main work horse (2x unrolled search loop). + if (!is_byte) { + lhz(ch1, 0, addr); + lhz(ch2, 2, addr); + } else { + lbz(ch1, 0, addr); + lbz(ch2, 1, addr); + } + (needle != R0) ? cmpw(CCR0, ch1, needle) : cmplwi(CCR0, ch1, (unsigned int)needleChar); + (needle != R0) ? cmpw(CCR1, ch2, needle) : cmplwi(CCR1, ch2, (unsigned int)needleChar); + beq(CCR0, L_Found1); // Did we find the needle? + beq(CCR1, L_Found2); + addi(addr, addr, 2 * h_csize); + bdnz(L_InnerLoop); +//16: + bind(L_FinalCheck); + andi_(R0, haycnt, 1); + beq(CCR0, L_NotFound); + if (!is_byte) { lhz(ch1, 0, addr); } else { lbz(ch1, 0, addr); } // One position left at which we have to compare. + (needle != R0) ? cmpw(CCR1, ch1, needle) : cmplwi(CCR1, ch1, (unsigned int)needleChar); + beq(CCR1, L_Found1); +//21: + bind(L_NotFound); + li(result, -1); // Not found. + b(L_End); + + bind(L_Found2); + addi(addr, addr, h_csize); +//24: + bind(L_Found1); // Return index ... + subf(result, haystack, addr); // relative to haystack, ... + if (!is_byte) { srdi(result, result, 1); } // in characters. + bind(L_End); +} // string_indexof_char + + +void MacroAssembler::has_negatives(Register src, Register cnt, Register result, + Register tmp1, Register tmp2) { + const Register tmp0 = R0; + assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2); + Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone; + + // Check if cnt >= 8 (= 16 bytes) + lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080 + srwi_(tmp2, cnt, 4); + li(result, 1); // Assume there's a negative byte. + beq(CCR0, Lslow); + ori(tmp1, tmp1, 0x8080); + rldimi(tmp1, tmp1, 32, 0); + mtctr(tmp2); + + // 2x unrolled loop + bind(Lfastloop); + ld(tmp2, 0, src); + ld(tmp0, 8, src); + + orr(tmp0, tmp2, tmp0); + + and_(tmp0, tmp0, tmp1); + bne(CCR0, Ldone); // Found negative byte. + addi(src, src, 16); + + bdnz(Lfastloop); + + bind(Lslow); // Fallback to slow version + rldicl_(tmp0, cnt, 0, 64-4); + beq(CCR0, Lnoneg); + mtctr(tmp0); + bind(Lloop); + lbz(tmp0, 0, src); + addi(src, src, 1); + andi_(tmp0, tmp0, 0x80); + bne(CCR0, Ldone); // Found negative byte. + bdnz(Lloop); + bind(Lnoneg); + li(result, 0); + + bind(Ldone); +} + + +// Intrinsics for non-CompactStrings + // Search for a single jchar in an jchar[]. // // Assumes that result differs from all other registers. @@ -3613,6 +4163,8 @@ void MacroAssembler::char_arrays_equalsImm(Register str1_reg, Register str2_reg, bind(Ldone_false); } +#endif // Compiler2 + // Helpers for Intrinsic Emitters // // Revert the byte order of a 32bit value in a register diff --git a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp index 925e73a82d1..53a269a83c2 100644 --- a/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/macroAssembler_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -679,6 +679,39 @@ class MacroAssembler: public Assembler { void clear_memory_doubleword(Register base_ptr, Register cnt_dwords, Register tmp = R0); +#ifdef COMPILER2 + // Intrinsics for CompactStrings + // Compress char[] to byte[] by compressing 16 bytes at once. + void string_compress_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, + Label& Lfailure); + + // Compress char[] to byte[]. cnt must be positive int. + void string_compress(Register src, Register dst, Register cnt, Register tmp, Label& Lfailure); + + // Inflate byte[] to char[] by inflating 16 bytes at once. + void string_inflate_16(Register src, Register dst, Register cnt, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); + + // Inflate byte[] to char[]. cnt must be positive int. + void string_inflate(Register src, Register dst, Register cnt, Register tmp); + + void string_compare(Register str1, Register str2, Register cnt1, Register cnt2, + Register tmp1, Register result, int ae); + + void array_equals(bool is_array_equ, Register ary1, Register ary2, + Register limit, Register tmp1, Register result, bool is_byte); + + void string_indexof(Register result, Register haystack, Register haycnt, + Register needle, ciTypeArray* needle_values, Register needlecnt, int needlecntval, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, int ae); + + void string_indexof_char(Register result, Register haystack, Register haycnt, + Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte); + + void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); + + // Intrinsics for non-CompactStrings // Needle of length 1. void string_indexof_1(Register result, Register haystack, Register haycnt, Register needle, jchar needleChar, @@ -694,6 +727,7 @@ class MacroAssembler: public Assembler { Register tmp5_reg); void char_arrays_equalsImm(Register str1_reg, Register str2_reg, int cntval, Register result_reg, Register tmp1_reg, Register tmp2_reg); +#endif // Emitters for BigInteger.multiplyToLen intrinsic. inline void multiply64(Register dest_hi, Register dest_lo, diff --git a/hotspot/src/cpu/ppc/vm/ppc.ad b/hotspot/src/cpu/ppc/vm/ppc.ad index e9dfa9c5bf1..df119f8bdf1 100644 --- a/hotspot/src/cpu/ppc/vm/ppc.ad +++ b/hotspot/src/cpu/ppc/vm/ppc.ad @@ -1,6 +1,6 @@ // // Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. -// Copyright (c) 2012, 2015 SAP SE. All rights reserved. +// Copyright (c) 2012, 2016 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 @@ -2024,13 +2024,13 @@ const bool Matcher::match_rule_supported(int opcode) { return (UsePopCountInstruction && VM_Version::has_popcntw()); case Op_StrComp: - return SpecialStringCompareTo && !CompactStrings; + return SpecialStringCompareTo; case Op_StrEquals: - return SpecialStringEquals && !CompactStrings; + return SpecialStringEquals; case Op_StrIndexOf: - return SpecialStringIndexOf && !CompactStrings; + return SpecialStringIndexOf; case Op_StrIndexOfChar: - return SpecialStringIndexOf && !CompactStrings; + return SpecialStringIndexOf; } return true; // Per default match rules are supported. @@ -11022,6 +11022,584 @@ instruct inlineCallClearArray(rarg1RegL cnt, rarg2RegP base, Universe dummy, reg ins_pipe(pipe_class_default); %} +instruct string_compareL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare char[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareLU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::LU); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_compareUL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt1, rarg4RegI cnt2, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrCompNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp (Binary str1 cnt1) (Binary str2 cnt2))); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL ctr, KILL cr0, TEMP tmp); + ins_cost(300); + format %{ "String Compare byte[] $str1,$cnt1,$str2,$cnt2 -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_compare($str2$$Register, $str1$$Register, + $cnt2$$Register, $cnt1$$Register, + $tmp$$Register, + $result$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_equalsL(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Equals byte[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $tmp$$Register, + $result$$Register, true /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct string_equalsU(rarg1RegP str1, rarg2RegP str2, rarg3RegI cnt, iRegIdst result, + iRegIdst tmp, regCTR ctr, flagsRegCR0 cr0) %{ + predicate(((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP tmp, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Equals char[] $str1,$str2,$cnt -> $result \t// KILL $tmp" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(false, $str1$$Register, $str2$$Register, + $cnt$$Register, $tmp$$Register, + $result$$Register, false /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct array_equalsB(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(true, $ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, + $result$$Register, true /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct array_equalsC(rarg1RegP ary1, rarg2RegP ary2, iRegIdst result, + iRegIdst tmp1, iRegIdst tmp2, regCTR ctr, flagsRegCR0 cr0, flagsRegCR0 cr1) %{ + predicate(((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(TEMP_DEF result, USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0, KILL cr1); + ins_cost(300); + format %{ "Array Equals $ary1,$ary2 -> $result \t// KILL $tmp1,$tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ array_equals(true, $ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, + $result$$Register, false /* byte */); + %} + ins_pipe(pipe_class_default); +%} + +instruct indexOf_imm1_char_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr; +#ifdef VM_LITTLE_ENDIAN + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); +#else + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); +#endif + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_char_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, true /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_char_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + immP needleImm, immL offsetImm, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary (AddP needleImm offsetImm) needlecntImm))); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + ins_cost(150); + + format %{ "String IndexOf CSCL1 $haystack[0..$haycnt], $needleImm+$offsetImm[0..$needlecntImm]" + "-> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + immPOper *needleOper = (immPOper *)$needleImm; + const TypeOopPtr *t = needleOper->type()->isa_oopptr(); + ciTypeArray* needle_values = t->const_oop()->as_type_array(); // Pointer to live char * + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr; +#ifdef VM_LITTLE_ENDIAN + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); +#else + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); +#endif + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_L(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, true /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm1_UL(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + rscratch2RegP needle, immI_1 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL needle, TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(180); + + format %{ "String IndexOf SCL1 $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $needle, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + guarantee(needle_values, "sanity"); + jchar chr = (jchar)needle_values->element_value(0).as_byte(); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + R0, chr, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOfChar_U(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt, + iRegIsrc ch, iRegIdst tmp1, iRegIdst tmp2, + flagsRegCR0 cr0, flagsRegCR1 cr1, regCTR ctr) %{ + match(Set result (StrIndexOfChar (Binary haystack haycnt) ch)); + effect(TEMP tmp1, TEMP tmp2, KILL cr0, KILL cr1, KILL ctr); + predicate(CompactStrings); + ins_cost(180); + + format %{ "String IndexOfChar $haystack[0..$haycnt], $ch" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof_char($result$$Register, + $haystack$$Register, $haycnt$$Register, + $ch$$Register, 0 /* this is not used if the character is already in a register */, + $tmp1$$Register, $tmp2$$Register, false /*is_byte*/); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_imm_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, + iRegPsrc needle, uimmI15 needlecntImm, + iRegIdst tmp1, iRegIdst tmp2, iRegIdst tmp3, iRegIdst tmp4, iRegIdst tmp5, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecntImm))); + effect(USE_KILL haycnt, /* better: TDEF haycnt, */ TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + // Required for EA: check if it is still a type_array. + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop() && + n->in(3)->in(1)->bottom_type()->is_aryptr()->const_oop()->is_type_array()); + ins_cost(250); + + format %{ "String IndexOf SCL $haystack[0..$haycnt], $needle[0..$needlecntImm]" + " -> $result \t// KILL $haycnt, $tmp1, $tmp2, $tmp3, $tmp4, $tmp5, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Node *ndl = in(operand_index($needle)); // The node that defines needle. + ciTypeArray* needle_values = ndl->bottom_type()->is_aryptr()->const_oop()->as_type_array(); + + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, needle_values, $tmp5$$Register, $needlecntImm$$constant, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_U(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_L(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_compare); +%} + +instruct indexOf_UL(iRegIdst result, iRegPsrc haystack, rscratch1RegI haycnt, iRegPsrc needle, rscratch2RegI needlecnt, + iRegLdst tmp1, iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, + flagsRegCR0 cr0, flagsRegCR1 cr1, flagsRegCR6 cr6, regCTR ctr) %{ + match(Set result (StrIndexOf (Binary haystack haycnt) (Binary needle needlecnt))); + effect(USE_KILL haycnt, USE_KILL needlecnt, /*better: TDEF haycnt, TDEF needlecnt,*/ + TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr0, KILL cr1, KILL cr6, KILL ctr); + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + ins_cost(300); + + format %{ "String IndexOf $haystack[0..$haycnt], $needle[0..$needlecnt]" + " -> $result \t// KILL $haycnt, $needlecnt, $tmp1, $tmp2, $tmp3, $tmp4, $cr0, $cr1" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ string_indexof($result$$Register, + $haystack$$Register, $haycnt$$Register, + $needle$$Register, NULL, $needlecnt$$Register, 0, // needlecnt not constant. + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_compare); +%} + +// char[] to byte[] compression +instruct string_compress(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set result (StrCompressedCopy src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Compress $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Lskip, Ldone; + __ li($result$$Register, 0); + __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Ldone); + __ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Lskip); + __ string_compress($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register, Ldone); + __ bind(Lskip); + __ mr($result$$Register, $len$$Register); + __ bind(Ldone); + %} + ins_pipe(pipe_class_default); +%} + +// byte[] to char[] inflation +instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set dummy (StrInflatedCopy src (Binary dst len))); + effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "String Inflate $src,$dst,$len \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Ldone; + __ string_inflate_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register); + __ rldicl_($tmp1$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Ldone); + __ string_inflate($src$$Register, $dst$$Register, $tmp1$$Register, $tmp2$$Register); + __ bind(Ldone); + %} + ins_pipe(pipe_class_default); +%} + +// StringCoding.java intrinsics +instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, + regCTR ctr, flagsRegCR0 cr0) +%{ + match(Set result (HasNegatives ary1 len)); + effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ has_negatives($ary1$$Register, $len$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register); + %} + ins_pipe(pipe_class_default); +%} + +// encode char[] to byte[] in ISO_8859_1 +instruct encode_iso_array(rarg1RegP src, rarg2RegP dst, iRegIsrc len, iRegIdst result, iRegLdst tmp1, + iRegLdst tmp2, iRegLdst tmp3, iRegLdst tmp4, iRegLdst tmp5, regCTR ctr, flagsRegCR0 cr0) %{ + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, + USE_KILL src, USE_KILL dst, KILL ctr, KILL cr0); + ins_cost(300); + format %{ "Encode array $src,$dst,$len -> $result \t// KILL $tmp1, $tmp2, $tmp3, $tmp4, $tmp5" %} + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + Label Lslow, Lfailure1, Lfailure2, Ldone; + __ string_compress_16($src$$Register, $dst$$Register, $len$$Register, $tmp1$$Register, + $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, $tmp5$$Register, Lfailure1); + __ rldicl_($result$$Register, $len$$Register, 0, 64-3); // Remaining characters. + __ beq(CCR0, Ldone); + __ bind(Lslow); + __ string_compress($src$$Register, $dst$$Register, $result$$Register, $tmp2$$Register, Lfailure2); + __ li($result$$Register, 0); + __ b(Ldone); + + __ bind(Lfailure1); + __ mr($result$$Register, $len$$Register); + __ mfctr($tmp1$$Register); + __ rldimi_($result$$Register, $tmp1$$Register, 3, 0); // Remaining characters. + __ beq(CCR0, Ldone); + __ b(Lslow); + + __ bind(Lfailure2); + __ mfctr($result$$Register); // Remaining characters. + + __ bind(Ldone); + __ subf($result$$Register, $result$$Register, $len$$Register); + %} + ins_pipe(pipe_class_default); +%} + + // String_IndexOf for needle of length 1. // // Match needle into immediate operands: no loadConP node needed. Saves one @@ -11060,11 +11638,11 @@ instruct string_indexOf_imm1_char(iRegIdst result, iRegPsrc haystack, iRegIsrc h if (java_lang_String::has_coder_field()) { // New compact strings byte array strings #ifdef VM_LITTLE_ENDIAN - chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) | - (jchar)needle_values->element_value(0).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); #else - chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) | - (jchar)needle_values->element_value(1).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); #endif } else { // Old char array strings @@ -11115,11 +11693,11 @@ instruct string_indexOf_imm1(iRegIdst result, iRegPsrc haystack, iRegIsrc haycnt if (java_lang_String::has_coder_field()) { // New compact strings byte array strings #ifdef VM_LITTLE_ENDIAN - chr = (((jchar)needle_values->element_value(1).as_byte()) << 8) | - (jchar)needle_values->element_value(0).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(1).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(0).as_byte()); #else - chr = (((jchar)needle_values->element_value(0).as_byte()) << 8) | - (jchar)needle_values->element_value(1).as_byte(); + chr = (((jchar)(unsigned char)needle_values->element_value(0).as_byte()) << 8) | + ((jchar)(unsigned char)needle_values->element_value(1).as_byte()); #endif } else { // Old char array strings @@ -11321,6 +11899,20 @@ instruct minI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ %} %} +instruct minI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set dst (MinI src1 src2)); + effect(KILL cr0); + predicate(VM_Version::has_isel()); + ins_cost(DEFAULT_COST*2); + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ cmpw(CCR0, $src1$$Register, $src2$$Register); + __ isel($dst$$Register, CCR0, Assembler::less, /*invert*/false, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_class_default); +%} + instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ match(Set dst (MaxI src1 src2)); ins_cost(DEFAULT_COST*6); @@ -11341,6 +11933,20 @@ instruct maxI_reg_reg_Ex(iRegIdst dst, iRegIsrc src1, iRegIsrc src2) %{ %} %} +instruct maxI_reg_reg_isel(iRegIdst dst, iRegIsrc src1, iRegIsrc src2, flagsRegCR0 cr0) %{ + match(Set dst (MaxI src1 src2)); + effect(KILL cr0); + predicate(VM_Version::has_isel()); + ins_cost(DEFAULT_COST*2); + + ins_encode %{ + // TODO: PPC port $archOpcode(ppc64Opcode_compound); + __ cmpw(CCR0, $src1$$Register, $src2$$Register); + __ isel($dst$$Register, CCR0, Assembler::greater, /*invert*/false, $src1$$Register, $src2$$Register); + %} + ins_pipe(pipe_class_default); +%} + //---------- Population Count Instructions ------------------------------------ // Popcnt for Power7. diff --git a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp index c3f6922fe2d..85a83c8179b 100644 --- a/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/stubGenerator_ppc.cpp @@ -2609,9 +2609,7 @@ class StubGenerator: public StubCodeGenerator { * R5_ARG3 - int length (of buffer) * * scratch: - * R6_ARG4 - crc table address - * R7_ARG5 - tmp1 - * R8_ARG6 - tmp2 + * R2, R6-R12 * * Ouput: * R3_RET - int crc result @@ -2623,22 +2621,25 @@ class StubGenerator: public StubCodeGenerator { address start = __ function_entry(); // Remember stub start address (is rtn value). // arguments to kernel_crc32: - Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call. - Register data = R4_ARG2; // source byte array - Register dataLen = R5_ARG3; // #bytes to process - Register table = R6_ARG4; // crc table address + const Register crc = R3_ARG1; // Current checksum, preset by caller or result from previous call. + const Register data = R4_ARG2; // source byte array + const Register dataLen = R5_ARG3; // #bytes to process + const Register table = R6_ARG4; // crc table address - Register t0 = R9; // work reg for kernel* emitters - Register t1 = R10; // work reg for kernel* emitters - Register t2 = R11; // work reg for kernel* emitters - Register t3 = R12; // work reg for kernel* emitters + const Register t0 = R2; + const Register t1 = R7; + const Register t2 = R8; + const Register t3 = R9; + const Register tc0 = R10; + const Register tc1 = R11; + const Register tc2 = R12; BLOCK_COMMENT("Stub body {"); assert_different_registers(crc, data, dataLen, table); StubRoutines::ppc64::generate_load_crc_table_addr(_masm, table); - __ kernel_crc32_1byte(crc, data, dataLen, table, t0, t1, t2, t3); + __ kernel_crc32_1word(crc, data, dataLen, table, t0, t1, t2, t3, tc0, tc1, tc2, table); BLOCK_COMMENT("return"); __ mr_if_needed(R3_RET, crc); // Updated crc is function result. No copying required (R3_ARG1 == R3_RET). diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp index 51bc85d869d..63c0e30a913 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -53,7 +53,7 @@ void VM_Version::initialize() { // If PowerArchitecturePPC64 hasn't been specified explicitly determine from features. if (FLAG_IS_DEFAULT(PowerArchitecturePPC64)) { - if (VM_Version::has_tcheck() && VM_Version::has_lqarx()) { + if (VM_Version::has_lqarx()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 8); } else if (VM_Version::has_popcntw()) { FLAG_SET_ERGO(uintx, PowerArchitecturePPC64, 7); @@ -68,8 +68,7 @@ void VM_Version::initialize() { bool PowerArchitecturePPC64_ok = false; switch (PowerArchitecturePPC64) { - case 8: if (!VM_Version::has_tcheck() ) break; - if (!VM_Version::has_lqarx() ) break; + case 8: if (!VM_Version::has_lqarx() ) break; case 7: if (!VM_Version::has_popcntw()) break; case 6: if (!VM_Version::has_cmpb() ) break; case 5: if (!VM_Version::has_popcntb()) break; @@ -80,7 +79,7 @@ void VM_Version::initialize() { UINTX_FORMAT " on this machine", PowerArchitecturePPC64); // Power 8: Configure Data Stream Control Register. - if (PowerArchitecturePPC64 >= 8) { + if (has_mfdscr()) { config_dscr(); } @@ -112,7 +111,7 @@ void VM_Version::initialize() { // Create and print feature-string. char buf[(num_features+1) * 16]; // Max 16 chars per feature. jio_snprintf(buf, sizeof(buf), - "ppc64%s%s%s%s%s%s%s%s%s%s%s%s", + "ppc64%s%s%s%s%s%s%s%s%s%s%s%s%s", (has_fsqrt() ? " fsqrt" : ""), (has_isel() ? " isel" : ""), (has_lxarxeh() ? " lxarxeh" : ""), @@ -125,7 +124,8 @@ void VM_Version::initialize() { (has_lqarx() ? " lqarx" : ""), (has_vcipher() ? " vcipher" : ""), (has_vpmsumb() ? " vpmsumb" : ""), - (has_tcheck() ? " tcheck" : "") + (has_tcheck() ? " tcheck" : ""), + (has_mfdscr() ? " mfdscr" : "") // Make sure number of %s matches num_features! ); _features_string = os::strdup(buf); @@ -610,6 +610,7 @@ void VM_Version::determine_features() { a->vcipher(VR0, VR1, VR2); // code[10] -> vcipher a->vpmsumb(VR0, VR1, VR2); // code[11] -> vpmsumb a->tcheck(0); // code[12] -> tcheck + a->mfdscr(R0); // code[13] -> mfdscr a->blr(); // Emit function to set one cache line to zero. Emit function descriptor and get pointer to it. @@ -657,6 +658,7 @@ void VM_Version::determine_features() { if (code[feature_cntr++]) features |= vcipher_m; if (code[feature_cntr++]) features |= vpmsumb_m; if (code[feature_cntr++]) features |= tcheck_m; + if (code[feature_cntr++]) features |= mfdscr_m; // Print the detection code. if (PrintAssembly) { @@ -670,8 +672,6 @@ void VM_Version::determine_features() { // Power 8: Configure Data Stream Control Register. void VM_Version::config_dscr() { - assert(has_tcheck(), "Only execute on Power 8 or later!"); - // 7 InstWords for each call (function descriptor + blr instruction). const int code_size = (2+2*7)*BytesPerInstWord; diff --git a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp index 46fdd6b6470..fccb4e21874 100644 --- a/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp +++ b/hotspot/src/cpu/ppc/vm/vm_version_ppc.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -45,6 +45,7 @@ protected: vcipher, vpmsumb, tcheck, + mfdscr, num_features // last entry to count features }; enum Feature_Flag_Set { @@ -62,6 +63,7 @@ protected: vcipher_m = (1 << vcipher), vpmsumb_m = (1 << vpmsumb), tcheck_m = (1 << tcheck ), + mfdscr_m = (1 << mfdscr ), all_features_m = (unsigned long)-1 }; @@ -94,6 +96,7 @@ public: static bool has_vcipher() { return (_features & vcipher_m) != 0; } static bool has_vpmsumb() { return (_features & vpmsumb_m) != 0; } static bool has_tcheck() { return (_features & tcheck_m) != 0; } + static bool has_mfdscr() { return (_features & mfdscr_m) != 0; } // Assembler testing static void allow_all(); diff --git a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp index da9869fdb4d..65cbf6e8315 100644 --- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp @@ -1349,9 +1349,12 @@ static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { } } else if (dst.first()->is_stack()) { // reg to stack - __ st_ptr(src.first()->as_Register(), SP, reg2offset(dst.first()) + STACK_BIAS); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), L5); + __ st_ptr(L5, SP, reg2offset(dst.first()) + STACK_BIAS); } else { - __ mov(src.first()->as_Register(), dst.first()->as_Register()); + // Some compilers (gcc) expect a clean 32 bit value on function entry + __ signx(src.first()->as_Register(), dst.first()->as_Register()); } } diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 6bbef4e5708..5cf884a5501 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -948,28 +948,28 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, } #endif - uint instr; - instr = (Assembler::ldst_op << 30) - | (dst_enc << 25) - | (primary << 19) - | (src1_enc << 14); + uint instr = (Assembler::ldst_op << 30) + | (dst_enc << 25) + | (primary << 19) + | (src1_enc << 14); uint index = src2_enc; int disp = disp32; if (src1_enc == R_SP_enc || src1_enc == R_FP_enc) { disp += STACK_BIAS; - // Quick fix for JDK-8029668: check that stack offset fits, bailout if not + // Check that stack offset fits, load into O7 if not if (!Assembler::is_simm13(disp)) { - ra->C->record_method_not_compilable("unable to handle large constant offsets"); - return; + MacroAssembler _masm(&cbuf); + __ set(disp, O7); + if (index != R_G0_enc) { + __ add(O7, reg_to_register_object(index), O7); + } + index = R_O7_enc; + disp = 0; } } - // We should have a compiler bailout here rather than a guarantee. - // Better yet would be some mechanism to handle variable-size matches correctly. - guarantee(Assembler::is_simm13(disp), "Do not match large constant offsets" ); - if( disp == 0 ) { // use reg-reg form // bit 13 is already zero @@ -983,7 +983,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, PhaseRegAlloc* ra, const MachNode* n, cbuf.insts()->emit_int32(instr); #ifdef ASSERT - { + if (VerifyOops) { MacroAssembler _masm(&cbuf); if (is_verified_oop_base) { __ verify_oop(reg_to_register_object(src1_enc)); @@ -1342,7 +1342,7 @@ int MachEpilogNode::safepoint_offset() const { // Figure out which register class each belongs in: rc_int, rc_float, rc_stack enum RC { rc_bad, rc_int, rc_float, rc_stack }; static enum RC rc_class( OptoReg::Name reg ) { - if( !OptoReg::is_valid(reg) ) return rc_bad; + if (!OptoReg::is_valid(reg)) return rc_bad; if (OptoReg::is_stack(reg)) return rc_stack; VMReg r = OptoReg::as_VMReg(reg); if (r->is_Register()) return rc_int; @@ -1350,66 +1350,79 @@ static enum RC rc_class( OptoReg::Name reg ) { return rc_float; } -static int impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool do_size, bool is_load, int offset, int reg, int opcode, const char *op_str, int size, outputStream* st ) { +#ifndef PRODUCT +ATTRIBUTE_PRINTF(2, 3) +static void print_helper(outputStream* st, const char* format, ...) { + if (st->position() > 0) { + st->cr(); + st->sp(); + } + va_list ap; + va_start(ap, format); + st->vprint(format, ap); + va_end(ap); +} +#endif // !PRODUCT + +static void impl_helper(const MachNode* mach, CodeBuffer* cbuf, PhaseRegAlloc* ra, bool is_load, int offset, int reg, int opcode, const char *op_str, outputStream* st) { if (cbuf) { emit_form3_mem_reg(*cbuf, ra, mach, opcode, -1, R_SP_enc, offset, 0, Matcher::_regEncode[reg]); } #ifndef PRODUCT - else if (!do_size) { - if (size != 0) st->print("\n\t"); - if (is_load) st->print("%s [R_SP + #%d],R_%s\t! spill",op_str,offset,OptoReg::regname(reg)); - else st->print("%s R_%s,[R_SP + #%d]\t! spill",op_str,OptoReg::regname(reg),offset); + else { + if (is_load) { + print_helper(st, "%s [R_SP + #%d],R_%s\t! spill", op_str, offset, OptoReg::regname(reg)); + } else { + print_helper(st, "%s R_%s,[R_SP + #%d]\t! spill", op_str, OptoReg::regname(reg), offset); + } } #endif - return size+4; } -static int impl_mov_helper( CodeBuffer *cbuf, bool do_size, int src, int dst, int op1, int op2, const char *op_str, int size, outputStream* st ) { - if( cbuf ) emit3( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src] ); +static void impl_mov_helper(CodeBuffer *cbuf, int src, int dst, int op1, int op2, const char *op_str, outputStream* st) { + if (cbuf) { + emit3(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst], op1, 0, op2, Matcher::_regEncode[src]); + } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("%s R_%s,R_%s\t! spill",op_str,OptoReg::regname(src),OptoReg::regname(dst)); + else { + print_helper(st, "%s R_%s,R_%s\t! spill", op_str, OptoReg::regname(src), OptoReg::regname(dst)); } #endif - return size+4; } -uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, - PhaseRegAlloc *ra_, - bool do_size, - outputStream* st ) const { +static void mach_spill_copy_implementation_helper(const MachNode* mach, + CodeBuffer *cbuf, + PhaseRegAlloc *ra_, + outputStream* st) { // Get registers to move - OptoReg::Name src_second = ra_->get_reg_second(in(1)); - OptoReg::Name src_first = ra_->get_reg_first(in(1)); - OptoReg::Name dst_second = ra_->get_reg_second(this ); - OptoReg::Name dst_first = ra_->get_reg_first(this ); + OptoReg::Name src_second = ra_->get_reg_second(mach->in(1)); + OptoReg::Name src_first = ra_->get_reg_first(mach->in(1)); + OptoReg::Name dst_second = ra_->get_reg_second(mach); + OptoReg::Name dst_first = ra_->get_reg_first(mach); enum RC src_second_rc = rc_class(src_second); - enum RC src_first_rc = rc_class(src_first); + enum RC src_first_rc = rc_class(src_first); enum RC dst_second_rc = rc_class(dst_second); - enum RC dst_first_rc = rc_class(dst_first); + enum RC dst_first_rc = rc_class(dst_first); - assert( OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register" ); + assert(OptoReg::is_valid(src_first) && OptoReg::is_valid(dst_first), "must move at least 1 register"); - // Generate spill code! - int size = 0; - - if( src_first == dst_first && src_second == dst_second ) - return size; // Self copy, no move + if (src_first == dst_first && src_second == dst_second) { + return; // Self copy, no move + } // -------------------------------------- // Check for mem-mem move. Load into unused float registers and fall into // the float-store case. - if( src_first_rc == rc_stack && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_stack && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second ) { + if ((src_first&1) == 0 && src_first+1 == src_second) { src_second = OptoReg::Name(R_F31_num); src_second_rc = rc_float; - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F30_num,Assembler::lddf_op3,"LDDF",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::lddf_op3, "LDDF", st); } else { - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F30_num,Assembler::ldf_op3 ,"LDF ",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F30_num, Assembler::ldf_op3, "LDF ", st); } src_first = OptoReg::Name(R_F30_num); src_first_rc = rc_float; @@ -1417,7 +1430,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if( src_second_rc == rc_stack && dst_second_rc == rc_stack ) { int offset = ra_->reg2offset(src_second); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,R_F31_num,Assembler::ldf_op3,"LDF ",size, st); + impl_helper(mach, cbuf, ra_, true, offset, R_F31_num, Assembler::ldf_op3, "LDF ", st); src_second = OptoReg::Name(R_F31_num); src_second_rc = rc_float; } @@ -1427,36 +1440,38 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) { int offset = frame::register_save_words*wordSize; if (cbuf) { - emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16 ); - impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); - impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); - emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16 ); + emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16); + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); + emit3_simm13(*cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16); } #ifndef PRODUCT - else if (!do_size) { - if (size != 0) st->print("\n\t"); - st->print( "SUB R_SP,16,R_SP\n"); - impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); - impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); - st->print("\tADD R_SP,16,R_SP\n"); + else { + print_helper(st, "SUB R_SP,16,R_SP"); + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); + print_helper(st, "ADD R_SP,16,R_SP"); } #endif - size += 16; } // Check for float->int copy on T4 if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) { // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mdtox_opf,"MOVDTOX",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mstouw_opf,"MOVSTOUW",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mdtox_opf, "MOVDTOX", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mstouw_opf, "MOVSTOUW", st); } // Check for int->float copy on T4 if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) { // Further check for aligned-adjacent pair, so we can use a double move - if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mxtod_opf,"MOVXTOD",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mwtos_opf,"MOVWTOS",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mxtod_opf, "MOVXTOD", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::mftoi_op3, Assembler::mwtos_opf, "MOVWTOS", st); } // -------------------------------------- @@ -1466,10 +1481,10 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // there. Misaligned sources only come from native-long-returns (handled // special below). #ifndef _LP64 - if( src_first_rc == rc_int && // source is already big-endian + if (src_first_rc == rc_int && // source is already big-endian src_second_rc != rc_bad && // 64-bit move - ((dst_first&1)!=0 || dst_second != dst_first+1) ) { // misaligned dst - assert( (src_first&1)==0 && src_second == src_first+1, "source must be aligned" ); + ((dst_first & 1) != 0 || dst_second != dst_first + 1)) { // misaligned dst + assert((src_first & 1) == 0 && src_second == src_first + 1, "source must be aligned"); // Do the big-endian flop. OptoReg::Name tmp = dst_first ; dst_first = dst_second ; dst_second = tmp ; enum RC tmp_rc = dst_first_rc; dst_first_rc = dst_second_rc; dst_second_rc = tmp_rc; @@ -1478,30 +1493,28 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // -------------------------------------- // Check for integer reg-reg copy - if( src_first_rc == rc_int && dst_first_rc == rc_int ) { + if (src_first_rc == rc_int && dst_first_rc == rc_int) { #ifndef _LP64 - if( src_first == R_O0_num && src_second == R_O1_num ) { // Check for the evil O0/O1 native long-return case + if (src_first == R_O0_num && src_second == R_O1_num) { // Check for the evil O0/O1 native long-return case // Note: The _first and _second suffixes refer to the addresses of the the 2 halves of the 64-bit value // as stored in memory. On a big-endian machine like SPARC, this means that the _second // operand contains the least significant word of the 64-bit value and vice versa. OptoReg::Name tmp = OptoReg::Name(R_O7_num); - assert( (dst_first&1)==0 && dst_second == dst_first+1, "return a native O0/O1 long to an aligned-adjacent 64-bit reg" ); + assert((dst_first & 1) == 0 && dst_second == dst_first + 1, "return a native O0/O1 long to an aligned-adjacent 64-bit reg" ); // Shift O0 left in-place, zero-extend O1, then OR them into the dst - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[tmp], Assembler::sllx_op3, Matcher::_regEncode[src_first], 0x1020 ); - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[src_second], Assembler::srl_op3, Matcher::_regEncode[src_second], 0x0000 ); - emit3 ( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler:: or_op3, Matcher::_regEncode[tmp], 0, Matcher::_regEncode[src_second] ); + if ( cbuf ) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[tmp], Assembler::sllx_op3, Matcher::_regEncode[src_first], 0x1020); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[src_second], Assembler::srl_op3, Matcher::_regEncode[src_second], 0x0000); + emit3 (*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler:: or_op3, Matcher::_regEncode[tmp], 0, Matcher::_regEncode[src_second]); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SLLX R_%s,32,R_%s\t! Move O0-first to O7-high\n\t", OptoReg::regname(src_first), OptoReg::regname(tmp)); - st->print("SRL R_%s, 0,R_%s\t! Zero-extend O1\n\t", OptoReg::regname(src_second), OptoReg::regname(src_second)); - st->print("OR R_%s,R_%s,R_%s\t! spill",OptoReg::regname(tmp), OptoReg::regname(src_second), OptoReg::regname(dst_first)); + } else { + print_helper(st, "SLLX R_%s,32,R_%s\t! Move O0-first to O7-high\n\t", OptoReg::regname(src_first), OptoReg::regname(tmp)); + print_helper(st, "SRL R_%s, 0,R_%s\t! Zero-extend O1\n\t", OptoReg::regname(src_second), OptoReg::regname(src_second)); + print_helper(st, "OR R_%s,R_%s,R_%s\t! spill",OptoReg::regname(tmp), OptoReg::regname(src_second), OptoReg::regname(dst_first)); #endif } - return size+12; - } - else if( dst_first == R_I0_num && dst_second == R_I1_num ) { + return; + } else if (dst_first == R_I0_num && dst_second == R_I1_num) { // returning a long value in I0/I1 // a SpillCopy must be able to target a return instruction's reg_class // Note: The _first and _second suffixes refer to the addresses of the the 2 halves of the 64-bit value @@ -1511,27 +1524,25 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, if (src_first == dst_first) { tdest = OptoReg::Name(R_O7_num); - size += 4; } - if( cbuf ) { - assert( (src_first&1) == 0 && (src_first+1) == src_second, "return value was in an aligned-adjacent 64-bit reg"); + if (cbuf) { + assert((src_first & 1) == 0 && (src_first + 1) == src_second, "return value was in an aligned-adjacent 64-bit reg"); // Shift value in upper 32-bits of src to lower 32-bits of I0; move lower 32-bits to I1 // ShrL_reg_imm6 - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[tdest], Assembler::srlx_op3, Matcher::_regEncode[src_second], 32 | 0x1000 ); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[tdest], Assembler::srlx_op3, Matcher::_regEncode[src_second], 32 | 0x1000); // ShrR_reg_imm6 src, 0, dst - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srl_op3, Matcher::_regEncode[src_first], 0x0000 ); + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srl_op3, Matcher::_regEncode[src_first], 0x0000); if (tdest != dst_first) { - emit3 ( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler::or_op3, 0/*G0*/, 0/*op2*/, Matcher::_regEncode[tdest] ); + emit3 (*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_first], Assembler::or_op3, 0/*G0*/, 0/*op2*/, Matcher::_regEncode[tdest]); } } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); // %%%%% !!!!! - st->print("SRLX R_%s,32,R_%s\t! Extract MSW\n\t",OptoReg::regname(src_second),OptoReg::regname(tdest)); - st->print("SRL R_%s, 0,R_%s\t! Extract LSW\n\t",OptoReg::regname(src_first),OptoReg::regname(dst_second)); + else { + print_helper(st, "SRLX R_%s,32,R_%s\t! Extract MSW\n\t",OptoReg::regname(src_second),OptoReg::regname(tdest)); + print_helper(st, "SRL R_%s, 0,R_%s\t! Extract LSW\n\t",OptoReg::regname(src_first),OptoReg::regname(dst_second)); if (tdest != dst_first) { - st->print("MOV R_%s,R_%s\t! spill\n\t", OptoReg::regname(tdest), OptoReg::regname(dst_first)); + print_helper(st, "MOV R_%s,R_%s\t! spill\n\t", OptoReg::regname(tdest), OptoReg::regname(dst_first)); } } #endif // PRODUCT @@ -1539,65 +1550,77 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, } #endif // !_LP64 // Else normal reg-reg copy - assert( src_second != dst_first, "smashed second before evacuating it" ); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::or_op3,0,"MOV ",size, st); - assert( (src_first&1) == 0 && (dst_first&1) == 0, "never move second-halves of int registers" ); + assert(src_second != dst_first, "smashed second before evacuating it"); + impl_mov_helper(cbuf, src_first, dst_first, Assembler::or_op3, 0, "MOV ", st); + assert((src_first & 1) == 0 && (dst_first & 1) == 0, "never move second-halves of int registers"); // This moves an aligned adjacent pair. // See if we are done. - if( src_first+1 == src_second && dst_first+1 == dst_second ) - return size; + if (src_first + 1 == src_second && dst_first + 1 == dst_second) { + return; + } } // Check for integer store - if( src_first_rc == rc_int && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_int && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(dst_first); // Further check for aligned-adjacent pair, so we can use a double store - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stx_op3,"STX ",size, st); - size = impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stw_op3,"STW ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stx_op3, "STX ", st); + return; + } + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stw_op3, "STW ", st); } // Check for integer load - if( dst_first_rc == rc_int && src_first_rc == rc_stack ) { + if (dst_first_rc == rc_int && src_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::ldx_op3 ,"LDX ",size, st); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldx_op3, "LDX ", st); + return; + } + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lduw_op3, "LDUW", st); } // Check for float reg-reg copy - if( src_first_rc == rc_float && dst_first_rc == rc_float ) { + if (src_first_rc == rc_float && dst_first_rc == rc_float) { // Further check for aligned-adjacent pair, so we can use a double move - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::fpop1_op3,Assembler::fmovd_opf,"FMOVD",size, st); - size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::fpop1_op3,Assembler::fmovs_opf,"FMOVS",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovd_opf, "FMOVD", st); + return; + } + impl_mov_helper(cbuf, src_first, dst_first, Assembler::fpop1_op3, Assembler::fmovs_opf, "FMOVS", st); } // Check for float store - if( src_first_rc == rc_float && dst_first_rc == rc_stack ) { + if (src_first_rc == rc_float && dst_first_rc == rc_stack) { int offset = ra_->reg2offset(dst_first); // Further check for aligned-adjacent pair, so we can use a double store - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stdf_op3,"STDF",size, st); - size = impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stdf_op3, "STDF", st); + return; + } + impl_helper(mach, cbuf, ra_, false, offset, src_first, Assembler::stf_op3, "STF ", st); } // Check for float load - if( dst_first_rc == rc_float && src_first_rc == rc_stack ) { + if (dst_first_rc == rc_float && src_first_rc == rc_stack) { int offset = ra_->reg2offset(src_first); // Further check for aligned-adjacent pair, so we can use a double load - if( (src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second ) - return impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::lddf_op3,"LDDF",size, st); - size = impl_helper(this,cbuf,ra_,do_size,true,offset,dst_first,Assembler::ldf_op3 ,"LDF ",size, st); + if ((src_first & 1) == 0 && src_first + 1 == src_second && (dst_first & 1) == 0 && dst_first + 1 == dst_second) { + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::lddf_op3, "LDDF", st); + return; + } + impl_helper(mach, cbuf, ra_, true, offset, dst_first, Assembler::ldf_op3, "LDF ", st); } // -------------------------------------------------------------------- // Check for hi bits still needing moving. Only happens for misaligned // arguments to native calls. - if( src_second == dst_second ) - return size; // Self copy; no move - assert( src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad" ); + if (src_second == dst_second) { + return; // Self copy; no move + } + assert(src_second_rc != rc_bad && dst_second_rc != rc_bad, "src_second & dst_second cannot be Bad"); #ifndef _LP64 // In the LP64 build, all registers can be moved as aligned/adjacent @@ -1609,52 +1632,57 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf, // 32-bits of a 64-bit register, but are needed in low bits of another // register (else it's a hi-bits-to-hi-bits copy which should have // happened already as part of a 64-bit move) - if( src_second_rc == rc_int && dst_second_rc == rc_int ) { - assert( (src_second&1)==1, "its the evil O0/O1 native return case" ); - assert( (dst_second&1)==0, "should have moved with 1 64-bit move" ); + if (src_second_rc == rc_int && dst_second_rc == rc_int) { + assert((src_second & 1) == 1, "its the evil O0/O1 native return case"); + assert((dst_second & 1) == 0, "should have moved with 1 64-bit move"); // Shift src_second down to dst_second's low bits. - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020 ); + if (cbuf) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[dst_second], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SRLX R_%s,32,R_%s\t! spill: Move high bits down low",OptoReg::regname(src_second-1),OptoReg::regname(dst_second)); + } else { + print_helper(st, "SRLX R_%s,32,R_%s\t! spill: Move high bits down low", OptoReg::regname(src_second - 1), OptoReg::regname(dst_second)); #endif } - return size+4; + return; } // Check for high word integer store. Must down-shift the hi bits // into a temp register, then fall into the case of storing int bits. - if( src_second_rc == rc_int && dst_second_rc == rc_stack && (src_second&1)==1 ) { + if (src_second_rc == rc_int && dst_second_rc == rc_stack && (src_second & 1) == 1) { // Shift src_second down to dst_second's low bits. - if( cbuf ) { - emit3_simm13( *cbuf, Assembler::arith_op, Matcher::_regEncode[R_O7_num], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020 ); + if (cbuf) { + emit3_simm13(*cbuf, Assembler::arith_op, Matcher::_regEncode[R_O7_num], Assembler::srlx_op3, Matcher::_regEncode[src_second-1], 0x1020); #ifndef PRODUCT - } else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); - st->print("SRLX R_%s,32,R_%s\t! spill: Move high bits down low",OptoReg::regname(src_second-1),OptoReg::regname(R_O7_num)); + } else { + print_helper(st, "SRLX R_%s,32,R_%s\t! spill: Move high bits down low", OptoReg::regname(src_second-1), OptoReg::regname(R_O7_num)); #endif } - size+=4; src_second = OptoReg::Name(R_O7_num); // Not R_O7H_num! } // Check for high word integer load - if( dst_second_rc == rc_int && src_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,true ,ra_->reg2offset(src_second),dst_second,Assembler::lduw_op3,"LDUW",size, st); + if (dst_second_rc == rc_int && src_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, true, ra_->reg2offset(src_second), dst_second, Assembler::lduw_op3, "LDUW", size, st); // Check for high word integer store - if( src_second_rc == rc_int && dst_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,false,ra_->reg2offset(dst_second),src_second,Assembler::stw_op3 ,"STW ",size, st); + if (src_second_rc == rc_int && dst_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, false, ra_->reg2offset(dst_second), src_second, Assembler::stw_op3, "STW ", size, st); // Check for high word float store - if( src_second_rc == rc_float && dst_second_rc == rc_stack ) - return impl_helper(this,cbuf,ra_,do_size,false,ra_->reg2offset(dst_second),src_second,Assembler::stf_op3 ,"STF ",size, st); + if (src_second_rc == rc_float && dst_second_rc == rc_stack) + return impl_helper(this, cbuf, ra_, false, ra_->reg2offset(dst_second), src_second, Assembler::stf_op3, "STF ", size, st); #endif // !_LP64 Unimplemented(); +} + +uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, + PhaseRegAlloc *ra_, + bool do_size, + outputStream* st) const { + assert(!do_size, "not supported"); + mach_spill_copy_implementation_helper(this, cbuf, ra_, st); return 0; } @@ -1669,19 +1697,19 @@ void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return implementation( NULL, ra_, true, NULL ); + return MachNode::size(ra_); } //============================================================================= #ifndef PRODUCT -void MachNopNode::format( PhaseRegAlloc *, outputStream *st ) const { +void MachNopNode::format(PhaseRegAlloc *, outputStream *st) const { st->print("NOP \t# %d bytes pad for loops and calls", 4 * _count); } #endif -void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc * ) const { +void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *) const { MacroAssembler _masm(&cbuf); - for(int i = 0; i < _count; i += 1) { + for (int i = 0; i < _count; i += 1) { __ nop(); } } @@ -5197,7 +5225,6 @@ instruct stkI_to_regF(regF dst, stackSlotI src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $src,$dst\t! stkI to regF" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -5208,7 +5235,6 @@ instruct stkL_to_regD(regD dst, stackSlotL src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $src,$dst\t! stkL to regD" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -5219,7 +5245,6 @@ instruct regF_to_stkI(stackSlotI dst, regF src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$dst\t! regF to stkI" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -5230,7 +5255,6 @@ instruct regD_to_stkL(stackSlotL dst, regD src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$dst\t! regD to stkL" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -5240,7 +5264,6 @@ instruct regD_to_stkL(stackSlotL dst, regD src) %{ instruct regI_to_stkLHi(stackSlotL dst, iRegI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST*2); - size(8); format %{ "STW $src,$dst.hi\t! long\n\t" "STW R_G0,$dst.lo" %} opcode(Assembler::stw_op3); @@ -5252,7 +5275,6 @@ instruct regL_to_stkD(stackSlotD dst, iRegL src) %{ // No match rule to avoid chain rule match. effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! regL to stkD" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5266,7 +5288,6 @@ instruct stkI_to_regI( iRegI dst, stackSlotI src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $src,$dst\t!stk" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5278,7 +5299,6 @@ instruct regI_to_stkI( stackSlotI dst, iRegI src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$dst\t!stk" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5290,7 +5310,6 @@ instruct stkL_to_regL( iRegL dst, stackSlotL src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t! long" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5302,7 +5321,6 @@ instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! long" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5314,7 +5332,6 @@ instruct regL_to_stkL(stackSlotL dst, iRegL src) %{ instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t!ptr" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -5325,7 +5342,6 @@ instruct stkP_to_regP( iRegP dst, stackSlotP src ) %{ instruct regP_to_stkP(stackSlotP dst, iRegP src) %{ match(Set dst src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t!ptr" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -5771,7 +5787,6 @@ instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{ match(Set dst (LoadL_unaligned mem)); effect(KILL tmp); ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - size(16); format %{ "LDUW $mem+4,R_O7\t! misaligned long\n" "\tLDUW $mem ,$dst\n" "\tSLLX #32, $dst, $dst\n" @@ -5786,7 +5801,6 @@ instruct loadRange(iRegI dst, memory mem) %{ match(Set dst (LoadRange mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $mem,$dst\t! range" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -5797,7 +5811,6 @@ instruct loadRange(iRegI dst, memory mem) %{ instruct loadI_freg(regF dst, memory mem) %{ match(Set dst (LoadI mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $mem,$dst\t! for fitos/fitod" %} opcode(Assembler::ldf_op3); @@ -5876,7 +5889,6 @@ instruct loadD(regD dst, memory mem) %{ match(Set dst (LoadD mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $mem,$dst" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -5887,7 +5899,6 @@ instruct loadD(regD dst, memory mem) %{ instruct loadD_unaligned(regD_low dst, memory mem ) %{ match(Set dst (LoadD_unaligned mem)); ins_cost(MEMORY_REF_COST*2+DEFAULT_COST); - size(8); format %{ "LDF $mem ,$dst.hi\t! misaligned double\n" "\tLDF $mem+4,$dst.lo\t!" %} opcode(Assembler::ldf_op3); @@ -5900,7 +5911,6 @@ instruct loadF(regF dst, memory mem) %{ match(Set dst (LoadF mem)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $mem,$dst" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg( mem, dst ) ); @@ -6119,7 +6129,6 @@ instruct prefetchAlloc( memory mem ) %{ predicate(AllocatePrefetchInstr == 0); match( PrefetchAllocation mem ); ins_cost(MEMORY_REF_COST); - size(4); format %{ "PREFETCH $mem,2\t! Prefetch allocation" %} opcode(Assembler::prefetch_op3); @@ -6175,7 +6184,6 @@ instruct storeB(memory mem, iRegI src) %{ match(Set mem (StoreB mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6186,7 +6194,6 @@ instruct storeB0(memory mem, immI0 src) %{ match(Set mem (StoreB mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! byte" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6197,7 +6204,6 @@ instruct storeCM0(memory mem, immI0 src) %{ match(Set mem (StoreCM mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STB $src,$mem\t! CMS card-mark byte 0" %} opcode(Assembler::stb_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6209,7 +6215,6 @@ instruct storeC(memory mem, iRegI src) %{ match(Set mem (StoreC mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6220,7 +6225,6 @@ instruct storeC0(memory mem, immI0 src) %{ match(Set mem (StoreC mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STH $src,$mem\t! short" %} opcode(Assembler::sth_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6232,7 +6236,6 @@ instruct storeI(memory mem, iRegI src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6243,7 +6246,6 @@ instruct storeI(memory mem, iRegI src) %{ instruct storeL(memory mem, iRegL src) %{ match(Set mem (StoreL mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem\t! long" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6254,7 +6256,6 @@ instruct storeI0(memory mem, immI0 src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6265,7 +6266,6 @@ instruct storeL0(memory mem, immL0 src) %{ match(Set mem (StoreL mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6277,7 +6277,6 @@ instruct storeI_Freg(memory mem, regF src) %{ match(Set mem (StoreI mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$mem\t! after fstoi/fdtoi" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6288,7 +6287,6 @@ instruct storeI_Freg(memory mem, regF src) %{ instruct storeP(memory dst, sp_ptr_RegP src) %{ match(Set dst (StoreP dst src)); ins_cost(MEMORY_REF_COST); - size(4); #ifndef _LP64 format %{ "STW $src,$dst\t! ptr" %} @@ -6304,7 +6302,6 @@ instruct storeP(memory dst, sp_ptr_RegP src) %{ instruct storeP0(memory dst, immP0 src) %{ match(Set dst (StoreP dst src)); ins_cost(MEMORY_REF_COST); - size(4); #ifndef _LP64 format %{ "STW $src,$dst\t! ptr" %} @@ -6379,7 +6376,6 @@ instruct storeD( memory mem, regD src) %{ match(Set mem (StoreD mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$mem" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6390,7 +6386,6 @@ instruct storeD0( memory mem, immD0 src) %{ match(Set mem (StoreD mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$mem" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -6402,7 +6397,6 @@ instruct storeF( memory mem, regF src) %{ match(Set mem (StoreF mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$mem" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg( mem, src ) ); @@ -6413,7 +6407,6 @@ instruct storeF0( memory mem, immF0 src) %{ match(Set mem (StoreF mem src)); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$mem\t! storeF0" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( mem, R_G0 ) ); @@ -7068,7 +7061,6 @@ instruct loadPLocked(iRegP dst, memory mem) %{ ins_cost(MEMORY_REF_COST); #ifndef _LP64 - size(4); format %{ "LDUW $mem,$dst\t! ptr" %} opcode(Assembler::lduw_op3, 0, REGP_OP); #else @@ -8138,7 +8130,6 @@ instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDUW $src,$dst\t! MoveF2I" %} opcode(Assembler::lduw_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -8150,7 +8141,6 @@ instruct MoveI2F_stack_reg(regF dst, stackSlotI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDF $src,$dst\t! MoveI2F" %} opcode(Assembler::ldf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -8162,7 +8152,6 @@ instruct MoveD2L_stack_reg(iRegL dst, stackSlotD src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDX $src,$dst\t! MoveD2L" %} opcode(Assembler::ldx_op3); ins_encode(simple_form3_mem_reg( src, dst ) ); @@ -8174,7 +8163,6 @@ instruct MoveL2D_stack_reg(regD dst, stackSlotL src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "LDDF $src,$dst\t! MoveL2D" %} opcode(Assembler::lddf_op3); ins_encode(simple_form3_mem_reg(src, dst)); @@ -8186,7 +8174,6 @@ instruct MoveF2I_reg_stack(stackSlotI dst, regF src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STF $src,$dst\t! MoveF2I" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -8198,7 +8185,6 @@ instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STW $src,$dst\t! MoveI2F" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -8210,7 +8196,6 @@ instruct MoveD2L_reg_stack(stackSlotL dst, regD src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STDF $src,$dst\t! MoveD2L" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); @@ -8222,7 +8207,6 @@ instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ effect(DEF dst, USE src); ins_cost(MEMORY_REF_COST); - size(4); format %{ "STX $src,$dst\t! MoveL2D" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); @@ -8427,7 +8411,6 @@ instruct convI2D_reg(regD_low dst, iRegI src) %{ instruct convI2D_mem(regD_low dst, memory mem) %{ match(Set dst (ConvI2D (LoadI mem))); ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); format %{ "LDF $mem,$dst\n\t" "FITOD $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitod_opf); @@ -8468,7 +8451,6 @@ instruct convI2F_reg(regF dst, iRegI src) %{ instruct convI2F_mem( regF dst, memory mem ) %{ match(Set dst (ConvI2F (LoadI mem))); ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); format %{ "LDF $mem,$dst\n\t" "FITOS $dst,$dst" %} opcode(Assembler::ldf_op3, Assembler::fitos_opf); diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp index 9a6679d17ab..34041ed9943 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp @@ -463,3 +463,37 @@ unsigned int VM_Version::calc_parallel_worker_threads() { } return result; } + + +int VM_Version::parse_features(const char* implementation) { + int features = unknown_m; + // Convert to UPPER case before compare. + char* impl = os::strdup_check_oom(implementation); + + for (int i = 0; impl[i] != 0; i++) + impl[i] = (char)toupper((uint)impl[i]); + + if (strstr(impl, "SPARC64") != NULL) { + features |= sparc64_family_m; + } else if (strstr(impl, "SPARC-M") != NULL) { + // M-series SPARC is based on T-series. + features |= (M_family_m | T_family_m); + } else if (strstr(impl, "SPARC-T") != NULL) { + features |= T_family_m; + if (strstr(impl, "SPARC-T1") != NULL) { + features |= T1_model_m; + } + } else { + if (strstr(impl, "SPARC") == NULL) { +#ifndef PRODUCT + // kstat on Solaris 8 virtual machines (branded zones) + // returns "(unsupported)" implementation. Solaris 8 is not + // supported anymore, but include this check to be on the + // safe side. + warning("Can't parse CPU implementation = '%s', assume generic SPARC", impl); +#endif + } + } + os::free((void*)impl); + return features; +} diff --git a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp index 0609fa8b9a0..f2c5955905e 100644 --- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp @@ -121,7 +121,7 @@ protected: static bool is_T1_model(int features) { return is_T_family(features) && ((features & T1_model_m) != 0); } static int maximum_niagara1_processor_count() { return 32; } - + static int parse_features(const char* implementation); public: // Initialization static void initialize(); diff --git a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp index eb155c20be9..fc69cb45e5b 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreterGenerator_x86.cpp @@ -161,13 +161,7 @@ address TemplateInterpreterGenerator::generate_exception_handler_common( create_klass_exception), rarg, rarg2); } else { - // kind of lame ExternalAddress can't take NULL because - // external_word_Relocation will assert. - if (message != NULL) { - __ lea(rarg2, ExternalAddress((address)message)); - } else { - __ movptr(rarg2, NULL_WORD); - } + __ lea(rarg2, ExternalAddress((address)message)); __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), rarg, rarg2); diff --git a/hotspot/src/cpu/x86/vm/x86_32.ad b/hotspot/src/cpu/x86/vm/x86_32.ad index f684cd5b5cd..b09ca8e36ab 100644 --- a/hotspot/src/cpu/x86/vm/x86_32.ad +++ b/hotspot/src/cpu/x86/vm/x86_32.ad @@ -7236,6 +7236,7 @@ instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlags instruct compareAndSwapL( rRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7249,6 +7250,7 @@ instruct compareAndSwapL( rRegI res, eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL instruct compareAndSwapP( rRegI res, pRegP mem_ptr, eAXRegP oldval, eCXRegP newval, eFlagsReg cr) %{ match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7261,6 +7263,7 @@ instruct compareAndSwapP( rRegI res, pRegP mem_ptr, eAXRegP oldval, eCXRegP new instruct compareAndSwapI( rRegI res, pRegP mem_ptr, eAXRegI oldval, eCXRegI newval, eFlagsReg cr) %{ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" "MOV $res,0\n\t" @@ -7271,6 +7274,31 @@ instruct compareAndSwapI( rRegI res, pRegP mem_ptr, eAXRegI oldval, eCXRegI newv ins_pipe( pipe_cmpxchg ); %} +instruct compareAndExchangeL( eSIRegP mem_ptr, eADXRegL oldval, eBCXRegL newval, eFlagsReg cr ) %{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG8 [$mem_ptr],$newval\t# If EDX:EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg8(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( pRegP mem_ptr, eAXRegP oldval, eCXRegP newval, eFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeI( pRegP mem_ptr, eAXRegI oldval, eCXRegI newval, eFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + format %{ "CMPXCHG [$mem_ptr],$newval\t# If EAX==[$mem_ptr] Then store $newval into [$mem_ptr]\n\t" %} + ins_encode( enc_cmpxchg(mem_ptr) ); + ins_pipe( pipe_cmpxchg ); +%} + instruct xaddI_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem add)); diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index 455354834ea..6f32ace2f18 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -7281,6 +7281,7 @@ instruct compareAndSwapP(rRegI res, %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgq $mem_ptr,$newval\t# " @@ -7305,6 +7306,7 @@ instruct compareAndSwapL(rRegI res, %{ predicate(VM_Version::supports_cx8()); match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgq $mem_ptr,$newval\t# " @@ -7328,6 +7330,7 @@ instruct compareAndSwapI(rRegI res, rFlagsReg cr) %{ match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgl $mem_ptr,$newval\t# " @@ -7351,6 +7354,7 @@ instruct compareAndSwapN(rRegI res, rax_RegN oldval, rRegN newval, rFlagsReg cr) %{ match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval))); + match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval))); effect(KILL cr, KILL oldval); format %{ "cmpxchgl $mem_ptr,$newval\t# " @@ -7368,6 +7372,83 @@ instruct compareAndSwapN(rRegI res, ins_pipe( pipe_cmpxchg ); %} +instruct compareAndExchangeI( + memory mem_ptr, + rax_RegI oldval, rRegI newval, + rFlagsReg cr) +%{ + match(Set oldval (CompareAndExchangeI mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeL( + memory mem_ptr, + rax_RegL oldval, rRegL newval, + rFlagsReg cr) +%{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeL mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem_wide(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeN( + memory mem_ptr, + rax_RegN oldval, rRegN newval, + rFlagsReg cr) %{ + match(Set oldval (CompareAndExchangeN mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgl $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + +instruct compareAndExchangeP( + memory mem_ptr, + rax_RegP oldval, rRegP newval, + rFlagsReg cr) +%{ + predicate(VM_Version::supports_cx8()); + match(Set oldval (CompareAndExchangeP mem_ptr (Binary oldval newval))); + effect(KILL cr); + + format %{ "cmpxchgq $mem_ptr,$newval\t# " + "If rax == $mem_ptr then store $newval into $mem_ptr\n\t" %} + opcode(0x0F, 0xB1); + ins_encode(lock_prefix, + REX_reg_mem_wide(newval, mem_ptr), + OpcP, OpcS, + reg_mem(newval, mem_ptr) // lock cmpxchg + ); + ins_pipe( pipe_cmpxchg ); +%} + instruct xaddI_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{ predicate(n->as_LoadStore()->result_not_used()); match(Set dummy (GetAndAddI mem add)); diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/module-info.java b/hotspot/src/jdk.hotspot.agent/share/classes/module-info.java new file mode 100644 index 00000000000..85b163bcd02 --- /dev/null +++ b/hotspot/src/jdk.hotspot.agent/share/classes/module-info.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +module jdk.hotspot.agent { + requires java.datatransfer; + requires java.desktop; + requires java.rmi; + requires java.scripting; + requires jdk.jcmd; + requires jdk.jdi; + + // RMI needs to serialize types in this package + exports sun.jvm.hotspot.debugger.remote to java.rmi; + provides com.sun.jdi.connect.Connector with sun.jvm.hotspot.jdi.SACoreAttachingConnector; + provides com.sun.jdi.connect.Connector with sun.jvm.hotspot.jdi.SADebugServerAttachingConnector; + provides com.sun.jdi.connect.Connector with sun.jvm.hotspot.jdi.SAPIDAttachingConnector; + + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.JStack; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.JInfo; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.ClassLoaderStats; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.FinalizerInfo; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.HeapDumper; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.HeapSummary; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.ObjectHistogram; + provides jdk.internal.vm.agent.spi.ToolProvider with sun.jvm.hotspot.tools.PMap; +} + diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java index a5fac511d18..34f5bfbefef 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @@ -31,14 +31,14 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.tools.*; import sun.jvm.hotspot.utilities.*; +import jdk.internal.vm.agent.spi.ToolProvider; /** A command line tool to print class loader statistics. */ -public class ClassLoaderStats extends Tool { +public class ClassLoaderStats extends Tool implements ToolProvider { boolean verbose = true; public ClassLoaderStats() { @@ -49,6 +49,16 @@ public class ClassLoaderStats extends Tool { super(d); } + @Override + public String getName() { + return "classLoaderStats"; + } + + @Override + public void run(String... arguments) { + execute(arguments); + } + public static void main(String[] args) { ClassLoaderStats cls = new ClassLoaderStats(); cls.execute(args); diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java index 58819a0a7dd..9da8e523afb 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/FinalizerInfo.java @@ -25,24 +25,21 @@ package sun.jvm.hotspot.tools; import sun.jvm.hotspot.debugger.JVMDebugger; -import sun.jvm.hotspot.tools.*; import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.VM; import sun.jvm.hotspot.utilities.SystemDictionaryHelper; -import sun.jvm.hotspot.utilities.ObjectReader; -import sun.jvm.hotspot.utilities.MarkBits; +import jdk.internal.vm.agent.spi.ToolProvider; -import java.util.HashMap; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; /* * Iterates over the queue of object pending finalization and prints a * summary of these objects in the form of a histogram. */ -public class FinalizerInfo extends Tool { +public class FinalizerInfo extends Tool implements ToolProvider { public FinalizerInfo() { super(); @@ -52,6 +49,16 @@ public class FinalizerInfo extends Tool { super(d); } + @Override + public String getName() { + return "finalizerInfo"; + } + + @Override + public void run(String... arguments) { + execute(arguments); + } + public static void main(String[] args) { FinalizerInfo finfo = new FinalizerInfo(); finfo.execute(args); diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java index 1b93504313a..d0a11abd095 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapDumper.java @@ -26,6 +26,8 @@ package sun.jvm.hotspot.tools; import sun.jvm.hotspot.utilities.HeapHprofBinWriter; import sun.jvm.hotspot.debugger.JVMDebugger; +import jdk.internal.vm.agent.spi.ToolProvider; + import java.io.IOException; /* @@ -33,12 +35,16 @@ import java.io.IOException; * process/core as a HPROF binary file. It can also be used as a standalone * tool if required. */ -public class HeapDumper extends Tool { +public class HeapDumper extends Tool implements ToolProvider { private static String DEFAULT_DUMP_FILE = "heap.bin"; private String dumpFile; + public HeapDumper() { + this.dumpFile = DEFAULT_DUMP_FILE; + } + public HeapDumper(String dumpFile) { this.dumpFile = dumpFile; } @@ -48,6 +54,11 @@ public class HeapDumper extends Tool { this.dumpFile = dumpFile; } + @Override + public String getName() { + return "heapDumper"; + } + protected void printFlagsUsage() { System.out.println(" \tto dump heap to " + DEFAULT_DUMP_FILE); @@ -69,18 +80,22 @@ public class HeapDumper extends Tool { // JDK jmap utility will always invoke this tool as: // HeapDumper -f public static void main(String args[]) { - String file = DEFAULT_DUMP_FILE; + HeapDumper dumper = new HeapDumper(); + dumper.run(args); + } + + @Override + public void run(String... args) { if (args.length > 2) { if (args[0].equals("-f")) { - file = args[1]; + this.dumpFile = args[1]; String[] newargs = new String[args.length-2]; System.arraycopy(args, 2, newargs, 0, args.length-2); args = newargs; } } - HeapDumper dumper = new HeapDumper(file); - dumper.execute(args); + execute(args); } } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java index 601283072ff..5c1012bf644 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java @@ -33,8 +33,9 @@ import sun.jvm.hotspot.debugger.JVMDebugger; import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; +import jdk.internal.vm.agent.spi.ToolProvider; -public class HeapSummary extends Tool { +public class HeapSummary extends Tool implements ToolProvider { public HeapSummary() { super(); @@ -49,6 +50,16 @@ public class HeapSummary extends Tool { hs.execute(args); } + @Override + public String getName() { + return "heapSummary"; + } + + @Override + public void run(String... arguments) { + execute(arguments); + } + public void run() { CollectedHeap heap = VM.getVM().getUniverse().heap(); VM.Flag[] flags = VM.getVM().getCommandLineFlags(); diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java index 7469de28f40..50f9c30975b 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JInfo.java @@ -27,8 +27,9 @@ package sun.jvm.hotspot.tools; import sun.jvm.hotspot.debugger.JVMDebugger; import sun.jvm.hotspot.runtime.Arguments; import sun.jvm.hotspot.runtime.VM; +import jdk.internal.vm.agent.spi.ToolProvider; -public class JInfo extends Tool { +public class JInfo extends Tool implements ToolProvider { public JInfo() { super(); } @@ -94,13 +95,14 @@ public class JInfo extends Tool { tool.run(); } - public static void main(String[] args) { + @Override + public void run(String... args) { int mode = -1; switch (args.length) { case 1: if (args[0].charAt(0) == '-') { // -h or -help or some invalid flag - new JInfo(mode).usage(); + usage(); } else { mode = MODE_BOTH; } @@ -114,7 +116,7 @@ public class JInfo extends Tool { mode = MODE_SYSPROPS; } else if (modeFlag.charAt(0) == '-') { // -h or -help or some invalid flag - new JInfo(mode).usage(); + usage(); } else { mode = MODE_BOTH; } @@ -131,11 +133,16 @@ public class JInfo extends Tool { } default: - new JInfo(mode).usage(); + usage(); } - JInfo jinfo = new JInfo(mode); - jinfo.execute(args); + this.mode = mode; + execute(args); + } + + public static void main(String[] args) { + JInfo jinfo = new JInfo(); + jinfo.run(args); } private void printVMFlags() { diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java index b8609bcdbeb..821ed388853 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JStack.java @@ -25,8 +25,9 @@ package sun.jvm.hotspot.tools; import sun.jvm.hotspot.debugger.JVMDebugger; +import jdk.internal.vm.agent.spi.ToolProvider; -public class JStack extends Tool { +public class JStack extends Tool implements ToolProvider { public JStack(boolean mixedMode, boolean concurrentLocks) { this.mixedMode = mixedMode; this.concurrentLocks = concurrentLocks; @@ -66,9 +67,8 @@ public class JStack extends Tool { tool.run(); } - public static void main(String[] args) { - boolean mixedMode = false; - boolean concurrentLocks = false; + @Override + public void run(String... args) { int used = 0; for (int i = 0; i < args.length; i++) { if (args[i].equals("-m")) { @@ -88,8 +88,12 @@ public class JStack extends Tool { args = newArgs; } - JStack jstack = new JStack(mixedMode, concurrentLocks); - jstack.execute(args); + execute(args); + } + + public static void main(String[] args) { + JStack jstack = new JStack(); + jstack.run(args); } private boolean mixedMode; diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java index ddedcae5394..0dc100eebe5 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ObjectHistogram.java @@ -27,11 +27,13 @@ package sun.jvm.hotspot.tools; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; +import jdk.internal.vm.agent.spi.ToolProvider; + import java.io.PrintStream; /** A sample tool which uses the Serviceability Agent's APIs to obtain an object histogram from a remote or crashed VM. */ -public class ObjectHistogram extends Tool { +public class ObjectHistogram extends Tool implements ToolProvider { public ObjectHistogram() { super(); @@ -41,6 +43,16 @@ public class ObjectHistogram extends Tool { super(d); } + @Override + public String getName() { + return "objectHistogram"; + } + + @Override + public void run(String... arguments) { + execute(arguments); + } + public void run() { run(System.out, System.err); } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java index 43bcd593f30..0c0ccbf6c8c 100644 --- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java +++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PMap.java @@ -28,9 +28,9 @@ import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.cdbg.*; -import sun.jvm.hotspot.runtime.*; +import jdk.internal.vm.agent.spi.ToolProvider; -public class PMap extends Tool { +public class PMap extends Tool implements ToolProvider { public PMap() { super(); @@ -40,6 +40,16 @@ public class PMap extends Tool { super(d); } + @Override + public String getName() { + return "pmap"; + } + + @Override + public void run(String... arguments) { + execute(arguments); + } + public void run() { run(System.out); } diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/development/Server24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/development/Server24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/About24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/About24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Delete24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Delete24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Find16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Find16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Find16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Find16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Help24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Help24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/History24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/History24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Information24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Information24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/New24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/New24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Open24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Open24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Save24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Save24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Save24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/SaveAs24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/SaveAs24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Zoom16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/Zoom16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/Zoom16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/general/ZoomIn24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/general/ZoomIn24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Down16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Down16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Down16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Up16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/navigation/Up16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/navigation/Up16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignCenter24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignCenter24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignLeft24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignLeft24.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight16.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight16.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight16.gif diff --git a/hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif b/hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight24.gif similarity index 100% rename from hotspot/src/jdk.hotspot.agent/share/classes/images/toolbarButtonGraphics/text/AlignRight24.gif rename to hotspot/src/jdk.hotspot.agent/share/classes/toolbarButtonGraphics/text/AlignRight24.gif diff --git a/hotspot/src/jdk.vm.ci/share/classes/META-INF/services/jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory b/hotspot/src/jdk.vm.ci/share/classes/META-INF/services/jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory deleted file mode 100644 index fe3a4573058..00000000000 --- a/hotspot/src/jdk.vm.ci/share/classes/META-INF/services/jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory +++ /dev/null @@ -1,3 +0,0 @@ -jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory -jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory -jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java index 37393ff08bc..972aea94231 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java @@ -22,6 +22,7 @@ */ package jdk.vm.ci.amd64; +import static jdk.vm.ci.code.MemoryBarriers.LOAD_LOAD; import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE; import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE; import static jdk.vm.ci.code.Register.SPECIAL; @@ -220,7 +221,7 @@ public class AMD64 extends Architecture { private final AMD64Kind largestKind; public AMD64(EnumSet features, EnumSet flags) { - super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_STORE | STORE_STORE, 1, 8); + super("AMD64", AMD64Kind.QWORD, ByteOrder.LITTLE_ENDIAN, true, allRegisters, LOAD_LOAD | LOAD_STORE | STORE_STORE, 1, 8); this.features = features; this.flags = flags; assert features.contains(CPUFeature.SSE2) : "minimum config for x64"; diff --git a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 3e90a4d73b0..88da9e5b32a 100644 --- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -1141,7 +1141,7 @@ public class HotSpotVMConfig { @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_sp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaSpOffset; @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_pc", type = "address", get = HotSpotVMField.Type.OFFSET) @Stable private int javaFrameAnchorLastJavaPcOffset; - @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; + @HotSpotVMField(name = "JavaFrameAnchor::_last_Java_fp", type = "intptr_t*", get = HotSpotVMField.Type.OFFSET, archs = {"aarch64, amd64"}) @Stable private int javaFrameAnchorLastJavaFpOffset; @HotSpotVMField(name = "JavaFrameAnchor::_flags", type = "int", get = HotSpotVMField.Type.OFFSET, archs = {"sparc"}) @Stable private int javaFrameAnchorFlagsOffset; public int threadLastJavaSpOffset() { @@ -1152,11 +1152,8 @@ public class HotSpotVMConfig { return javaThreadAnchorOffset + javaFrameAnchorLastJavaPcOffset; } - /** - * This value is only valid on AMD64. - */ public int threadLastJavaFpOffset() { - // TODO add an assert for AMD64 + assert getHostArchitectureName().equals("aarch64") || getHostArchitectureName().equals("amd64"); return javaThreadAnchorOffset + javaFrameAnchorLastJavaFpOffset; } diff --git a/hotspot/src/jdk.vm.ci/share/classes/module-info.java b/hotspot/src/jdk.vm.ci/share/classes/module-info.java new file mode 100644 index 00000000000..a59a37d56e2 --- /dev/null +++ b/hotspot/src/jdk.vm.ci/share/classes/module-info.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module jdk.vm.ci { + uses jdk.vm.ci.hotspot.HotSpotVMEventListener; + uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; + uses jdk.vm.ci.runtime.JVMCICompilerFactory; + + provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory; + provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory; + provides jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory with + jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory; +} diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp index f63a789b89c..2193a9611a3 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, 2015, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2015 SAP SE. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 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 @@ -36,6 +36,7 @@ #include "compiler/compileBroker.hpp" #include "interpreter/interpreter.hpp" #include "jvm_aix.h" +#include "logging/log.hpp" #include "libo4.hpp" #include "libperfstat_aix.hpp" #include "libodm_aix.hpp" @@ -791,13 +792,8 @@ static void *java_start(Thread *thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - trcVerbose("newborn Thread : pthread-id %u, ktid " UINT64_FORMAT - ", stack %p ... %p, stacksize 0x%IX (%IB)", - pthread_id, kernel_thread_id, - thread->stack_end(), - thread->stack_base(), - thread->stack_size(), - thread->stack_size()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); // Normally, pthread stacks on AIX live in the data segment (are allocated with malloc() // by the pthread library). In rare cases, this may not be the case, e.g. when third-party @@ -805,7 +801,7 @@ static void *java_start(Thread *thread) { // guard pages on those stacks, because the stacks may reside in memory which is not // protectable (shmated). if (thread->stack_base() > ::sbrk(0)) { - trcVerbose("Thread " UINT64_FORMAT ": stack not in data segment.", (uint64_t) pthread_id); + log_warning(os, thread)("Thread stack not in data segment."); } // Try to randomize the cache line index of hot stack frames. @@ -839,8 +835,8 @@ static void *java_start(Thread *thread) { // Call one more level start routine. thread->run(); - trcVerbose("Thread finished : pthread-id %u, ktid " UINT64_FORMAT ".", - pthread_id, kernel_thread_id); + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); return 0; } @@ -908,20 +904,19 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); - if (ret == 0) { - trcVerbose("Created New Thread : pthread-id %u", tid); - } else { - if (os::Aix::on_pase()) { - // QIBM_MULTI_THREADED=Y is needed when the launcher is started on iSeries - // using QSH. Otherwise pthread_create fails with errno=11. - trcVerbose("(Please make sure you set the environment variable " - "QIBM_MULTI_THREADED=Y before running this program.)"); - } - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } + if (ret != 0) { // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -958,13 +953,6 @@ bool os::create_attached_thread(JavaThread* thread) { const pthread_t pthread_id = ::pthread_self(); const tid_t kernel_thread_id = ::thread_self(); - trcVerbose("attaching Thread : pthread-id %u, ktid " UINT64_FORMAT ", stack %p ... %p, stacksize 0x%IX (%IB)", - pthread_id, kernel_thread_id, - thread->stack_end(), - thread->stack_base(), - thread->stack_size(), - thread->stack_size()); - // OSThread::thread_id is the pthread id. osthread->set_thread_id(pthread_id); @@ -990,6 +978,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Aix::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", kernel thread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) kernel_thread_id); + return true; } diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 8fdc6bc63b7..3d6f8fd6422 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -32,6 +32,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_bsd.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_bsd.inline.hpp" @@ -681,6 +682,9 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::Bsd::gettid()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + #ifdef __APPLE__ uint64_t unique_thread_id = locate_unique_thread_id(osthread->thread_id()); guarantee(unique_thread_id != 0, "unique thread id was not found"); @@ -716,6 +720,9 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return 0; } @@ -776,12 +783,18 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); if (ret != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -858,6 +871,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Bsd::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return true; } diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index 3783351c345..d46a1146dd7 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -662,6 +662,9 @@ static void *java_start(Thread *thread) { osthread->set_thread_id(os::current_thread_id()); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) { @@ -691,6 +694,9 @@ static void *java_start(Thread *thread) { // call one more level start routine thread->run(); + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return 0; } @@ -756,12 +762,18 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, pthread_t tid; int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread); + char buf[64]; + if (ret == 0) { + log_info(os, thread)("Thread started (pthread id: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } else { + log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.", + strerror(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr)); + } + pthread_attr_destroy(&attr); if (ret != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("pthread_create()"); - } // Need to clean up stuff we've allocated so far thread->set_osthread(NULL); delete osthread; @@ -858,6 +870,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Linux::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").", + os::current_thread_id(), (uintx) pthread_self()); + return true; } diff --git a/hotspot/src/os/posix/dtrace/hotspot_jni.d b/hotspot/src/os/posix/dtrace/hotspot_jni.d index cca1c517650..eb95b7e4c3a 100644 --- a/hotspot/src/os/posix/dtrace/hotspot_jni.d +++ b/hotspot/src/os/posix/dtrace/hotspot_jni.d @@ -300,6 +300,8 @@ provider hotspot_jni { probe GetLongField__return(uintptr_t); probe GetMethodID__entry(void*, void*, const char*, const char*); probe GetMethodID__return(uintptr_t); + probe GetModule__entry(void*, void*); + probe GetModule__return(void*); probe GetObjectArrayElement__entry(void*, void*, uintptr_t); probe GetObjectArrayElement__return(void*); probe GetObjectClass__entry(void*, void*); diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index 8cccda34d21..85407bd3cad 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -1071,6 +1071,19 @@ void os::Posix::ucontext_set_pc(ucontext_t* ctx, address pc) { #endif } +char* os::Posix::describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr) { + size_t stack_size = 0; + size_t guard_size = 0; + int detachstate = 0; + pthread_attr_getstacksize(attr, &stack_size); + pthread_attr_getguardsize(attr, &guard_size); + pthread_attr_getdetachstate(attr, &detachstate); + jio_snprintf(buf, buflen, "stacksize: " SIZE_FORMAT "k, guardsize: " SIZE_FORMAT "k, %s", + stack_size / 1024, guard_size / 1024, + (detachstate == PTHREAD_CREATE_DETACHED ? "detached" : "joinable")); + return buf; +} + os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); diff --git a/hotspot/src/os/posix/vm/os_posix.hpp b/hotspot/src/os/posix/vm/os_posix.hpp index be464ea8fa1..0196e989456 100644 --- a/hotspot/src/os/posix/vm/os_posix.hpp +++ b/hotspot/src/os/posix/vm/os_posix.hpp @@ -76,6 +76,11 @@ public: static address ucontext_get_pc(const ucontext_t* ctx); // Set PC into context. Needed for continuation after signal. static void ucontext_set_pc(ucontext_t* ctx, address pc); + + // Helper function; describes pthread attributes as short string. String is written + // to buf with len buflen; buf is returned. + static char* describe_pthread_attr(char* buf, size_t buflen, const pthread_attr_t* attr); + }; /* diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index ae008b6dbe9..bc8138db6ff 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_solaris.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_solaris.inline.hpp" @@ -68,6 +69,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" // put OS-includes here @@ -736,6 +738,9 @@ extern "C" void* java_start(void* thread_addr) { osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound thread->_schedctl = (void *) schedctl_init(); + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + if (UseNUMA) { int lgrp_id = os::numa_get_group_id(); if (lgrp_id != -1) { @@ -781,6 +786,8 @@ extern "C" void* java_start(void* thread_addr) { Atomic::dec(&os::Solaris::_os_thread_count); } + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); + if (UseDetachedThreads) { thr_exit(NULL); ShouldNotReachHere(); @@ -853,6 +860,9 @@ bool os::create_attached_thread(JavaThread* thread) { // and save the caller's signal mask os::Solaris::hotspot_sigmask(thread); + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + return true; } @@ -879,6 +889,24 @@ bool os::create_main_thread(JavaThread* thread) { return true; } +// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() +static char* describe_thr_create_attributes(char* buf, size_t buflen, + size_t stacksize, long flags) { + stringStream ss(buf, buflen); + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); + ss.print("flags: "); + #define PRINT_FLAG(f) if (flags & f) ss.print( #f " "); + #define ALL(X) \ + X(THR_SUSPENDED) \ + X(THR_DETACHED) \ + X(THR_BOUND) \ + X(THR_NEW_LWP) \ + X(THR_DAEMON) + ALL(PRINT_FLAG) + #undef ALL + #undef PRINT_FLAG + return buf; +} bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { @@ -974,10 +1002,17 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, osthread->set_thread_id(-1); status = thr_create(NULL, stack_size, java_start, thread, flags, &tid); + + char buf[64]; + if (status == 0) { + log_info(os, thread)("Thread started (tid: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } else { + log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", + strerror(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } + if (status != 0) { - if (PrintMiscellaneous && (Verbose || WizardMode)) { - perror("os::create_thread"); - } thread->set_osthread(NULL); // Need to clean up stuff we've allocated so far delete osthread; diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 19d7319e7e1..f8bc6081d8b 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -35,6 +35,7 @@ #include "compiler/disassembler.hpp" #include "interpreter/interpreter.hpp" #include "jvm_windows.h" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "mutex_windows.inline.hpp" @@ -71,6 +72,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" #include "utilities/growableArray.hpp" +#include "utilities/macros.hpp" #include "utilities/vmError.hpp" #ifdef _DEBUG @@ -436,6 +438,8 @@ static unsigned __stdcall java_start(Thread* thread) { res = 20115; // java thread } + log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", os::current_thread_id()); + // Install a win32 structured exception handler around every thread created // by VM, so VM can generate error dump when an exception occurred in non- // Java thread (e.g. VM thread). @@ -446,6 +450,8 @@ static unsigned __stdcall java_start(Thread* thread) { // Nothing to do. } + log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); + // One less thread is executing // When the VMThread gets here, the main thread may have already exited // which frees the CodeHeap containing the Atomic::add code @@ -509,6 +515,10 @@ bool os::create_attached_thread(JavaThread* thread) { osthread->set_state(RUNNABLE); thread->set_osthread(osthread); + + log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", + os::current_thread_id()); + return true; } @@ -530,6 +540,27 @@ bool os::create_main_thread(JavaThread* thread) { return true; } +// Helper function to trace _beginthreadex attributes, +// similar to os::Posix::describe_pthread_attr() +static char* describe_beginthreadex_attributes(char* buf, size_t buflen, + size_t stacksize, unsigned initflag) { + stringStream ss(buf, buflen); + if (stacksize == 0) { + ss.print("stacksize: default, "); + } else { + ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); + } + ss.print("flags: "); + #define PRINT_FLAG(f) if (initflag & f) ss.print( #f " "); + #define ALL(X) \ + X(CREATE_SUSPENDED) \ + X(STACK_SIZE_PARAM_IS_A_RESERVATION) + ALL(PRINT_FLAG) + #undef ALL + #undef PRINT_FLAG + return buf; +} + // Allocate and initialize a new OSThread bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { @@ -596,14 +627,24 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, // document because JVM uses C runtime library. The good news is that the // flag appears to work with _beginthredex() as well. + const unsigned initflag = CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION; HANDLE thread_handle = (HANDLE)_beginthreadex(NULL, (unsigned)stack_size, (unsigned (__stdcall *)(void*)) java_start, thread, - CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, + initflag, &thread_id); + char buf[64]; + if (thread_handle != NULL) { + log_info(os, thread)("Thread started (tid: %u, attributes: %s)", + thread_id, describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + } else { + log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.", + strerror(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag)); + } + if (thread_handle == NULL) { // Need to clean up stuff we've allocated so far CloseHandle(osthread->interrupt_event()); @@ -1668,8 +1709,7 @@ void os::win32::print_windows_version(outputStream* st) { if (is_workstation) { st->print("10"); } else { - // The server version name of Windows 10 is not known at this time - st->print("%d.%d", major_version, minor_version); + st->print("Server 2016"); } break; diff --git a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp index 971fa84fc64..837607e6781 100644 --- a/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp +++ b/hotspot/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp @@ -264,6 +264,7 @@ void PICL::close_library() { // We need to keep these here as long as we have to build on Solaris // versions before 10. + #ifndef SI_ARCHITECTURE_32 #define SI_ARCHITECTURE_32 516 /* basic 32-bit SI_ARCHITECTURE */ #endif @@ -272,36 +273,87 @@ void PICL::close_library() { #define SI_ARCHITECTURE_64 517 /* basic 64-bit SI_ARCHITECTURE */ #endif -static void do_sysinfo(int si, const char* string, int* features, int mask) { - char tmp; - size_t bufsize = sysinfo(si, &tmp, 1); +#ifndef SI_CPUBRAND +#define SI_CPUBRAND 523 /* return cpu brand string */ +#endif - // All SI defines used below must be supported. - guarantee(bufsize != -1, "must be supported"); +class Sysinfo { + char* _string; +public: + Sysinfo(int si) : _string(NULL) { + char tmp; + size_t bufsize = sysinfo(si, &tmp, 1); - char* buf = (char*) os::malloc(bufsize, mtInternal); - - if (buf == NULL) - return; - - if (sysinfo(si, buf, bufsize) == bufsize) { - // Compare the string. - if (strcmp(buf, string) == 0) { - *features |= mask; + if (bufsize != -1) { + char* buf = (char*) os::malloc(bufsize, mtInternal); + if (buf != NULL) { + if (sysinfo(si, buf, bufsize) == bufsize) { + _string = buf; + } else { + os::free(buf); + } + } } } - os::free(buf); -} + ~Sysinfo() { + if (_string != NULL) { + os::free(_string); + } + } + + const char* value() const { + return _string; + } + + bool valid() const { + return _string != NULL; + } + + bool match(const char* s) const { + return valid() ? strcmp(_string, s) == 0 : false; + } + + bool match_substring(const char* s) const { + return valid() ? strstr(_string, s) != NULL : false; + } +}; + +class Sysconf { + int _value; +public: + Sysconf(int sc) : _value(-1) { + _value = sysconf(sc); + } + bool valid() const { + return _value != -1; + } + int value() const { + return _value; + } +}; + + +#ifndef _SC_DCACHE_LINESZ +#define _SC_DCACHE_LINESZ 508 /* Data cache line size */ +#endif + +#ifndef _SC_L2CACHE_LINESZ +#define _SC_L2CACHE_LINESZ 527 /* Size of L2 cache line */ +#endif int VM_Version::platform_features(int features) { assert(os::Solaris::supports_getisax(), "getisax() must be available"); // Check 32-bit architecture. - do_sysinfo(SI_ARCHITECTURE_32, "sparc", &features, v8_instructions_m); + if (Sysinfo(SI_ARCHITECTURE_32).match("sparc")) { + features |= v8_instructions_m; + } // Check 64-bit architecture. - do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); + if (Sysinfo(SI_ARCHITECTURE_64).match("sparcv9")) { + features |= generic_v9_m; + } // Extract valid instruction set extensions. uint_t avs[2]; @@ -388,67 +440,63 @@ int VM_Version::platform_features(int features) { if (av & AV_SPARC_SHA512) features |= sha512_instruction_m; // Determine the machine type. - do_sysinfo(SI_MACHINE, "sun4v", &features, sun4v_m); + if (Sysinfo(SI_MACHINE).match("sun4v")) { + features |= sun4v_m; + } - { - // Using kstat to determine the machine type. + bool use_solaris_12_api = false; + Sysinfo impl(SI_CPUBRAND); + if (impl.valid()) { + // If SI_CPUBRAND works, that means Solaris 12 API to get the cache line sizes + // is available to us as well + use_solaris_12_api = true; + features |= parse_features(impl.value()); + } else { + // Otherwise use kstat to determine the machine type. kstat_ctl_t* kc = kstat_open(); kstat_t* ksp = kstat_lookup(kc, (char*)"cpu_info", -1, NULL); - const char* implementation = "UNKNOWN"; + const char* implementation; + bool has_implementation = false; if (ksp != NULL) { if (kstat_read(kc, ksp, NULL) != -1 && ksp->ks_data != NULL) { kstat_named_t* knm = (kstat_named_t *)ksp->ks_data; for (int i = 0; i < ksp->ks_ndata; i++) { if (strcmp((const char*)&(knm[i].name),"implementation") == 0) { implementation = KSTAT_NAMED_STR_PTR(&knm[i]); + has_implementation = true; #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print_cr("cpu_info.implementation: %s", implementation); } #endif - // Convert to UPPER case before compare. - char* impl = os::strdup_check_oom(implementation); - - for (int i = 0; impl[i] != 0; i++) - impl[i] = (char)toupper((uint)impl[i]); - - if (strstr(impl, "SPARC64") != NULL) { - features |= sparc64_family_m; - } else if (strstr(impl, "SPARC-M") != NULL) { - // M-series SPARC is based on T-series. - features |= (M_family_m | T_family_m); - } else if (strstr(impl, "SPARC-T") != NULL) { - features |= T_family_m; - if (strstr(impl, "SPARC-T1") != NULL) { - features |= T1_model_m; - } - } else { - if (strstr(impl, "SPARC") == NULL) { -#ifndef PRODUCT - // kstat on Solaris 8 virtual machines (branded zones) - // returns "(unsupported)" implementation. Solaris 8 is not - // supported anymore, but include this check to be on the - // safe side. - warning("kstat cpu_info implementation = '%s', assume generic SPARC", impl); -#endif - implementation = "SPARC"; - } - } - os::free((void*)impl); + features |= parse_features(implementation); break; } } // for( } } - assert(strcmp(implementation, "UNKNOWN") != 0, - "unknown cpu info (changed kstat interface?)"); + assert(has_implementation, "unknown cpu info (changed kstat interface?)"); kstat_close(kc); } - // Figure out cache line sizes using PICL - PICL picl((features & sparc64_family_m) != 0, (features & sun4v_m) != 0); - _L1_data_cache_line_size = picl.L1_data_cache_line_size(); - _L2_data_cache_line_size = picl.L2_data_cache_line_size(); + bool is_sun4v = (features & sun4v_m) != 0; + if (use_solaris_12_api && is_sun4v) { + // If Solaris 12 API is supported and it's sun4v use sysconf() to get the cache line sizes + Sysconf l1_dcache_line_size(_SC_DCACHE_LINESZ); + if (l1_dcache_line_size.valid()) { + _L1_data_cache_line_size = l1_dcache_line_size.value(); + } + Sysconf l2_dcache_line_size(_SC_L2CACHE_LINESZ); + if (l2_dcache_line_size.valid()) { + _L2_data_cache_line_size = l2_dcache_line_size.value(); + } + } else { + // Otherwise figure out the cache line sizes using PICL + bool is_fujitsu = (features & sparc64_family_m) != 0; + PICL picl(is_fujitsu, is_sun4v); + _L1_data_cache_line_size = picl.L1_data_cache_line_size(); + _L2_data_cache_line_size = picl.L2_data_cache_line_size(); + } return features; } diff --git a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp index 71e1e8b6aad..8045f792b76 100644 --- a/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp +++ b/hotspot/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp @@ -51,11 +51,8 @@ void MacroAssembler::int3() { // movl reg, [reg + thread_ptr_offset] Load thread // void MacroAssembler::get_thread(Register thread) { - // can't use ExternalAddress because it can't take NULL - AddressLiteral null(0, relocInfo::none); - prefix(FS_segment); - movptr(thread, null); + movptr(thread, ExternalAddress(NULL)); assert(os::win32::get_thread_ptr_offset() != 0, "Thread Pointer Offset has not been initialized"); movl(thread, Address(thread, os::win32::get_thread_ptr_offset())); diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp index d408c904c6c..a3faa48e426 100644 --- a/hotspot/src/share/vm/adlc/formssel.cpp +++ b/hotspot/src/share/vm/adlc/formssel.cpp @@ -3491,6 +3491,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const { "LoadPLocked", "StorePConditional", "StoreIConditional", "StoreLConditional", "CompareAndSwapI", "CompareAndSwapL", "CompareAndSwapP", "CompareAndSwapN", + "WeakCompareAndSwapI", "WeakCompareAndSwapL", "WeakCompareAndSwapP", "WeakCompareAndSwapN", + "CompareAndExchangeI", "CompareAndExchangeL", "CompareAndExchangeP", "CompareAndExchangeN", "StoreCM", "ClearArray", "GetAndAddI", "GetAndSetI", "GetAndSetP", diff --git a/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp b/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp index 1cdde1186b2..00790396214 100644 --- a/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp +++ b/hotspot/src/share/vm/c1/c1_CFGPrinter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,9 @@ // compilation for later analysis. class CFGPrinterOutput; -class IntervalList; +class Interval; + +typedef GrowableArray IntervalList; class CFGPrinter : public AllStatic { private: diff --git a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp index e06aa581833..033beb0d25e 100644 --- a/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp +++ b/hotspot/src/share/vm/c1/c1_Canonicalizer.cpp @@ -222,27 +222,36 @@ void Canonicalizer::do_StoreField (StoreField* x) { } void Canonicalizer::do_ArrayLength (ArrayLength* x) { - NewArray* array = x->array()->as_NewArray(); - if (array != NULL && array->length() != NULL) { - Constant* length = array->length()->as_Constant(); - if (length != NULL) { - // do not use the Constant itself, but create a new Constant - // with same value Otherwise a Constant is live over multiple - // blocks without being registered in a state array. + NewArray* na; + Constant* ct; + LoadField* lf; + + if ((na = x->array()->as_NewArray()) != NULL) { + // New arrays might have the known length. + // Do not use the Constant itself, but create a new Constant + // with same value Otherwise a Constant is live over multiple + // blocks without being registered in a state array. + Constant* length; + if (na->length() != NULL && + (length = na->length()->as_Constant()) != NULL) { assert(length->type()->as_IntConstant() != NULL, "array length must be integer"); set_constant(length->type()->as_IntConstant()->value()); } - } else { - LoadField* lf = x->array()->as_LoadField(); - if (lf != NULL) { - ciField* field = lf->field(); - if (field->is_constant() && field->is_static()) { - // final static field - ciObject* c = field->constant_value().as_object(); - if (c->is_array()) { - ciArray* array = (ciArray*) c; - set_constant(array->length()); - } + + } else if ((ct = x->array()->as_Constant()) != NULL) { + // Constant arrays have constant lengths. + ArrayConstant* cnst = ct->type()->as_ArrayConstant(); + if (cnst != NULL) { + set_constant(cnst->value()->length()); + } + + } else if ((lf = x->array()->as_LoadField()) != NULL) { + ciField* field = lf->field(); + if (field->is_constant() && field->is_static()) { + assert(PatchALot || ScavengeRootsInCode < 2, "Constant field loads are folded during parsing"); + ciObject* c = field->constant_value().as_object(); + if (!c->is_null_object()) { + set_constant(c->as_array()->length()); } } } diff --git a/hotspot/src/share/vm/c1/c1_Compiler.cpp b/hotspot/src/share/vm/c1/c1_Compiler.cpp index 5dbe6c209f3..78d71b89444 100644 --- a/hotspot/src/share/vm/c1/c1_Compiler.cpp +++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp @@ -228,8 +228,6 @@ bool Compiler::is_intrinsic_supported(const methodHandle& method) { case vmIntrinsics::_getCharStringU: case vmIntrinsics::_putCharStringU: #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: case vmIntrinsics::_counterTime: #endif break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp index 30ae8f86e9f..a3a2ce52f42 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp @@ -43,6 +43,9 @@ #if INCLUDE_ALL_GCS #include "gc/g1/heapRegion.hpp" #endif // INCLUDE_ALL_GCS +#ifdef TRACE_HAVE_INTRINSICS +#include "trace/traceMacros.hpp" +#endif #ifdef ASSERT #define __ gen()->lir(__FILE__, __LINE__)-> @@ -3067,42 +3070,7 @@ void LIRGenerator::do_RuntimeCall(address routine, Intrinsic* x) { __ move(reg, result); } -#ifdef TRACE_HAVE_INTRINSICS -void LIRGenerator::do_ThreadIDIntrinsic(Intrinsic* x) { - LIR_Opr thread = getThreadPointer(); - LIR_Opr osthread = new_pointer_register(); - __ move(new LIR_Address(thread, in_bytes(JavaThread::osthread_offset()), osthread->type()), osthread); - size_t thread_id_size = OSThread::thread_id_size(); - if (thread_id_size == (size_t) BytesPerLong) { - LIR_Opr id = new_register(T_LONG); - __ move(new LIR_Address(osthread, in_bytes(OSThread::thread_id_offset()), T_LONG), id); - __ convert(Bytecodes::_l2i, id, rlock_result(x)); - } else if (thread_id_size == (size_t) BytesPerInt) { - __ move(new LIR_Address(osthread, in_bytes(OSThread::thread_id_offset()), T_INT), rlock_result(x)); - } else { - ShouldNotReachHere(); - } -} -void LIRGenerator::do_ClassIDIntrinsic(Intrinsic* x) { - CodeEmitInfo* info = state_for(x); - CodeEmitInfo* info2 = new CodeEmitInfo(info); // Clone for the second null check - BasicType klass_pointer_type = NOT_LP64(T_INT) LP64_ONLY(T_LONG); - assert(info != NULL, "must have info"); - LIRItem arg(x->argument_at(1), this); - arg.load_item(); - LIR_Opr klass = new_pointer_register(); - __ move(new LIR_Address(arg.result(), java_lang_Class::klass_offset_in_bytes(), klass_pointer_type), klass, info); - LIR_Opr id = new_register(T_LONG); - ByteSize offset = TRACE_ID_OFFSET; - LIR_Address* trace_id_addr = new LIR_Address(klass, in_bytes(offset), T_LONG); - __ move(trace_id_addr, id); - __ logical_or(id, LIR_OprFact::longConst(0x01l), id); - __ store(id, trace_id_addr); - __ logical_and(id, LIR_OprFact::longConst(~0x3l), id); - __ move(id, rlock_result(x)); -} -#endif void LIRGenerator::do_Intrinsic(Intrinsic* x) { switch (x->id()) { @@ -3115,8 +3083,6 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { } #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_threadID: do_ThreadIDIntrinsic(x); break; - case vmIntrinsics::_classID: do_ClassIDIntrinsic(x); break; case vmIntrinsics::_counterTime: do_RuntimeCall(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), x); break; diff --git a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp index 9438d77288c..4f459dbd1a0 100644 --- a/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.hpp @@ -440,10 +440,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { void do_SwitchRanges(SwitchRangeArray* x, LIR_Opr value, BlockBegin* default_sux); void do_RuntimeCall(address routine, Intrinsic* x); -#ifdef TRACE_HAVE_INTRINSICS - void do_ThreadIDIntrinsic(Intrinsic* x); - void do_ClassIDIntrinsic(Intrinsic* x); -#endif + ciKlass* profile_type(ciMethodData* md, int md_first_offset, int md_offset, intptr_t profiled_k, Value arg, LIR_Opr& mdp, bool not_null, ciKlass* signature_at_call_k, ciKlass* callee_signature_k); diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp index cda969cb4b8..eb49e97d896 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1434,42 +1434,74 @@ int LinearScan::interval_cmp(Interval** a, Interval** b) { } #ifndef PRODUCT -bool LinearScan::is_sorted(IntervalArray* intervals) { - int from = -1; - int i, j; - for (i = 0; i < intervals->length(); i ++) { - Interval* it = intervals->at(i); - if (it != NULL) { - if (from > it->from()) { - assert(false, ""); - return false; - } - from = it->from(); +int interval_cmp(Interval* const& l, Interval* const& r) { + return l->from() - r->from(); +} + +bool find_interval(Interval* interval, IntervalArray* intervals) { + bool found; + int idx = intervals->find_sorted(interval, found); + + if (!found) { + return false; + } + + int from = interval->from(); + + // The index we've found using binary search is pointing to an interval + // that is defined in the same place as the interval we were looking for. + // So now we have to look around that index and find exact interval. + for (int i = idx; i >= 0; i--) { + if (intervals->at(i) == interval) { + return true; + } + if (intervals->at(i)->from() != from) { + break; } } - // check in both directions if sorted list and unsorted list contain same intervals - for (i = 0; i < interval_count(); i++) { - if (interval_at(i) != NULL) { - int num_found = 0; - for (j = 0; j < intervals->length(); j++) { - if (interval_at(i) == intervals->at(j)) { - num_found++; - } - } - assert(num_found == 1, "lists do not contain same intervals"); + for (int i = idx + 1; i < intervals->length(); i++) { + if (intervals->at(i) == interval) { + return true; + } + if (intervals->at(i)->from() != from) { + break; } } - for (j = 0; j < intervals->length(); j++) { - int num_found = 0; - for (i = 0; i < interval_count(); i++) { - if (interval_at(i) == intervals->at(j)) { - num_found++; - } + + return false; +} + +bool LinearScan::is_sorted(IntervalArray* intervals) { + int from = -1; + int null_count = 0; + + for (int i = 0; i < intervals->length(); i++) { + Interval* it = intervals->at(i); + if (it != NULL) { + assert(from <= it->from(), "Intervals are unordered"); + from = it->from(); + } else { + null_count++; } - assert(num_found == 1, "lists do not contain same intervals"); } + assert(null_count == 0, "Sorted intervals should not contain nulls"); + + null_count = 0; + + for (int i = 0; i < interval_count(); i++) { + Interval* interval = interval_at(i); + if (interval != NULL) { + assert(find_interval(interval, intervals), "Lists do not contain same intervals"); + } else { + null_count++; + } + } + + assert(interval_count() - null_count == intervals->length(), + "Sorted list should contain the same amount of non-NULL intervals as unsorted list"); + return true; } #endif @@ -1536,7 +1568,7 @@ void LinearScan::sort_intervals_before_allocation() { sorted_len++; } } - IntervalArray* sorted_list = new IntervalArray(sorted_len); + IntervalArray* sorted_list = new IntervalArray(sorted_len, sorted_len, NULL); // special sorting algorithm: the original interval-list is almost sorted, // only some intervals are swapped. So this is much faster than a complete QuickSort @@ -1574,8 +1606,8 @@ void LinearScan::sort_intervals_after_allocation() { _needs_full_resort = false; } - IntervalArray* old_list = _sorted_intervals; - IntervalList* new_list = _new_intervals_from_allocation; + IntervalArray* old_list = _sorted_intervals; + IntervalList* new_list = _new_intervals_from_allocation; int old_len = old_list->length(); int new_len = new_list->length(); @@ -1589,7 +1621,8 @@ void LinearScan::sort_intervals_after_allocation() { new_list->sort(interval_cmp); // merge old and new list (both already sorted) into one combined list - IntervalArray* combined_list = new IntervalArray(old_len + new_len); + int combined_list_len = old_len + new_len; + IntervalArray* combined_list = new IntervalArray(combined_list_len, combined_list_len, NULL); int old_idx = 0; int new_idx = 0; @@ -3211,6 +3244,10 @@ void LinearScan::verify_intervals() { has_error = true; } + // special intervals that are created in MoveResolver + // -> ignore them because the range information has no meaning there + if (i1->from() == 1 && i1->to() == 2) continue; + if (i1->first() == Range::end()) { tty->print_cr("Interval %d has no Range", i1->reg_num()); i1->print(); tty->cr(); has_error = true; @@ -3225,18 +3262,13 @@ void LinearScan::verify_intervals() { for (int j = i + 1; j < len; j++) { Interval* i2 = interval_at(j); - if (i2 == NULL) continue; - - // special intervals that are created in MoveResolver - // -> ignore them because the range information has no meaning there - if (i1->from() == 1 && i1->to() == 2) continue; - if (i2->from() == 1 && i2->to() == 2) continue; + if (i2 == NULL || (i2->from() == 1 && i2->to() == 2)) continue; int r1 = i1->assigned_reg(); int r1Hi = i1->assigned_regHi(); int r2 = i2->assigned_reg(); int r2Hi = i2->assigned_regHi(); - if (i1->intersects(i2) && (r1 == r2 || r1 == r2Hi || (r1Hi != any_reg && (r1Hi == r2 || r1Hi == r2Hi)))) { + if ((r1 == r2 || r1 == r2Hi || (r1Hi != any_reg && (r1Hi == r2 || r1Hi == r2Hi))) && i1->intersects(i2)) { tty->print_cr("Intervals %d and %d overlap and have the same register assigned", i1->reg_num(), i2->reg_num()); i1->print(); tty->cr(); i2->print(); tty->cr(); @@ -3429,7 +3461,8 @@ void LinearScan::verify_registers() { void RegisterVerifier::verify(BlockBegin* start) { // setup input registers (method arguments) for first block - IntervalList* input_state = new IntervalList(state_size(), NULL); + int input_state_len = state_size(); + IntervalList* input_state = new IntervalList(input_state_len, input_state_len, NULL); CallingConvention* args = compilation()->frame_map()->incoming_arguments(); for (int n = 0; n < args->length(); n++) { LIR_Opr opr = args->at(n); @@ -3543,7 +3576,7 @@ void RegisterVerifier::process_successor(BlockBegin* block, IntervalList* input_ IntervalList* RegisterVerifier::copy(IntervalList* input_state) { IntervalList* copy_state = new IntervalList(input_state->length()); - copy_state->push_all(input_state); + copy_state->appendAll(input_state); return copy_state; } @@ -5506,7 +5539,7 @@ void LinearScanWalker::split_and_spill_intersecting_intervals(int reg, int regHi IntervalList* processed = _spill_intervals[reg]; for (int i = 0; i < _spill_intervals[regHi]->length(); i++) { Interval* it = _spill_intervals[regHi]->at(i); - if (processed->index_of(it) == -1) { + if (processed->find_from_end(it) == -1) { remove_from_list(it); split_and_spill_interval(it); } diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.hpp b/hotspot/src/share/vm/c1/c1_LinearScan.hpp index 8504cccedcd..7d296e3f674 100644 --- a/hotspot/src/share/vm/c1/c1_LinearScan.hpp +++ b/hotspot/src/share/vm/c1/c1_LinearScan.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,8 @@ class LinearScan; class MoveResolver; class Range; -define_array(IntervalArray, Interval*) -define_stack(IntervalList, IntervalArray) +typedef GrowableArray IntervalArray; +typedef GrowableArray IntervalList; define_array(IntervalsArray, IntervalList*) define_stack(IntervalsList, IntervalsArray) diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 92c721575d0..12b58adb872 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -661,7 +661,7 @@ JRT_ENTRY(void, Runtime1::throw_class_cast_exception(JavaThread* thread, oopDesc NOT_PRODUCT(_throw_class_cast_exception_count++;) ResourceMark rm(thread); char* message = SharedRuntime::generate_class_cast_message( - thread, object->klass()->external_name()); + thread, object->klass()); SharedRuntime::throw_and_post_jvmti_exception( thread, vmSymbols::java_lang_ClassCastException(), message); JRT_END diff --git a/hotspot/src/share/vm/ci/ciArray.cpp b/hotspot/src/share/vm/ci/ciArray.cpp index f527d3ed538..04a6db8df3f 100644 --- a/hotspot/src/share/vm/ci/ciArray.cpp +++ b/hotspot/src/share/vm/ci/ciArray.cpp @@ -107,8 +107,9 @@ ciConstant ciArray::element_value_by_offset(intptr_t element_offset) { intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt); intptr_t index = (element_offset - header) >> shift; intptr_t offset = header + ((intptr_t)index << shift); - if (offset != element_offset || index != (jint)index) + if (offset != element_offset || index != (jint)index || index < 0 || index >= length()) { return ciConstant(); + } return element_value((jint) index); } diff --git a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp index 6ceacdc5a5a..b67450bf026 100644 --- a/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp +++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.cpp @@ -41,58 +41,37 @@ ciConstantPoolCache::ciConstantPoolCache(Arena* arena, _keys = new (arena) GrowableArray(arena, expected_size, 0, 0); } +int ciConstantPoolCache::key_compare(const int& key, const int& elt) { + if (key < elt) return -1; + else if (key > elt) return 1; + else return 0; +} + // ------------------------------------------------------------------ // ciConstantPoolCache::get // // Get the entry at some index void* ciConstantPoolCache::get(int index) { ASSERT_IN_VM; - int pos = find(index); - if (pos >= _keys->length() || - _keys->at(pos) != index) { + bool found = false; + int pos = _keys->find_sorted(index, found); + if (!found) { // This element is not present in the cache. return NULL; } return _elements->at(pos); } -// ------------------------------------------------------------------ -// ciConstantPoolCache::find -// -// Use binary search to find the position of this index in the cache. -// If there is no entry in the cache corresponding to this oop, return -// the position at which the index would be inserted. -int ciConstantPoolCache::find(int key) { - int min = 0; - int max = _keys->length()-1; - - while (max >= min) { - int mid = (max + min) / 2; - int value = _keys->at(mid); - if (value < key) { - min = mid + 1; - } else if (value > key) { - max = mid - 1; - } else { - return mid; - } - } - return min; -} - // ------------------------------------------------------------------ // ciConstantPoolCache::insert // // Insert a ciObject into the table at some index. void ciConstantPoolCache::insert(int index, void* elem) { - int i; - int pos = find(index); - for (i = _keys->length()-1; i >= pos; i--) { - _keys->at_put_grow(i+1, _keys->at(i)); - _elements->at_put_grow(i+1, _elements->at(i)); - } - _keys->at_put_grow(pos, index); - _elements->at_put_grow(pos, elem); + bool found = false; + int pos = _keys->find_sorted(index, found); + assert(!found, "duplicate"); + _keys->insert_before(pos, index); + _elements->insert_before(pos, elem); } // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp index 17cf77681e0..8c726a0154f 100644 --- a/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp +++ b/hotspot/src/share/vm/ci/ciConstantPoolCache.hpp @@ -38,7 +38,7 @@ private: GrowableArray* _keys; GrowableArray* _elements; - int find(int index); + static int key_compare(const int& key, const int& elt); public: ciConstantPoolCache(Arena* arena, int expected_size); diff --git a/hotspot/src/share/vm/ci/ciEnv.cpp b/hotspot/src/share/vm/ci/ciEnv.cpp index 2775c6776f5..21e952ee57f 100644 --- a/hotspot/src/share/vm/ci/ciEnv.cpp +++ b/hotspot/src/share/vm/ci/ciEnv.cpp @@ -370,9 +370,9 @@ bool ciEnv::check_klass_accessibility(ciKlass* accessing_klass, resolved_klass = ObjArrayKlass::cast(resolved_klass)->bottom_klass(); } if (resolved_klass->is_instance_klass()) { - return Reflection::verify_class_access(accessing_klass->get_Klass(), - resolved_klass, - true); + return (Reflection::verify_class_access(accessing_klass->get_Klass(), + resolved_klass, + true) == Reflection::ACCESS_OK); } return true; } diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.cpp b/hotspot/src/share/vm/ci/ciObjectFactory.cpp index 240ed839bf0..bcb7540a3e9 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.cpp @@ -260,6 +260,13 @@ ciObject* ciObjectFactory::get(oop key) { return new_object; } +int ciObjectFactory::metadata_compare(Metadata* const& key, ciMetadata* const& elt) { + Metadata* value = elt->constant_encoding(); + if (key < value) return -1; + else if (key > value) return 1; + else return 0; +} + // ------------------------------------------------------------------ // ciObjectFactory::get_metadata // @@ -280,7 +287,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } #endif // ASSERT int len = _ci_metadata->length(); - int index = find(key, _ci_metadata); + bool found = false; + int index = _ci_metadata->find_sorted(key, found); #ifdef ASSERT if (CIObjectFactoryVerify) { for (int i=0; i<_ci_metadata->length(); i++) { @@ -290,7 +298,8 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { } } #endif - if (!is_found_at(index, key, _ci_metadata)) { + + if (!found) { // The ciMetadata does not yet exist. Create it and insert it // into the cache. ciMetadata* new_object = create_new_metadata(key); @@ -300,10 +309,10 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) { if (len != _ci_metadata->length()) { // creating the new object has recursively entered new objects // into the table. We need to recompute our index. - index = find(key, _ci_metadata); + index = _ci_metadata->find_sorted(key, found); } - assert(!is_found_at(index, key, _ci_metadata), "no double insert"); - insert(index, new_object, _ci_metadata); + assert(!found, "no double insert"); + _ci_metadata->insert_before(index, new_object); return new_object; } return _ci_metadata->at(index)->as_metadata(); @@ -655,60 +664,6 @@ void ciObjectFactory::init_ident_of(ciBaseObject* obj) { obj->set_ident(_next_ident++); } -// ------------------------------------------------------------------ -// ciObjectFactory::find -// -// Use binary search to find the position of this oop in the cache. -// If there is no entry in the cache corresponding to this oop, return -// the position at which the oop should be inserted. -int ciObjectFactory::find(Metadata* key, GrowableArray* objects) { - int min = 0; - int max = objects->length()-1; - - // print_contents(); - - while (max >= min) { - int mid = (max + min) / 2; - Metadata* value = objects->at(mid)->constant_encoding(); - if (value < key) { - min = mid + 1; - } else if (value > key) { - max = mid - 1; - } else { - return mid; - } - } - return min; -} - -// ------------------------------------------------------------------ -// ciObjectFactory::is_found_at -// -// Verify that the binary seach found the given key. -bool ciObjectFactory::is_found_at(int index, Metadata* key, GrowableArray* objects) { - return (index < objects->length() && - objects->at(index)->constant_encoding() == key); -} - - -// ------------------------------------------------------------------ -// ciObjectFactory::insert -// -// Insert a ciObject into the table at some index. -void ciObjectFactory::insert(int index, ciMetadata* obj, GrowableArray* objects) { - int len = objects->length(); - if (len == index) { - objects->append(obj); - } else { - objects->append(objects->at(len-1)); - int pos; - for (pos = len-2; pos >= index; pos--) { - objects->at_put(pos+1,objects->at(pos)); - } - objects->at_put(index, obj); - } -} - static ciObjectFactory::NonPermObject* emptyBucket = NULL; // ------------------------------------------------------------------ diff --git a/hotspot/src/share/vm/ci/ciObjectFactory.hpp b/hotspot/src/share/vm/ci/ciObjectFactory.hpp index 4cdcc69beac..4f0cbd7ac73 100644 --- a/hotspot/src/share/vm/ci/ciObjectFactory.hpp +++ b/hotspot/src/share/vm/ci/ciObjectFactory.hpp @@ -68,9 +68,7 @@ private: NonPermObject* _non_perm_bucket[NON_PERM_BUCKETS]; int _non_perm_count; - int find(Metadata* key, GrowableArray* objects); - bool is_found_at(int index, Metadata* key, GrowableArray* objects); - void insert(int index, ciMetadata* obj, GrowableArray* objects); + static int metadata_compare(Metadata* const& key, ciMetadata* const& elt); ciObject* create_new_object(oop o); ciMetadata* create_new_metadata(Metadata* o); diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index a75504d2025..3be9d2f9b47 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/defaultMethods.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verificationType.hpp" @@ -103,8 +104,6 @@ #define JAVA_9_VERSION 53 -enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names - void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream, ConstantPool* cp, const int length, @@ -1965,7 +1964,7 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data, const vmSymbols::SID sid = vmSymbols::find_sid(name); // Privileged code can use all annotations. Other code silently drops some. const bool privileged = loader_data->is_the_null_class_loader_data() || - loader_data->is_ext_class_loader_data() || + loader_data->is_platform_class_loader_data() || loader_data->is_anonymous(); switch (sid) { case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): { @@ -4358,17 +4357,29 @@ static Array* compute_transitive_interfaces(const InstanceKlass* super, static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) { assert(this_klass != NULL, "invariant"); const Klass* const super = this_klass->super(); - if ((super != NULL) && - (!Reflection::verify_class_access(this_klass, super, false))) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s cannot access its superclass %s", - this_klass->external_name(), - super->external_name() - ); - return; + if (super != NULL) { + Reflection::VerifyClassAccessResults vca_result = + Reflection::verify_class_access(this_klass, super, false); + if (vca_result != Reflection::ACCESS_OK) { + ResourceMark rm(THREAD); + char* msg = Reflection::verify_class_access_msg(this_klass, super, vca_result); + if (msg == NULL) { + ResourceMark rm(THREAD); + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "class %s cannot access its superclass %s", + this_klass->external_name(), + super->external_name()); + } else { + // Add additional message content. + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "superclass access check failed: %s", + msg); + } + } } } @@ -4380,16 +4391,26 @@ static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS) for (int i = lng - 1; i >= 0; i--) { Klass* const k = local_interfaces->at(i); assert (k != NULL && k->is_interface(), "invalid interface"); - if (!Reflection::verify_class_access(this_klass, k, false)) { + Reflection::VerifyClassAccessResults vca_result = + Reflection::verify_class_access(this_klass, k, false); + if (vca_result != Reflection::ACCESS_OK) { ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "class %s cannot access its superinterface %s", - this_klass->external_name(), - k->external_name() - ); - return; + char* msg = Reflection::verify_class_access_msg(this_klass, k, vca_result); + if (msg == NULL) { + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "class %s cannot access its superinterface %s", + this_klass->external_name(), + k->external_name()); + } else { + // Add additional message content. + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "superinterface check failed: %s", + msg); + } } } } @@ -4489,12 +4510,14 @@ void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const { const bool is_super = (flags & JVM_ACC_SUPER) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; + const bool is_module_info= (flags & JVM_ACC_MODULE) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; if ((is_abstract && is_final) || (is_interface && !is_abstract) || (is_interface && major_gte_15 && (is_super || is_enum)) || - (!is_interface && major_gte_15 && is_annotation)) { + (!is_interface && major_gte_15 && is_annotation) || + is_module_info) { ResourceMark rm(THREAD); Exceptions::fthrow( THREAD_AND_LOCATION, @@ -4650,65 +4673,9 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) const { assert(_need_verify, "only called when _need_verify is true"); - int i = 0; - const int count = length >> 2; - for (int k=0; k= 128 (highest bit 1) for v == 0 or v >= 128. - const unsigned char res = b0 | b0 - 1 | - b1 | b1 - 1 | - b2 | b2 - 1 | - b3 | b3 - 1; - if (res >= 128) break; - i += 4; + if (!UTF8::is_legal_utf8(buffer, length, _major_version <= 47)) { + classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); } - for(; i < length; i++) { - unsigned short c; - // no embedded zeros - guarantee_property((buffer[i] != 0), "Illegal UTF8 string in constant pool in class file %s", CHECK); - if(buffer[i] < 128) { - continue; - } - if ((i + 5) < length) { // see if it's legal supplementary character - if (UTF8::is_supplementary_character(&buffer[i])) { - c = UTF8::get_supplementary_character(&buffer[i]); - i += 5; - continue; - } - } - switch (buffer[i] >> 4) { - default: break; - case 0x8: case 0x9: case 0xA: case 0xB: case 0xF: - classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); - case 0xC: case 0xD: // 110xxxxx 10xxxxxx - c = (buffer[i] & 0x1F) << 6; - i++; - if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) { - c += buffer[i] & 0x3F; - if (_major_version <= 47 || c == 0 || c >= 0x80) { - // for classes with major > 47, c must a null or a character in its shortest form - break; - } - } - classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); - case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx - c = (buffer[i] & 0xF) << 12; - i += 2; - if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) { - c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F); - if (_major_version <= 47 || c >= 0x800) { - // for classes with major > 47, c must be in its shortest form - break; - } - } - classfile_parse_error("Illegal UTF8 string in constant pool in class file %s", CHECK); - } // end of switch - } // end of for } // Unqualified names may not contain the characters '.', ';', '[', or '/'. @@ -4716,24 +4683,35 @@ void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, // or . Note that method names may not be or in this // method. Because these names have been checked as special cases before // calling this method in verify_legal_method_name. -static bool verify_unqualified_name(const char* name, - unsigned int length, - int type) { +// +// This method is also called from the modular system APIs in modules.cpp +// to verify the validity of module and package names. +bool ClassFileParser::verify_unqualified_name(const char* name, + unsigned int length, + int type) { for (const char* p = name; p != name + length;) { jchar ch = *p; if (ch < 128) { - p++; - if (ch == '.' || ch == ';' || ch == '[') { + if (ch == '.') { + // permit '.' in module names unless it's the first char, or + // preceding char is also a '.', or last char is a '.'. + if ((type != ClassFileParser::LegalModule) || + (p == name) || (*(p-1) == '.') || + (p == name + length - 1)) { + return false; + } + } + if (ch == ';' || ch == '[' ) { return false; // do not permit '.', ';', or '[' } - if (type != LegalClass && ch == '/') { + if (type != ClassFileParser::LegalClass && ch == '/') { return false; // do not permit '/' unless it's class name } - if (type == LegalMethod && (ch == '<' || ch == '>')) { + if (type == ClassFileParser::LegalMethod && (ch == '<' || ch == '>')) { return false; // do not permit '<' or '>' in method names } - } - else { + p++; + } else { char* tmp_p = UTF8::next(p, &ch); p = tmp_p; } @@ -5192,7 +5170,7 @@ static void check_methods_for_intrinsics(const InstanceKlass* ik, } } -InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) { +InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook, TRAPS) { if (_klass != NULL) { return _klass; } @@ -5200,14 +5178,14 @@ InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) { InstanceKlass* const ik = InstanceKlass::allocate_instance_klass(*this, CHECK_NULL); - fill_instance_klass(ik, CHECK_NULL); + fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL); assert(_klass == ik, "invariant"); return ik; } -void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { +void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) { assert(ik != NULL, "invariant"); set_klass_to_deallocate(ik); @@ -5272,6 +5250,12 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { ik->set_host_klass(_host_klass); } + // Set PackageEntry for this_klass + oop cl = ik->class_loader(); + Handle clh = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(cl)); + ClassLoaderData* cld = ClassLoaderData::class_loader_data_or_null(clh()); + ik->set_package(cld, CHECK); + const Array* const methods = ik->methods(); assert(methods != NULL, "invariant"); const int methods_len = methods->length(); @@ -5327,10 +5311,18 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { } } + // Obtain this_klass' module entry + ModuleEntry* module_entry = ik->module(); + assert(module_entry != NULL, "module_entry should always be set"); + + // Obtain java.lang.reflect.Module + Handle module_handle(THREAD, JNIHandles::resolve(module_entry->module())); + // Allocate mirror and initialize static fields // The create_mirror() call will also call compute_modifiers() java_lang_Class::create_mirror(ik, _loader_data->class_loader(), + module_handle, _protection_domain, CHECK); @@ -5344,6 +5336,15 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { CHECK); } + // Add read edges to the unnamed modules of the bootstrap and app class loaders. + if (changed_by_loadhook && !module_handle.is_null() && module_entry->is_named() && + !module_entry->has_default_read_edges()) { + if (!module_entry->set_has_default_read_edges()) { + // We won a potential race + JvmtiExport::add_default_read_edges(module_handle, THREAD); + } + } + // Update the loader_data graph. record_defined_class_dependencies(ik, CHECK); @@ -5351,11 +5352,24 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { if (!is_internal()) { if (log_is_enabled(Info, classload)) { - ik->print_loading_log(LogLevel::Info, _loader_data, _stream); - } - // No 'else' here as logging levels are not mutually exclusive - if (log_is_enabled(Debug, classload)) { - ik->print_loading_log(LogLevel::Debug, _loader_data, _stream); + ResourceMark rm; + const char* module_name = NULL; + static const size_t modules_image_name_len = strlen(MODULES_IMAGE_NAME); + size_t stream_len = strlen(_stream->source()); + // See if _stream->source() ends in "modules" + if (module_entry->is_named() && modules_image_name_len < stream_len && + (strncmp(_stream->source() + stream_len - modules_image_name_len, + MODULES_IMAGE_NAME, modules_image_name_len) == 0)) { + module_name = module_entry->name()->as_C_string(); + } + + if (log_is_enabled(Info, classload)) { + ik->print_loading_log(LogLevel::Info, _loader_data, module_name, _stream); + } + // No 'else' here as logging levels are not mutually exclusive + if (log_is_enabled(Debug, classload)) { + ik->print_loading_log(LogLevel::Debug, _loader_data, module_name, _stream); + } } if (log_is_enabled(Info, classresolve)) { @@ -5380,7 +5394,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) { } } - TRACE_INIT_ID(ik); + TRACE_INIT_KLASS_ID(ik); // If we reach here, all is well. // Now remove the InstanceKlass* from the _klass_to_deallocate field diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp index d6fd836d61c..3ee99df2e3b 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.hpp +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp @@ -73,6 +73,8 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { NOF_PUBLICITY_LEVELS }; + enum { LegalClass, LegalField, LegalMethod, LegalModule }; // used to verify unqualified names + private: const ClassFileStream* _stream; // Actual input stream const Symbol* _requested_name; @@ -155,7 +157,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { ConstantPool* cp, TRAPS); - void fill_instance_klass(InstanceKlass* ik, TRAPS); + void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, TRAPS); void set_klass(InstanceKlass* instance); void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } @@ -482,7 +484,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { ~ClassFileParser(); - InstanceKlass* create_instance_klass(TRAPS); + InstanceKlass* create_instance_klass(bool cf_changed_in_CFLH, TRAPS); const ClassFileStream* clone_stream() const; @@ -512,6 +514,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { bool is_internal() const { return INTERNAL == _pub_level; } + static bool verify_unqualified_name(const char* name, unsigned int length, int type); }; #endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP diff --git a/hotspot/src/share/vm/classfile/classLoader.cpp b/hotspot/src/share/vm/classfile/classLoader.cpp index 14feb9876cf..d4196c38bd6 100644 --- a/hotspot/src/share/vm/classfile/classLoader.cpp +++ b/hotspot/src/share/vm/classfile/classLoader.cpp @@ -29,6 +29,9 @@ #include "classfile/classLoaderExt.hpp" #include "classfile/javaClasses.hpp" #include "classfile/jimage.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/klassFactory.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -37,6 +40,7 @@ #include "gc/shared/generation.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/oopMapCache.hpp" +#include "logging/logTag.hpp" #include "memory/allocation.inline.hpp" #include "memory/filemap.hpp" #include "memory/oopFactory.hpp" @@ -137,11 +141,14 @@ PerfCounter* ClassLoader::_load_instance_class_failCounter = NULL; ClassPathEntry* ClassLoader::_first_entry = NULL; ClassPathEntry* ClassLoader::_last_entry = NULL; int ClassLoader::_num_entries = 0; -PackageHashtable* ClassLoader::_package_hash_table = NULL; - +ClassPathEntry* ClassLoader::_first_append_entry = NULL; +bool ClassLoader::_has_jimage = false; #if INCLUDE_CDS +GrowableArray* ClassLoader::_boot_modules_array = NULL; +GrowableArray* ClassLoader::_platform_modules_array = NULL; SharedPathsMiscInfo* ClassLoader::_shared_paths_misc_info = NULL; #endif + // helper routines bool string_starts_with(const char* str, const char* str_to_find) { size_t str_len = strlen(str); @@ -161,7 +168,7 @@ static const char* get_jimage_version_string() { return (const char*)version_string; } -bool string_ends_with(const char* str, const char* str_to_find) { +bool ClassLoader::string_ends_with(const char* str, const char* str_to_find) { size_t str_len = strlen(str); size_t str_to_find_len = strlen(str_to_find); if (str_to_find_len > str_len) { @@ -355,15 +362,49 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) { if (location == 0) { char package[JIMAGE_MAX_PATH]; name_to_package(name, package, JIMAGE_MAX_PATH); + +#if INCLUDE_CDS + if (package[0] == '\0' && DumpSharedSpaces) { + return NULL; + } +#endif if (package[0] != '\0') { - const char* module = (*JImagePackageToModule)(_jimage, package); - if (module == NULL) { - module = "java.base"; + if (!Universe::is_module_initialized()) { + location = (*JImageFindResource)(_jimage, "java.base", get_jimage_version_string(), name, &size); +#if INCLUDE_CDS + // CDS uses the boot class loader to load classes whose packages are in + // modules defined for other class loaders. So, for now, get their module + // names from the "modules" jimage file. + if (DumpSharedSpaces && location == 0) { + const char* module_name = (*JImagePackageToModule)(_jimage, package); + if (module_name != NULL) { + location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size); + } } - location = (*JImageFindResource)(_jimage, module, get_jimage_version_string(), name, &size); +#endif + + } else { + // Get boot class loader's package entry table + PackageEntryTable* pkgEntryTable = + ClassLoaderData::the_null_class_loader_data()->packages(); + // Get package's package entry + TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package, CHECK_NULL); + PackageEntry* package_entry = pkgEntryTable->lookup_only(pkg_symbol); + + if (package_entry != NULL) { + ResourceMark rm; + // Get the module name + ModuleEntry* module = package_entry->module(); + assert(module != NULL, "Boot classLoader package missing module"); + assert(module->is_named(), "Boot classLoader package is in unnamed module"); + const char* module_name = module->name()->as_C_string(); + if (module_name != NULL) { + location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size); + } + } + } } } - if (location != 0) { if (UsePerfData) { ClassLoader::perf_sys_classfile_bytes_read()->inc(size); @@ -408,43 +449,39 @@ void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) { } } } +#endif bool ClassPathImageEntry::is_jrt() { - return string_ends_with(name(), BOOT_IMAGE_NAME); + return ClassLoader::is_jrt(name()); } -#endif #if INCLUDE_CDS void ClassLoader::exit_with_path_failure(const char* error, const char* message) { assert(DumpSharedSpaces, "only called at dump time"); - tty->print_cr("Hint: enable -XX:+TraceClassPaths to diagnose the failure"); + tty->print_cr("Hint: enable -Xlog:classpath=info to diagnose the failure"); vm_exit_during_initialization(error, message); } #endif -void ClassLoader::trace_class_path(outputStream* out, const char* msg, const char* name) { - if (!TraceClassPaths) { - return; - } - - if (msg) { - out->print("%s", msg); - } - if (name) { - if (strlen(name) < 256) { - out->print("%s", name); - } else { - // For very long paths, we need to print each character separately, - // as print_cr() has a length limit - while (name[0] != '\0') { - out->print("%c", name[0]); - name++; +void ClassLoader::trace_class_path(const char* msg, const char* name) { + if (log_is_enabled(Info, classpath)) { + ResourceMark rm; + outputStream* out = LogHandle(classpath)::info_stream(); + if (msg) { + out->print("%s", msg); + } + if (name) { + if (strlen(name) < 256) { + out->print("%s", name); + } else { + // For very long paths, we need to print each character separately, + // as print_cr() has a length limit + while (name[0] != '\0') { + out->print("%c", name[0]); + name++; + } } } - } - if (msg && msg[0] == '[') { - out->print_cr("]"); - } else { out->cr(); } } @@ -470,18 +507,20 @@ void ClassLoader::check_shared_classpath(const char *path) { void ClassLoader::setup_bootstrap_search_path() { assert(_first_entry == NULL, "should not setup bootstrap class search path twice"); const char* sys_class_path = Arguments::get_sysclasspath(); + const char* java_class_path = Arguments::get_appclasspath(); if (PrintSharedArchiveAndExit) { // Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily // the same as the bootcp of the shared archive. } else { - trace_class_path(tty, "[Bootstrap loader class path=", sys_class_path); + trace_class_path("bootstrap loader class path=", sys_class_path); + trace_class_path("classpath: ", java_class_path); } #if INCLUDE_CDS if (DumpSharedSpaces) { _shared_paths_misc_info->add_boot_classpath(sys_class_path); } #endif - setup_search_path(sys_class_path); + setup_search_path(sys_class_path, true); } #if INCLUDE_CDS @@ -501,10 +540,11 @@ bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) { } #endif -void ClassLoader::setup_search_path(const char *class_path) { +void ClassLoader::setup_search_path(const char *class_path, bool bootstrap_search) { int offset = 0; int len = (int)strlen(class_path); int end = 0; + bool mark_append_entry = false; // Iterate over class path entries for (int start = 0; start < len; start = end) { @@ -513,10 +553,23 @@ void ClassLoader::setup_search_path(const char *class_path) { } EXCEPTION_MARK; ResourceMark rm(THREAD); + mark_append_entry = (mark_append_entry || + (bootstrap_search && (start == Arguments::bootclassloader_append_index()))); char* path = NEW_RESOURCE_ARRAY(char, end - start + 1); strncpy(path, &class_path[start], end - start); path[end - start] = '\0'; - update_class_path_entry_list(path, false); + update_class_path_entry_list(path, false, mark_append_entry, false); + + // Check on the state of the boot loader's append path + if (mark_append_entry && (_first_append_entry == NULL)) { + // Failure to mark the first append entry, most likely + // due to a non-existent path. Record the next entry + // as the first boot loader append entry. + mark_append_entry = true; + } else { + mark_append_entry = false; + } + #if INCLUDE_CDS if (DumpSharedSpaces) { check_shared_classpath(path); @@ -578,9 +631,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str } } } - if (TraceClassPaths) { - tty->print_cr("[Opened %s]", path); - } + log_info(classpath)("opened: %s", path); log_info(classload)("opened: %s", path); } else { // Directory @@ -619,6 +670,18 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) { return NULL; } +// The boot class loader must adhere to specfic visibility rules. +// Prior to loading a class in a named package, the package is checked +// to see if it is in a module defined to the boot loader. If the +// package is not in a module defined to the boot loader, the class +// must be loaded only in the boot loader's append path, which +// consists of [-Xbootclasspath/a]; [jvmti appended entries] +void ClassLoader::set_first_append_entry(ClassPathEntry *new_entry) { + if (_first_append_entry == NULL) { + _first_append_entry = new_entry; + } +} + // returns true if entry already on class path bool ClassLoader::contains_entry(ClassPathEntry *entry) { ClassPathEntry* e = _first_entry; @@ -644,9 +707,31 @@ void ClassLoader::add_to_list(ClassPathEntry *new_entry) { _num_entries ++; } +void ClassLoader::prepend_to_list(ClassPathEntry *new_entry) { + if (new_entry != NULL) { + if (_last_entry == NULL) { + _first_entry = _last_entry = new_entry; + } else { + new_entry->set_next(_first_entry); + _first_entry = new_entry; + } + } + _num_entries ++; +} + +void ClassLoader::add_to_list(const char *apath) { + update_class_path_entry_list((char*)apath, false, false, false); +} + +void ClassLoader::prepend_to_list(const char *apath) { + update_class_path_entry_list((char*)apath, false, false, true); +} + // Returns true IFF the file/dir exists and the entry was successfully created. bool ClassLoader::update_class_path_entry_list(const char *path, bool check_for_duplicates, + bool mark_append_entry, + bool prepend_entry, bool throw_exception) { struct stat st; if (os::stat(path, &st) == 0) { @@ -657,12 +742,20 @@ bool ClassLoader::update_class_path_entry_list(const char *path, if (new_entry == NULL) { return false; } - // The kernel VM adds dynamically to the end of the classloader path and - // doesn't reorder the bootclasspath which would break java.lang.Package - // (see PackageInfo). + + // Ensure that the first boot loader append entry will always be set correctly. + assert((!mark_append_entry || + (mark_append_entry && (!check_for_duplicates || !contains_entry(new_entry)))), + "failed to mark boot loader's first append boundary"); + + // Do not reorder the bootclasspath which would break get_system_package(). // Add new entry to linked list + if (!check_for_duplicates || !contains_entry(new_entry)) { - ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry); + ClassLoaderExt::add_class_path_entry(path, check_for_duplicates, new_entry, prepend_entry); + if (mark_append_entry) { + set_first_append_entry(new_entry); + } } return true; } else { @@ -763,246 +856,205 @@ int ClassLoader::crc32(int crc, const char* buf, int len) { return (*Crc32)(crc, (const jbyte*)buf, len); } -// PackageInfo data exists in order to support the java.lang.Package -// class. A Package object provides information about a java package -// (version, vendor, etc.) which originates in the manifest of the jar -// file supplying the package. For application classes, the ClassLoader -// object takes care of this. - -// For system (boot) classes, the Java code in the Package class needs -// to be able to identify which source jar file contained the boot -// class, so that it can extract the manifest from it. This table -// identifies java packages with jar files in the boot classpath. - -// Because the boot classpath cannot change, the classpath index is -// sufficient to identify the source jar file or directory. (Since -// directories have no manifests, the directory name is not required, -// but is available.) - -// When using sharing -- the pathnames of entries in the boot classpath -// may not be the same at runtime as they were when the archive was -// created (NFS, Samba, etc.). The actual files and directories named -// in the classpath must be the same files, in the same order, even -// though the exact name is not the same. - -class PackageInfo: public BasicHashtableEntry { -public: - const char* _pkgname; // Package name - int _classpath_index; // Index of directory or JAR file loaded from - - PackageInfo* next() { - return (PackageInfo*)BasicHashtableEntry::next(); - } - - const char* pkgname() { return _pkgname; } - void set_pkgname(char* pkgname) { _pkgname = pkgname; } - - const char* filename() { - return ClassLoader::classpath_entry(_classpath_index)->name(); - } - - void set_index(int index) { - _classpath_index = index; - } -}; - - -class PackageHashtable : public BasicHashtable { -private: - inline unsigned int compute_hash(const char *s, int n) { - unsigned int val = 0; - while (--n >= 0) { - val = *s++ + 31 * val; - } - return val; - } - - PackageInfo* bucket(int index) { - return (PackageInfo*)BasicHashtable::bucket(index); - } - - PackageInfo* get_entry(int index, unsigned int hash, - const char* pkgname, size_t n) { - for (PackageInfo* pp = bucket(index); pp != NULL; pp = pp->next()) { - if (pp->hash() == hash && - strncmp(pkgname, pp->pkgname(), n) == 0 && - pp->pkgname()[n] == '\0') { - return pp; - } - } - return NULL; - } - -public: - PackageHashtable(int table_size) - : BasicHashtable(table_size, sizeof(PackageInfo)) {} - - PackageHashtable(int table_size, HashtableBucket* t, int number_of_entries) - : BasicHashtable(table_size, sizeof(PackageInfo), t, number_of_entries) {} - - PackageInfo* get_entry(const char* pkgname, int n) { - unsigned int hash = compute_hash(pkgname, n); - return get_entry(hash_to_index(hash), hash, pkgname, n); - } - - PackageInfo* new_entry(char* pkgname, int n) { - unsigned int hash = compute_hash(pkgname, n); - PackageInfo* pp; - pp = (PackageInfo*)BasicHashtable::new_entry(hash); - pp->set_pkgname(pkgname); - return pp; - } - - void add_entry(PackageInfo* pp) { - int index = hash_to_index(pp->hash()); - BasicHashtable::add_entry(index, pp); - } - - void copy_pkgnames(const char** packages) { - int n = 0; - for (int i = 0; i < table_size(); ++i) { - for (PackageInfo* pp = bucket(i); pp != NULL; pp = pp->next()) { - packages[n++] = pp->pkgname(); - } - } - assert(n == number_of_entries(), "just checking"); - } - - CDS_ONLY(void copy_table(char** top, char* end, PackageHashtable* table);) -}; - #if INCLUDE_CDS -void PackageHashtable::copy_table(char** top, char* end, - PackageHashtable* table) { - // Copy (relocate) the table to the shared space. - BasicHashtable::copy_table(top, end); - - // Calculate the space needed for the package name strings. - int i; - intptr_t* tableSize = (intptr_t*)(*top); - *top += sizeof(intptr_t); // For table size - char* tableStart = *top; - - for (i = 0; i < table_size(); ++i) { - for (PackageInfo* pp = table->bucket(i); - pp != NULL; - pp = pp->next()) { - int n1 = (int)(strlen(pp->pkgname()) + 1); - if (*top + n1 >= end) { - report_out_of_shared_space(SharedMiscData); +void ClassLoader::initialize_module_loader_map(JImageFile* jimage) { + jlong size; + JImageLocationRef location = (*JImageFindResource)(jimage, "java.base", get_jimage_version_string(), MODULE_LOADER_MAP, &size); + if (location == 0) { + vm_exit_during_initialization( + "Cannot find ModuleLoaderMap location from modules jimage.", NULL); + } + char* buffer = NEW_RESOURCE_ARRAY(char, size); + jlong read = (*JImageGetResource)(jimage, location, buffer, size); + if (read != size) { + vm_exit_during_initialization( + "Cannot find ModuleLoaderMap resource from modules jimage.", NULL); + } + char* char_buf = (char*)buffer; + int buflen = (int)strlen(char_buf); + char* begin_ptr = char_buf; + char* end_ptr = strchr(begin_ptr, '\n'); + bool process_boot_modules = false; + _boot_modules_array = new (ResourceObj::C_HEAP, mtInternal) + GrowableArray(INITIAL_BOOT_MODULES_ARRAY_SIZE, true); + _platform_modules_array = new (ResourceObj::C_HEAP, mtInternal) + GrowableArray(INITIAL_PLATFORM_MODULES_ARRAY_SIZE, true); + while (end_ptr != NULL && (end_ptr - char_buf) < buflen) { + // Allocate a buffer from the C heap to be appended to the _boot_modules_array + // or the _platform_modules_array. + char* temp_name = NEW_C_HEAP_ARRAY(char, (size_t)(end_ptr - begin_ptr + 1), mtInternal); + strncpy(temp_name, begin_ptr, end_ptr - begin_ptr); + temp_name[end_ptr - begin_ptr] = '\0'; + if (strncmp(temp_name, "BOOT", 4) == 0) { + process_boot_modules = true; + FREE_C_HEAP_ARRAY(char, temp_name); + } else if (strncmp(temp_name, "PLATFORM", 8) == 0) { + process_boot_modules = false; + FREE_C_HEAP_ARRAY(char, temp_name); + } else { + // module name + if (process_boot_modules) { + _boot_modules_array->append(temp_name); + } else { + _platform_modules_array->append(temp_name); } - pp->set_pkgname((char*)memcpy(*top, pp->pkgname(), n1)); - *top += n1; } + begin_ptr = ++end_ptr; + end_ptr = strchr(begin_ptr, '\n'); } - *top = (char*)align_size_up((intptr_t)*top, sizeof(HeapWord)); - if (*top >= end) { - report_out_of_shared_space(SharedMiscData); - } - - // Write table size - intptr_t len = *top - (char*)tableStart; - *tableSize = len; -} - - -void ClassLoader::copy_package_info_buckets(char** top, char* end) { - _package_hash_table->copy_buckets(top, end); -} - -void ClassLoader::copy_package_info_table(char** top, char* end) { - _package_hash_table->copy_table(top, end, _package_hash_table); + FREE_RESOURCE_ARRAY(u1, buffer, size); } #endif -PackageInfo* ClassLoader::lookup_package(const char *pkgname) { - const char *cp = strrchr(pkgname, '/'); +// Function add_package extracts the package from the fully qualified class name +// and checks if the package is in the boot loader's package entry table. If so, +// then it sets the classpath_index in the package entry record. +// +// The classpath_index field is used to find the entry on the boot loader class +// path for packages with classes loaded by the boot loader from -Xbootclasspath/a +// in an unnamed module. It is also used to indicate (for all packages whose +// classes are loaded by the boot loader) that at least one of the package's +// classes has been loaded. +bool ClassLoader::add_package(const char *fullq_class_name, s2 classpath_index, TRAPS) { + assert(fullq_class_name != NULL, "just checking"); + + // Get package name from fully qualified class name. + const char *cp = strrchr(fullq_class_name, '/'); if (cp != NULL) { - // Package prefix found - int n = cp - pkgname + 1; - return _package_hash_table->get_entry(pkgname, n); + int len = cp - fullq_class_name; + PackageEntryTable* pkg_entry_tbl = + ClassLoaderData::the_null_class_loader_data()->packages(); + TempNewSymbol pkg_symbol = + SymbolTable::new_symbol(fullq_class_name, len, CHECK_false); + PackageEntry* pkg_entry = pkg_entry_tbl->lookup_only(pkg_symbol); + if (pkg_entry != NULL) { + assert(classpath_index != -1, "Unexpected classpath_index"); + pkg_entry->set_classpath_index(classpath_index); + } else { + return false; + } + } + return true; +} + +oop ClassLoader::get_system_package(const char* name, TRAPS) { + // Look up the name in the boot loader's package entry table. + if (name != NULL) { + TempNewSymbol package_sym = SymbolTable::new_symbol(name, (int)strlen(name), CHECK_NULL); + // Look for the package entry in the boot loader's package entry table. + PackageEntry* package = + ClassLoaderData::the_null_class_loader_data()->packages()->lookup_only(package_sym); + + // Return NULL if package does not exist or if no classes in that package + // have been loaded. + if (package != NULL && package->has_loaded_class()) { + ModuleEntry* module = package->module(); + if (module->location() != NULL) { + ResourceMark rm(THREAD); + Handle ml = java_lang_String::create_from_str( + module->location()->as_C_string(), THREAD); + return ml(); + } + // Return entry on boot loader class path. + Handle cph = java_lang_String::create_from_str( + ClassLoader::classpath_entry(package->classpath_index())->name(), THREAD); + return cph(); + } } return NULL; } - -bool ClassLoader::add_package(const char *pkgname, int classpath_index, TRAPS) { - assert(pkgname != NULL, "just checking"); - // Bootstrap loader no longer holds system loader lock obj serializing - // load_instance_class and thereby add_package - { - MutexLocker ml(PackageTable_lock, THREAD); - // First check for previously loaded entry - PackageInfo* pp = lookup_package(pkgname); - if (pp != NULL) { - // Existing entry found, check source of package - pp->set_index(classpath_index); - return true; - } - - const char *cp = strrchr(pkgname, '/'); - if (cp != NULL) { - // Package prefix found - int n = cp - pkgname + 1; - - char* new_pkgname = NEW_C_HEAP_ARRAY(char, n + 1, mtClass); - if (new_pkgname == NULL) { - return false; - } - - memcpy(new_pkgname, pkgname, n); - new_pkgname[n] = '\0'; - pp = _package_hash_table->new_entry(new_pkgname, n); - pp->set_index(classpath_index); - - // Insert into hash table - _package_hash_table->add_entry(pp); - } - return true; - } -} - - -oop ClassLoader::get_system_package(const char* name, TRAPS) { - PackageInfo* pp; - { - MutexLocker ml(PackageTable_lock, THREAD); - pp = lookup_package(name); - } - if (pp == NULL) { - return NULL; - } else { - Handle p = java_lang_String::create_from_str(pp->filename(), THREAD); - return p(); - } -} - - objArrayOop ClassLoader::get_system_packages(TRAPS) { ResourceMark rm(THREAD); - int nof_entries; - const char** packages; + // List of pointers to PackageEntrys that have loaded classes. + GrowableArray* loaded_class_pkgs = new GrowableArray(50); { - MutexLocker ml(PackageTable_lock, THREAD); - // Allocate resource char* array containing package names - nof_entries = _package_hash_table->number_of_entries(); - if ((packages = NEW_RESOURCE_ARRAY(const char*, nof_entries)) == NULL) { - return NULL; + MutexLocker ml(Module_lock, THREAD); + + PackageEntryTable* pe_table = + ClassLoaderData::the_null_class_loader_data()->packages(); + + // Collect the packages that have at least one loaded class. + for (int x = 0; x < pe_table->table_size(); x++) { + for (PackageEntry* package_entry = pe_table->bucket(x); + package_entry != NULL; + package_entry = package_entry->next()) { + if (package_entry->has_loaded_class()) { + loaded_class_pkgs->append(package_entry); + } + } } - _package_hash_table->copy_pkgnames(packages); - } - // Allocate objArray and fill with java.lang.String - objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), - nof_entries, CHECK_0); - objArrayHandle result(THREAD, r); - for (int i = 0; i < nof_entries; i++) { - Handle str = java_lang_String::create_from_str(packages[i], CHECK_0); - result->obj_at_put(i, str()); } + + // Allocate objArray and fill with java.lang.String + objArrayOop r = oopFactory::new_objArray(SystemDictionary::String_klass(), + loaded_class_pkgs->length(), CHECK_NULL); + objArrayHandle result(THREAD, r); + for (int x = 0; x < loaded_class_pkgs->length(); x++) { + PackageEntry* package_entry = loaded_class_pkgs->at(x); + Handle str = java_lang_String::create_from_symbol(package_entry->name(), CHECK_NULL); + result->obj_at_put(x, str()); + } return result(); } +#if INCLUDE_CDS +s2 ClassLoader::module_to_classloader(const char* module_name) { + + assert(_boot_modules_array != NULL, "_boot_modules_array is NULL"); + assert(_platform_modules_array != NULL, "_platform_modules_array is NULL"); + + int array_size = _boot_modules_array->length(); + for (int i = 0; i < array_size; i++) { + if (strcmp(module_name, _boot_modules_array->at(i)) == 0) { + return BOOT_LOADER; + } + } + + array_size = _platform_modules_array->length(); + for (int i = 0; i < array_size; i++) { + if (strcmp(module_name, _platform_modules_array->at(i)) == 0) { + return PLATFORM_LOADER; + } + } + + return APP_LOADER; +} +#endif + +s2 ClassLoader::classloader_type(Symbol* class_name, ClassPathEntry* e, + int classpath_index, TRAPS) { +#if INCLUDE_CDS + // obtain the classloader type based on the class name. + // First obtain the package name based on the class name. Then obtain + // the classloader type based on the package name from the jimage using + // a jimage API. If the classloader type cannot be found from the + // jimage, it is determined by the class path entry. + jshort loader_type = ClassLoader::APP_LOADER; + if (e->is_jrt()) { + int length = 0; + const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length); + if (pkg_string != NULL) { + ResourceMark rm; + TempNewSymbol pkg_name = SymbolTable::new_symbol((const char*)pkg_string, length, THREAD); + const char* pkg_name_C_string = (const char*)(pkg_name->as_C_string()); + ClassPathImageEntry* cpie = (ClassPathImageEntry*)e; + JImageFile* jimage = cpie->jimage(); + char* module_name = (char*)(*JImagePackageToModule)(jimage, pkg_name_C_string); + if (module_name != NULL) { + loader_type = ClassLoader::module_to_classloader(module_name); + } + } + } else if (ClassLoaderExt::is_boot_classpath(classpath_index)) { + loader_type = ClassLoader::BOOT_LOADER; + } + return loader_type; +#endif + return ClassLoader::BOOT_LOADER; // the classloader type is ignored in non-CDS cases +} + + // caller needs ResourceMark const char* ClassLoader::file_name_for_class_name(const char* class_name, int class_name_len) { @@ -1021,7 +1073,7 @@ const char* ClassLoader::file_name_for_class_name(const char* class_name, return file_name; } -instanceKlassHandle ClassLoader::load_class(Symbol* name, TRAPS) { +instanceKlassHandle ClassLoader::load_class(Symbol* name, bool search_append_only, TRAPS) { assert(name != NULL, "invariant"); assert(THREAD->is_Java_thread(), "must be a JavaThread"); @@ -1040,24 +1092,54 @@ instanceKlassHandle ClassLoader::load_class(Symbol* name, TRAPS) { ClassLoaderExt::Context context(class_name, file_name, THREAD); - // Lookup stream + // Lookup stream for parsing .class file ClassFileStream* stream = NULL; - int classpath_index = 0; - ClassPathEntry* e = _first_entry; - { - PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(), - ((JavaThread*)THREAD)->get_thread_stat()->perf_timers_addr(), - PerfClassTraceTime::CLASS_LOAD); + s2 classpath_index = 0; - for (; e != NULL; e = e->next(), ++classpath_index) { - stream = e->open_stream(file_name, CHECK_NULL); - if (NULL == stream) { - continue; + // If DumpSharedSpaces is true, boot loader visibility boundaries are set + // to be _first_entry to the end (all path entries). + // + // If search_append_only is true, boot loader visibility boundaries are + // set to be _fist_append_entry to the end. This includes: + // [-Xbootclasspath/a]; [jvmti appended entries] + // + // If both DumpSharedSpaces and search_append_only are false, boot loader + // visibility boundaries are set to be _first_entry to the entry before + // the _first_append_entry. This would include: + // [-Xpatch:]; [exploded build | modules] + // + // DumpSharedSpaces and search_append_only are mutually exclusive and cannot + // be true at the same time. + ClassPathEntry* e = (search_append_only ? _first_append_entry : _first_entry); + ClassPathEntry* last_e = + (search_append_only || DumpSharedSpaces ? NULL : _first_append_entry); + + { + if (search_append_only) { + // For the boot loader append path search, must calculate + // the starting classpath_index prior to attempting to + // load the classfile. + ClassPathEntry *tmp_e = _first_entry; + while ((tmp_e != NULL) && (tmp_e != _first_append_entry)) { + tmp_e = tmp_e->next(); + ++classpath_index; } + } + + // Attempt to load the classfile from either: + // - [-Xpatch:dir]; exploded build | modules + // or + // - [-Xbootclasspath/a]; [jvmti appended entries] + while ((e != NULL) && (e != last_e)) { + stream = e->open_stream(file_name, CHECK_NULL); if (!context.check(stream, classpath_index)) { return NULL; } - break; + if (NULL != stream) { + break; + } + e = e->next(); + ++classpath_index; } } @@ -1088,32 +1170,16 @@ instanceKlassHandle ClassLoader::load_class(Symbol* name, TRAPS) { return NULL; } - return context.record_result(classpath_index, e, result, THREAD); + jshort loader_type = classloader_type(name, e, classpath_index, CHECK_NULL); + return context.record_result(classpath_index, loader_type, e, result, THREAD); } -void ClassLoader::create_package_info_table(HashtableBucket *t, int length, - int number_of_entries) { - assert(_package_hash_table == NULL, "One package info table allowed."); - assert(length == package_hash_table_size * sizeof(HashtableBucket), - "bad shared package info size."); - _package_hash_table = new PackageHashtable(package_hash_table_size, t, - number_of_entries); -} - - -void ClassLoader::create_package_info_table() { - assert(_package_hash_table == NULL, "shouldn't have one yet"); - _package_hash_table = new PackageHashtable(package_hash_table_size); -} - - // Initialize the class loader's access to methods in libzip. Parse and // process the boot classpath into a list ClassPathEntry objects. Once // this list has been created, it must not change order (see class PackageInfo) // it can be appended to and is by jvmti and the kernel vm. void ClassLoader::initialize() { - assert(_package_hash_table == NULL, "should have been initialized by now."); EXCEPTION_MARK; if (UsePerfData) { @@ -1261,12 +1327,48 @@ bool ClassLoader::get_canonical_path(const char* orig, char* out, int len) { return true; } -#ifndef PRODUCT +void ClassLoader::create_javabase() { + Thread* THREAD = Thread::current(); -void ClassLoader::verify() { - _package_hash_table->verify(); + // Create java.base's module entry for the boot + // class loader prior to loading j.l.Ojbect. + ClassLoaderData* null_cld = ClassLoaderData::the_null_class_loader_data(); + + // Get module entry table + ModuleEntryTable* null_cld_modules = null_cld->modules(); + if (null_cld_modules == NULL) { + vm_exit_during_initialization("No ModuleEntryTable for the boot class loader"); + } + + { + MutexLocker ml(Module_lock, THREAD); + ModuleEntry* jb_module = null_cld_modules->locked_create_entry_or_null(Handle(NULL), vmSymbols::java_base(), NULL, NULL, null_cld); + if (jb_module == NULL) { + vm_exit_during_initialization("Unable to create ModuleEntry for java.base"); + } + ModuleEntryTable::set_javabase_module(jb_module); + } + + // When looking for the jimage file, only + // search the boot loader's module path which + // can consist of [-Xpatch]; exploded build | modules + // Do not search the boot loader's append path. + ClassPathEntry* e = _first_entry; + ClassPathEntry* last_e = _first_append_entry; + while ((e != NULL) && (e != last_e)) { + JImageFile *jimage = e->jimage(); + if (jimage != NULL && e->is_jrt()) { + set_has_jimage(true); +#if INCLUDE_CDS + ClassLoader::initialize_module_loader_map(jimage); +#endif + return; + } + e = e->next(); + } } +#ifndef PRODUCT // CompileTheWorld // @@ -1328,10 +1430,6 @@ void ClassPathDirEntry::compile_the_world(Handle loader, TRAPS) { tty->cr(); } -bool ClassPathDirEntry::is_jrt() { - return false; -} - void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) { real_jzfile* zip = (real_jzfile*) _zip; tty->print_cr("CompileTheWorld : Compiling all classes in %s", zip->name); @@ -1353,10 +1451,6 @@ void ClassPathZipEntry::compile_the_world(Handle loader, TRAPS) { } } -bool ClassPathZipEntry::is_jrt() { - return false; -} - void ClassLoader::compile_the_world() { EXCEPTION_MARK; HandleMark hm(THREAD); @@ -1369,7 +1463,7 @@ void ClassLoader::compile_the_world() { ClassPathEntry* e = _first_entry; jlong start = os::javaTimeMillis(); while (e != NULL) { - // We stop at bootmodules.jimage, unless it is the first bootstrap path entry + // We stop at "modules" jimage, unless it is the first bootstrap path entry if (e->is_jrt() && e != _first_entry) break; e->compile_the_world(system_class_loader, CATCH); e = e->next(); diff --git a/hotspot/src/share/vm/classfile/classLoader.hpp b/hotspot/src/share/vm/classfile/classLoader.hpp index 92ee90f2675..4d5d2c9231c 100644 --- a/hotspot/src/share/vm/classfile/classLoader.hpp +++ b/hotspot/src/share/vm/classfile/classLoader.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,8 +33,17 @@ // The VM class loader. #include -// Name of boot module image -#define BOOT_IMAGE_NAME "bootmodules.jimage" +// Name of boot "modules" image +#define MODULES_IMAGE_NAME "modules" + +// Name of the resource containing mapping from module names to defining class loader type +#define MODULE_LOADER_MAP "jdk/internal/vm/cds/resources/ModuleLoaderMap.dat" + +// Initial sizes of the following arrays are based on the generated ModuleLoaderMap.dat +#define INITIAL_BOOT_MODULES_ARRAY_SIZE 30 +#define INITIAL_PLATFORM_MODULES_ARRAY_SIZE 15 + +// Class path entry (directory or zip file) class JImageFile; class ClassFileStream; @@ -49,6 +58,7 @@ public: // may have unlocked readers, so write atomically. OrderAccess::release_store_ptr(&_next, next); } + virtual bool is_jrt() = 0; virtual bool is_jar_file() const = 0; virtual const char* name() const = 0; virtual JImageFile* jimage() const = 0; @@ -59,13 +69,13 @@ public: virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0; // Debugging NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;) - NOT_PRODUCT(virtual bool is_jrt() = 0;) }; class ClassPathDirEntry: public ClassPathEntry { private: const char* _dir; // Name of directory public: + bool is_jrt() { return false; } bool is_jar_file() const { return false; } const char* name() const { return _dir; } JImageFile* jimage() const { return NULL; } @@ -73,7 +83,6 @@ class ClassPathDirEntry: public ClassPathEntry { ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_jrt();) }; @@ -96,6 +105,7 @@ class ClassPathZipEntry: public ClassPathEntry { jzfile* _zip; // The zip archive const char* _zip_name; // Name of zip archive public: + bool is_jrt() { return false; } bool is_jar_file() const { return true; } const char* name() const { return _zip_name; } JImageFile* jimage() const { return NULL; } @@ -106,7 +116,6 @@ class ClassPathZipEntry: public ClassPathEntry { void contents_do(void f(const char* name, void* context), void* context); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_jrt();) }; @@ -116,29 +125,28 @@ private: JImageFile* _jimage; const char* _name; public: + bool is_jrt(); bool is_jar_file() const { return false; } bool is_open() const { return _jimage != NULL; } const char* name() const { return _name == NULL ? "" : _name; } JImageFile* jimage() const { return _jimage; } ClassPathImageEntry(JImageFile* jimage, const char* name); ~ClassPathImageEntry(); - static void name_to_package(const char* name, char* buffer, int length); + void name_to_package(const char* name, char* package, int length); ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) - NOT_PRODUCT(bool is_jrt();) }; -class PackageHashtable; -class PackageInfo; class SharedPathsMiscInfo; -template class HashtableBucket; class ClassLoader: AllStatic { public: - enum SomeConstants { - package_hash_table_size = 31 // Number of buckets + enum ClassLoaderType { + BOOT_LOADER = 1, /* boot loader */ + PLATFORM_LOADER = 2, /* PlatformClassLoader */ + APP_LOADER = 3 /* AppClassLoader */ }; protected: @@ -177,41 +185,60 @@ class ClassLoader: AllStatic { static PerfCounter* _isUnsyncloadClass; static PerfCounter* _load_instance_class_failCounter; - // First entry in linked list of ClassPathEntry instances + // First entry in linked list of ClassPathEntry instances. + // This consists of entries made up by: + // - boot loader modules + // [-Xpatch]; exploded build | modules; + // - boot loader append path + // [-Xbootclasspath/a]; [jvmti appended entries] static ClassPathEntry* _first_entry; // Last entry in linked list of ClassPathEntry instances static ClassPathEntry* _last_entry; static int _num_entries; - // Hash table used to keep track of loaded packages - static PackageHashtable* _package_hash_table; + // Pointer into the linked list of ClassPathEntry instances. + // Marks the start of: + // - the boot loader's append path + // [-Xbootclasspath/a]; [jvmti appended entries] + static ClassPathEntry* _first_append_entry; + static const char* _shared_archive; + // True if the boot path has a "modules" jimage + static bool _has_jimage; + + // Array of module names associated with the boot class loader + CDS_ONLY(static GrowableArray* _boot_modules_array;) + + // Array of module names associated with the platform class loader + CDS_ONLY(static GrowableArray* _platform_modules_array;) + // Info used by CDS CDS_ONLY(static SharedPathsMiscInfo * _shared_paths_misc_info;) - // Hash function - static unsigned int hash(const char *s, int n); - // Returns the package file name corresponding to the specified package - // or class name, or null if not found. - static PackageInfo* lookup_package(const char *pkgname); - // Adds a new package entry for the specified class or package name and - // corresponding directory or jar file name. - static bool add_package(const char *pkgname, int classpath_index, TRAPS); - // Initialization static void setup_bootstrap_search_path(); - static void setup_search_path(const char *class_path); + static void setup_search_path(const char *class_path, bool setting_bootstrap); static void load_zip_library(); static void load_jimage_library(); static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st, bool throw_exception, TRAPS); + public: + + // If the package for the fully qualified class name is in the boot + // loader's package entry table then add_package() sets the classpath_index + // field so that get_system_package() will know to return a non-null value + // for the package's location. And, so that the package will be added to + // the list of packages returned by get_system_packages(). + // For packages whose classes are loaded from the boot loader class path, the + // classpath_index indicates which entry on the boot loader class path. + static bool add_package(const char *fullq_class_name, s2 classpath_index, TRAPS); + // Canonicalizes path names, so strcmp will work properly. This is mainly // to avoid confusing the zip library static bool get_canonical_path(const char* orig, char* out, int len); - static const char* file_name_for_class_name(const char* class_name, int class_name_len); @@ -220,6 +247,8 @@ class ClassLoader: AllStatic { static int crc32(int crc, const char* buf, int len); static bool update_class_path_entry_list(const char *path, bool check_for_duplicates, + bool mark_append_entry, + bool prepend_entry, bool throw_exception=true); static void print_bootclasspath(); @@ -284,8 +313,18 @@ class ClassLoader: AllStatic { return _load_instance_class_failCounter; } + // Sets _has_jimage to TRUE if "modules" jimage file exists + static void set_has_jimage(bool val) { + _has_jimage = val; + } + + static bool has_jimage() { return _has_jimage; } + + // Create the ModuleEntry for java.base + static void create_javabase(); + // Load individual .class file - static instanceKlassHandle load_class(Symbol* class_name, TRAPS); + static instanceKlassHandle load_class(Symbol* class_name, bool search_append_only, TRAPS); // If the specified package has been loaded by the system, then returns // the name of the directory or ZIP file that the package was loaded from. @@ -304,9 +343,7 @@ class ClassLoader: AllStatic { // Initialization static void initialize(); CDS_ONLY(static void initialize_shared_path();) - static void create_package_info_table(); - static void create_package_info_table(HashtableBucket *t, int length, - int number_of_entries); + static int compute_Object_vtable(); static ClassPathEntry* classpath_entry(int n) { @@ -320,8 +357,6 @@ class ClassLoader: AllStatic { #if INCLUDE_CDS // Sharing dump and restore - static void copy_package_info_buckets(char** top, char* end); - static void copy_package_info_table(char** top, char* end); static void check_shared_classpath(const char *path); static void finalize_shared_paths_misc_info(); @@ -329,9 +364,14 @@ class ClassLoader: AllStatic { static void* get_shared_paths_misc_info(); static bool check_shared_paths_misc_info(void* info, int size); static void exit_with_path_failure(const char* error, const char* message); -#endif - static void trace_class_path(outputStream* out, const char* msg, const char* name = NULL); + static s2 module_to_classloader(const char* module_name); + static void initialize_module_loader_map(JImageFile* jimage); +#endif + static s2 classloader_type(Symbol* class_name, ClassPathEntry* e, + int classpath_index, TRAPS); + + static void trace_class_path(const char* msg, const char* name = NULL); // VM monitoring and management support static jlong classloader_time_ms(); @@ -342,15 +382,30 @@ class ClassLoader: AllStatic { static jlong class_link_count(); static jlong class_link_time_ms(); + static void set_first_append_entry(ClassPathEntry* entry); + // indicates if class path already contains a entry (exact match by name) static bool contains_entry(ClassPathEntry* entry); // adds a class path list static void add_to_list(ClassPathEntry* new_entry); + // prepends a class path list + static void prepend_to_list(ClassPathEntry* new_entry); + // creates a class path zip entry (returns NULL if JAR file cannot be opened) static ClassPathZipEntry* create_class_path_zip_entry(const char *apath); + // add a path to class path list + static void add_to_list(const char* apath); + + // prepend a path to class path list + static void prepend_to_list(const char* apath); + + static bool string_ends_with(const char* str, const char* str_to_find); + + static bool is_jrt(const char* name) { return string_ends_with(name, MODULES_IMAGE_NAME); } + // Debugging static void verify() PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/classfile/classLoaderData.cpp b/hotspot/src/share/vm/classfile/classLoaderData.cpp index 9543a1fac7b..f3278a7f8de 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp @@ -31,7 +31,7 @@ // // Class loaders that implement a deterministic name resolution strategy // (including with respect to their delegation behavior), such as the boot, the -// extension, and the system loaders of the JDK's built-in class loader +// platform, and the system loaders of the JDK's built-in class loader // hierarchy, always produce the same linkset for a given configuration. // // ClassLoaderData carries information related to a linkset (e.g., @@ -51,6 +51,8 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.hpp" #include "classfile/metadataOnStackMark.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" #include "gc/shared/gcLocker.hpp" @@ -83,6 +85,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen // The null-class-loader should always be kept alive. _keep_alive(is_anonymous || h_class_loader.is_null()), _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), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true, @@ -168,6 +171,30 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) { } } +void ClassLoaderData::modules_do(void f(ModuleEntry*)) { + if (_modules != NULL) { + for (int i = 0; i < _modules->table_size(); i++) { + for (ModuleEntry* entry = _modules->bucket(i); + entry != NULL; + entry = entry->next()) { + f(entry); + } + } + } +} + +void ClassLoaderData::packages_do(void f(PackageEntry*)) { + if (_packages != NULL) { + for (int i = 0; i < _packages->table_size(); i++) { + for (PackageEntry* entry = _packages->bucket(i); + entry != NULL; + entry = entry->next()) { + f(entry); + } + } + } +} + void ClassLoaderData::record_dependency(const Klass* k, TRAPS) { assert(k != NULL, "invariant"); @@ -341,6 +368,46 @@ void ClassLoaderData::unload() { } } +PackageEntryTable* ClassLoaderData::packages() { + // Lazily create the package entry table at first request. + if (_packages == NULL) { + MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); + // Check again if _packages has been allocated while we were getting this lock. + if (_packages != NULL) { + return _packages; + } + // Ensure _packages is stable, since it is examined without a lock + OrderAccess::storestore(); + _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size); + } + return _packages; +} + +ModuleEntryTable* ClassLoaderData::modules() { + // Lazily create the module entry table at first request. + if (_modules == NULL) { + MutexLocker m1(Module_lock); + // Check again if _modules has been allocated while we were getting this lock. + if (_modules != NULL) { + return _modules; + } + + ModuleEntryTable* temp_table = new ModuleEntryTable(ModuleEntryTable::_moduletable_entry_size); + // Each loader has one unnamed module entry. Create it before + // any classes, loaded by this loader, are defined in case + // they end up being defined in loader's unnamed module. + temp_table->create_unnamed_module(this); + + { + MutexLockerEx m1(metaspace_lock(), Mutex::_no_safepoint_check_flag); + // Ensure _modules is stable, since it is examined without a lock + OrderAccess::storestore(); + _modules = temp_table; + } + } + return _modules; +} + oop ClassLoaderData::keep_alive_object() const { assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive"); return is_anonymous() ? _klasses->java_mirror() : class_loader(); @@ -358,16 +425,30 @@ ClassLoaderData::~ClassLoaderData() { // Release C heap structures for all the classes. classes_do(InstanceKlass::release_C_heap_structures); + // Release C heap allocated hashtable for all the packages. + if (_packages != NULL) { + // Destroy the table itself + delete _packages; + _packages = NULL; + } + + // Release C heap allocated hashtable for all the modules. + if (_modules != NULL) { + // Destroy the table itself + delete _modules; + _modules = NULL; + } + + // release the metaspace Metaspace *m = _metaspace; if (m != NULL) { _metaspace = NULL; - // release the metaspace delete m; - // release the handles - if (_handles != NULL) { - JNIHandleBlock::release_block(_handles); - _handles = NULL; - } + } + // release the handles + if (_handles != NULL) { + JNIHandleBlock::release_block(_handles); + _handles = NULL; } // Clear all the JNI handles for methods @@ -389,10 +470,10 @@ ClassLoaderData::~ClassLoaderData() { } /** - * Returns true if this class loader data is for the extension class loader. + * Returns true if this class loader data is for the platform class loader. */ -bool ClassLoaderData::is_ext_class_loader_data() const { - return SystemDictionary::is_ext_class_loader(class_loader()); +bool ClassLoaderData::is_platform_class_loader_data() const { + return SystemDictionary::is_platform_class_loader(class_loader()); } Metaspace* ClassLoaderData::metaspace_non_null() { @@ -438,6 +519,10 @@ jobject ClassLoaderData::add_handle(Handle h) { return handles()->allocate_handle(h()); } +void ClassLoaderData::remove_handle(jobject h) { + _handles->release_handle(h); +} + // Add this metadata pointer to be freed when it's safe. This is only during // class unloading because Handles might point to this metadata field. void ClassLoaderData::add_to_deallocate_list(Metadata* m) { @@ -712,6 +797,40 @@ void ClassLoaderDataGraph::methods_do(void f(Method*)) { } } +void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) { + assert_locked_or_safepoint(Module_lock); + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->modules_do(f); + } +} + +void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->modules_do(f); + } +} + +void ClassLoaderDataGraph::packages_do(void f(PackageEntry*)) { + assert_locked_or_safepoint(Module_lock); + for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { + cld->packages_do(f); + } +} + +void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!"); + // Only walk the head until any clds not purged from prior unloading + // (CMS doesn't purge right away). + for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); + cld->packages_do(f); + } +} + void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { cld->loaded_classes_do(klass_closure); @@ -723,6 +842,7 @@ void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) { // Only walk the head until any clds not purged from prior unloading // (CMS doesn't purge right away). for (ClassLoaderData* cld = _unloading; cld != _saved_unloading; cld = cld->next()) { + assert(cld->is_unloading(), "invariant"); cld->classes_do(f); } } @@ -800,6 +920,12 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, data = _head; while (data != NULL) { if (data->is_alive(is_alive_closure)) { + if (data->packages_defined()) { + data->packages()->purge_all_package_exports(); + } + if (data->modules_defined()) { + data->modules()->purge_all_module_reads(); + } // clean metaspace if (walk_all_metadata) { data->classes_do(InstanceKlass::purge_previous_versions); @@ -992,6 +1118,7 @@ void ClassLoaderData::print_value_on(outputStream* out) const { Ticks ClassLoaderDataGraph::_class_unload_time; void ClassLoaderDataGraph::class_unload_event(Klass* const k) { + assert(k != NULL, "invariant"); // post class unload event EventClassUnload event(UNTIMED); diff --git a/hotspot/src/share/vm/classfile/classLoaderData.hpp b/hotspot/src/share/vm/classfile/classLoaderData.hpp index f6e82fa12bc..4b6d24722d3 100644 --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp @@ -53,6 +53,10 @@ class ClassLoaderData; class JNIMethodBlock; class JNIHandleBlock; class Metadebug; +class ModuleEntry; +class PackageEntry; +class ModuleEntryTable; +class PackageEntryTable; // GC root for walking class loader data created @@ -92,6 +96,10 @@ class ClassLoaderDataGraph : public AllStatic { static void classes_do(KlassClosure* klass_closure); static void classes_do(void f(Klass* const)); static void methods_do(void f(Method*)); + static void modules_do(void f(ModuleEntry*)); + static void modules_unloading_do(void f(ModuleEntry*)); + static void packages_do(void f(PackageEntry*)); + static void packages_unloading_do(void f(PackageEntry*)); static void loaded_classes_do(KlassClosure* klass_closure); static void classes_unloading_do(void f(Klass* const)); static bool do_unloading(BoolObjectClosure* is_alive, bool clean_previous_versions); @@ -172,9 +180,12 @@ class ClassLoaderData : public CHeapObj { volatile int _claimed; // true if claimed, for example during GC traces. // To avoid applying oop closure more than once. // Has to be an int because we cas it. - Klass* _klasses; // The classes defined by the class loader. + JNIHandleBlock* _handles; // Handles to constant pool arrays, Modules, etc, which + // have the same life cycle of the corresponding ClassLoader. - JNIHandleBlock* _handles; // Handles to constant pool arrays + Klass* _klasses; // The classes defined by the class loader. + PackageEntryTable* _packages; // The packages defined by the class loader. + ModuleEntryTable* _modules; // The modules defined by the class loader. // These method IDs are created for the class loader and set to NULL when the // class loader is unloaded. They are rarely freed, only for redefine classes @@ -218,6 +229,8 @@ class ClassLoaderData : public CHeapObj { void loaded_classes_do(KlassClosure* klass_closure); void classes_do(void f(InstanceKlass*)); void methods_do(void f(Method*)); + void modules_do(void f(ModuleEntry*)); + void packages_do(void f(PackageEntry*)); // Deallocate free list during class unloading. void free_deallocate_list(); @@ -256,7 +269,7 @@ class ClassLoaderData : public CHeapObj { bool is_the_null_class_loader_data() const { return this == _the_null_class_loader_data; } - bool is_ext_class_loader_data() const; + bool is_platform_class_loader_data() const; // The Metaspace is created lazily so may be NULL. This // method will allocate a Metaspace if needed. @@ -293,11 +306,16 @@ class ClassLoaderData : public CHeapObj { const char* loader_name(); jobject add_handle(Handle h); + void remove_handle(jobject h); void add_class(Klass* k, bool publicize = true); void remove_class(Klass* k); bool contains_klass(Klass* k); void record_dependency(const Klass* to, TRAPS); void init_dependencies(TRAPS); + PackageEntryTable* packages(); + bool packages_defined() { return (_packages != NULL); } + ModuleEntryTable* modules(); + bool modules_defined() { return (_modules != NULL); } void add_to_deallocate_list(Metadata* m); diff --git a/hotspot/src/share/vm/classfile/classLoaderExt.hpp b/hotspot/src/share/vm/classfile/classLoaderExt.hpp index 990a8b61f04..7fa11b2f614 100644 --- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp +++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,12 +49,14 @@ public: return false; } - instanceKlassHandle record_result(const int classpath_index, + instanceKlassHandle record_result(const s2 classpath_index, + const jshort classloader_type, const ClassPathEntry* e, instanceKlassHandle result, TRAPS) { if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) { if (DumpSharedSpaces) { result->set_shared_classpath_index(classpath_index); + result->set_class_loader_type(classloader_type); } return result; } else { @@ -65,13 +67,27 @@ public: static void add_class_path_entry(const char* path, bool check_for_duplicates, - ClassPathEntry* new_entry) { - ClassLoader::add_to_list(new_entry); + ClassPathEntry* new_entry, bool prepend_entry) { + if (prepend_entry) { + ClassLoader::prepend_to_list(new_entry); + } else { + ClassLoader::add_to_list(new_entry); + } } static void append_boot_classpath(ClassPathEntry* new_entry) { ClassLoader::add_to_list(new_entry); + // During jvmti live phase an entry can be appended to the boot + // loader's ClassPathEntry instances. Need to mark the start + // of the boot loader's append path in case there was no reason + // to mark it initially in setup_bootstrap_search_path. + if (ClassLoader::_first_append_entry == NULL) { + ClassLoader::set_first_append_entry(new_entry); + } } static void setup_search_paths() {} + static bool is_boot_classpath(int classpath_index) { + return true; + } static Klass* load_one_class(ClassListParser* parser, TRAPS); }; diff --git a/hotspot/src/share/vm/classfile/dictionary.cpp b/hotspot/src/share/vm/classfile/dictionary.cpp index 6f70ef9b47e..61c3bad0f8e 100644 --- a/hotspot/src/share/vm/classfile/dictionary.cpp +++ b/hotspot/src/share/vm/classfile/dictionary.cpp @@ -135,8 +135,10 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, oop protection_dom // via a store to _pd_set. OrderAccess::release_store_ptr(&_pd_set, new_head); } - if (TraceProtectionDomainVerification && WizardMode) { - print(); + if (log_is_enabled(Trace, protectiondomain)) { + ResourceMark rm; + outputStream* log = LogHandle(protectiondomain)::trace_stream(); + print_count(log); } } diff --git a/hotspot/src/share/vm/classfile/dictionary.hpp b/hotspot/src/share/vm/classfile/dictionary.hpp index a77f33717f3..a873fdd3e47 100644 --- a/hotspot/src/share/vm/classfile/dictionary.hpp +++ b/hotspot/src/share/vm/classfile/dictionary.hpp @@ -29,6 +29,7 @@ #include "oops/instanceKlass.hpp" #include "oops/oop.hpp" #include "utilities/hashtable.hpp" +#include "utilities/ostream.hpp" class DictionaryEntry; class PSPromotionManager; @@ -323,14 +324,14 @@ class DictionaryEntry : public HashtableEntry { return (klass->name() == class_name && _loader_data == loader_data); } - void print() { + void print_count(outputStream *st) { int count = 0; for (ProtectionDomainEntry* current = _pd_set; current != NULL; current = current->_next) { count++; } - tty->print_cr("pd set = #%d", count); + st->print_cr("pd set count = #%d", count); } }; diff --git a/hotspot/src/share/vm/classfile/javaClasses.cpp b/hotspot/src/share/vm/classfile/javaClasses.cpp index 2df6a47088c..a69b87e22d4 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.cpp +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp @@ -24,7 +24,9 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/stringTable.hpp" #include "classfile/vmSymbols.hpp" #include "code/debugInfo.hpp" @@ -768,7 +770,7 @@ void java_lang_Class::fixup_mirror(KlassHandle k, TRAPS) { } } } - create_mirror(k, Handle(NULL), Handle(NULL), CHECK); + create_mirror(k, Handle(NULL), Handle(NULL), Handle(NULL), CHECK); } void java_lang_Class::initialize_mirror_fields(KlassHandle k, @@ -789,7 +791,7 @@ void java_lang_Class::initialize_mirror_fields(KlassHandle k, } void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, - Handle protection_domain, TRAPS) { + Handle module, Handle protection_domain, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); // Use this moment of initialization to cache modifier_flags also, // to support Class.getModifiers(). Instance classes recalculate @@ -849,11 +851,25 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, assert(class_loader() == k->class_loader(), "should be same"); set_class_loader(mirror(), class_loader()); + // set the module field in the java_lang_Class instance + // This may be null during bootstrap but will get fixed up later on. + set_module(mirror(), module()); + // Setup indirection from klass->mirror last // after any exceptions can happen during allocations. if (!k.is_null()) { k->set_java_mirror(mirror()); } + + // Keep list of classes needing java.base module fixup. + if (!ModuleEntryTable::javabase_defined()) { + if (fixup_module_field_list() == NULL) { + GrowableArray* list = + new (ResourceObj::C_HEAP, mtClass) GrowableArray(500, true); + set_fixup_module_field_list(list); + } + fixup_module_field_list()->push(k()); + } } else { if (fixup_mirror_list() == NULL) { GrowableArray* list = @@ -864,6 +880,10 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, } } +void java_lang_Class::fixup_module_field(KlassHandle k, Handle module) { + assert(_module_offset != 0, "must have been computed already"); + java_lang_Class::set_module(k->java_mirror(), module()); +} int java_lang_Class::oop_size(oop java_class) { assert(_oop_size_offset != 0, "must be set"); @@ -931,6 +951,16 @@ oop java_lang_Class::class_loader(oop java_class) { return java_class->obj_field(_class_loader_offset); } +oop java_lang_Class::module(oop java_class) { + assert(_module_offset != 0, "must be set"); + return java_class->obj_field(_module_offset); +} + +void java_lang_Class::set_module(oop java_class, oop module) { + assert(_module_offset != 0, "must be set"); + java_class->obj_field_put(_module_offset, module); +} + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) @@ -1116,6 +1146,10 @@ void java_lang_Class::compute_offsets() { k, vmSymbols::componentType_name(), vmSymbols::class_signature()); + compute_offset(_module_offset, + k, vmSymbols::module_name(), + vmSymbols::module_signature()); + // Init lock is a C union with component_mirror. Only instanceKlass mirrors have // init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops // GC treats them the same. @@ -1668,28 +1702,48 @@ char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, buf_len += (int)strlen(source_file_name); } + char *module_name = NULL, *module_version = NULL; + ModuleEntry* module = holder->module(); + if (module->is_named()) { + module_name = module->name()->as_C_string(); + buf_len += (int)strlen(module_name); + if (module->version() != NULL) { + module_version = module->version()->as_C_string(); + buf_len += (int)strlen(module_version); + } + } + // Allocate temporary buffer with extra space for formatting and line number char* buf = NEW_RESOURCE_ARRAY(char, buf_len + 64); // Print stack trace line in buffer - sprintf(buf, "\tat %s.%s", klass_name, method_name); + sprintf(buf, "\tat %s.%s(", klass_name, method_name); + + // Print module information + if (module_name != NULL) { + if (module_version != NULL) { + sprintf(buf + (int)strlen(buf), "%s@%s/", module_name, module_version); + } else { + sprintf(buf + (int)strlen(buf), "%s/", module_name); + } + } if (!version_matches(method, version)) { - strcat(buf, "(Redefined)"); + strcat(buf, "Redefined)"); } else { int line_number = Backtrace::get_line_number(method, bci); if (line_number == -2) { - strcat(buf, "(Native Method)"); + strcat(buf, "Native Method)"); } else { if (source_file_name != NULL && (line_number != -1)) { // Sourcename and linenumber - sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); + sprintf(buf + (int)strlen(buf), "%s:%d)", source_file_name, line_number); } else if (source_file_name != NULL) { // Just sourcename - sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); + sprintf(buf + (int)strlen(buf), "%s)", source_file_name); } else { // Neither sourcename nor linenumber - sprintf(buf + (int)strlen(buf), "(Unknown Source)"); + sprintf(buf + (int)strlen(buf), "Unknown Source)"); } nmethod* nm = method->code(); if (WizardMode && nm != NULL) { @@ -2094,6 +2148,20 @@ oop java_lang_StackTraceElement::create(Handle mirror, int method_id, oop methodname = StringTable::intern(sym, CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); + // Fill in module name and version + ModuleEntry* module = holder->module(); + if (module->is_named()) { + oop module_name = StringTable::intern(module->name(), CHECK_0); + java_lang_StackTraceElement::set_moduleName(element(), module_name); + oop module_version; + if (module->version() != NULL) { + module_version = StringTable::intern(module->version(), CHECK_0); + } else { + module_version = NULL; + } + java_lang_StackTraceElement::set_moduleVersion(element(), module_version); + } + if (!version_matches(method, version)) { // The method was redefined, accurate line number information isn't available java_lang_StackTraceElement::set_fileName(element(), NULL); @@ -2753,6 +2821,80 @@ void java_lang_reflect_Parameter::set_executable(oop param, oop value) { } +int java_lang_reflect_Module::loader_offset; +int java_lang_reflect_Module::name_offset; +int java_lang_reflect_Module::_module_entry_offset = -1; + +Handle java_lang_reflect_Module::create(Handle loader, Handle module_name, TRAPS) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + + Symbol* name = vmSymbols::java_lang_reflect_Module(); + Klass* k = SystemDictionary::resolve_or_fail(name, true, CHECK_NH); + instanceKlassHandle klass (THREAD, k); + + Handle jlrmh = klass->allocate_instance_handle(CHECK_NH); + JavaValue result(T_VOID); + JavaCalls::call_special(&result, jlrmh, KlassHandle(THREAD, klass()), + vmSymbols::object_initializer_name(), + vmSymbols::java_lang_reflect_module_init_signature(), + loader, module_name, CHECK_NH); + return jlrmh; +} + +void java_lang_reflect_Module::compute_offsets() { + Klass* k = SystemDictionary::reflect_Module_klass(); + if(NULL != k) { + compute_offset(loader_offset, k, vmSymbols::loader_name(), vmSymbols::classloader_signature()); + compute_offset(name_offset, k, vmSymbols::name_name(), vmSymbols::string_signature()); + MODULE_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); + } +} + + +oop java_lang_reflect_Module::loader(oop module) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + return module->obj_field(loader_offset); +} + +void java_lang_reflect_Module::set_loader(oop module, oop value) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + module->obj_field_put(loader_offset, value); +} + +oop java_lang_reflect_Module::name(oop module) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + return module->obj_field(name_offset); +} + +void java_lang_reflect_Module::set_name(oop module, oop value) { + assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); + module->obj_field_put(name_offset, value); +} + +ModuleEntry* java_lang_reflect_Module::module_entry(oop module, TRAPS) { + assert(_module_entry_offset != -1, "Uninitialized module_entry_offset"); + assert(module != NULL, "module can't be null"); + assert(module->is_oop(), "module must be oop"); + + ModuleEntry* module_entry = (ModuleEntry*)module->address_field(_module_entry_offset); + if (module_entry == NULL) { + // If the inject field containing the ModuleEntry* is null then return the + // class loader's unnamed module. + oop loader = java_lang_reflect_Module::loader(module); + Handle h_loader = Handle(THREAD, loader); + ClassLoaderData* loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); + return loader_cld->modules()->unnamed_module(); + } + return module_entry; +} + +void java_lang_reflect_Module::set_module_entry(oop module, ModuleEntry* module_entry) { + assert(_module_entry_offset != -1, "Uninitialized module_entry_offset"); + assert(module != NULL, "module can't be null"); + assert(module->is_oop(), "module must be oop"); + module->address_field_put(_module_entry_offset, (address)module_entry); +} + Handle sun_reflect_ConstantPool::create(TRAPS) { assert(Universe::is_fully_initialized(), "Need to find another solution to the reflection problem"); Klass* k = SystemDictionary::reflect_ConstantPool_klass(); @@ -3352,6 +3494,7 @@ oop java_security_AccessControlContext::create(objArrayHandle context, bool isPr bool java_lang_ClassLoader::offsets_computed = false; int java_lang_ClassLoader::_loader_data_offset = -1; int java_lang_ClassLoader::parallelCapable_offset = -1; +int java_lang_ClassLoader::unnamedModule_offset = -1; ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) { assert(loader != NULL && loader->is_oop(), "loader must be oop"); @@ -3371,6 +3514,9 @@ void java_lang_ClassLoader::compute_offsets() { compute_optional_offset(parallelCapable_offset, k1, vmSymbols::parallelCapable_name(), vmSymbols::concurrenthashmap_signature()); + compute_offset(unnamedModule_offset, + k1, vmSymbols::unnamedModule_name(), vmSymbols::module_signature()); + CLASSLOADER_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } @@ -3438,6 +3584,10 @@ oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) { return loader; } +oop java_lang_ClassLoader::unnamedModule(oop loader) { + assert(is_instance(loader), "loader must be oop"); + return loader->obj_field(unnamedModule_offset); +} // Support for java_lang_System int java_lang_System::in_offset_in_bytes() { @@ -3470,11 +3620,13 @@ int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; int java_lang_Class::_static_oop_field_count_offset; int java_lang_Class::_class_loader_offset; +int java_lang_Class::_module_offset; int java_lang_Class::_protection_domain_offset; int java_lang_Class::_component_mirror_offset; int java_lang_Class::_init_lock_offset; int java_lang_Class::_signers_offset; GrowableArray* java_lang_Class::_fixup_mirror_list = NULL; +GrowableArray* java_lang_Class::_fixup_module_field_list = NULL; int java_lang_Throwable::backtrace_offset; int java_lang_Throwable::detailMessage_offset; int java_lang_Throwable::cause_offset; @@ -3534,6 +3686,8 @@ int java_lang_StackTraceElement::declaringClass_offset; int java_lang_StackTraceElement::methodName_offset; int java_lang_StackTraceElement::fileName_offset; int java_lang_StackTraceElement::lineNumber_offset; +int java_lang_StackTraceElement::moduleName_offset; +int java_lang_StackTraceElement::moduleVersion_offset; int java_lang_StackFrameInfo::_declaringClass_offset; int java_lang_StackFrameInfo::_memberName_offset; int java_lang_StackFrameInfo::_bci_offset; @@ -3575,6 +3729,14 @@ void java_lang_StackTraceElement::set_lineNumber(oop element, int value) { element->int_field_put(lineNumber_offset, value); } +void java_lang_StackTraceElement::set_moduleName(oop element, oop value) { + element->obj_field_put(moduleName_offset, value); +} + +void java_lang_StackTraceElement::set_moduleVersion(oop element, oop value) { + element->obj_field_put(moduleVersion_offset, value); +} + // Support for java_lang_StackFrameInfo void java_lang_StackFrameInfo::set_declaringClass(oop element, oop value) { element->obj_field_put(_declaringClass_offset, value); @@ -3713,6 +3875,8 @@ void JavaClasses::compute_hard_coded_offsets() { java_lang_System::static_security_offset = java_lang_System::hc_static_security_offset * x; // java_lang_StackTraceElement + java_lang_StackTraceElement::moduleName_offset = java_lang_StackTraceElement::hc_moduleName_offset * x + header; + java_lang_StackTraceElement::moduleVersion_offset = java_lang_StackTraceElement::hc_moduleVersion_offset * x + header; java_lang_StackTraceElement::declaringClass_offset = java_lang_StackTraceElement::hc_declaringClass_offset * x + header; java_lang_StackTraceElement::methodName_offset = java_lang_StackTraceElement::hc_methodName_offset * x + header; java_lang_StackTraceElement::fileName_offset = java_lang_StackTraceElement::hc_fileName_offset * x + header; @@ -3752,6 +3916,7 @@ void JavaClasses::compute_offsets() { sun_reflect_ConstantPool::compute_offsets(); sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets(); java_lang_reflect_Parameter::compute_offsets(); + java_lang_reflect_Module::compute_offsets(); java_lang_StackFrameInfo::compute_offsets(); java_lang_LiveStackFrameInfo::compute_offsets(); @@ -3899,7 +4064,7 @@ void JavaClasses::check_offsets() { // java.lang.ClassLoader - CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent, "Ljava/lang/ClassLoader;"); + CHECK_OFFSET("java/lang/ClassLoader", java_lang_ClassLoader, parent, "Ljava/lang/ClassLoader;"); // java.lang.System diff --git a/hotspot/src/share/vm/classfile/javaClasses.hpp b/hotspot/src/share/vm/classfile/javaClasses.hpp index 9f7c2d1233a..6c487534018 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp @@ -210,12 +210,14 @@ class java_lang_Class : AllStatic { static int _init_lock_offset; static int _signers_offset; static int _class_loader_offset; + static int _module_offset; static int _component_mirror_offset; static bool offsets_computed; static int classRedefinedCount_offset; static GrowableArray* _fixup_mirror_list; + static GrowableArray* _fixup_module_field_list; static void set_init_lock(oop java_class, oop init_lock); static void set_protection_domain(oop java_class, oop protection_domain); @@ -226,10 +228,13 @@ class java_lang_Class : AllStatic { static void compute_offsets(); // Instance creation - static void create_mirror(KlassHandle k, Handle class_loader, + static void create_mirror(KlassHandle k, Handle class_loader, Handle module, Handle protection_domain, TRAPS); static void fixup_mirror(KlassHandle k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); + + static void fixup_module_field(KlassHandle k, Handle module); + // Conversion static Klass* as_Klass(oop java_class); static void set_klass(oop java_class, Klass* klass); @@ -267,18 +272,29 @@ class java_lang_Class : AllStatic { static void set_signers(oop java_class, objArrayOop signers); static oop class_loader(oop java_class); + static void set_module(oop java_class, oop module); + static oop module(oop java_class); static int oop_size(oop java_class); static void set_oop_size(oop java_class, int size); static int static_oop_field_count(oop java_class); static void set_static_oop_field_count(oop java_class, int size); + static GrowableArray* fixup_mirror_list() { return _fixup_mirror_list; } static void set_fixup_mirror_list(GrowableArray* v) { _fixup_mirror_list = v; } + + static GrowableArray* fixup_module_field_list() { + return _fixup_module_field_list; + } + static void set_fixup_module_field_list(GrowableArray* v) { + _fixup_module_field_list = v; + } + // Debugging friend class JavaClasses; friend class InstanceKlass; // verification code accesses offsets @@ -758,6 +774,39 @@ class java_lang_reflect_Parameter { friend class JavaClasses; }; +#define MODULE_INJECTED_FIELDS(macro) \ + macro(java_lang_reflect_Module, module_entry, intptr_signature, false) + +class java_lang_reflect_Module { + private: + static int loader_offset; + static int name_offset; + static int _module_entry_offset; + static void compute_offsets(); + + public: + // Allocation + static Handle create(Handle loader, Handle module_name, TRAPS); + + // Testers + static bool is_subclass(Klass* klass) { + return klass->is_subclass_of(SystemDictionary::reflect_Module_klass()); + } + static bool is_instance(oop obj); + + // Accessors + static oop loader(oop module); + static void set_loader(oop module, oop value); + + static oop name(oop module); + static void set_name(oop module, oop value); + + static ModuleEntry* module_entry(oop module, TRAPS); + static void set_module_entry(oop module, ModuleEntry* module_entry); + + friend class JavaClasses; +}; + // Interface to sun.reflect.ConstantPool objects class sun_reflect_ConstantPool { private: @@ -1203,6 +1252,7 @@ class java_lang_ClassLoader : AllStatic { static bool offsets_computed; static int parent_offset; static int parallelCapable_offset; + static int unnamedModule_offset; public: static void compute_offsets(); @@ -1227,6 +1277,8 @@ class java_lang_ClassLoader : AllStatic { } static bool is_instance(oop obj); + static oop unnamedModule(oop loader); + // Debugging friend class JavaClasses; friend class ClassFileParser; // access to number_of_fake_fields @@ -1266,12 +1318,16 @@ class java_lang_System : AllStatic { class java_lang_StackTraceElement: AllStatic { private: enum { - hc_declaringClass_offset = 0, - hc_methodName_offset = 1, - hc_fileName_offset = 2, - hc_lineNumber_offset = 3 + hc_moduleName_offset = 0, + hc_moduleVersion_offset = 1, + hc_declaringClass_offset = 2, + hc_methodName_offset = 3, + hc_fileName_offset = 4, + hc_lineNumber_offset = 5 }; + static int moduleName_offset; + static int moduleVersion_offset; static int declaringClass_offset; static int methodName_offset; static int fileName_offset; @@ -1279,6 +1335,8 @@ class java_lang_StackTraceElement: AllStatic { public: // Setters + static void set_moduleName(oop element, oop value); + static void set_moduleVersion(oop element, oop value); static void set_declaringClass(oop element, oop value); static void set_methodName(oop element, oop value); static void set_fileName(oop element, oop value); @@ -1456,8 +1514,8 @@ class InjectedField { CLASSLOADER_INJECTED_FIELDS(macro) \ MEMBERNAME_INJECTED_FIELDS(macro) \ CALLSITECONTEXT_INJECTED_FIELDS(macro) \ - STACKFRAMEINFO_INJECTED_FIELDS(macro) - + STACKFRAMEINFO_INJECTED_FIELDS(macro) \ + MODULE_INJECTED_FIELDS(macro) // Interface to hard-coded offset checking diff --git a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp index 05deb981ba1..1aba5b8f8c1 100644 --- a/hotspot/src/share/vm/classfile/javaClasses.inline.hpp +++ b/hotspot/src/share/vm/classfile/javaClasses.inline.hpp @@ -171,6 +171,10 @@ inline bool java_lang_invoke_DirectMethodHandle::is_instance(oop obj) { +inline bool java_lang_reflect_Module::is_instance(oop obj) { + return obj != NULL && is_subclass(obj->klass()); +} + inline int Backtrace::merge_bci_and_version(int bci, int version) { // only store u2 for version, checking for overflow. if (version > USHRT_MAX || version < 0) version = USHRT_MAX; diff --git a/hotspot/src/share/vm/classfile/jimage.hpp b/hotspot/src/share/vm/classfile/jimage.hpp index 90f6dad9fd1..e538ac805f8 100644 --- a/hotspot/src/share/vm/classfile/jimage.hpp +++ b/hotspot/src/share/vm/classfile/jimage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,7 +22,7 @@ * */ -#include "jni.h" +#include "prims/jni.h" // Opaque reference to a JImage file. class JImageFile; @@ -35,6 +35,8 @@ typedef jlong JImageLocationRef; // JImage Error Codes +// Resource was not found +#define JIMAGE_NOT_FOUND (0) // The image file is not prefixed with 0xCAFEDADA #define JIMAGE_BAD_MAGIC (-1) // The image file does not have a compatible (translatable) version @@ -55,7 +57,7 @@ typedef jlong JImageLocationRef; * * Ex. * jint error; - * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error); + * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error); * if (image == NULL) { * tty->print_cr("JImage failed to open: %d", error); * ... diff --git a/hotspot/src/share/vm/classfile/klassFactory.cpp b/hotspot/src/share/vm/classfile/klassFactory.cpp index 14af5574021..11b07f6b24a 100644 --- a/hotspot/src/share/vm/classfile/klassFactory.cpp +++ b/hotspot/src/share/vm/classfile/klassFactory.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "classfile/klassFactory.hpp" #include "memory/resourceArea.hpp" #include "prims/jvmtiEnvBase.hpp" +#include "trace/traceMacros.hpp" static ClassFileStream* prologue(ClassFileStream* stream, Symbol* name, @@ -102,11 +103,15 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream, assert(loader_data != NULL, "invariant"); assert(THREAD->is_Java_thread(), "must be a JavaThread"); + bool changed_by_loadhook = false; + ResourceMark rm; HandleMark hm; JvmtiCachedClassFileData* cached_class_file = NULL; + ClassFileStream* old_stream = stream; + stream = prologue(stream, name, loader_data, @@ -124,8 +129,8 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream, ClassFileParser::BROADCAST, // publicity level CHECK_NULL); - instanceKlassHandle result = parser.create_instance_klass(CHECK_NULL); - assert(result == parser.create_instance_klass(THREAD), "invariant"); + instanceKlassHandle result = parser.create_instance_klass(old_stream != stream, CHECK_NULL); + assert(result == parser.create_instance_klass(old_stream != stream, THREAD), "invariant"); if (result.is_null()) { return NULL; @@ -136,5 +141,7 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream, result->set_cached_class_file(cached_class_file); } + TRACE_KLASS_CREATION(result, parser, THREAD); + return result; } diff --git a/hotspot/src/share/vm/classfile/moduleEntry.cpp b/hotspot/src/share/vm/classfile/moduleEntry.cpp new file mode 100644 index 00000000000..e86ed6acabf --- /dev/null +++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp @@ -0,0 +1,405 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "oops/symbol.hpp" +#include "prims/jni.h" +#include "runtime/handles.inline.hpp" +#include "runtime/safepoint.hpp" +#include "trace/traceMacros.hpp" +#include "utilities/events.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.inline.hpp" + +ModuleEntry* ModuleEntryTable::_javabase_module = NULL; + + +void ModuleEntry::set_location(Symbol* location) { + if (_location != NULL) { + // _location symbol's refcounts are managed by ModuleEntry, + // must decrement the old one before updating. + _location->decrement_refcount(); + } + + _location = location; + + if (location != NULL) { + location->increment_refcount(); + } +} + +void ModuleEntry::set_version(Symbol* version) { + if (_version != NULL) { + // _version symbol's refcounts are managed by ModuleEntry, + // must decrement the old one before updating. + _version->decrement_refcount(); + } + + _version = version; + + if (version != NULL) { + version->increment_refcount(); + } +} + +// Returns the shared ProtectionDomain +Handle ModuleEntry::shared_protection_domain() { + return Handle(JNIHandles::resolve(_pd)); +} + +// Set the shared ProtectionDomain atomically +void ModuleEntry::set_shared_protection_domain(ClassLoaderData *loader_data, + Handle pd_h) { + // Create a JNI handle for the shared ProtectionDomain and save it atomically. + // If someone beats us setting the _pd cache, the created JNI handle is destroyed. + jobject obj = loader_data->add_handle(pd_h); + if (Atomic::cmpxchg_ptr(obj, &_pd, NULL) != NULL) { + loader_data->remove_handle(obj); + } +} + +// Returns true if this module can read module m +bool ModuleEntry::can_read(ModuleEntry* m) const { + assert(m != NULL, "No module to lookup in this module's reads list"); + + // Unnamed modules read everyone and all modules + // read java.base. If either of these conditions + // hold, readability has been established. + if (!this->is_named() || + (m == ModuleEntryTable::javabase_module())) { + return true; + } + + MutexLocker m1(Module_lock); + if (!has_reads()) { + return false; + } else { + return _reads->contains(m); + } +} + +// Add a new module to this module's reads list +void ModuleEntry::add_read(ModuleEntry* m) { + MutexLocker m1(Module_lock); + if (m == NULL) { + set_can_read_all_unnamed(); + } else { + if (_reads == NULL) { + // Lazily create a module's reads list + _reads = new (ResourceObj::C_HEAP, mtClass)GrowableArray(MODULE_READS_SIZE, true); + } + _reads->append_if_missing(m); + } +} + +bool ModuleEntry::has_reads() const { + assert_locked_or_safepoint(Module_lock); + return ((_reads != NULL) && !_reads->is_empty()); +} + +// Purge dead module entries out of reads list. +void ModuleEntry::purge_reads() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + if (has_reads()) { + // Go backwards because this removes entries that are dead. + int len = _reads->length(); + for (int idx = len - 1; idx >= 0; idx--) { + ModuleEntry* module_idx = _reads->at(idx); + ClassLoaderData* cld = module_idx->loader(); + if (cld->is_unloading()) { + _reads->delete_at(idx); + } + } + } +} + +void ModuleEntry::module_reads_do(ModuleClosure* const f) { + assert_locked_or_safepoint(Module_lock); + assert(f != NULL, "invariant"); + + if (has_reads()) { + int reads_len = _reads->length(); + for (int i = 0; i < reads_len; ++i) { + f->do_module(_reads->at(i)); + } + } +} + +void ModuleEntry::delete_reads() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + delete _reads; + _reads = NULL; +} + +ModuleEntryTable::ModuleEntryTable(int table_size) + : Hashtable(table_size, sizeof(ModuleEntry)), _unnamed_module(NULL) +{ +} + +ModuleEntryTable::~ModuleEntryTable() { + assert_locked_or_safepoint(Module_lock); + + // Walk through all buckets and all entries in each bucket, + // freeing each entry. + for (int i = 0; i < table_size(); ++i) { + for (ModuleEntry* m = bucket(i); m != NULL;) { + ModuleEntry* to_remove = m; + // read next before freeing. + m = m->next(); + + ResourceMark rm; + log_debug(modules)("ModuleEntryTable: deleting module: %s", to_remove->name() != NULL ? + to_remove->name()->as_C_string() : UNNAMED_MODULE); + + // Clean out the C heap allocated reads list first before freeing the entry + to_remove->delete_reads(); + if (to_remove->name() != NULL) { + to_remove->name()->decrement_refcount(); + } + if (to_remove->version() != NULL) { + to_remove->version()->decrement_refcount(); + } + if (to_remove->location() != NULL) { + to_remove->location()->decrement_refcount(); + } + + // Unlink from the Hashtable prior to freeing + unlink_entry(to_remove); + FREE_C_HEAP_ARRAY(char, to_remove); + } + } + assert(number_of_entries() == 0, "should have removed all entries"); + assert(new_entry_free_list() == NULL, "entry present on ModuleEntryTable's free list"); + free_buckets(); +} + +void ModuleEntryTable::create_unnamed_module(ClassLoaderData* loader_data) { + assert_locked_or_safepoint(Module_lock); + + // Each ModuleEntryTable has exactly one unnamed module + if (loader_data->is_the_null_class_loader_data()) { + // For the boot loader, the java.lang.reflect.Module for the unnamed module + // is not known until a call to JVM_SetBootLoaderUnnamedModule is made. At + // this point initially create the ModuleEntry for the unnamed module. + _unnamed_module = new_entry(0, Handle(NULL), NULL, NULL, NULL, loader_data); + } else { + // For all other class loaders the java.lang.reflect.Module for their + // corresponding unnamed module can be found in the java.lang.ClassLoader object. + oop module = java_lang_ClassLoader::unnamedModule(loader_data->class_loader()); + _unnamed_module = new_entry(0, Handle(module), NULL, NULL, NULL, loader_data); + + // Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module + // object. + java_lang_reflect_Module::set_module_entry(module, _unnamed_module); + } + + // Add to bucket 0, no name to hash on + add_entry(0, _unnamed_module); +} + +ModuleEntry* ModuleEntryTable::new_entry(unsigned int hash, Handle module_handle, Symbol* name, + Symbol* version, Symbol* location, + ClassLoaderData* loader_data) { + assert_locked_or_safepoint(Module_lock); + ModuleEntry* entry = (ModuleEntry*) NEW_C_HEAP_ARRAY(char, entry_size(), mtClass); + + // Initialize everything BasicHashtable would + entry->set_next(NULL); + entry->set_hash(hash); + entry->set_literal(name); + + // Initialize fields specific to a ModuleEntry + entry->init(); + if (name != NULL) { + name->increment_refcount(); + } else { + // Unnamed modules can read all other unnamed modules. + entry->set_can_read_all_unnamed(); + } + + if (!module_handle.is_null()) { + entry->set_module(loader_data->add_handle(module_handle)); + } + + entry->set_loader(loader_data); + entry->set_version(version); + entry->set_location(location); + + TRACE_INIT_MODULE_ID(entry); + + return entry; +} + +void ModuleEntryTable::add_entry(int index, ModuleEntry* new_entry) { + assert_locked_or_safepoint(Module_lock); + Hashtable::add_entry(index, (HashtableEntry*)new_entry); +} + +ModuleEntry* ModuleEntryTable::locked_create_entry_or_null(Handle module_handle, + Symbol* module_name, + Symbol* module_version, + Symbol* module_location, + ClassLoaderData* loader_data) { + assert(module_name != NULL, "ModuleEntryTable locked_create_entry_or_null should never be called for unnamed module."); + assert_locked_or_safepoint(Module_lock); + // Check if module already exists. + if (lookup_only(module_name) != NULL) { + return NULL; + } else { + ModuleEntry* entry = new_entry(compute_hash(module_name), module_handle, module_name, + module_version, module_location, loader_data); + add_entry(index_for(module_name), entry); + return entry; + } +} + +// lookup_only by Symbol* to find a ModuleEntry. +ModuleEntry* ModuleEntryTable::lookup_only(Symbol* name) { + if (name == NULL) { + // Return this table's unnamed module + return unnamed_module(); + } + int index = index_for(name); + for (ModuleEntry* m = bucket(index); m != NULL; m = m->next()) { + if (m->name()->fast_compare(name) == 0) { + return m; + } + } + return NULL; +} + +// Remove dead modules from all other alive modules' reads list. +// This should only occur at class unloading. +void ModuleEntryTable::purge_all_module_reads() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + for (int i = 0; i < table_size(); i++) { + for (ModuleEntry* entry = bucket(i); + entry != NULL; + entry = entry->next()) { + entry->purge_reads(); + } + } +} + +void ModuleEntryTable::finalize_javabase(Handle module_handle, Symbol* version, Symbol* location) { + assert_locked_or_safepoint(Module_lock); + ClassLoaderData* boot_loader_data = ClassLoaderData::the_null_class_loader_data(); + ModuleEntryTable* module_table = boot_loader_data->modules(); + + assert(module_table != NULL, "boot loader's ModuleEntryTable not defined"); + + if (module_handle.is_null()) { + fatal("Unable to finalize module definition for java.base"); + } + + // Set java.lang.reflect.Module, version and location for java.base + ModuleEntry* jb_module = javabase_module(); + assert(jb_module != NULL, "java.base ModuleEntry not defined"); + jb_module->set_module(boot_loader_data->add_handle(module_handle)); + jb_module->set_version(version); + jb_module->set_location(location); + // Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object. + java_lang_reflect_Module::set_module_entry(module_handle(), jb_module); +} + +void ModuleEntryTable::patch_javabase_entries(Handle module_handle) { + if (module_handle.is_null()) { + fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module"); + } + + // Do the fixups for the basic primitive types + java_lang_Class::set_module(Universe::int_mirror(), module_handle()); + java_lang_Class::set_module(Universe::float_mirror(), module_handle()); + java_lang_Class::set_module(Universe::double_mirror(), module_handle()); + java_lang_Class::set_module(Universe::byte_mirror(), module_handle()); + java_lang_Class::set_module(Universe::bool_mirror(), module_handle()); + java_lang_Class::set_module(Universe::char_mirror(), module_handle()); + java_lang_Class::set_module(Universe::long_mirror(), module_handle()); + java_lang_Class::set_module(Universe::short_mirror(), module_handle()); + java_lang_Class::set_module(Universe::void_mirror(), module_handle()); + + // Do the fixups for classes that have already been created. + GrowableArray * list = java_lang_Class::fixup_module_field_list(); + int list_length = list->length(); + for (int i = 0; i < list_length; i++) { + Klass* k = list->at(i); + assert(k->is_klass(), "List should only hold classes"); + Thread* THREAD = Thread::current(); + KlassHandle kh(THREAD, k); + java_lang_Class::fixup_module_field(kh, module_handle); + } + + delete java_lang_Class::fixup_module_field_list(); + java_lang_Class::set_fixup_module_field_list(NULL); +} + +#ifndef PRODUCT +void ModuleEntryTable::print() { + tty->print_cr("Module Entry Table (table_size=%d, entries=%d)", + table_size(), number_of_entries()); + for (int i = 0; i < table_size(); i++) { + for (ModuleEntry* probe = bucket(i); + probe != NULL; + probe = probe->next()) { + probe->print(); + } + } +} + +void ModuleEntry::print() { + ResourceMark rm; + tty->print_cr("entry "PTR_FORMAT" name %s module "PTR_FORMAT" loader %s version %s location %s strict %s next "PTR_FORMAT, + p2i(this), + name() == NULL ? UNNAMED_MODULE : name()->as_C_string(), + p2i(module()), + loader()->loader_name(), + version() != NULL ? version()->as_C_string() : "NULL", + location() != NULL ? location()->as_C_string() : "NULL", + BOOL_TO_STR(!can_read_all_unnamed()), p2i(next())); +} +#endif + +void ModuleEntryTable::verify() { + int element_count = 0; + for (int i = 0; i < table_size(); i++) { + for (ModuleEntry* probe = bucket(i); + probe != NULL; + probe = probe->next()) { + probe->verify(); + element_count++; + } + } + guarantee(number_of_entries() == element_count, + "Verify of Module Entry Table failed"); + debug_only(verify_lookup_length((double)number_of_entries() / table_size())); +} + +void ModuleEntry::verify() { + guarantee(loader() != NULL, "A module entry must be associated with a loader."); +} diff --git a/hotspot/src/share/vm/classfile/moduleEntry.hpp b/hotspot/src/share/vm/classfile/moduleEntry.hpp new file mode 100644 index 00000000000..d67251c1869 --- /dev/null +++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp @@ -0,0 +1,230 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_CLASSFILE_MODULEENTRY_HPP +#define SHARE_VM_CLASSFILE_MODULEENTRY_HPP + +#include "classfile/classLoaderData.hpp" +#include "classfile/vmSymbols.hpp" +#include "oops/symbol.hpp" +#include "prims/jni.h" +#include "runtime/mutexLocker.hpp" +#include "trace/traceMacros.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.hpp" + +#define UNNAMED_MODULE "Unnamed Module" + +class ModuleClosure; + +// A ModuleEntry describes a module that has been defined by a call to JVM_DefineModule. +// It contains: +// - Symbol* containing the module's name. +// - pointer to the java.lang.reflect.Module for this module. +// - ClassLoaderData*, class loader of this module. +// - a growable array containg other module entries that this module can read. +// - a flag indicating if this module can read all unnamed modules. +// +// The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either +// data structure. +class ModuleEntry : public HashtableEntry { +private: + jobject _module; // java.lang.reflect.Module + jobject _pd; // java.security.ProtectionDomain, cached + // for shared classes from this module + ClassLoaderData* _loader; + GrowableArray* _reads; // list of modules that are readable by this module + Symbol* _version; // module version number + Symbol* _location; // module location + bool _can_read_all_unnamed; + bool _has_default_read_edges; // JVMTI redefine/retransform support + TRACE_DEFINE_TRACE_ID_FIELD; + enum {MODULE_READS_SIZE = 101}; // Initial size of list of modules that the module can read. + +public: + void init() { + _module = NULL; + _loader = NULL; + _pd = NULL; + _reads = NULL; + _version = NULL; + _location = NULL; + _can_read_all_unnamed = false; + _has_default_read_edges = false; + } + + Symbol* name() const { return literal(); } + void set_name(Symbol* n) { set_literal(n); } + + jobject module() const { return _module; } + void set_module(jobject j) { _module = j; } + + // The shared ProtectionDomain reference is set once the VM loads a shared class + // originated from the current Module. The referenced ProtectionDomain object is + // created by the ClassLoader when loading a class (shared or non-shared) from the + // Module for the first time. This ProtectionDomain object is used for all + // classes from the Module loaded by the same ClassLoader. + Handle shared_protection_domain(); + void set_shared_protection_domain(ClassLoaderData *loader_data, + Handle pd); + + ClassLoaderData* loader() const { return _loader; } + void set_loader(ClassLoaderData* l) { _loader = l; } + + Symbol* version() const { return _version; } + void set_version(Symbol* version); + + Symbol* location() const { return _location; } + void set_location(Symbol* location); + + bool can_read(ModuleEntry* m) const; + bool has_reads() const; + void add_read(ModuleEntry* m); + + bool is_named() const { return (literal() != NULL); } + + bool can_read_all_unnamed() const { + assert(is_named() || _can_read_all_unnamed == true, + "unnamed modules can always read all unnamed modules"); + return _can_read_all_unnamed; + } + + // Modules can only go from strict to loose. + void set_can_read_all_unnamed() { _can_read_all_unnamed = true; } + + bool has_default_read_edges() const { + return _has_default_read_edges; + } + + // Sets true and returns the previous value. + bool set_has_default_read_edges() { + MutexLocker ml(Module_lock); + bool prev = _has_default_read_edges; + _has_default_read_edges = true; + return prev; + } + + ModuleEntry* next() const { + return (ModuleEntry*)HashtableEntry::next(); + } + ModuleEntry** next_addr() { + return (ModuleEntry**)HashtableEntry::next_addr(); + } + + // iteration support for readability + void module_reads_do(ModuleClosure* const f); + + TRACE_DEFINE_TRACE_ID_METHODS; + + // Purge dead weak references out of reads list when any given class loader is unloaded. + void purge_reads(); + void delete_reads(); + + void print() PRODUCT_RETURN; + void verify(); +}; + +// Iterator interface +class ModuleClosure: public StackObj { + public: + virtual void do_module(ModuleEntry* const module) = 0; +}; + + +// The ModuleEntryTable is a Hashtable containing a list of all modules defined +// by a particular class loader. Each module is represented as a ModuleEntry node. +// +// Each ModuleEntryTable contains a _javabase_module field which allows for the +// creation of java.base's ModuleEntry very early in bootstrapping before the +// corresponding JVM_DefineModule call for java.base occurs during module system +// initialization. Setting up java.base's ModuleEntry early enables classes, +// loaded prior to the module system being initialized to be created with their +// PackageEntry node's correctly pointing at java.base's ModuleEntry. No class +// outside of java.base is allowed to be loaded pre-module system initialization. +// +// The ModuleEntryTable's lookup is lock free. +// +class ModuleEntryTable : public Hashtable { + friend class VMStructs; +public: + enum Constants { + _moduletable_entry_size = 109 // number of entries in module entry table + }; + +private: + static ModuleEntry* _javabase_module; + ModuleEntry* _unnamed_module; + + ModuleEntry* new_entry(unsigned int hash, Handle module_handle, Symbol* name, Symbol* version, + Symbol* location, ClassLoaderData* class_loader); + void add_entry(int index, ModuleEntry* new_entry); + + int entry_size() const { return BasicHashtable::entry_size(); } + + ModuleEntry** bucket_addr(int i) { + return (ModuleEntry**)Hashtable::bucket_addr(i); + } + + static unsigned int compute_hash(Symbol* name) { return ((name == NULL) ? 0 : (unsigned int)(name->identity_hash())); } + int index_for(Symbol* name) const { return hash_to_index(compute_hash(name)); } + +public: + ModuleEntryTable(int table_size); + ~ModuleEntryTable(); + + ModuleEntry* bucket(int i) { + return (ModuleEntry*)Hashtable::bucket(i); + } + + // Create module in loader's module entry table, if already exists then + // return null. Assume Module_lock has been locked by caller. + ModuleEntry* locked_create_entry_or_null(Handle module_handle, + Symbol* module_name, + Symbol* module_version, + Symbol* module_location, + ClassLoaderData* loader_data); + + // Only lookup module within loader's module entry table. The table read is lock-free. + ModuleEntry* lookup_only(Symbol* name); + + // purge dead weak references out of reads list + void purge_all_module_reads(); + + // Special handling for unnamed module, one per class loader's ModuleEntryTable + void create_unnamed_module(ClassLoaderData* loader_data); + ModuleEntry* unnamed_module() { return _unnamed_module; } + + // Special handling for java.base + static ModuleEntry* javabase_module() { return _javabase_module; } + static void set_javabase_module(ModuleEntry* java_base) { _javabase_module = java_base; } + static bool javabase_defined() { return ((_javabase_module != NULL) && + (_javabase_module->module() != NULL)); } + static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location); + static void patch_javabase_entries(Handle module_handle); + + void print() PRODUCT_RETURN; + void verify(); +}; + +#endif // SHARE_VM_CLASSFILE_MODULEENTRY_HPP diff --git a/hotspot/src/share/vm/classfile/modules.cpp b/hotspot/src/share/vm/classfile/modules.cpp new file mode 100644 index 00000000000..a4a23d44e49 --- /dev/null +++ b/hotspot/src/share/vm/classfile/modules.cpp @@ -0,0 +1,964 @@ +/* +* 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. +* +*/ + +#include "precompiled.hpp" +#include "classfile/classFileParser.hpp" +#include "classfile/classLoader.hpp" +#include "classfile/classLoaderData.inline.hpp" +#include "classfile/javaAssertions.hpp" +#include "classfile/javaClasses.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" +#include "classfile/packageEntry.hpp" +#include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" +#include "classfile/vmSymbols.hpp" +#include "logging/log.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" +#include "runtime/reflection.hpp" +#include "utilities/utf8.hpp" + +static bool verify_module_name(char *module_name) { + if (module_name == NULL) return false; + int len = (int)strlen(module_name); + return (len > 0 && len <= Symbol::max_length() && + UTF8::is_legal_utf8((unsigned char *)module_name, len, false) && + ClassFileParser::verify_unqualified_name(module_name, len, + ClassFileParser::LegalModule)); +} + +bool Modules::verify_package_name(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) && + ClassFileParser::verify_unqualified_name(package_name, len, + ClassFileParser::LegalClass)); +} + +static char* get_module_name(oop module, TRAPS) { + oop name_oop = java_lang_reflect_Module::name(module); + if (name_oop == NULL) { + THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), "Null module name"); + } + char* module_name = java_lang_String::as_utf8_string(name_oop); + if (!verify_module_name(module_name)) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid module name: %s", + module_name != NULL ? module_name : "NULL")); + } + return module_name; +} + +static const char* get_module_version(jstring version) { + if (version == NULL) { + return NULL; + } + return java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(version)); +} + +static ModuleEntryTable* get_module_entry_table(Handle h_loader, TRAPS) { + // This code can be called during start-up, before the classLoader's classLoader data got + // created. So, call register_loader() to make sure the classLoader data gets created. + ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); + return loader_cld->modules(); +} + +static PackageEntryTable* get_package_entry_table(Handle h_loader, TRAPS) { + // This code can be called during start-up, before the classLoader's classLoader data got + // created. So, call register_loader() to make sure the classLoader data gets created. + ClassLoaderData *loader_cld = SystemDictionary::register_loader(h_loader, CHECK_NULL); + return loader_cld->packages(); +} + +static ModuleEntry* get_module_entry(jobject module, TRAPS) { + Handle module_h(THREAD, JNIHandles::resolve(module)); + if (!java_lang_reflect_Module::is_instance(module_h())) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), "Bad module object"); + } + return java_lang_reflect_Module::module_entry(module_h(), CHECK_NULL); +} + +static PackageEntry* get_package_entry(ModuleEntry* module_entry, jstring package, 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()->packages(); + assert(package_entry_table != NULL, "Unexpected null package entry table"); + return package_entry_table->lookup_only(pkg_symbol); +} + +static PackageEntry* get_package_entry_by_name(Symbol* package, + Handle h_loader, + TRAPS) { + if (package != NULL) { + ResourceMark rm(THREAD); + if (Modules::verify_package_name(package->as_C_string())) { + PackageEntryTable* const package_entry_table = + get_package_entry_table(h_loader, CHECK_NULL); + assert(package_entry_table != NULL, "Unexpected null package entry table"); + return package_entry_table->lookup_only(package); + } + } + return NULL; +} + +// Check if -Xpatch: was specified. If so, prepend each /module_name, +// if it exists, to bootpath so boot loader can find the class files. Also, if +// using exploded modules, append /modules/module_name, if it exists, +// to bootpath so that its class files can be found by the boot loader. +static void add_to_boot_loader_list(char *module_name, TRAPS) { + // java.base should be handled by argument parsing. + assert(strcmp(module_name, "java.base") != 0, "Unexpected java.base module name"); + char file_sep = os::file_separator()[0]; + size_t module_len = strlen(module_name); + + // If -Xpatch is set then add /module_name paths. + char** patch_dirs = Arguments::patch_dirs(); + if (patch_dirs != NULL) { + int dir_count = Arguments::patch_dirs_count(); + for (int x = 0; x < dir_count; x++) { + // Really shouldn't be NULL, but check can't hurt + if (patch_dirs[x] != NULL) { + size_t len = strlen(patch_dirs[x]); + if (len != 0) { // Ignore empty strings. + len = len + module_len + 2; + char* prefix_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); + jio_snprintf(prefix_path, len, "%s%c%s", patch_dirs[x], file_sep, module_name); + + // See if Xpatch module path exists. + struct stat st; + if ((os::stat(prefix_path, &st) != 0)) { + FREE_C_HEAP_ARRAY(char, prefix_path); + } else { + { + HandleMark hm; + Handle loader_lock = Handle(THREAD, SystemDictionary::system_loader_lock()); + ObjectLocker ol(loader_lock, THREAD); + ClassLoader::prepend_to_list(prefix_path); + } + log_info(classload)("opened: -Xpatch %s", prefix_path); + } + } + } + } + } + + // If "modules" jimage does not exist then assume exploded form + // ${java.home}/modules/ + char* path = NULL; + if (!ClassLoader::has_jimage()) { + const char* home = Arguments::get_java_home(); + size_t len = strlen(home) + module_len + 32; + path = NEW_C_HEAP_ARRAY(char, len, mtInternal); + jio_snprintf(path, len, "%s%cmodules%c%s", home, file_sep, file_sep, module_name); + struct stat st; + // See if exploded module path exists. + if ((os::stat(path, &st) != 0)) { + FREE_C_HEAP_ARRAY(char, path); + path = NULL; + } + } + + if (path != NULL) { + HandleMark hm; + Handle loader_lock = Handle(THREAD, SystemDictionary::system_loader_lock()); + ObjectLocker ol(loader_lock, THREAD); + + log_info(classload)("opened: %s", path); + ClassLoader::add_to_list(path); + } +} + +bool Modules::is_package_defined(Symbol* package, Handle h_loader, TRAPS) { + PackageEntry* res = get_package_entry_by_name(package, h_loader, CHECK_false); + return res != NULL; +} + +static void define_javabase_module(jobject module, jstring version, + jstring location, jobjectArray packages, TRAPS) { + ResourceMark rm(THREAD); + + Handle module_handle(THREAD, JNIHandles::resolve(module)); + + // Obtain java.base's module version + const char* module_version = get_module_version(version); + TempNewSymbol version_symbol; + if (module_version != NULL) { + version_symbol = SymbolTable::new_symbol(module_version, CHECK); + } else { + version_symbol = NULL; + } + + // Obtain java.base's location + const char* module_location = NULL; + TempNewSymbol location_symbol = NULL; + if (location != NULL) { + module_location = + java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); + if (module_location != NULL) { + location_symbol = SymbolTable::new_symbol(module_location, CHECK); + } + } + + 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"); + } + char *package_name = java_lang_String::as_utf8_string(string_obj); + if (!Modules::verify_package_name(package_name)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid package name: %s for module: java.base", package_name)); + } + Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); + // append_if_missing() returns FALSE if entry already exists. + if (!pkg_list->append_if_missing(pkg_symbol)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Duplicate package name: %s for module java.base", + package_name)); + } + } + + // Validate java_base's loader is the boot loader. + oop loader = java_lang_reflect_Module::loader(module_handle()); + if (loader != NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader must be the boot class loader"); + } + Handle h_loader = Handle(THREAD, loader); + + // Ensure the boot loader's PackageEntryTable has been created + PackageEntryTable* package_table = get_package_entry_table(h_loader, CHECK); + assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table"); + + // Ensure java.base's ModuleEntry has been created + assert(ModuleEntryTable::javabase_module() != NULL, "No ModuleEntry for java.base"); + + { + MutexLocker m1(Module_lock, THREAD); + + // Verify that all java.base packages created during bootstrapping are in + // pkg_list. If any are not in pkg_list, than a non-java.base class was + // loaded erroneously pre java.base module definition. + package_table->verify_javabase_packages(pkg_list); + + // loop through and add any new packages for java.base + PackageEntry* pkg; + for (int x = 0; x < pkg_list->length(); x++) { + // Some of java.base's packages were added early in bootstrapping, ignore duplicates. + if (package_table->lookup_only(pkg_list->at(x)) == NULL) { + pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_module()); + assert(pkg != NULL, "Unable to create a java.base package entry"); + } + // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of + // the Symbol* that was created above for each package. The refcount was incremented + // by SymbolTable::new_symbol and as well by the PackageEntry creation. + pkg_list->at(x)->decrement_refcount(); + } + + // Finish defining java.base's ModuleEntry + ModuleEntryTable::finalize_javabase(module_handle, version_symbol, location_symbol); + } + + log_debug(modules)("define_javabase_module(): Definition of module: java.base," + " version: %s, location: %s, package #: %d", + module_version != NULL ? module_version : "NULL", + module_location != NULL ? module_location : "NULL", + pkg_list->length()); + + // packages defined to java.base + for (int x = 0; x < pkg_list->length(); x++) { + log_trace(modules)("define_javabase_module(): creation of package %s for module java.base", + (pkg_list->at(x))->as_C_string()); + } + + // Patch any previously loaded classes' module field with java.base's jlr.Module. + ModuleEntryTable::patch_javabase_entries(module_handle); +} + +void Modules::define_module(jobject module, jstring version, + jstring location, jobjectArray packages, TRAPS) { + ResourceMark rm(THREAD); + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); + } + Handle module_handle(THREAD, JNIHandles::resolve(module)); + if (!java_lang_reflect_Module::is_subclass(module_handle->klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is not a subclass of java.lang.reflect.Module"); + } + + char* module_name = get_module_name(module_handle(), CHECK); + if (module_name == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Module name cannot be null"); + } + + // Special handling of java.base definition + if (strcmp(module_name, "java.base") == 0) { + define_javabase_module(module, version, location, packages, CHECK); + return; + } + + const char* module_version = get_module_version(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(), + err_msg("Bad package name for module: %s", module_name)); + } + char *package_name = java_lang_String::as_utf8_string(string_obj); + if (!verify_package_name(package_name)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Invalid package name: %s for module: %s", + package_name, module_name)); + } + Symbol* pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); + // append_if_missing() returns FALSE if entry already exists. + if (!pkg_list->append_if_missing(pkg_symbol)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Duplicate package name: %s for module %s", + package_name, module_name)); + } + } + + oop loader = java_lang_reflect_Module::loader(module_handle()); + // Make sure loader is not the sun.reflect.DelegatingClassLoader. + if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader is an invalid delegating class loader"); + } + Handle h_loader = Handle(THREAD, loader); + + // Check that loader is a subclass of java.lang.ClassLoader. + if (loader != NULL && !java_lang_ClassLoader::is_subclass(h_loader->klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader is not a subclass of java.lang.ClassLoader"); + } + + ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK); + assert(module_table != NULL, "module entry table shouldn't be null"); + + // 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. + TempNewSymbol version_symbol; + if (module_version != NULL) { + version_symbol = SymbolTable::new_symbol(module_version, CHECK); + } else { + version_symbol = NULL; + } + + // Create symbol* entry for module location. + const char* module_location = NULL; + TempNewSymbol location_symbol = NULL; + if (location != NULL) { + module_location = + java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(location)); + if (module_location != NULL) { + location_symbol = SymbolTable::new_symbol(module_location, CHECK); + } + } + + ClassLoaderData* loader_data = ClassLoaderData::class_loader_data_or_null(h_loader()); + assert(loader_data != NULL, "class loader data shouldn't be null"); + + PackageEntryTable* package_table = NULL; + { + MutexLocker ml(Module_lock, THREAD); + + if (num_packages > 0) { + package_table = get_package_entry_table(h_loader, CHECK); + assert(package_table != NULL, "Missing package_table"); + + // 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) { + // 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; + } + } + } // if (num_packages > 0)... + + // Add the module and its packages. + if (!dupl_modules && dupl_pkg_index == -1) { + // 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); + + if (module_entry == NULL) { + dupl_modules = true; + } else { + // Add the packages. + assert(pkg_list->length() == 0 || package_table != NULL, "Bad package table"); + PackageEntry* pkg; + for (int y = 0; y < pkg_list->length(); y++) { + pkg = package_table->locked_create_entry_or_null(pkg_list->at(y), module_entry); + assert(pkg != NULL, "Unable to create a module's package entry"); + + // Unable to have a GrowableArray of TempNewSymbol. Must decrement the refcount of + // the Symbol* that was created above for each package. The refcount was incremented + // by SymbolTable::new_symbol and as well by the PackageEntry creation. + pkg_list->at(y)->decrement_refcount(); + } + + // Store pointer to ModuleEntry record in java.lang.reflect.Module object. + java_lang_reflect_Module::set_module_entry(module_handle(), module_entry); + } + } + } // Release the lock + + // any errors ? + if (dupl_modules) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + 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)); + } + + if (log_is_enabled(Debug, modules)) { + outputStream* logst = LogHandle(modules)::debug_stream(); + logst->print("define_module(): creation of module: %s, version: %s, location: %s, ", + module_name, module_version != NULL ? module_version : "NULL", + module_location != NULL ? module_location : "NULL"); + loader_data->print_value_on(logst); + logst->print_cr(", package #: %d", pkg_list->length()); + for (int y = 0; y < pkg_list->length(); y++) { + log_trace(modules)("define_module(): creation of package %s for module %s", + (pkg_list->at(y))->as_C_string(), module_name); + } + } + + if (loader == NULL && !Universe::is_module_initialized()) { + // Now that the module is defined, if it is in the bootloader, make sure that + // its classes can be found. Check if -Xpatch: was specified. If + // so prepend /module_name, if it exists, to bootpath. Also, if using + // exploded modules, prepend /modules/module_name, if it exists, + // to bootpath. + add_to_boot_loader_list(module_name, CHECK); + } +} + +void Modules::set_bootloader_unnamed_module(jobject module, TRAPS) { + ResourceMark rm(THREAD); + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), "Null module object"); + } + Handle module_handle(THREAD, JNIHandles::resolve(module)); + if (!java_lang_reflect_Module::is_subclass(module_handle->klass())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is not a subclass of java.lang.reflect.Module"); + } + + // Ensure that this is an unnamed module + oop name = java_lang_reflect_Module::name(module_handle()); + if (name != NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "boot loader's unnamed module's java.lang.reflect.Module has a name"); + } + + // Validate java_base's loader is the boot loader. + oop loader = java_lang_reflect_Module::loader(module_handle()); + if (loader != NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader must be the boot class loader"); + } + Handle h_loader = Handle(THREAD, loader); + + log_debug(modules)("set_bootloader_unnamed_module(): recording unnamed module for boot loader"); + + // Ensure the boot loader's PackageEntryTable has been created + ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK); + + // Set java.lang.reflect.Module for the boot loader's unnamed module + ModuleEntry* unnamed_module = module_table->unnamed_module(); + assert(unnamed_module != NULL, "boot loader's unnamed ModuleEntry not defined"); + unnamed_module->set_module(ClassLoaderData::the_null_class_loader_data()->add_handle(module_handle)); + // Store pointer to the ModuleEntry in the unnamed module's java.lang.reflect.Module object. + 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) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "package is null"); + } + if (from_module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "from_module is null"); + } + ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK); + if (from_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "from_module cannot be found"); + } + + // All packages in unnamed are exported by default. + if (!from_module_entry->is_named()) return; + + ModuleEntry* to_module_entry; + if (to_module == NULL) { + to_module_entry = NULL; // It's an unqualified export. + } else { + to_module_entry = get_module_entry(to_module, CHECK); + if (to_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "to_module is invalid"); + } + } + + PackageEntry *package_entry = get_package_entry(from_module_entry, package, 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 : "", + from_module_entry->name()->as_C_string())); + } + if (package_entry->module() != from_module_entry) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package: %s found in module %s, not in from_module: %s", + package_entry->name()->as_C_string(), + package_entry->module()->name()->as_C_string(), + from_module_entry->name()->as_C_string())); + } + + log_debug(modules)("add_module_exports(): package %s in module %s is exported to module %s", + package_entry->name()->as_C_string(), + from_module_entry->name()->as_C_string(), + to_module_entry == NULL ? "NULL" : + to_module_entry->is_named() ? + to_module_entry->name()->as_C_string() : UNNAMED_MODULE); + + // Do nothing if modules are the same or if package is already exported unqualifiedly. + if (from_module_entry != to_module_entry && !package_entry->is_unqual_exported()) { + package_entry->set_exported(to_module_entry); + } +} + + +void Modules::add_module_exports_qualified(jobject from_module, jstring package, + jobject to_module, TRAPS) { + if (to_module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "to_module is null"); + } + add_module_exports(from_module, package, to_module, CHECK); +} + +void Modules::add_reads_module(jobject from_module, jobject to_module, TRAPS) { + if (from_module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "from_module is null"); + } + + ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK); + if (from_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "from_module is not valid"); + } + + ModuleEntry* to_module_entry; + if (to_module != NULL) { + to_module_entry = get_module_entry(to_module, CHECK); + if (to_module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "to_module is invalid"); + } + } else { + to_module_entry = NULL; + } + + ResourceMark rm(THREAD); + log_debug(modules)("add_reads_module(): Adding read from module %s to module %s", + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE, + to_module_entry == NULL ? "all unnamed" : + (to_module_entry->is_named() ? + to_module_entry->name()->as_C_string() : UNNAMED_MODULE)); + + // if modules are the same or if from_module is unnamed then no need to add the read. + if (from_module_entry != to_module_entry && from_module_entry->is_named()) { + from_module_entry->add_read(to_module_entry); + } +} + +jboolean Modules::can_read_module(jobject asking_module, jobject target_module, TRAPS) { + if (asking_module == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "asking_module is null", JNI_FALSE); + } + + ModuleEntry* asking_module_entry = get_module_entry(asking_module, CHECK_false); + if (asking_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "asking_module is invalid", JNI_FALSE); + } + + // Calling can_read_all_unnamed() with NULL tests if a module is loose. + if (target_module == NULL) { + return asking_module_entry->can_read_all_unnamed(); + } + + ModuleEntry* target_module_entry = get_module_entry(target_module, CHECK_false); + if (target_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "target_module is invalid", JNI_FALSE); + } + + ResourceMark rm(THREAD); + log_debug(modules)("can_read_module(): module %s trying to read module %s, allowed = %s", + asking_module_entry->is_named() ? + asking_module_entry->name()->as_C_string() : UNNAMED_MODULE, + target_module_entry->is_named() ? + target_module_entry->name()->as_C_string() : UNNAMED_MODULE, + BOOL_TO_STR(asking_module_entry == target_module_entry || + (asking_module_entry->can_read_all_unnamed() && + !target_module_entry->is_named()) || + asking_module_entry->can_read(target_module_entry))); + + // Return true if: + // 1. the modules are the same, or + // 2. the asking_module is unnamed (because unnamed modules read everybody), or + // 3. the asking_module is loose and the target module is unnamed, or + // 4. if can_read() returns true. + if (asking_module_entry == target_module_entry || + (asking_module_entry->can_read_all_unnamed() && !target_module_entry->is_named())) { + return true; + } + return asking_module_entry->can_read(target_module_entry); +} + +jboolean Modules::is_exported_to_module(jobject from_module, jstring package, + jobject to_module, TRAPS) { + if (package == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "package is null", JNI_FALSE); + } + if (from_module == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "from_module is null", JNI_FALSE); + } + ModuleEntry* from_module_entry = get_module_entry(from_module, CHECK_false); + if (from_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "from_module is invalid", JNI_FALSE); + } + ModuleEntry* to_module_entry; + if (to_module == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "to_module is null", JNI_FALSE); + } + to_module_entry = get_module_entry(to_module, CHECK_false); + if (to_module_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "to_module is invalid", JNI_FALSE); + } + + PackageEntry *package_entry = get_package_entry(from_module_entry, package, + CHECK_false); + ResourceMark rm(THREAD); + if (package_entry == NULL) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package not found in from_module: %s", + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE), + JNI_FALSE); + } + if (package_entry->module() != from_module_entry) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package: %s found in module %s, not in from_module: %s", + package_entry->name()->as_C_string(), + package_entry->module()->is_named() ? + package_entry->module()->name()->as_C_string() : UNNAMED_MODULE, + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE), + JNI_FALSE); + } + + log_debug(modules)("is_exported_to_module: package %s from module %s checking" + " if exported to module %s, exported? = %s", + package_entry->name()->as_C_string(), + from_module_entry->is_named() ? + from_module_entry->name()->as_C_string() : UNNAMED_MODULE, + to_module_entry->is_named() ? + to_module_entry->name()->as_C_string() : UNNAMED_MODULE, + BOOL_TO_STR(!from_module_entry->is_named() || + package_entry->is_unqual_exported() || + from_module_entry == to_module_entry || + package_entry->is_qexported_to(to_module_entry))); + + // Return true if: + // 1. from_module is unnamed because unnamed modules export all their packages (by default), or + // 2. if the package is unqualifiedly exported, or + // 3. if the modules are the same, or + // 4. if the package is exported to to_module + return (!from_module_entry->is_named() || + package_entry->is_unqual_exported() || + from_module_entry == to_module_entry || + package_entry->is_qexported_to(to_module_entry)); +} + +// This method is called by JFR and JNI. +jobject Modules::get_module(jclass clazz, TRAPS) { + assert(ModuleEntryTable::javabase_defined(), "Attempt to call get_module before java.base is defined"); + + if (clazz == NULL) { + THROW_MSG_(vmSymbols::java_lang_NullPointerException(), + "class is null", JNI_FALSE); + } + oop mirror = JNIHandles::resolve_non_null(clazz); + if (mirror == NULL) { + log_debug(modules)("get_module(): no mirror, returning NULL"); + return NULL; + } + if (!java_lang_Class::is_instance(mirror)) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Invalid class", JNI_FALSE); + } + + oop module = java_lang_Class::module(mirror); + + assert(module != NULL, "java.lang.Class module field not set"); + assert(java_lang_reflect_Module::is_subclass(module->klass()), "Module is not a java.lang.reflect.Module"); + + if (log_is_enabled(Debug, modules)) { + ResourceMark rm(THREAD); + outputStream* logst = LogHandle(modules)::debug_stream(); + Klass* klass = java_lang_Class::as_Klass(mirror); + oop module_name = java_lang_reflect_Module::name(module); + if (module_name != NULL) { + logst->print("get_module(): module "); + java_lang_String::print(module_name, tty); + } else { + logst->print("get_module(): Unamed Module"); + } + if (klass != NULL) { + logst->print_cr(" for class %s", klass->external_name()); + } else { + logst->print_cr(" for primitive class"); + } + } + + return JNIHandles::make_local(THREAD, module); +} + + +jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRAPS) { + ResourceMark rm(THREAD); + assert(ModuleEntryTable::javabase_defined(), + "Attempt to call get_module_from_pkg before java.base is defined"); + + if (NULL == package) { + 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. + if (loader != NULL && !java_lang_ClassLoader::is_subclass(h_loader->klass())) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Class loader is not a subclass of java.lang.ClassLoader", JNI_FALSE); + } + + if (strlen(package_str) == 0) { + // Return the unnamed module + ModuleEntryTable* module_table = get_module_entry_table(h_loader, CHECK_NULL); + if (NULL == module_table) return NULL; + const ModuleEntry* const unnamed_module = module_table->unnamed_module(); + return JNIHandles::make_local(THREAD, JNIHandles::resolve(unnamed_module->module())); + + } else { + TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL); + return get_module(package_sym, h_loader, CHECK_NULL); + } + return NULL; +} + + +// This method is called by JFR and by the above method. +jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) { + const PackageEntry* const pkg_entry = + get_package_entry_by_name(package_name, h_loader, THREAD); + const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL); + + if (module_entry != NULL && + module_entry->module() != NULL) { + return JNIHandles::make_local(THREAD, JNIHandles::resolve(module_entry->module())); + } + + return NULL; +} + +void Modules::add_module_package(jobject module, jstring package, TRAPS) { + ResourceMark rm(THREAD); + + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "module is null"); + } + if (package == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "package is null"); + } + ModuleEntry* module_entry = get_module_entry(module, CHECK); + if (module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is invalid"); + } + if (!module_entry->is_named()) { + 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)); + } + + log_debug(modules)("add_module_package(): Adding package %s to module %s", + package_name, module_entry->name()->as_C_string()); + + TempNewSymbol pkg_symbol = SymbolTable::new_symbol(package_name, CHECK); + PackageEntryTable* package_table = module_entry->loader()->packages(); + assert(package_table != NULL, "Missing package_table"); + + bool pkg_exists = false; + { + 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)) { + 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)); + } +} + +// Export package in module to all unnamed modules. +void Modules::add_module_exports_to_all_unnamed(jobject module, jstring package, TRAPS) { + if (module == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "module is null"); + } + if (package == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "package is null"); + } + ModuleEntry* module_entry = get_module_entry(module, CHECK); + if (module_entry == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "module is invalid"); + } + + if (module_entry->is_named()) { // No-op for unnamed module. + PackageEntry *package_entry = get_package_entry(module_entry, package, 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 : "", + module_entry->name()->as_C_string())); + } + if (package_entry->module() != module_entry) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + err_msg("Package: %s found in module %s, not in module: %s", + package_entry->name()->as_C_string(), + package_entry->module()->name()->as_C_string(), + module_entry->name()->as_C_string())); + } + + log_debug(modules)("add_module_exports_to_all_unnamed(): package %s in module" + " %s is exported to all unnamed modules", + 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(); + } + } +} diff --git a/hotspot/src/share/vm/classfile/modules.hpp b/hotspot/src/share/vm/classfile/modules.hpp new file mode 100644 index 00000000000..d8abd7552bc --- /dev/null +++ b/hotspot/src/share/vm/classfile/modules.hpp @@ -0,0 +1,151 @@ +/* +* 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. +* +*/ + +#ifndef SHARE_VM_CLASSFILE_MODULES_HPP +#define SHARE_VM_CLASSFILE_MODULES_HPP + +#include "memory/allocation.hpp" +#include "runtime/handles.hpp" + +class Symbol; + +class Modules : AllStatic { + +public: + // define_module defines a module containing the specified packages. It binds the + // module to its class loader by creating the ModuleEntry record in the + // ClassLoader's ModuleEntry table, and creates PackageEntry records in the class + // loader's PackageEntry table. As in JVM_DefineClass the jstring format for all + // package names must use "/" and not "." + // + // IllegalArgumentExceptions are thrown for the following : + // * Module's Class loader is not a subclass of java.lang.ClassLoader + // * Module's Class loader already has a module with that name + // * Module's Class loader has already defined types for any of the module's packages + // * Module_name is syntactically bad + // * Packages contains an illegal package name + // * Packages contains a duplicate package name + // * A package already exists in another module for this class loader + // * Module is an unnamed module + // NullPointerExceptions are thrown if module is null. + static void define_module(jobject module, jstring version, + jstring location, jobjectArray packages, TRAPS); + + // Provides the java.lang.reflect.Module for the unnamed module defined + // to the boot loader. + // + // IllegalArgumentExceptions are thrown for the following : + // * Module has a name + // * Module is not a subclass of java.lang.reflect.Module + // * Module's class loader is not the boot loader + // NullPointerExceptions are thrown if module is null. + static void set_bootloader_unnamed_module(jobject module, TRAPS); + + // This either does a qualified export of package in module from_module to module + // to_module or, if to_module is null, does an unqualified export of package. + // The format for the package name must use "/' not ".". + // + // Error conditions causing IlegalArgumentException to be throw : + // * Module from_module does not exist + // * Module to_module is not null and does not exist + // * 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); + + // This does a qualified export of package in module from_module to module + // to_module. The format for the package name must use "/' not ".". + // + // Error conditions causing IlegalArgumentException to be throw : + // * Module from_module does not exist + // * Module to_module does not exist + // * 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); + + // 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. + // If to_module is null then from_module is marked as a loose module (meaning that + // from_module can read all current and future unnamed modules). + // An IllegalArgumentException is thrown if from_module is null or either (non-null) + // module does not exist. + static void add_reads_module(jobject from_module, jobject to_module, TRAPS); + + // can_read_module returns TRUE if module asking_module can read module target_module, + // or if they are the same module, or if the asking_module is loose and target_module + // is null. + // + // Throws IllegalArgumentException if: + // * either asking_module or target_module is not a java.lang.reflect.Module + static jboolean can_read_module(jobject asking_module, jobject target_module, TRAPS); + + // If package is valid then this returns TRUE if module from_module exports + // package to module to_module, if from_module and to_module are the same + // module, or if package is exported without qualification. + // + // IllegalArgumentException is throw if: + // * Either to_module or from_module does not exist + // * package is syntactically incorrect + // * package is not in from_module + static jboolean is_exported_to_module(jobject from_module, jstring package, jobject to_module, TRAPS); + + // Return the java.lang.reflect.Module object for this class object. + static jobject get_module(jclass clazz, TRAPS); + + // Return the java.lang.reflect.Module object for this class loader and package. + // Returns NULL if the class loader has not loaded any classes in the package. + // The package should contain /'s, not .'s, as in java/lang, not java.lang. + // 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); + + // If package is defined by loader, return the + // java.lang.reflect.Module object for the module in which the package is defined. + // Returns NULL if package is invalid or not defined by loader. + static jobject get_module(Symbol* package_name, Handle h_loader, TRAPS); + + // This adds package to module. + // It throws IllegalArgumentException if: + // * Module is bad + // * 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); + + // 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); + + // Return TRUE if package_name is syntactically valid, false otherwise. + static bool verify_package_name(char *package_name); + + // Return TRUE iff package is defined by loader + static bool is_package_defined(Symbol* package_name, Handle h_loader, TRAPS); +}; + +#endif // SHARE_VM_CLASSFILE_MODULES_HPP diff --git a/hotspot/src/share/vm/classfile/packageEntry.cpp b/hotspot/src/share/vm/classfile/packageEntry.cpp new file mode 100644 index 00000000000..b3117d483c1 --- /dev/null +++ b/hotspot/src/share/vm/classfile/packageEntry.cpp @@ -0,0 +1,322 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" +#include "memory/resourceArea.hpp" +#include "oops/symbol.hpp" +#include "runtime/handles.inline.hpp" +#include "trace/traceMacros.hpp" +#include "utilities/events.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.inline.hpp" + +// Return true if this package is exported to m. +bool PackageEntry::is_qexported_to(ModuleEntry* m) const { + assert(m != NULL, "No module to lookup in this package's qualified exports list"); + MutexLocker m1(Module_lock); + if (!_is_exported) { + return false; + } else if (_is_exported_allUnnamed && !m->is_named()) { + return true; + } else if (_qualified_exports == NULL) { + return false; + } else { + return _qualified_exports->contains(m); + } +} + +// Add a module to the package's qualified export list. +void PackageEntry::add_qexport(ModuleEntry* m) { + assert_locked_or_safepoint(Module_lock); + assert(_is_exported == true, "Adding a qualified export to a package that is not exported"); + if (_qualified_exports == NULL) { + // Lazily create a package's qualified exports list. + // Initial size is small, do not anticipate export lists to be large. + _qualified_exports = + new (ResourceObj::C_HEAP, mtClass) GrowableArray(QUAL_EXP_SIZE, true); + } + _qualified_exports->append_if_missing(m); +} + +// Set the package's exported state based on the value of the ModuleEntry. +void PackageEntry::set_exported(ModuleEntry* m) { + MutexLocker m1(Module_lock); + if (is_unqual_exported()) { + // An exception could be thrown, but choose to simply ignore. + // Illegal to convert an unqualified exported package to be qualifiedly exported + return; + } + + if (m == NULL) { + // NULL indicates the package is being unqualifiedly exported + if (_is_exported && _qualified_exports != NULL) { + // 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 + set_unqual_exported(); + + } else { + // Add the exported module + _is_exported = true; + add_qexport(m); + } +} + +// Remove dead module entries within the package's exported list. +void PackageEntry::purge_qualified_exports() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + if (_qualified_exports != NULL) { + // Go backwards because this removes entries that are dead. + int len = _qualified_exports->length(); + for (int idx = len - 1; idx >= 0; idx--) { + ModuleEntry* module_idx = _qualified_exports->at(idx); + ClassLoaderData* cld = module_idx->loader(); + if (cld->is_unloading()) { + _qualified_exports->delete_at(idx); + } + } + } +} + +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; +} + +PackageEntryTable::PackageEntryTable(int table_size) + : Hashtable(table_size, sizeof(PackageEntry)) +{ +} + +PackageEntryTable::~PackageEntryTable() { + assert_locked_or_safepoint(Module_lock); + + // Walk through all buckets and all entries in each bucket, + // freeing each entry. + for (int i = 0; i < table_size(); ++i) { + for (PackageEntry* p = bucket(i); p != NULL;) { + PackageEntry* to_remove = p; + // read next before freeing. + p = p->next(); + + // Clean out the C heap allocated qualified exports list first before freeing the entry + to_remove->delete_qualified_exports(); + to_remove->name()->decrement_refcount(); + + // Unlink from the Hashtable prior to freeing + unlink_entry(to_remove); + FREE_C_HEAP_ARRAY(char, to_remove); + } + } + assert(number_of_entries() == 0, "should have removed all entries"); + assert(new_entry_free_list() == NULL, "entry present on PackageEntryTable's free list"); + free_buckets(); +} + +PackageEntry* PackageEntryTable::new_entry(unsigned int hash, Symbol* name, ModuleEntry* module) { + assert_locked_or_safepoint(Module_lock); + PackageEntry* entry = (PackageEntry*) NEW_C_HEAP_ARRAY(char, entry_size(), mtClass); + + // Initialize everything BasicHashtable would + entry->set_next(NULL); + entry->set_hash(hash); + entry->set_literal(name); + + TRACE_INIT_PACKAGE_ID(entry); + + // Initialize fields specific to a PackageEntry + entry->init(); + entry->name()->increment_refcount(); + if (!module->is_named()) { + // Set the exported state to true because all packages + // within the unnamed module are unqualifiedly exported + entry->set_exported(true); + } + entry->set_module(module); + return entry; +} + +void PackageEntryTable::add_entry(int index, PackageEntry* new_entry) { + assert_locked_or_safepoint(Module_lock); + Hashtable::add_entry(index, (HashtableEntry*)new_entry); +} + +// Create package in loader's package entry table and return the entry. +// If entry already exists, return null. Assume Module lock was taken by caller. +PackageEntry* PackageEntryTable::locked_create_entry_or_null(Symbol* name, ModuleEntry* module) { + assert_locked_or_safepoint(Module_lock); + // Check if package already exists. Return NULL if it does. + if (lookup_only(name) != NULL) { + return NULL; + } else { + PackageEntry* entry = new_entry(compute_hash(name), name, module); + add_entry(index_for(name), entry); + return entry; + } +} + +PackageEntry* PackageEntryTable::lookup(Symbol* name, ModuleEntry* module) { + PackageEntry* p = lookup_only(name); + if (p != NULL) { + return p; + } else { + // If not found, add to table. Grab the PackageEntryTable lock first. + MutexLocker ml(Module_lock); + + // Since look-up was done lock-free, we need to check if another thread beat + // us in the race to insert the package. + PackageEntry* test = lookup_only(name); + if (test != NULL) { + // A race occurred and another thread introduced the package. + return test; + } else { + assert(module != NULL, "module should never be null"); + PackageEntry* entry = new_entry(compute_hash(name), name, module); + add_entry(index_for(name), entry); + return entry; + } + } +} + +PackageEntry* PackageEntryTable::lookup_only(Symbol* name) { + int index = index_for(name); + for (PackageEntry* p = bucket(index); p != NULL; p = p->next()) { + if (p->name()->fast_compare(name) == 0) { + return p; + } + } + return NULL; +} + +// Called when a define module for java.base is being processed. +// Verify the packages loaded thus far are in java.base's package list. +void PackageEntryTable::verify_javabase_packages(GrowableArray *pkg_list) { + for (int i = 0; i < table_size(); i++) { + for (PackageEntry* entry = bucket(i); + entry != NULL; + entry = entry->next()) { + ModuleEntry* m = entry->module(); + Symbol* module_name = (m == NULL ? NULL : m->name()); + if (module_name != NULL && + (module_name->fast_compare(vmSymbols::java_base()) == 0) && + !pkg_list->contains(entry->name())) { + ResourceMark rm; + vm_exit_during_initialization("A non-java.base package was loaded prior to module system initialization", entry->name()->as_C_string()); + } + } + } + +} + +// Remove dead entries from all packages' exported list +void PackageEntryTable::purge_all_package_exports() { + assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); + for (int i = 0; i < table_size(); i++) { + for (PackageEntry* entry = bucket(i); + entry != NULL; + entry = entry->next()) { + if (entry->exported_pending_delete()) { + // exported list is pending deletion due to a transition + // from qualified to unqualified + entry->delete_qualified_exports(); + } else if (entry->is_qual_exported()) { + entry->purge_qualified_exports(); + } + } + } +} + +#ifndef PRODUCT +void PackageEntryTable::print() { + tty->print_cr("Package Entry Table (table_size=%d, entries=%d)", + table_size(), number_of_entries()); + for (int i = 0; i < table_size(); i++) { + for (PackageEntry* probe = bucket(i); + probe != NULL; + probe = probe->next()) { + probe->print(); + } + } +} + +void PackageEntry::print() { + ResourceMark rm; + tty->print_cr("package entry "PTR_FORMAT" name %s module %s classpath_index " + INT32_FORMAT " is_exported %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, _is_exported_allUnnamed, p2i(next())); +} +#endif + +void PackageEntryTable::verify() { + int element_count = 0; + for (int index = 0; index < table_size(); index++) { + for (PackageEntry* probe = bucket(index); + probe != NULL; + probe = probe->next()) { + probe->verify(); + element_count++; + } + } + guarantee(number_of_entries() == element_count, + "Verify of Package Entry Table failed"); + debug_only(verify_lookup_length((double)number_of_entries() / table_size())); +} + +void PackageEntry::verify() { + guarantee(name() != NULL, "A package entry must have a corresponding symbol name."); +} + +// iteration of qualified exports +void PackageEntry::package_exports_do(ModuleClosure* const f) { + assert_locked_or_safepoint(Module_lock); + assert(f != NULL, "invariant"); + + if (is_qual_exported()) { + int qe_len = _qualified_exports->length(); + + for (int i = 0; i < qe_len; ++i) { + f->do_module(_qualified_exports->at(i)); + } + } +} diff --git a/hotspot/src/share/vm/classfile/packageEntry.hpp b/hotspot/src/share/vm/classfile/packageEntry.hpp new file mode 100644 index 00000000000..368609c21b6 --- /dev/null +++ b/hotspot/src/share/vm/classfile/packageEntry.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP +#define SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP + +#include "classfile/moduleEntry.hpp" +#include "oops/symbol.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/hashtable.hpp" + +// 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, either qualifiedly or +// unqualifiedly. +// - a flag indicating if this package is exported to all unnamed modules. +// - a growable array containing other module entries that this +// package is exported to. +// +// Packages that are: +// - not exported: _qualified_exports = NULL && _is_exported is false +// - qualified exports: (_qualified_exports != NULL || _is_exported_allUnnamed is true) && _is_exported is true +// - unqualified exports: (_qualified_exports = NULL && _is_exported_allUnnamed is false) && _is_exported is true +// +// The Mutex Module_lock is shared between ModuleEntry and PackageEntry, to lock either +// data structure. +class PackageEntry : public HashtableEntry { +private: + ModuleEntry* _module; + // 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; + bool _is_exported_allUnnamed; + GrowableArray* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint + GrowableArray* _qualified_exports; + TRACE_DEFINE_TRACE_ID_FIELD; + + // Initial size of a package entry's list of qualified exports. + enum {QUAL_EXP_SIZE = 43}; + +public: + void init() { + _module = NULL; + _classpath_index = -1; + _is_exported = false; + _is_exported_allUnnamed = 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; } + void set_module(ModuleEntry* m) { _module = m; } + + // package's export state + bool is_exported() const { return _is_exported; } // qualifiedly or unqualifiedly exported + bool is_qual_exported() const { + return (_is_exported && (_qualified_exports != NULL || _is_exported_allUnnamed)); + } + bool is_unqual_exported() const { + return (_is_exported && (_qualified_exports == NULL && !_is_exported_allUnnamed)); + } + void set_unqual_exported() { + _is_exported = true; + _is_exported_allUnnamed = false; + _qualified_exports = NULL; + } + bool exported_pending_delete() const { return (_exported_pending_delete != NULL); } + + void set_exported(bool e) { _is_exported = e; } + void set_exported(ModuleEntry* m); + + void set_is_exported_allUnnamed() { + if (!is_unqual_exported()) { + _is_exported_allUnnamed = true; + _is_exported = true; + } + } + bool is_exported_allUnnamed() const { + assert(_is_exported || !_is_exported_allUnnamed, + "is_allUnnamed set without is_exported being set"); + return _is_exported_allUnnamed; + } + + void set_classpath_index(s2 classpath_index) { + _classpath_index = classpath_index; + } + s2 classpath_index() const { return _classpath_index; } + + bool has_loaded_class() const { return _classpath_index != -1; } + + // returns true if the package is defined in the unnamed module + bool in_unnamed_module() const { return !_module->is_named(); } + + // returns true if the package specifies m as a qualified export + bool is_qexported_to(ModuleEntry* m) const; + + // add the module to the package's qualified exports + void add_qexport(ModuleEntry* m); + + PackageEntry* next() const { + return (PackageEntry*)HashtableEntry::next(); + } + + PackageEntry** next_addr() { + return (PackageEntry**)HashtableEntry::next_addr(); + } + + // iteration of qualified exports + void package_exports_do(ModuleClosure* const f); + + TRACE_DEFINE_TRACE_ID_METHODS; + + // Purge dead weak references out of exported list when any given class loader is unloaded. + void purge_qualified_exports(); + void delete_qualified_exports(); + + void print() PRODUCT_RETURN; + void verify(); +}; + +// The PackageEntryTable is a Hashtable containing a list of all packages defined +// by a particular class loader. Each package is represented as a PackageEntry node. +// The PackageEntryTable's lookup is lock free. +// +class PackageEntryTable : public Hashtable { + friend class VMStructs; +public: + enum Constants { + _packagetable_entry_size = 1009 // number of entries in package entry table + }; + +private: + PackageEntry* new_entry(unsigned int hash, Symbol* name, ModuleEntry* module); + void add_entry(int index, PackageEntry* new_entry); + + int entry_size() const { return BasicHashtable::entry_size(); } + + PackageEntry** bucket_addr(int i) { + return (PackageEntry**)Hashtable::bucket_addr(i); + } + + static unsigned int compute_hash(Symbol* name) { return (unsigned int)(name->identity_hash()); } + int index_for(Symbol* name) const { return hash_to_index(compute_hash(name)); } + +public: + PackageEntryTable(int table_size); + ~PackageEntryTable(); + + PackageEntry* bucket(int i) { + return (PackageEntry*)Hashtable::bucket(i); + } + + // Create package in loader's package entry table and return the entry. + // If entry already exists, return null. Assume Module lock was taken by caller. + PackageEntry* locked_create_entry_or_null(Symbol* name, ModuleEntry* module); + + // lookup Package with loader's package entry table, if not found add + PackageEntry* lookup(Symbol* name, ModuleEntry* module); + + // Only lookup Package within loader's package entry table. The table read is lock-free. + PackageEntry* lookup_only(Symbol* Package); + + void verify_javabase_packages(GrowableArray *pkg_list); + + // purge dead weak references out of exported list + void purge_all_package_exports(); + + void print() PRODUCT_RETURN; + void verify(); +}; + +#endif // SHARE_VM_CLASSFILE_PACKAGEENTRY_HPP diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp index 9233e3243ad..939e136de3c 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,15 +26,15 @@ #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/sharedPathsMiscInfo.hpp" +#include "logging/log.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceShared.hpp" #include "runtime/arguments.hpp" +#include "utilities/ostream.hpp" void SharedPathsMiscInfo::add_path(const char* path, int type) { - if (TraceClassPaths) { - tty->print("[type=%s] ", type_name(type)); - trace_class_path("[Add misc shared path ", path); - } + log_info(classpath)("type=%s ", type_name(type)); + ClassLoader::trace_class_path("add misc shared path ", path); write(path, strlen(path) + 1); write_jint(jint(type)); } @@ -67,11 +67,29 @@ bool SharedPathsMiscInfo::read(void* ptr, size_t size) { } bool SharedPathsMiscInfo::fail(const char* msg, const char* name) { - ClassLoader::trace_class_path(tty, msg, name); + ClassLoader::trace_class_path(msg, name); MetaspaceShared::set_archive_loading_failed(); return false; } +void SharedPathsMiscInfo::print_path(int type, const char* path) { + ResourceMark rm; + outputStream* out = LogHandle(classpath)::info_stream(); + switch (type) { + case BOOT: + out->print("Expecting BOOT path=%s", path); + break; + case NON_EXIST: + out->print("Expecting that %s does not exist", path); + break; + case REQUIRED: + out->print("Expecting that file %s must exist and is not altered", path); + break; + default: + ShouldNotReachHere(); + } +} + bool SharedPathsMiscInfo::check() { // The whole buffer must be 0 terminated so that we can use strlen and strcmp // without fear. @@ -90,17 +108,14 @@ bool SharedPathsMiscInfo::check() { if (!read_jint(&type)) { return fail("Corrupted archive file header"); } - if (TraceClassPaths) { - tty->print("[type=%s ", type_name(type)); - print_path(tty, type, path); - tty->print_cr("]"); - } + log_info(classpath)("type=%s ", type_name(type)); + print_path(type, path); if (!check(type, path)) { if (!PrintSharedArchiveAndExit) { return false; } } else { - trace_class_path("[ok"); + ClassLoader::trace_class_path("ok"); } } @@ -111,7 +126,7 @@ bool SharedPathsMiscInfo::check(jint type, const char* path) { switch (type) { case BOOT: if (os::file_name_strcmp(path, Arguments::get_sysclasspath()) != 0) { - return fail("[BOOT classpath mismatch, actual: -Dsun.boot.class.path=", Arguments::get_sysclasspath()); + return fail("[BOOT classpath mismatch, actual =", Arguments::get_sysclasspath()); } break; case NON_EXIST: // fall-through diff --git a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp index 652d20c883a..435630febac 100644 --- a/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp +++ b/hotspot/src/share/vm/classfile/sharedPathsMiscInfo.hpp @@ -64,9 +64,6 @@ protected: void write(const void* ptr, size_t size); bool read(void* ptr, size_t size); - static void trace_class_path(const char* msg, const char* name = NULL) { - ClassLoader::trace_class_path(tty, msg, name); - } protected: static bool fail(const char* msg, const char* name = NULL); virtual bool check(jint type, const char* path); @@ -144,21 +141,7 @@ public: } } - virtual void print_path(outputStream* out, int type, const char* path) { - switch (type) { - case BOOT: - out->print("Expecting -Dsun.boot.class.path=%s", path); - break; - case NON_EXIST: - out->print("Expecting that %s does not exist", path); - break; - case REQUIRED: - out->print("Expecting that file %s must exist and is not altered", path); - break; - default: - ShouldNotReachHere(); - } - } + virtual void print_path(int type, const char* path); bool check(); bool read_jint(jint *ptr) { diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp index 2a61613e910..71f176bd988 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp @@ -32,6 +32,7 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/klassFactory.hpp" #include "classfile/loaderConstraints.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/placeholders.hpp" #include "classfile/resolutionErrors.hpp" #include "classfile/stringTable.hpp" @@ -51,6 +52,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" +#include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiEnvBase.hpp" #include "prims/methodHandles.hpp" @@ -171,13 +173,13 @@ bool SystemDictionary::is_parallelDefine(Handle class_loader) { } /** - * Returns true if the passed class loader is the extension class loader. + * Returns true if the passed class loader is the platform class loader. */ -bool SystemDictionary::is_ext_class_loader(Handle class_loader) { +bool SystemDictionary::is_platform_class_loader(Handle class_loader) { if (class_loader.is_null()) { return false; } - return (class_loader->klass()->name() == vmSymbols::sun_misc_Launcher_ExtClassLoader()); + return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass()); } // ---------------------------------------------------------------------------- @@ -430,12 +432,15 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, // Now we have to call back to java to check if the initating class has access JavaValue result(T_VOID); - if (TraceProtectionDomainVerification) { + if (log_is_enabled(Debug, protectiondomain)) { + ResourceMark rm; // Print out trace information - tty->print_cr("Checking package access"); - tty->print(" - class loader: "); class_loader()->print_value_on(tty); tty->cr(); - tty->print(" - protection domain: "); protection_domain()->print_value_on(tty); tty->cr(); - tty->print(" - loading: "); klass()->print_value_on(tty); tty->cr(); + outputStream* log = LogHandle(protectiondomain)::debug_stream(); + log->print_cr("Checking package access"); + log->print("class loader: "); class_loader()->print_value_on(log); + log->print(" protection domain: "); protection_domain()->print_value_on(log); + log->print(" loading: "); klass()->print_value_on(log); + log->cr(); } KlassHandle system_loader(THREAD, SystemDictionary::ClassLoader_klass()); @@ -448,13 +453,10 @@ void SystemDictionary::validate_protection_domain(instanceKlassHandle klass, protection_domain, THREAD); - if (TraceProtectionDomainVerification) { - if (HAS_PENDING_EXCEPTION) { - tty->print_cr(" -> DENIED !!!!!!!!!!!!!!!!!!!!!"); - } else { - tty->print_cr(" -> granted"); - } - tty->cr(); + if (HAS_PENDING_EXCEPTION) { + log_debug(protectiondomain)("DENIED !!!!!!!!!!!!!!!!!!!!!"); + } else { + log_debug(protectiondomain)("granted"); } if (HAS_PENDING_EXCEPTION) return; @@ -1144,6 +1146,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, const char* pkg = "java/"; if (!HAS_PENDING_EXCEPTION && !class_loader.is_null() && + !SystemDictionary::is_platform_class_loader(class_loader) && parsed_name != NULL && !strncmp((const char*)parsed_name->bytes(), pkg, strlen(pkg))) { // It is illegal to define classes in the "java." package from @@ -1236,13 +1239,88 @@ instanceKlassHandle SystemDictionary::load_shared_class( instanceKlassHandle ik (THREAD, find_shared_class(class_name)); // Make sure we only return the boot class for the NULL classloader. if (ik.not_null() && - SharedClassUtil::is_shared_boot_class(ik()) && class_loader.is_null()) { + ik->is_shared_boot_class() && class_loader.is_null()) { Handle protection_domain; return load_shared_class(ik, class_loader, protection_domain, THREAD); } return instanceKlassHandle(); } +// Check if a shared class can be loaded by the specific classloader: +// +// NULL classloader: +// - Module class from "modules" jimage. ModuleEntry must be defined in the classloader. +// - Class from -Xbootclasspath/a. The class has no defined PackageEntry, or must +// be defined in an unnamed module. +bool SystemDictionary::is_shared_class_visible(Symbol* class_name, + instanceKlassHandle ik, + Handle class_loader, TRAPS) { + int path_index = ik->shared_classpath_index(); + SharedClassPathEntry* ent = + (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index); + if (!Universe::is_module_initialized()) { + assert(ent->is_jrt(), + "Loading non-bootstrap classes before the module system is initialized"); + assert(class_loader.is_null(), "sanity"); + return true; + } + // Get the pkg_entry from the classloader + TempNewSymbol pkg_name = NULL; + PackageEntry* pkg_entry = NULL; + ModuleEntry* mod_entry = NULL; + int length = 0; + ClassLoaderData* loader_data = class_loader_data(class_loader); + const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length); + if (pkg_string != NULL) { + pkg_name = SymbolTable::new_symbol((const char*)pkg_string, + length, CHECK_(false)); + if (loader_data != NULL) { + pkg_entry = loader_data->packages()->lookup_only(pkg_name); + } + if (pkg_entry != NULL) { + mod_entry = pkg_entry->module(); + } + } + + if (class_loader.is_null()) { + // The NULL classloader can load archived class originated from the + // "modules" jimage and the -Xbootclasspath/a. For class from the + // "modules" jimage, the PackageEntry/ModuleEntry must be defined + // by the NULL classloader. + if (mod_entry != NULL) { + // PackageEntry/ModuleEntry is found in the classloader. Check if the + // ModuleEntry's location agrees with the archived class' origination. + if (ent->is_jrt() && mod_entry->location()->starts_with("jrt:")) { + return true; // Module class from the "module" jimage + } + } + + // If the archived class is not from the "module" jimage, the class can be + // loaded by the NULL classloader if + // + // 1. the class is from the unamed package + // 2. or, the class is not from a module defined in the NULL classloader + // 3. or, the class is from an unamed module + if (!ent->is_jrt() && ik->is_shared_boot_class()) { + // the class is from the -Xbootclasspath/a + if (pkg_string == NULL || + pkg_entry == NULL || + pkg_entry->in_unnamed_module()) { + assert(mod_entry == NULL || + mod_entry == loader_data->modules()->unnamed_module(), + "the unnamed module is not defined in the classloader"); + return true; + } + } + return false; + } else { + bool res = SystemDictionaryShared::is_shared_class_visible_for_classloader( + ik, class_loader, pkg_string, pkg_name, + pkg_entry, mod_entry, CHECK_(false)); + return res; + } +} + instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, Handle class_loader, Handle protection_domain, TRAPS) { @@ -1250,6 +1328,12 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, instanceKlassHandle nh = instanceKlassHandle(); // null Handle Symbol* class_name = ik->name(); + bool visible = is_shared_class_visible( + class_name, ik, class_loader, CHECK_(nh)); + if (!visible) { + return nh; + } + // Found the class, now load the superclass and interfaces. If they // are shared, add them to the main system dictionary and reset // their hierarchy references (supers, subs, and interfaces). @@ -1303,12 +1387,20 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, } if (log_is_enabled(Info, classload)) { - ik()->print_loading_log(LogLevel::Info, loader_data, NULL); + ik()->print_loading_log(LogLevel::Info, loader_data, NULL, NULL); } // No 'else' here as logging levels are not mutually exclusive if (log_is_enabled(Debug, classload)) { - ik()->print_loading_log(LogLevel::Debug, loader_data, NULL); + ik()->print_loading_log(LogLevel::Debug, loader_data, NULL, NULL); + } + + // For boot loader, ensure that GetSystemPackage knows that a class in this + // package was loaded. + if (class_loader.is_null()) { + int path_index = ik->shared_classpath_index(); + ResourceMark rm; + ClassLoader::add_package(ik->name()->as_C_string(), path_index, THREAD); } if (DumpLoadedClassList != NULL && classlist_file->is_open()) { @@ -1329,7 +1421,68 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik, instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) { instanceKlassHandle nh = instanceKlassHandle(); // null Handle + if (class_loader.is_null()) { + int length = 0; + PackageEntry* pkg_entry = NULL; + bool search_only_bootloader_append = false; + ClassLoaderData *loader_data = class_loader_data(class_loader); + + // Find the package in the boot loader's package entry table. + const jbyte* pkg_string = InstanceKlass::package_from_name(class_name, length); + if (pkg_string != NULL) { + TempNewSymbol pkg_name = SymbolTable::new_symbol((const char*)pkg_string, length, CHECK_(nh)); + pkg_entry = loader_data->packages()->lookup_only(pkg_name); + } + + // Prior to attempting to load the class, enforce the boot loader's + // visibility boundaries. + if (!Universe::is_module_initialized()) { + // During bootstrapping, prior to module initialization, any + // class attempting to be loaded must be checked against the + // java.base packages in the boot loader's PackageEntryTable. + // No class outside of java.base is allowed to be loaded during + // this bootstrapping window. + if (!DumpSharedSpaces) { + if (pkg_entry == NULL || pkg_entry->in_unnamed_module()) { + // Class is either in the unnamed package or in + // a named package within the unnamed module. Either + // case is outside of java.base, do not attempt to + // load the class post java.base definition. If + // java.base has not been defined, let the class load + // and its package will be checked later by + // ModuleEntryTable::verify_javabase_packages. + if (ModuleEntryTable::javabase_defined()) { + return nh; + } + } else { + // Check that the class' package is defined within java.base. + ModuleEntry* mod_entry = pkg_entry->module(); + Symbol* mod_entry_name = mod_entry->name(); + if (mod_entry_name->fast_compare(vmSymbols::java_base()) != 0) { + return nh; + } + } + } + } else { + assert(!DumpSharedSpaces, "Archive dumped after module system initialization"); + // After the module system has been initialized, check if the class' + // package is in a module defined to the boot loader. + if (pkg_string == NULL || pkg_entry == NULL || pkg_entry->in_unnamed_module()) { + // Class is either in the unnamed package, in a named package + // within a module not defined to the boot loader or in a + // a named package within the unnamed module. In all cases, + // limit visibility to search for the class only in the boot + // loader's append path. + search_only_bootloader_append = true; + } + } + + // Prior to bootstrapping's module initialization, never load a class outside + // of the boot loader's module path + assert(Universe::is_module_initialized() || DumpSharedSpaces || + !search_only_bootloader_append, + "Attempt to load a class outside of boot loader's module path"); // Search the shared system dictionary for classes preloaded into the // shared spaces. @@ -1344,7 +1497,7 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha if (k.is_null()) { // Use VM class loader PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time()); - k = ClassLoader::load_class(class_name, CHECK_(nh)); + k = ClassLoader::load_class(class_name, search_only_bootloader_append, CHECK_(nh)); } // find_or_define_instance_class may return a different InstanceKlass @@ -1669,7 +1822,7 @@ Klass* SystemDictionary::find_class(Symbol* class_name, ClassLoaderData* loader_ } -// Get the next class in the diictionary. +// Get the next class in the dictionary. Klass* SystemDictionary::try_get_next_class() { return dictionary()->try_get_next_class(); } @@ -1940,6 +2093,11 @@ void SystemDictionary::initialize_wk_klasses_until(WKID limit_id, WKID &start_id void SystemDictionary::initialize_preloaded_classes(TRAPS) { assert(WK_KLASS(Object_klass) == NULL, "preloaded classes should only be initialized once"); + + // Create the ModuleEntry for java.base. This call needs to be done here, + // after vmSymbols::initialize() is called but before any classes are pre-loaded. + ClassLoader::create_javabase(); + // Preload commonly used klasses WKID scan = FIRST_WKID; // first do Object, then String, Class diff --git a/hotspot/src/share/vm/classfile/systemDictionary.hpp b/hotspot/src/share/vm/classfile/systemDictionary.hpp index 628895f1e44..1e148322348 100644 --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp @@ -135,6 +135,7 @@ class SymbolPropertyTable; do_klass(Properties_klass, java_util_Properties, Pre ) \ do_klass(reflect_AccessibleObject_klass, java_lang_reflect_AccessibleObject, Pre ) \ do_klass(reflect_Field_klass, java_lang_reflect_Field, Pre ) \ + do_klass(reflect_Module_klass, java_lang_reflect_Module, Pre ) \ do_klass(reflect_Parameter_klass, java_lang_reflect_Parameter, Opt ) \ do_klass(reflect_Method_klass, java_lang_reflect_Method, Pre ) \ do_klass(reflect_Constructor_klass, java_lang_reflect_Constructor, Pre ) \ @@ -167,15 +168,17 @@ class SymbolPropertyTable; do_klass(StringBuffer_klass, java_lang_StringBuffer, Pre ) \ do_klass(StringBuilder_klass, java_lang_StringBuilder, Pre ) \ do_klass(internal_Unsafe_klass, jdk_internal_misc_Unsafe, Pre ) \ + do_klass(module_Modules_klass, jdk_internal_module_Modules, Pre ) \ \ /* support for CDS */ \ do_klass(ByteArrayInputStream_klass, java_io_ByteArrayInputStream, Pre ) \ do_klass(File_klass, java_io_File, Pre ) \ - do_klass(URLClassLoader_klass, java_net_URLClassLoader, Pre ) \ do_klass(URL_klass, java_net_URL, Pre ) \ do_klass(Jar_Manifest_klass, java_util_jar_Manifest, Pre ) \ - do_klass(sun_misc_Launcher_klass, sun_misc_Launcher, Pre ) \ + do_klass(jdk_internal_loader_ClassLoaders_AppClassLoader_klass, jdk_internal_loader_ClassLoaders_AppClassLoader, Pre ) \ + do_klass(jdk_internal_loader_ClassLoaders_PlatformClassLoader_klass, jdk_internal_loader_ClassLoaders_PlatformClassLoader, Pre ) \ do_klass(CodeSource_klass, java_security_CodeSource, Pre ) \ + do_klass(ParseUtil_klass, sun_net_www_ParseUtil, Pre ) \ \ do_klass(StackTraceElement_klass, java_lang_StackTraceElement, Opt ) \ \ @@ -639,6 +642,8 @@ protected: static instanceKlassHandle find_or_define_instance_class(Symbol* class_name, Handle class_loader, instanceKlassHandle k, TRAPS); + static bool is_shared_class_visible(Symbol* class_name, instanceKlassHandle ik, + Handle class_loader, TRAPS); static instanceKlassHandle load_shared_class(instanceKlassHandle ik, Handle class_loader, Handle protection_domain, @@ -653,7 +658,7 @@ public: static instanceKlassHandle load_shared_class(Symbol* class_name, Handle class_loader, TRAPS); - static bool is_ext_class_loader(Handle class_loader); + static bool is_platform_class_loader(Handle class_loader); protected: static Klass* find_shared_class(Symbol* class_name); diff --git a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp index 8ada71482c4..50b5dd80920 100644 --- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp +++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp @@ -44,6 +44,16 @@ public: oop class_loader = loader_data->class_loader(); return (class_loader == NULL); } + static bool is_shared_class_visible_for_classloader( + instanceKlassHandle ik, + Handle class_loader, + const jbyte* pkg_string, + Symbol* pkg_name, + PackageEntry* pkg_entry, + ModuleEntry* mod_entry, + TRAPS) { + return false; + } static Klass* dump_time_resolve_super_or_fail(Symbol* child_name, Symbol* class_name, diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp index 81dda6e4fd0..73324bc9ec6 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.cpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp @@ -328,8 +328,6 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) { assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); switch(id) { #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: @@ -544,6 +542,42 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getObjectAcquire: + case vmIntrinsics::_getBooleanAcquire: + case vmIntrinsics::_getByteAcquire: + case vmIntrinsics::_getShortAcquire: + case vmIntrinsics::_getCharAcquire: + case vmIntrinsics::_getIntAcquire: + case vmIntrinsics::_getLongAcquire: + case vmIntrinsics::_getFloatAcquire: + case vmIntrinsics::_getDoubleAcquire: + case vmIntrinsics::_putObjectRelease: + case vmIntrinsics::_putBooleanRelease: + case vmIntrinsics::_putByteRelease: + case vmIntrinsics::_putShortRelease: + case vmIntrinsics::_putCharRelease: + case vmIntrinsics::_putIntRelease: + case vmIntrinsics::_putLongRelease: + case vmIntrinsics::_putFloatRelease: + case vmIntrinsics::_putDoubleRelease: + case vmIntrinsics::_getObjectOpaque: + case vmIntrinsics::_getBooleanOpaque: + case vmIntrinsics::_getByteOpaque: + case vmIntrinsics::_getShortOpaque: + case vmIntrinsics::_getCharOpaque: + case vmIntrinsics::_getIntOpaque: + case vmIntrinsics::_getLongOpaque: + case vmIntrinsics::_getFloatOpaque: + case vmIntrinsics::_getDoubleOpaque: + case vmIntrinsics::_putObjectOpaque: + case vmIntrinsics::_putBooleanOpaque: + case vmIntrinsics::_putByteOpaque: + case vmIntrinsics::_putShortOpaque: + case vmIntrinsics::_putCharOpaque: + case vmIntrinsics::_putIntOpaque: + case vmIntrinsics::_putLongOpaque: + case vmIntrinsics::_putFloatOpaque: + case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getByte_raw: case vmIntrinsics::_getShort_raw: case vmIntrinsics::_getChar_raw: @@ -569,9 +603,27 @@ bool vmIntrinsics::is_disabled_by_flags(const methodHandle& method) { case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: - case vmIntrinsics::_compareAndSwapObject: case vmIntrinsics::_compareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLongAcquire: + case vmIntrinsics::_weakCompareAndSwapLongRelease: case vmIntrinsics::_compareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapIntAcquire: + case vmIntrinsics::_weakCompareAndSwapIntRelease: + case vmIntrinsics::_compareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: + case vmIntrinsics::_weakCompareAndSwapObjectRelease: + case vmIntrinsics::_compareAndExchangeIntVolatile: + case vmIntrinsics::_compareAndExchangeIntAcquire: + case vmIntrinsics::_compareAndExchangeIntRelease: + case vmIntrinsics::_compareAndExchangeLongVolatile: + case vmIntrinsics::_compareAndExchangeLongAcquire: + case vmIntrinsics::_compareAndExchangeLongRelease: + case vmIntrinsics::_compareAndExchangeObjectVolatile: + case vmIntrinsics::_compareAndExchangeObjectAcquire: + case vmIntrinsics::_compareAndExchangeObjectRelease: if (!InlineUnsafeOps) return true; break; case vmIntrinsics::_getShortUnaligned: diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp index ecbd0ab776d..111989451fb 100644 --- a/hotspot/src/share/vm/classfile/vmSymbols.hpp +++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp @@ -49,10 +49,12 @@ // Mapping function names to values. New entries should be added below. #define VM_SYMBOLS_DO(template, do_alias) \ - /* commonly used class names */ \ + /* commonly used class, package, module names */ \ + template(java_base, "java.base") \ template(java_lang_System, "java/lang/System") \ template(java_lang_Object, "java/lang/Object") \ template(java_lang_Class, "java/lang/Class") \ + template(java_lang_Package, "java/lang/Package") \ template(java_lang_String, "java/lang/String") \ template(java_lang_StringLatin1, "java/lang/StringLatin1") \ template(java_lang_StringUTF16, "java/lang/StringUTF16") \ @@ -87,6 +89,7 @@ template(java_lang_reflect_Method, "java/lang/reflect/Method") \ template(java_lang_reflect_Constructor, "java/lang/reflect/Constructor") \ template(java_lang_reflect_Field, "java/lang/reflect/Field") \ + template(java_lang_reflect_Module, "java/lang/reflect/Module") \ template(java_lang_reflect_Parameter, "java/lang/reflect/Parameter") \ template(java_lang_reflect_Array, "java/lang/reflect/Array") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ @@ -97,7 +100,6 @@ template(java_security_CodeSource, "java/security/CodeSource") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ template(java_security_SecureClassLoader, "java/security/SecureClassLoader") \ - template(java_net_URLClassLoader, "java/net/URLClassLoader") \ template(java_net_URL, "java/net/URL") \ template(java_util_jar_Manifest, "java/util/jar/Manifest") \ template(impliesCreateAccessControlContext_name, "impliesCreateAccessControlContext") \ @@ -116,17 +118,25 @@ template(java_util_Hashtable, "java/util/Hashtable") \ template(java_lang_Compiler, "java/lang/Compiler") \ template(jdk_internal_misc_Signal, "jdk/internal/misc/Signal") \ - template(sun_misc_Launcher, "sun/misc/Launcher") \ template(java_lang_AssertionStatusDirectives, "java/lang/AssertionStatusDirectives") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ - template(sun_misc_Launcher_ExtClassLoader, "sun/misc/Launcher$ExtClassLoader") \ + template(sun_net_www_ParseUtil, "sun/net/www/ParseUtil") \ + \ + template(jdk_internal_loader_ClassLoaders_AppClassLoader, "jdk/internal/loader/ClassLoaders$AppClassLoader") \ + template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \ \ /* Java runtime version access */ \ template(java_lang_VersionProps, "java/lang/VersionProps") \ template(java_runtime_name_name, "java_runtime_name") \ template(java_runtime_version_name, "java_runtime_version") \ \ + /* system initialization */ \ + template(initPhase1_name, "initPhase1") \ + template(initPhase2_name, "initPhase2") \ + template(initPhase3_name, "initPhase3") \ + template(java_lang_reflect_module_init_signature, "(Ljava/lang/ClassLoader;Ljava/lang/String;)V") \ + \ /* class file format tags */ \ template(tag_source_file, "SourceFile") \ template(tag_inner_classes, "InnerClasses") \ @@ -360,7 +370,6 @@ template(run_finalization_name, "runFinalization") \ template(run_finalizers_on_exit_name, "runFinalizersOnExit") \ template(dispatchUncaughtException_name, "dispatchUncaughtException") \ - template(initializeSystemClass_name, "initializeSystemClass") \ template(loadClass_name, "loadClass") \ template(loadClassInternal_name, "loadClassInternal") \ template(get_name, "get") \ @@ -446,14 +455,22 @@ template(signers_name, "signers_name") \ template(loader_data_name, "loader_data") \ template(vmdependencies_name, "vmdependencies") \ + template(loader_name, "loader") \ + template(module_name, "module") \ + template(getModule_name, "getModule") \ + template(addReads_name, "addReads") \ + template(addReads_signature, "(Ljava/lang/reflect/Module;Ljava/lang/reflect/Module;)V") \ template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ - template(getFileURL_name, "getFileURL") \ - template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ - template(definePackageInternal_name, "definePackageInternal") \ - template(definePackageInternal_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)V") \ + template(definePackage_name, "definePackage") \ + template(definePackage_signature, "(Ljava/lang/String;Ljava/lang/reflect/Module;)Ljava/lang/Package;") \ + template(defineOrCheckPackage_name, "defineOrCheckPackage") \ + template(defineOrCheckPackage_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)Ljava/lang/Package;") \ + template(fileToEncodedURL_name, "fileToEncodedURL") \ + template(fileToEncodedURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ template(getProtectionDomain_name, "getProtectionDomain") \ template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ + template(module_entry_name, "module_entry") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -531,6 +548,7 @@ template(void_class_signature, "()Ljava/lang/Class;") \ template(void_class_array_signature, "()[Ljava/lang/Class;") \ template(void_string_signature, "()Ljava/lang/String;") \ + template(void_module_signature, "()Ljava/lang/reflect/Module;") \ template(object_array_object_signature, "([Ljava/lang/Object;)Ljava/lang/Object;") \ template(object_object_array_object_signature, "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\ template(exception_void_signature, "(Ljava/lang/Exception;)V") \ @@ -550,6 +568,7 @@ template(reference_signature, "Ljava/lang/ref/Reference;") \ template(sun_misc_Cleaner_signature, "Lsun/misc/Cleaner;") \ template(executable_signature, "Ljava/lang/reflect/Executable;") \ + template(module_signature, "Ljava/lang/reflect/Module;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \ template(int_StringBuilder_signature, "(I)Ljava/lang/StringBuilder;") \ @@ -574,6 +593,9 @@ /* used to identify class loaders handling parallel class loading */ \ template(parallelCapable_name, "parallelLockMap") \ \ + /* used to return a class loader's unnamed module */ \ + template(unnamedModule_name, "unnamedModule") \ + \ /* JVM monitoring and management support */ \ template(java_lang_StackTraceElement_array, "[Ljava/lang/StackTraceElement;") \ template(java_lang_management_ThreadState, "java/lang/management/ThreadState") \ @@ -632,7 +654,10 @@ template(addThreadDumpForSynchronizers_signature, "(Ljava/lang/management/ThreadInfo;[Ljava/lang/Object;)V") \ \ /* JVMTI/java.lang.instrument support and VM Attach mechanism */ \ + template(jdk_internal_module_Modules, "jdk/internal/module/Modules") \ template(sun_misc_VMSupport, "sun/misc/VMSupport") \ + template(transformedByAgent_name, "transformedByAgent") \ + template(transformedByAgent_signature, "(Ljava/lang/reflect/Module;)V") \ template(appendToClassPathForInstrumentation_name, "appendToClassPathForInstrumentation") \ do_alias(appendToClassPathForInstrumentation_signature, string_void_signature) \ template(serializePropertiesToByteArray_name, "serializePropertiesToByteArray") \ @@ -1063,11 +1088,6 @@ do_name( isCompileConstant_name, "isCompileConstant") \ do_alias( isCompileConstant_signature, object_boolean_signature) \ \ - do_class(sun_hotspot_WhiteBox, "sun/hotspot/WhiteBox") \ - do_intrinsic(_deoptimize, sun_hotspot_WhiteBox, deoptimize_name, deoptimize_signature, F_R) \ - do_name( deoptimize_name, "deoptimize") \ - do_alias( deoptimize_signature, void_method_signature) \ - \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ do_signature(putObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)V") \ @@ -1146,6 +1166,64 @@ do_intrinsic(_putFloatVolatile, jdk_internal_misc_Unsafe, putFloatVolatile_name, putFloat_signature, F_RN) \ do_intrinsic(_putDoubleVolatile, jdk_internal_misc_Unsafe, putDoubleVolatile_name, putDouble_signature, F_RN) \ \ + do_name(getObjectOpaque_name,"getObjectOpaque") do_name(putObjectOpaque_name,"putObjectOpaque") \ + do_name(getBooleanOpaque_name,"getBooleanOpaque") do_name(putBooleanOpaque_name,"putBooleanOpaque") \ + do_name(getByteOpaque_name,"getByteOpaque") do_name(putByteOpaque_name,"putByteOpaque") \ + do_name(getShortOpaque_name,"getShortOpaque") do_name(putShortOpaque_name,"putShortOpaque") \ + do_name(getCharOpaque_name,"getCharOpaque") do_name(putCharOpaque_name,"putCharOpaque") \ + do_name(getIntOpaque_name,"getIntOpaque") do_name(putIntOpaque_name,"putIntOpaque") \ + do_name(getLongOpaque_name,"getLongOpaque") do_name(putLongOpaque_name,"putLongOpaque") \ + do_name(getFloatOpaque_name,"getFloatOpaque") do_name(putFloatOpaque_name,"putFloatOpaque") \ + do_name(getDoubleOpaque_name,"getDoubleOpaque") do_name(putDoubleOpaque_name,"putDoubleOpaque") \ + \ + do_intrinsic(_getObjectOpaque, jdk_internal_misc_Unsafe, getObjectOpaque_name, getObject_signature, F_R) \ + do_intrinsic(_getBooleanOpaque, jdk_internal_misc_Unsafe, getBooleanOpaque_name, getBoolean_signature, F_R) \ + do_intrinsic(_getByteOpaque, jdk_internal_misc_Unsafe, getByteOpaque_name, getByte_signature, F_R) \ + do_intrinsic(_getShortOpaque, jdk_internal_misc_Unsafe, getShortOpaque_name, getShort_signature, F_R) \ + do_intrinsic(_getCharOpaque, jdk_internal_misc_Unsafe, getCharOpaque_name, getChar_signature, F_R) \ + do_intrinsic(_getIntOpaque, jdk_internal_misc_Unsafe, getIntOpaque_name, getInt_signature, F_R) \ + do_intrinsic(_getLongOpaque, jdk_internal_misc_Unsafe, getLongOpaque_name, getLong_signature, F_R) \ + do_intrinsic(_getFloatOpaque, jdk_internal_misc_Unsafe, getFloatOpaque_name, getFloat_signature, F_R) \ + do_intrinsic(_getDoubleOpaque, jdk_internal_misc_Unsafe, getDoubleOpaque_name, getDouble_signature, F_R) \ + do_intrinsic(_putObjectOpaque, jdk_internal_misc_Unsafe, putObjectOpaque_name, putObject_signature, F_R) \ + do_intrinsic(_putBooleanOpaque, jdk_internal_misc_Unsafe, putBooleanOpaque_name, putBoolean_signature, F_R) \ + do_intrinsic(_putByteOpaque, jdk_internal_misc_Unsafe, putByteOpaque_name, putByte_signature, F_R) \ + do_intrinsic(_putShortOpaque, jdk_internal_misc_Unsafe, putShortOpaque_name, putShort_signature, F_R) \ + do_intrinsic(_putCharOpaque, jdk_internal_misc_Unsafe, putCharOpaque_name, putChar_signature, F_R) \ + do_intrinsic(_putIntOpaque, jdk_internal_misc_Unsafe, putIntOpaque_name, putInt_signature, F_R) \ + do_intrinsic(_putLongOpaque, jdk_internal_misc_Unsafe, putLongOpaque_name, putLong_signature, F_R) \ + do_intrinsic(_putFloatOpaque, jdk_internal_misc_Unsafe, putFloatOpaque_name, putFloat_signature, F_R) \ + do_intrinsic(_putDoubleOpaque, jdk_internal_misc_Unsafe, putDoubleOpaque_name, putDouble_signature, F_R) \ + \ + do_name(getObjectAcquire_name, "getObjectAcquire") do_name(putObjectRelease_name, "putObjectRelease") \ + do_name(getBooleanAcquire_name, "getBooleanAcquire") do_name(putBooleanRelease_name, "putBooleanRelease") \ + do_name(getByteAcquire_name, "getByteAcquire") do_name(putByteRelease_name, "putByteRelease") \ + do_name(getShortAcquire_name, "getShortAcquire") do_name(putShortRelease_name, "putShortRelease") \ + do_name(getCharAcquire_name, "getCharAcquire") do_name(putCharRelease_name, "putCharRelease") \ + do_name(getIntAcquire_name, "getIntAcquire") do_name(putIntRelease_name, "putIntRelease") \ + do_name(getLongAcquire_name, "getLongAcquire") do_name(putLongRelease_name, "putLongRelease") \ + do_name(getFloatAcquire_name, "getFloatAcquire") do_name(putFloatRelease_name, "putFloatRelease") \ + do_name(getDoubleAcquire_name, "getDoubleAcquire") do_name(putDoubleRelease_name, "putDoubleRelease") \ + \ + do_intrinsic(_getObjectAcquire, jdk_internal_misc_Unsafe, getObjectAcquire_name, getObject_signature, F_R) \ + do_intrinsic(_getBooleanAcquire, jdk_internal_misc_Unsafe, getBooleanAcquire_name, getBoolean_signature, F_R) \ + do_intrinsic(_getByteAcquire, jdk_internal_misc_Unsafe, getByteAcquire_name, getByte_signature, F_R) \ + do_intrinsic(_getShortAcquire, jdk_internal_misc_Unsafe, getShortAcquire_name, getShort_signature, F_R) \ + do_intrinsic(_getCharAcquire, jdk_internal_misc_Unsafe, getCharAcquire_name, getChar_signature, F_R) \ + do_intrinsic(_getIntAcquire, jdk_internal_misc_Unsafe, getIntAcquire_name, getInt_signature, F_R) \ + do_intrinsic(_getLongAcquire, jdk_internal_misc_Unsafe, getLongAcquire_name, getLong_signature, F_R) \ + do_intrinsic(_getFloatAcquire, jdk_internal_misc_Unsafe, getFloatAcquire_name, getFloat_signature, F_R) \ + do_intrinsic(_getDoubleAcquire, jdk_internal_misc_Unsafe, getDoubleAcquire_name, getDouble_signature, F_R) \ + do_intrinsic(_putObjectRelease, jdk_internal_misc_Unsafe, putObjectRelease_name, putObject_signature, F_R) \ + do_intrinsic(_putBooleanRelease, jdk_internal_misc_Unsafe, putBooleanRelease_name, putBoolean_signature, F_R) \ + do_intrinsic(_putByteRelease, jdk_internal_misc_Unsafe, putByteRelease_name, putByte_signature, F_R) \ + do_intrinsic(_putShortRelease, jdk_internal_misc_Unsafe, putShortRelease_name, putShort_signature, F_R) \ + do_intrinsic(_putCharRelease, jdk_internal_misc_Unsafe, putCharRelease_name, putChar_signature, F_R) \ + do_intrinsic(_putIntRelease, jdk_internal_misc_Unsafe, putIntRelease_name, putInt_signature, F_R) \ + do_intrinsic(_putLongRelease, jdk_internal_misc_Unsafe, putLongRelease_name, putLong_signature, F_R) \ + do_intrinsic(_putFloatRelease, jdk_internal_misc_Unsafe, putFloatRelease_name, putFloat_signature, F_R) \ + do_intrinsic(_putDoubleRelease, jdk_internal_misc_Unsafe, putDoubleRelease_name, putDouble_signature, F_R) \ + \ do_name(getShortUnaligned_name,"getShortUnaligned") do_name(putShortUnaligned_name,"putShortUnaligned") \ do_name(getCharUnaligned_name,"getCharUnaligned") do_name(putCharUnaligned_name,"putCharUnaligned") \ do_name(getIntUnaligned_name,"getIntUnaligned") do_name(putIntUnaligned_name,"putIntUnaligned") \ @@ -1197,24 +1275,68 @@ do_intrinsic(_putDouble_raw, jdk_internal_misc_Unsafe, putDouble_name, putDouble_raw_signature, F_R) \ do_intrinsic(_putAddress_raw, jdk_internal_misc_Unsafe, putAddress_name, putAddress_raw_signature, F_R) \ \ - do_intrinsic(_compareAndSwapObject, jdk_internal_misc_Unsafe, compareAndSwapObject_name, compareAndSwapObject_signature, F_R) \ - do_name( compareAndSwapObject_name, "compareAndSwapObject") \ - do_signature(compareAndSwapObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \ - do_intrinsic(_compareAndSwapLong, jdk_internal_misc_Unsafe, compareAndSwapLong_name, compareAndSwapLong_signature, F_R) \ - do_name( compareAndSwapLong_name, "compareAndSwapLong") \ - do_signature(compareAndSwapLong_signature, "(Ljava/lang/Object;JJJ)Z") \ - do_intrinsic(_compareAndSwapInt, jdk_internal_misc_Unsafe, compareAndSwapInt_name, compareAndSwapInt_signature, F_R) \ - do_name( compareAndSwapInt_name, "compareAndSwapInt") \ - do_signature(compareAndSwapInt_signature, "(Ljava/lang/Object;JII)Z") \ - do_intrinsic(_putOrderedObject, jdk_internal_misc_Unsafe, putOrderedObject_name, putOrderedObject_signature, F_R) \ - do_name( putOrderedObject_name, "putOrderedObject") \ - do_alias( putOrderedObject_signature, /*(LObject;JLObject;)V*/ putObject_signature) \ - do_intrinsic(_putOrderedLong, jdk_internal_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_R) \ - do_name( putOrderedLong_name, "putOrderedLong") \ - do_alias( putOrderedLong_signature, /*(Ljava/lang/Object;JJ)V*/ putLong_signature) \ - do_intrinsic(_putOrderedInt, jdk_internal_misc_Unsafe, putOrderedInt_name, putOrderedInt_signature, F_R) \ - do_name( putOrderedInt_name, "putOrderedInt") \ - do_alias( putOrderedInt_signature, /*(Ljava/lang/Object;JI)V*/ putInt_signature) \ + do_signature(compareAndSwapObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \ + do_signature(compareAndExchangeObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ + do_signature(compareAndSwapLong_signature, "(Ljava/lang/Object;JJJ)Z") \ + do_signature(compareAndExchangeLong_signature, "(Ljava/lang/Object;JJJ)J") \ + do_signature(compareAndSwapInt_signature, "(Ljava/lang/Object;JII)Z") \ + do_signature(compareAndExchangeInt_signature, "(Ljava/lang/Object;JII)I") \ + \ + do_name(compareAndSwapObject_name, "compareAndSwapObject") \ + do_name(compareAndExchangeObjectVolatile_name, "compareAndExchangeObjectVolatile") \ + do_name(compareAndExchangeObjectAcquire_name, "compareAndExchangeObjectAcquire") \ + do_name(compareAndExchangeObjectRelease_name, "compareAndExchangeObjectRelease") \ + do_name(compareAndSwapLong_name, "compareAndSwapLong") \ + do_name(compareAndExchangeLongVolatile_name, "compareAndExchangeLongVolatile") \ + do_name(compareAndExchangeLongAcquire_name, "compareAndExchangeLongAcquire") \ + do_name(compareAndExchangeLongRelease_name, "compareAndExchangeLongRelease") \ + do_name(compareAndSwapInt_name, "compareAndSwapInt") \ + do_name(compareAndExchangeIntVolatile_name, "compareAndExchangeIntVolatile") \ + do_name(compareAndExchangeIntAcquire_name, "compareAndExchangeIntAcquire") \ + do_name(compareAndExchangeIntRelease_name, "compareAndExchangeIntRelease") \ + \ + do_name(weakCompareAndSwapObject_name, "weakCompareAndSwapObject") \ + do_name(weakCompareAndSwapObjectAcquire_name, "weakCompareAndSwapObjectAcquire") \ + do_name(weakCompareAndSwapObjectRelease_name, "weakCompareAndSwapObjectRelease") \ + do_name(weakCompareAndSwapLong_name, "weakCompareAndSwapLong") \ + do_name(weakCompareAndSwapLongAcquire_name, "weakCompareAndSwapLongAcquire") \ + do_name(weakCompareAndSwapLongRelease_name, "weakCompareAndSwapLongRelease") \ + do_name(weakCompareAndSwapInt_name, "weakCompareAndSwapInt") \ + do_name(weakCompareAndSwapIntAcquire_name, "weakCompareAndSwapIntAcquire") \ + do_name(weakCompareAndSwapIntRelease_name, "weakCompareAndSwapIntRelease") \ + \ + do_intrinsic(_compareAndSwapObject, jdk_internal_misc_Unsafe, compareAndSwapObject_name, compareAndSwapObject_signature, F_RN) \ + do_intrinsic(_compareAndExchangeObjectVolatile, jdk_internal_misc_Unsafe, compareAndExchangeObjectVolatile_name, compareAndExchangeObject_signature, F_RN) \ + do_intrinsic(_compareAndExchangeObjectAcquire, jdk_internal_misc_Unsafe, compareAndExchangeObjectAcquire_name, compareAndExchangeObject_signature, F_R) \ + do_intrinsic(_compareAndExchangeObjectRelease, jdk_internal_misc_Unsafe, compareAndExchangeObjectRelease_name, compareAndExchangeObject_signature, F_R) \ + do_intrinsic(_compareAndSwapLong, jdk_internal_misc_Unsafe, compareAndSwapLong_name, compareAndSwapLong_signature, F_RN) \ + do_intrinsic(_compareAndExchangeLongVolatile, jdk_internal_misc_Unsafe, compareAndExchangeLongVolatile_name, compareAndExchangeLong_signature, F_RN) \ + do_intrinsic(_compareAndExchangeLongAcquire, jdk_internal_misc_Unsafe, compareAndExchangeLongAcquire_name, compareAndExchangeLong_signature, F_R) \ + do_intrinsic(_compareAndExchangeLongRelease, jdk_internal_misc_Unsafe, compareAndExchangeLongRelease_name, compareAndExchangeLong_signature, F_R) \ + do_intrinsic(_compareAndSwapInt, jdk_internal_misc_Unsafe, compareAndSwapInt_name, compareAndSwapInt_signature, F_RN) \ + do_intrinsic(_compareAndExchangeIntVolatile, jdk_internal_misc_Unsafe, compareAndExchangeIntVolatile_name, compareAndExchangeInt_signature, F_RN) \ + do_intrinsic(_compareAndExchangeIntAcquire, jdk_internal_misc_Unsafe, compareAndExchangeIntAcquire_name, compareAndExchangeInt_signature, F_R) \ + do_intrinsic(_compareAndExchangeIntRelease, jdk_internal_misc_Unsafe, compareAndExchangeIntRelease_name, compareAndExchangeInt_signature, F_R) \ + \ + do_intrinsic(_weakCompareAndSwapObject, jdk_internal_misc_Unsafe, weakCompareAndSwapObject_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapObjectAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapObjectAcquire_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapObjectRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapObjectRelease_name, compareAndSwapObject_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLong, jdk_internal_misc_Unsafe, weakCompareAndSwapLong_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLongAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapLongAcquire_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapLongRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapLongRelease_name, compareAndSwapLong_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapInt, jdk_internal_misc_Unsafe, weakCompareAndSwapInt_name, compareAndSwapInt_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapIntAcquire, jdk_internal_misc_Unsafe, weakCompareAndSwapIntAcquire_name, compareAndSwapInt_signature, F_R) \ + do_intrinsic(_weakCompareAndSwapIntRelease, jdk_internal_misc_Unsafe, weakCompareAndSwapIntRelease_name, compareAndSwapInt_signature, F_R) \ + \ + do_intrinsic(_putOrderedObject, jdk_internal_misc_Unsafe, putOrderedObject_name, putOrderedObject_signature, F_RN) \ + do_name( putOrderedObject_name, "putOrderedObject") \ + do_alias( putOrderedObject_signature, /*(LObject;JLObject;)V*/ putObject_signature) \ + do_intrinsic(_putOrderedLong, jdk_internal_misc_Unsafe, putOrderedLong_name, putOrderedLong_signature, F_RN) \ + do_name( putOrderedLong_name, "putOrderedLong") \ + do_alias( putOrderedLong_signature, /*(Ljava/lang/Object;JJ)V*/ putLong_signature) \ + do_intrinsic(_putOrderedInt, jdk_internal_misc_Unsafe, putOrderedInt_name, putOrderedInt_signature, F_RN) \ + do_name( putOrderedInt_name, "putOrderedInt") \ + do_alias( putOrderedInt_signature, /*(Ljava/lang/Object;JI)V*/ putInt_signature) \ \ do_intrinsic(_getAndAddInt, jdk_internal_misc_Unsafe, getAndAddInt_name, getAndAddInt_signature, F_R) \ do_name( getAndAddInt_name, "getAndAddInt") \ diff --git a/hotspot/src/share/vm/code/codeCache.cpp b/hotspot/src/share/vm/code/codeCache.cpp index c7c31c30d3b..0882ee82739 100644 --- a/hotspot/src/share/vm/code/codeCache.cpp +++ b/hotspot/src/share/vm/code/codeCache.cpp @@ -1023,7 +1023,7 @@ void CodeCache::clear_inline_caches() { // Keeps track of time spent for checking dependencies NOT_PRODUCT(static elapsedTimer dependentCheckTime;) -int CodeCache::mark_for_deoptimization(DepChange& changes) { +int CodeCache::mark_for_deoptimization(KlassDepChange& changes) { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); int number_of_marked_CodeBlobs = 0; diff --git a/hotspot/src/share/vm/code/codeCache.hpp b/hotspot/src/share/vm/code/codeCache.hpp index a3da713c9e5..f07b4c940db 100644 --- a/hotspot/src/share/vm/code/codeCache.hpp +++ b/hotspot/src/share/vm/code/codeCache.hpp @@ -72,7 +72,7 @@ // Solaris and BSD. class OopClosure; -class DepChange; +class KlassDepChange; class CodeCache : AllStatic { friend class VMStructs; @@ -223,7 +223,7 @@ class CodeCache : AllStatic { // Deoptimization private: - static int mark_for_deoptimization(DepChange& changes); + static int mark_for_deoptimization(KlassDepChange& changes); #ifdef HOTSWAP static int mark_for_evol_deoptimization(instanceKlassHandle dependee); #endif // HOTSWAP diff --git a/hotspot/src/share/vm/code/dependencies.hpp b/hotspot/src/share/vm/code/dependencies.hpp index b62c6bf12ed..22a2fd2ce53 100644 --- a/hotspot/src/share/vm/code/dependencies.hpp +++ b/hotspot/src/share/vm/code/dependencies.hpp @@ -664,6 +664,8 @@ class DepChange : public StackObj { virtual bool is_klass_change() const { return false; } virtual bool is_call_site_change() const { return false; } + virtual void mark_for_deoptimization(nmethod* nm) = 0; + // Subclass casting with assertions. KlassDepChange* as_klass_change() { assert(is_klass_change(), "bad cast"); @@ -753,6 +755,10 @@ class KlassDepChange : public DepChange { // What kind of DepChange is this? virtual bool is_klass_change() const { return true; } + virtual void mark_for_deoptimization(nmethod* nm) { + nm->mark_for_deoptimization(/*inc_recompile_counts=*/true); + } + Klass* new_type() { return _new_type(); } // involves_context(k) is true if k is new_type or any of the super types @@ -772,6 +778,10 @@ class CallSiteDepChange : public DepChange { // What kind of DepChange is this? virtual bool is_call_site_change() const { return true; } + virtual void mark_for_deoptimization(nmethod* nm) { + nm->mark_for_deoptimization(/*inc_recompile_counts=*/false); + } + oop call_site() const { return _call_site(); } oop method_handle() const { return _method_handle(); } }; diff --git a/hotspot/src/share/vm/code/dependencyContext.cpp b/hotspot/src/share/vm/code/dependencyContext.cpp index dc19c4a0886..435fb0cdfb2 100644 --- a/hotspot/src/share/vm/code/dependencyContext.cpp +++ b/hotspot/src/share/vm/code/dependencyContext.cpp @@ -73,7 +73,7 @@ int DependencyContext::mark_dependent_nmethods(DepChange& changes) { nm->print(); nm->print_dependencies(); } - nm->mark_for_deoptimization(); + changes.mark_for_deoptimization(nm); found++; } } diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 63acd8f424d..46fe64850e4 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -536,7 +536,7 @@ void nmethod::init_defaults() { _has_method_handle_invokes = 0; _lazy_critical_native = 0; _has_wide_vectors = 0; - _marked_for_deoptimization = 0; + _mark_for_deoptimization_status = not_marked; _lock_count = 0; _stack_traversal_mark = 0; _unload_reported = false; // jvmti state @@ -1459,7 +1459,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { SharedRuntime::get_handle_wrong_method_stub()); } - if (is_in_use()) { + if (is_in_use() && update_recompile_counts()) { // It's a true state change, so mark the method as decompiled. // Do it only for transition from alive. inc_decompile_count(); diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 537a68ce566..6c0d9f839ac 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -107,6 +107,7 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC { // [Implicit Null Pointer exception table] // - implicit null table array +class DepChange; class Dependencies; class ExceptionHandlerTable; class ImplicitExceptionTable; @@ -188,7 +189,13 @@ class nmethod : public CodeBlob { bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper) - bool _marked_for_deoptimization; // Used for stack deoptimization + + enum MarkForDeoptimizationStatus { + not_marked, + deoptimize, + deoptimize_noupdate }; + + MarkForDeoptimizationStatus _mark_for_deoptimization_status; // Used for stack deoptimization // used by jvmti to track if an unload event has been posted for this nmethod. bool _unload_reported; @@ -462,8 +469,16 @@ class nmethod : public CodeBlob { void set_unloading_clock(unsigned char unloading_clock); unsigned char unloading_clock(); - bool is_marked_for_deoptimization() const { return _marked_for_deoptimization; } - void mark_for_deoptimization() { _marked_for_deoptimization = true; } + bool is_marked_for_deoptimization() const { return _mark_for_deoptimization_status != not_marked; } + void mark_for_deoptimization(bool inc_recompile_counts = true) { + _mark_for_deoptimization_status = (inc_recompile_counts ? deoptimize : deoptimize_noupdate); + } + bool update_recompile_counts() const { + // Update recompile counts when either the update is explicitly requested (deoptimize) + // or the nmethod is not marked for deoptimization at all (not_marked). + // The latter happens during uncommon traps when deoptimized nmethod is made not entrant. + return _mark_for_deoptimization_status != deoptimize_noupdate; + } void make_unloaded(BoolObjectClosure* is_alive, oop cause); diff --git a/hotspot/src/share/vm/code/relocInfo.cpp b/hotspot/src/share/vm/code/relocInfo.cpp index ec83dad64a8..444c91c46be 100644 --- a/hotspot/src/share/vm/code/relocInfo.cpp +++ b/hotspot/src/share/vm/code/relocInfo.cpp @@ -457,49 +457,6 @@ RelocationHolder Relocation::spec_simple(relocInfo::relocType rtype) { return itr._rh; } -int32_t Relocation::runtime_address_to_index(address runtime_address) { - assert(!is_reloc_index((intptr_t)runtime_address), "must not look like an index"); - - if (runtime_address == NULL) return 0; - - StubCodeDesc* p = StubCodeDesc::desc_for(runtime_address); - if (p != NULL && p->begin() == runtime_address) { - assert(is_reloc_index(p->index()), "there must not be too many stubs"); - return (int32_t)p->index(); - } else { - // Known "miscellaneous" non-stub pointers: - // os::get_polling_page(), SafepointSynchronize::address_of_state() - if (PrintRelocations) { - tty->print_cr("random unregistered address in relocInfo: " INTPTR_FORMAT, p2i(runtime_address)); - } -#ifndef _LP64 - return (int32_t) (intptr_t)runtime_address; -#else - // didn't fit return non-index - return -1; -#endif /* _LP64 */ - } -} - - -address Relocation::index_to_runtime_address(int32_t index) { - if (index == 0) return NULL; - - if (is_reloc_index(index)) { - StubCodeDesc* p = StubCodeDesc::desc_for_index(index); - assert(p != NULL, "there must be a stub for this index"); - return p->begin(); - } else { -#ifndef _LP64 - // this only works on 32bit machines - return (address) ((intptr_t) index); -#else - fatal("Relocation::index_to_runtime_address, int32_t not pointer sized"); - return NULL; -#endif /* _LP64 */ - } -} - address Relocation::old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest) { int sect = dest->section_index_of(newa); @@ -623,20 +580,13 @@ void trampoline_stub_Relocation::unpack_data() { void external_word_Relocation::pack_data_to(CodeSection* dest) { short* p = (short*) dest->locs_end(); - int32_t index = runtime_address_to_index(_target); #ifndef _LP64 - p = pack_1_int_to(p, index); + p = pack_1_int_to(p, (int32_t) (intptr_t)_target); #else - if (is_reloc_index(index)) { - p = pack_2_ints_to(p, index, 0); - } else { - jlong t = (jlong) _target; - int32_t lo = low(t); - int32_t hi = high(t); - p = pack_2_ints_to(p, lo, hi); - DEBUG_ONLY(jlong t1 = jlong_from(hi, lo)); - assert(!is_reloc_index(t1) && (address) t1 == _target, "not symmetric"); - } + jlong t = (jlong) _target; + int32_t lo = low(t); + int32_t hi = high(t); + p = pack_2_ints_to(p, lo, hi); #endif /* _LP64 */ dest->set_locs_end((relocInfo*) p); } @@ -644,16 +594,12 @@ void external_word_Relocation::pack_data_to(CodeSection* dest) { void external_word_Relocation::unpack_data() { #ifndef _LP64 - _target = index_to_runtime_address(unpack_1_int()); + _target = (address) (intptr_t)unpack_1_int(); #else int32_t lo, hi; unpack_2_ints(lo, hi); jlong t = jlong_from(hi, lo);; - if (is_reloc_index(t)) { - _target = index_to_runtime_address(t); - } else { - _target = (address) t; - } + _target = (address) t; #endif /* _LP64 */ } diff --git a/hotspot/src/share/vm/code/relocInfo.hpp b/hotspot/src/share/vm/code/relocInfo.hpp index a243bfdbee7..b399c093759 100644 --- a/hotspot/src/share/vm/code/relocInfo.hpp +++ b/hotspot/src/share/vm/code/relocInfo.hpp @@ -707,10 +707,6 @@ class Relocation VALUE_OBJ_CLASS_SPEC { assert(datalen()==0 || type()==relocInfo::none, "no data here"); } - static bool is_reloc_index(intptr_t index) { - return 0 < index && index < os::vm_page_size(); - } - protected: // Helper functions for pack_data_to() and unpack_data(). @@ -806,10 +802,6 @@ class Relocation VALUE_OBJ_CLASS_SPEC { return base + byte_offset; } - // these convert between indexes and addresses in the runtime system - static int32_t runtime_address_to_index(address runtime_address); - static address index_to_runtime_address(int32_t index); - // helpers for mapping between old and new addresses after a move or resize address old_addr_for(address newa, const CodeBuffer* src, CodeBuffer* dest); address new_addr_for(address olda, const CodeBuffer* src, CodeBuffer* dest); @@ -1253,7 +1245,8 @@ class external_word_Relocation : public DataRelocation { // Some address looking values aren't safe to treat as relocations // and should just be treated as constants. static bool can_be_relocated(address target) { - return target != NULL && !is_reloc_index((intptr_t)target); + assert(target == NULL || (uintptr_t)target >= (uintptr_t)os::vm_page_size(), INTPTR_FORMAT, (intptr_t)target); + return target != NULL; } private: diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp index 117e7d130ba..8689088455c 100644 --- a/hotspot/src/share/vm/compiler/compileBroker.cpp +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp @@ -469,7 +469,6 @@ CompileQueue* CompileBroker::compile_queue(int comp_level) { void CompileBroker::print_compile_queues(outputStream* st) { st->print_cr("Current compiles: "); MutexLocker locker(MethodCompileQueue_lock); - MutexLocker locker2(Threads_lock); char buf[2000]; int buflen = sizeof(buf); @@ -2152,18 +2151,33 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time if (CITime) { int bytes_compiled = method->code_size() + task->num_inlined_bytecodes(); - JVMCI_ONLY(CompilerStatistics* stats = compiler(task->comp_level())->stats();) if (is_osr) { _t_osr_compilation.add(time); _sum_osr_bytes_compiled += bytes_compiled; - JVMCI_ONLY(stats->_osr.update(time, bytes_compiled);) } else { _t_standard_compilation.add(time); _sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes(); - JVMCI_ONLY(stats->_standard.update(time, bytes_compiled);) } - JVMCI_ONLY(stats->_nmethods_size += code->total_size();) - JVMCI_ONLY(stats->_nmethods_code_size += code->insts_size();) + +#if INCLUDE_JVMCI + AbstractCompiler* comp = compiler(task->comp_level()); + if (comp) { + CompilerStatistics* stats = comp->stats(); + if (stats) { + if (is_osr) { + stats->_osr.update(time, bytes_compiled); + } else { + stats->_standard.update(time, bytes_compiled); + } + stats->_nmethods_size += code->total_size(); + stats->_nmethods_code_size += code->insts_size(); + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } + } else { // if (!comp) + assert(false, "Compiler object must exist"); + } +#endif // INCLUDE_JVMCI } if (UsePerfData) { @@ -2222,11 +2236,15 @@ const char* CompileBroker::compiler_name(int comp_level) { #if INCLUDE_JVMCI void CompileBroker::print_times(AbstractCompiler* comp) { CompilerStatistics* stats = comp->stats(); - tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", + if (stats) { + tty->print_cr(" %s {speed: %d bytes/s; standard: %6.3f s, %d bytes, %d methods; osr: %6.3f s, %d bytes, %d methods; nmethods_size: %d bytes; nmethods_code_size: %d bytes}", comp->name(), stats->bytes_per_second(), stats->_standard._time.seconds(), stats->_standard._bytes, stats->_standard._count, stats->_osr._time.seconds(), stats->_osr._bytes, stats->_osr._count, stats->_nmethods_size, stats->_nmethods_code_size); + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } comp->print_timers(); } #endif // INCLUDE_JVMCI @@ -2260,17 +2278,21 @@ void CompileBroker::print_times(bool per_compiler, bool aggregate) { } CompilerStatistics* stats = comp->stats(); - standard_compilation.add(stats->_standard._time); - osr_compilation.add(stats->_osr._time); + if (stats) { + standard_compilation.add(stats->_standard._time); + osr_compilation.add(stats->_osr._time); - standard_bytes_compiled += stats->_standard._bytes; - osr_bytes_compiled += stats->_osr._bytes; + standard_bytes_compiled += stats->_standard._bytes; + osr_bytes_compiled += stats->_osr._bytes; - standard_compile_count += stats->_standard._count; - osr_compile_count += stats->_osr._count; + standard_compile_count += stats->_standard._count; + osr_compile_count += stats->_osr._count; - nmethods_size += stats->_nmethods_size; - nmethods_code_size += stats->_nmethods_code_size; + nmethods_size += stats->_nmethods_size; + nmethods_code_size += stats->_nmethods_code_size; + } else { // if (!stats) + assert(false, "Compiler statistics object must exist"); + } if (per_compiler) { print_times(comp); diff --git a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp index 6962f158e5c..366bf4671b3 100644 --- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp +++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp @@ -615,7 +615,7 @@ ParNewGeneration::ParNewGeneration(ReservedSpace rs, size_t initial_byte_size) : DefNewGeneration(rs, initial_byte_size, "PCopy"), _overflow_list(NULL), _is_alive_closure(this), - _plab_stats(YoungPLABSize, PLABWeight) + _plab_stats("Young", YoungPLABSize, PLABWeight) { NOT_PRODUCT(_overflow_counter = ParGCWorkQueueOverflowInterval;) NOT_PRODUCT(_num_par_pushes = 0;) @@ -1008,9 +1008,7 @@ void ParNewGeneration::collect(bool full, from()->set_concurrent_iteration_safe_limit(from()->top()); to()->set_concurrent_iteration_safe_limit(to()->top()); - if (ResizePLAB) { - plab_stats()->adjust_desired_plab_sz(); - } + plab_stats()->adjust_desired_plab_sz(); TASKQUEUE_STATS_ONLY(thread_state_set.print_termination_stats()); TASKQUEUE_STATS_ONLY(thread_state_set.print_taskqueue_stats()); diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp index 0e2f4dd4bb3..5edec2775ed 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,19 +36,19 @@ ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : { // Ergonomically select initial concurrent refinement parameters if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { - FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, (intx)ParallelGCThreads); + FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, ParallelGCThreads); } set_green_zone(G1ConcRefinementGreenZone); if (FLAG_IS_DEFAULT(G1ConcRefinementYellowZone)) { FLAG_SET_DEFAULT(G1ConcRefinementYellowZone, green_zone() * 3); } - set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); + set_yellow_zone(MAX2(G1ConcRefinementYellowZone, green_zone())); if (FLAG_IS_DEFAULT(G1ConcRefinementRedZone)) { FLAG_SET_DEFAULT(G1ConcRefinementRedZone, yellow_zone() * 2); } - set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); + set_red_zone(MAX2(G1ConcRefinementRedZone, yellow_zone())); } ConcurrentG1Refine* ConcurrentG1Refine::create(G1CollectedHeap* g1h, CardTableEntryClosure* refine_closure, jint* ecode) { diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp index 0e5525f73c2..2333fea311f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,11 +61,11 @@ class ConcurrentG1Refine: public CHeapObj { * 2) green = 0. Means no caching. Can be a good way to minimize the * amount of time spent updating rsets during a collection. */ - int _green_zone; - int _yellow_zone; - int _red_zone; + size_t _green_zone; + size_t _yellow_zone; + size_t _red_zone; - int _thread_threshold_step; + size_t _thread_threshold_step; // We delay the refinement of 'hot' cards using the hot card cache. G1HotCardCache _hot_card_cache; @@ -100,17 +100,17 @@ class ConcurrentG1Refine: public CHeapObj { void print_worker_threads_on(outputStream* st) const; - void set_green_zone(int x) { _green_zone = x; } - void set_yellow_zone(int x) { _yellow_zone = x; } - void set_red_zone(int x) { _red_zone = x; } + void set_green_zone(size_t x) { _green_zone = x; } + void set_yellow_zone(size_t x) { _yellow_zone = x; } + void set_red_zone(size_t x) { _red_zone = x; } - int green_zone() const { return _green_zone; } - int yellow_zone() const { return _yellow_zone; } - int red_zone() const { return _red_zone; } + size_t green_zone() const { return _green_zone; } + size_t yellow_zone() const { return _yellow_zone; } + size_t red_zone() const { return _red_zone; } uint worker_thread_num() const { return _n_worker_threads; } - int thread_threshold_step() const { return _thread_threshold_step; } + size_t thread_threshold_step() const { return _thread_threshold_step; } G1HotCardCache* hot_card_cache() { return &_hot_card_cache; } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp index cefcab3065b..778b37f058e 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.cpp @@ -67,10 +67,12 @@ ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *nex void ConcurrentG1RefineThread::initialize() { // Current thread activation threshold - _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), - cg1r()->yellow_zone()); + _threshold = MIN2(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(), + cg1r()->yellow_zone()); // A thread deactivates once the number of buffer reached a deactivation threshold - _deactivation_threshold = MAX2(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone()); + _deactivation_threshold = + MAX2(_threshold - MIN2(_threshold, cg1r()->thread_threshold_step()), + cg1r()->green_zone()); } void ConcurrentG1RefineThread::wait_for_completed_buffers() { @@ -127,14 +129,14 @@ void ConcurrentG1RefineThread::run_service() { } DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); - log_debug(gc, refine)("Activated %d, on threshold: %d, current: %d", + log_debug(gc, refine)("Activated %d, on threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _threshold, dcqs.completed_buffers_num()); { SuspendibleThreadSetJoiner sts_join; do { - int curr_buffer_num = (int)dcqs.completed_buffers_num(); + size_t curr_buffer_num = dcqs.completed_buffers_num(); // If the number of the buffers falls down into the yellow zone, // that means that the transition period after the evacuation pause has ended. if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) { @@ -151,7 +153,7 @@ void ConcurrentG1RefineThread::run_service() { false /* during_pause */)); deactivate(); - log_debug(gc, refine)("Deactivated %d, off threshold: %d, current: %d", + log_debug(gc, refine)("Deactivated %d, off threshold: " SIZE_FORMAT ", current: " SIZE_FORMAT, _worker_id, _deactivation_threshold, dcqs.completed_buffers_num()); } diff --git a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp index 5b6d3ed79d5..40071766d6f 100644 --- a/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp +++ b/hotspot/src/share/vm/gc/g1/concurrentG1RefineThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,11 +53,11 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread { // The closure applied to completed log buffers. CardTableEntryClosure* _refine_closure; - int _thread_threshold_step; + size_t _thread_threshold_step; // This thread activation threshold - int _threshold; + size_t _threshold; // This thread deactivation threshold - int _deactivation_threshold; + size_t _deactivation_threshold; void wait_for_completed_buffers(); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp index 4c33fb9b211..d79ac8066b9 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp @@ -207,22 +207,24 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) { } -BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) { +BufferNode* DirtyCardQueueSet::get_completed_buffer(size_t stop_at) { BufferNode* nd = NULL; MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if ((int)_n_completed_buffers <= stop_at) { + if (_n_completed_buffers <= stop_at) { _process_completed = false; return NULL; } if (_completed_buffers_head != NULL) { nd = _completed_buffers_head; + assert(_n_completed_buffers > 0, "Invariant"); _completed_buffers_head = nd->next(); - if (_completed_buffers_head == NULL) - _completed_buffers_tail = NULL; _n_completed_buffers--; - assert(_n_completed_buffers >= 0, "Invariant"); + if (_completed_buffers_head == NULL) { + assert(_n_completed_buffers == 0, "Invariant"); + _completed_buffers_tail = NULL; + } } DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); return nd; @@ -230,7 +232,7 @@ BufferNode* DirtyCardQueueSet::get_completed_buffer(int stop_at) { bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, - int stop_at, + size_t stop_at, bool during_pause) { assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); BufferNode* nd = get_completed_buffer(stop_at); diff --git a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp index 17c92bb8ecf..96865a5784b 100644 --- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.hpp @@ -134,10 +134,10 @@ public: // is returned to the completed buffer set, and this call returns false. bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl, uint worker_i, - int stop_at, + size_t stop_at, bool during_pause); - BufferNode* get_completed_buffer(int stop_at); + BufferNode* get_completed_buffer(size_t stop_at); // Applies the current closure to all completed buffers, // non-consumptively. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp index f241d749045..743bdd598f7 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp @@ -1400,7 +1400,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc, JavaThread::dirty_card_queue_set().abandon_logs(); assert(dirty_card_queue_set().completed_buffers_num() == 0, "DCQS should be empty"); - _young_list->reset_sampled_info(); // At this point there should be no regions in the // entire heap tagged as young. assert(check_young_list_empty(true /* check_heap */), @@ -1761,8 +1760,8 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) : _young_list(new YoungList(this)), _gc_time_stamp(0), _summary_bytes_used(0), - _survivor_evac_stats(YoungPLABSize, PLABWeight), - _old_evac_stats(OldPLABSize, PLABWeight), + _survivor_evac_stats("Young", YoungPLABSize, PLABWeight), + _old_evac_stats("Old", OldPLABSize, PLABWeight), _expand_heap_after_alloc_failure(true), _old_marking_cycles_started(0), _old_marking_cycles_completed(0), @@ -1985,8 +1984,8 @@ jint G1CollectedHeap::initialize() { JavaThread::dirty_card_queue_set().initialize(_refine_cte_cl, DirtyCardQ_CBL_mon, DirtyCardQ_FL_lock, - concurrent_g1_refine()->yellow_zone(), - concurrent_g1_refine()->red_zone(), + (int)concurrent_g1_refine()->yellow_zone(), + (int)concurrent_g1_refine()->red_zone(), Shared_DirtyCardQ_lock, NULL, // fl_owner true); // init_free_ids @@ -3385,13 +3384,15 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { g1_policy()->clear_collection_set(); + record_obj_copy_mem_stats(); + _survivor_evac_stats.adjust_desired_plab_sz(); + _old_evac_stats.adjust_desired_plab_sz(); + // Start a new incremental collection set for the next pause. g1_policy()->start_incremental_cset_building(); clear_cset_fast_test(); - _young_list->reset_sampled_info(); - // Don't check the whole heap at this point as the // GC alloc regions from this pause have been tagged // as survivors and moved on to the survivor list. @@ -4398,6 +4399,8 @@ public: { } void work(uint worker_id) { + G1GCParPhaseTimesTracker x(_g1h->g1_policy()->phase_times(), G1GCPhaseTimes::PreserveCMReferents, worker_id); + ResourceMark rm; HandleMark hm; @@ -4461,13 +4464,8 @@ void G1CollectedHeap::process_weak_jni_handles() { g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0); } -// Weak Reference processing during an evacuation pause (part 1). -void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) { - double ref_proc_start = os::elapsedTime(); - - ReferenceProcessor* rp = _ref_processor_stw; - assert(rp->discovery_enabled(), "should have been enabled"); - +void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) { + double preserve_cm_referents_start = os::elapsedTime(); // Any reference objects, in the collection set, that were 'discovered' // by the CM ref processor should have already been copied (either by // applying the external root copy closure to the discovered lists, or @@ -4495,9 +4493,18 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per per_thread_states, no_of_gc_workers, _task_queues); - workers()->run_task(&keep_cm_referents); + g1_policy()->phase_times()->record_preserve_cm_referents_time_ms((os::elapsedTime() - preserve_cm_referents_start) * 1000.0); +} + +// Weak Reference processing during an evacuation pause (part 1). +void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) { + double ref_proc_start = os::elapsedTime(); + + ReferenceProcessor* rp = _ref_processor_stw; + assert(rp->discovery_enabled(), "should have been enabled"); + // Closure to test whether a referent is alive. G1STWIsAliveClosure is_alive(this); @@ -4529,6 +4536,8 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per NULL, _gc_timer_stw); } else { + uint no_of_gc_workers = workers()->active_workers(); + // Parallel reference processing assert(rp->num_q() == no_of_gc_workers, "sanity"); assert(no_of_gc_workers <= rp->max_num_q(), "sanity"); @@ -4586,6 +4595,12 @@ void G1CollectedHeap::enqueue_discovered_references(G1ParScanThreadStateSet* per g1_policy()->phase_times()->record_ref_enq_time(ref_enq_time * 1000.0); } +void G1CollectedHeap::merge_per_thread_state_info(G1ParScanThreadStateSet* per_thread_states) { + double merge_pss_time_start = os::elapsedTime(); + per_thread_states->flush(); + g1_policy()->phase_times()->record_merge_pss_time_ms((os::elapsedTime() - merge_pss_time_start) * 1000.0); +} + void G1CollectedHeap::pre_evacuate_collection_set() { _expand_heap_after_alloc_failure = true; _evacuation_failed = false; @@ -4644,6 +4659,7 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in // objects (and their reachable sub-graphs) that were // not copied during the pause. if (g1_policy()->should_process_references()) { + preserve_cm_referents(per_thread_states); process_discovered_references(per_thread_states); } else { ref_processor_stw()->verify_no_references_recorded(); @@ -4687,12 +4703,7 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in _allocator->release_gc_alloc_regions(evacuation_info); - per_thread_states->flush(); - - record_obj_copy_mem_stats(); - - _survivor_evac_stats.adjust_desired_plab_sz(); - _old_evac_stats.adjust_desired_plab_sz(); + merge_per_thread_state_info(per_thread_states); // Reset and re-enable the hot card cache. // Note the counts for the cards in the regions in the @@ -5188,8 +5199,8 @@ public: bool success() { return _success; } }; -bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample) { - bool ret = _young_list->check_list_empty(check_sample); +bool G1CollectedHeap::check_young_list_empty(bool check_heap) { + bool ret = _young_list->check_list_empty(); if (check_heap) { NoYoungRegionsClosure closure; diff --git a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp index 3d8badc27bb..adbf7a20ef8 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp @@ -511,6 +511,9 @@ protected: // allocated block, or else "NULL". HeapWord* expand_and_allocate(size_t word_size, AllocationContext_t context); + // Preserve any referents discovered by concurrent marking that have not yet been + // copied by the STW pause. + void preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states); // Process any reference objects discovered during // an incremental evacuation pause. void process_discovered_references(G1ParScanThreadStateSet* per_thread_states); @@ -519,6 +522,9 @@ protected: // after processing. void enqueue_discovered_references(G1ParScanThreadStateSet* per_thread_states); + // Merges the information gathered on a per-thread basis for all worker threads + // during GC into global variables. + void merge_per_thread_state_info(G1ParScanThreadStateSet* per_thread_states); public: WorkGang* workers() const { return _workers; } @@ -1333,8 +1339,7 @@ public: return _young_list->check_list_well_formed(); } - bool check_young_list_empty(bool check_heap, - bool check_sample = true); + bool check_young_list_empty(bool check_heap); // *** Stuff related to concurrent marking. It's not clear to me that so // many of these need to be public. diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp index 93b2cce3dd1..eda5e18e1a8 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp @@ -787,10 +787,9 @@ double G1CollectorPolicy::predict_survivor_regions_evac_time() const { return survivor_regions_evac_time; } -void G1CollectorPolicy::revise_young_list_target_length_if_necessary() { +void G1CollectorPolicy::revise_young_list_target_length_if_necessary(size_t rs_lengths) { guarantee( adaptive_young_list_length(), "should not call this otherwise" ); - size_t rs_lengths = _g1->young_list()->sampled_rs_lengths(); if (rs_lengths > _rs_lengths_prediction) { // add 10% to avoid having to recalculate often size_t rs_lengths_prediction = rs_lengths * 1100 / 1000; @@ -1118,14 +1117,15 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t _short_lived_surv_rate_group->start_adding_regions(); // Do that for any other surv rate groups + double scan_hcc_time_ms = ConcurrentG1Refine::hot_card_cache_enabled() ? average_time_ms(G1GCPhaseTimes::ScanHCC) : 0.0; + if (update_stats) { double cost_per_card_ms = 0.0; - double cost_scan_hcc = average_time_ms(G1GCPhaseTimes::ScanHCC); if (_pending_cards > 0) { - cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - cost_scan_hcc) / (double) _pending_cards; + cost_per_card_ms = (average_time_ms(G1GCPhaseTimes::UpdateRS) - scan_hcc_time_ms) / (double) _pending_cards; _cost_per_card_ms_seq->add(cost_per_card_ms); } - _cost_scan_hcc_seq->add(cost_scan_hcc); + _cost_scan_hcc_seq->add(scan_hcc_time_ms); double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { @@ -1215,8 +1215,6 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t // Note that _mmu_tracker->max_gc_time() returns the time in seconds. double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0; - double scan_hcc_time_ms = average_time_ms(G1GCPhaseTimes::ScanHCC); - if (update_rs_time_goal_ms < scan_hcc_time_ms) { log_debug(gc, ergo, refine)("Adjust concurrent refinement thresholds (scanning the HCC expected to take longer than Update RS time goal)." "Update RS time goal: %1.2fms Scan HCC time: %1.2fms", @@ -1302,12 +1300,12 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, const int k_gy = 3, k_gr = 6; const double inc_k = 1.1, dec_k = 0.9; - int g = cg1r->green_zone(); + size_t g = cg1r->green_zone(); if (update_rs_time > goal_ms) { - g = (int)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. + g = (size_t)(g * dec_k); // Can become 0, that's OK. That would mean a mutator-only processing. } else { if (update_rs_time < goal_ms && update_rs_processed_buffers > g) { - g = (int)MAX2(g * inc_k, g + 1.0); + g = (size_t)MAX2(g * inc_k, g + 1.0); } } // Change the refinement threads params @@ -1316,15 +1314,15 @@ void G1CollectorPolicy::adjust_concurrent_refinement(double update_rs_time, cg1r->set_red_zone(g * k_gr); cg1r->reinitialize_threads(); - int processing_threshold_delta = MAX2((int)(cg1r->green_zone() * _predictor.sigma()), 1); - int processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, + size_t processing_threshold_delta = MAX2(cg1r->green_zone() * _predictor.sigma(), 1); + size_t processing_threshold = MIN2(cg1r->green_zone() + processing_threshold_delta, cg1r->yellow_zone()); // Change the barrier params - dcqs.set_process_completed_threshold(processing_threshold); - dcqs.set_max_completed_queue(cg1r->red_zone()); + dcqs.set_process_completed_threshold((int)processing_threshold); + dcqs.set_max_completed_queue((int)cg1r->red_zone()); } - int curr_queue_size = dcqs.completed_buffers_num(); + size_t curr_queue_size = dcqs.completed_buffers_num(); if (curr_queue_size >= cg1r->yellow_zone()) { dcqs.set_completed_queue_padding(curr_queue_size); } else { diff --git a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp index fbdc47742cf..6db53e64119 100644 --- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp @@ -471,7 +471,7 @@ public: // Check the current value of the young list RSet lengths and // compare it against the last prediction. If the current value is // higher, recalculate the young list target length prediction. - void revise_young_list_target_length_if_necessary(); + void revise_young_list_target_length_if_necessary(size_t rs_lengths); // This should be called after the heap is resized. void record_new_heap_size(uint new_number_of_regions); diff --git a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp index edfb510d6fe..33e001122ae 100644 --- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1097,7 +1097,7 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { reset_marking_state(); } else { { - GCTraceTime(Debug, gc) trace("GC Aggregate Data", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc) trace("Aggregate Data", g1h->gc_timer_cm()); // Aggregate the per-task counting data that we have accumulated // while marking. @@ -2018,7 +2018,7 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { // Inner scope to exclude the cleaning of the string and symbol // tables from the displayed time. { - GCTraceTime(Debug, gc) trace("GC Ref Proc", g1h->gc_timer_cm()); + GCTraceTime(Debug, gc) trace("Reference Processing", g1h->gc_timer_cm()); ReferenceProcessor* rp = g1h->ref_processor_cm(); @@ -2271,7 +2271,7 @@ void G1ConcurrentMark::checkpointRootsFinalWork() { SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set(); guarantee(has_overflown() || satb_mq_set.completed_buffers_num() == 0, - "Invariant: has_overflown = %s, num buffers = %d", + "Invariant: has_overflown = %s, num buffers = " SIZE_FORMAT, BOOL_TO_STR(has_overflown()), satb_mq_set.completed_buffers_num()); @@ -2702,11 +2702,8 @@ public: }; static ReferenceProcessor* get_cm_oop_closure_ref_processor(G1CollectedHeap* g1h) { - ReferenceProcessor* result = NULL; - if (G1UseConcMarkReferenceProcessing) { - result = g1h->ref_processor_cm(); - assert(result != NULL, "should not be NULL"); - } + ReferenceProcessor* result = g1h->ref_processor_cm(); + assert(result != NULL, "CM reference processor should not be NULL"); return result; } diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp index a000a1e40ce..1cb7384ed46 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,15 +29,26 @@ #include "logging/log.hpp" #include "trace/tracing.hpp" +void G1EvacStats::log_plab_allocation() { + PLABStats::log_plab_allocation(); + log_debug(gc, plab)("%s other allocation: " + "region end waste: " SIZE_FORMAT "B, " + "regions filled: %u, " + "direct allocated: " SIZE_FORMAT "B, " + "failure used: " SIZE_FORMAT "B, " + "failure wasted: " SIZE_FORMAT "B", + _description, + _region_end_waste * HeapWordSize, + _regions_filled, + _direct_allocated * HeapWordSize, + _failure_used * HeapWordSize, + _failure_waste * HeapWordSize); +} + void G1EvacStats::adjust_desired_plab_sz() { + log_plab_allocation(); + if (!ResizePLAB) { - log_debug(gc, plab)(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " - "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " " - "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " " - "regions filled = %u direct_allocated = " SIZE_FORMAT " " - "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") ", - _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste, - _regions_filled, _direct_allocated, _failure_used, _failure_waste); // Clear accumulators for next round. reset(); return; @@ -107,18 +118,19 @@ void G1EvacStats::adjust_desired_plab_sz() { // Latch the result _desired_net_plab_sz = plab_sz; - log_debug(gc, plab)(" (allocated = " SIZE_FORMAT " wasted = " SIZE_FORMAT " " - "unused = " SIZE_FORMAT " used = " SIZE_FORMAT " " - "undo_waste = " SIZE_FORMAT " region_end_waste = " SIZE_FORMAT " " - "regions filled = %u direct_allocated = " SIZE_FORMAT " " - "failure_used = " SIZE_FORMAT " failure_waste = " SIZE_FORMAT ") " - " (plab_sz = " SIZE_FORMAT " desired_plab_sz = " SIZE_FORMAT ")", - _allocated, _wasted, _unused, used(), _undo_wasted, _region_end_waste, - _regions_filled, _direct_allocated, _failure_used, _failure_waste, - cur_plab_sz, plab_sz); - + log_sizing(cur_plab_sz, plab_sz); // Clear accumulators for next round. reset(); } +G1EvacStats::G1EvacStats(const char* description, size_t desired_plab_sz_, unsigned wt) : + PLABStats(description, desired_plab_sz_, wt), + _region_end_waste(0), + _regions_filled(0), + _direct_allocated(0), + _failure_used(0), + _failure_waste(0) { +} + + G1EvacStats::~G1EvacStats() { } diff --git a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp index 1d0a53f5453..b322593e7ea 100644 --- a/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp +++ b/hotspot/src/share/vm/gc/g1/g1EvacStats.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,20 +51,15 @@ class G1EvacStats : public PLABStats { _failure_waste = 0; } + virtual void log_plab_allocation(); + public: - G1EvacStats(size_t desired_plab_sz_, unsigned wt) : PLABStats(desired_plab_sz_, wt), - _region_end_waste(0), _regions_filled(0), _direct_allocated(0), - _failure_used(0), _failure_waste(0) { - } + G1EvacStats(const char* description, size_t desired_plab_sz_, unsigned wt); + + ~G1EvacStats(); virtual void adjust_desired_plab_sz(); - size_t allocated() const { return _allocated; } - size_t wasted() const { return _wasted; } - size_t unused() const { return _unused; } - size_t used() const { return allocated() - (wasted() + unused()); } - size_t undo_wasted() const { return _undo_wasted; } - uint regions_filled() const { return _regions_filled; } size_t region_end_waste() const { return _region_end_waste; } size_t direct_allocated() const { return _direct_allocated; } @@ -77,8 +72,6 @@ class G1EvacStats : public PLABStats { inline void add_direct_allocated(size_t value); inline void add_region_end_waste(size_t value); inline void add_failure_used_and_waste(size_t used, size_t waste); - - ~G1EvacStats(); }; #endif // SHARE_VM_GC_G1_G1EVACSTATS_HPP diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp index 706495fdbc7..9ab25e6a73f 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.cpp @@ -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 @@ -28,107 +28,70 @@ #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/workerDataArray.inline.hpp" -#include "memory/allocation.hpp" +#include "memory/resourceArea.hpp" #include "logging/log.hpp" #include "runtime/timer.hpp" #include "runtime/os.hpp" -// Helper class for avoiding interleaved logging -class LineBuffer: public StackObj { - -private: - static const int BUFFER_LEN = 1024; - static const int INDENT_CHARS = 3; - char _buffer[BUFFER_LEN]; - int _indent_level; - int _cur; - - void vappend(const char* format, va_list ap) ATTRIBUTE_PRINTF(2, 0) { - int res = vsnprintf(&_buffer[_cur], BUFFER_LEN - _cur, format, ap); - if (res != -1) { - _cur += res; - } else { - DEBUG_ONLY(warning("buffer too small in LineBuffer");) - _buffer[BUFFER_LEN -1] = 0; - _cur = BUFFER_LEN; // vsnprintf above should not add to _buffer if we are called again - } - } - -public: - explicit LineBuffer(int indent_level): _indent_level(indent_level), _cur(0) { - for (; (_cur < BUFFER_LEN && _cur < (_indent_level * INDENT_CHARS)); _cur++) { - _buffer[_cur] = ' '; - } - } - -#ifndef PRODUCT - ~LineBuffer() { - assert(_cur == _indent_level * INDENT_CHARS, "pending data in buffer - append_and_print_cr() not called?"); - } -#endif - - void append(const char* format, ...) ATTRIBUTE_PRINTF(2, 3) { - va_list ap; - va_start(ap, format); - vappend(format, ap); - va_end(ap); - } - - const char* to_string() { - _cur = _indent_level * INDENT_CHARS; - return _buffer; - } -}; - -static const char* Indents[4] = {"", " ", " ", " "}; +static const char* Indents[5] = {"", " ", " ", " ", " "}; G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _max_gc_threads(max_gc_threads) { assert(max_gc_threads > 0, "Must have some GC threads"); - _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start:", false, 2); - _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning:", true, 2); + _gc_par_phases[GCWorkerStart] = new WorkerDataArray(max_gc_threads, "GC Worker Start (ms):"); + _gc_par_phases[ExtRootScan] = new WorkerDataArray(max_gc_threads, "Ext Root Scanning (ms):"); // Root scanning phases - _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots:", true, 3); - _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots:", true, 3); - _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots:", true, 3); - _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots:", true, 3); - _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots:", true, 3); - _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots:", true, 3); - _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots:", true, 3); - _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots:", true, 3); - _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots:", true, 3); - _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots:", true, 3); - _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots:", true, 3); - _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD:", true, 3); - _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots:", true, 3); - _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering:", true, 3); + _gc_par_phases[ThreadRoots] = new WorkerDataArray(max_gc_threads, "Thread Roots (ms):"); + _gc_par_phases[StringTableRoots] = new WorkerDataArray(max_gc_threads, "StringTable Roots (ms):"); + _gc_par_phases[UniverseRoots] = new WorkerDataArray(max_gc_threads, "Universe Roots (ms):"); + _gc_par_phases[JNIRoots] = new WorkerDataArray(max_gc_threads, "JNI Handles Roots (ms):"); + _gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray(max_gc_threads, "ObjectSynchronizer Roots (ms):"); + _gc_par_phases[FlatProfilerRoots] = new WorkerDataArray(max_gc_threads, "FlatProfiler Roots (ms):"); + _gc_par_phases[ManagementRoots] = new WorkerDataArray(max_gc_threads, "Management Roots (ms):"); + _gc_par_phases[SystemDictionaryRoots] = new WorkerDataArray(max_gc_threads, "SystemDictionary Roots (ms):"); + _gc_par_phases[CLDGRoots] = new WorkerDataArray(max_gc_threads, "CLDG Roots (ms):"); + _gc_par_phases[JVMTIRoots] = new WorkerDataArray(max_gc_threads, "JVMTI Roots (ms):"); + _gc_par_phases[CMRefRoots] = new WorkerDataArray(max_gc_threads, "CM RefProcessor Roots (ms):"); + _gc_par_phases[WaitForStrongCLD] = new WorkerDataArray(max_gc_threads, "Wait For Strong CLD (ms):"); + _gc_par_phases[WeakCLDRoots] = new WorkerDataArray(max_gc_threads, "Weak CLD Roots (ms):"); + _gc_par_phases[SATBFiltering] = new WorkerDataArray(max_gc_threads, "SATB Filtering (ms):"); - _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS:", true, 2); - _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC:", true, 3); - _gc_par_phases[ScanHCC]->set_enabled(ConcurrentG1Refine::hot_card_cache_enabled()); - _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS:", true, 2); - _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning:", true, 2); - _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy:", true, 2); - _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination:", true, 2); - _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total:", true, 2); - _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End:", false, 2); - _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other:", true, 2); + _gc_par_phases[UpdateRS] = new WorkerDataArray(max_gc_threads, "Update RS (ms):"); + if (ConcurrentG1Refine::hot_card_cache_enabled()) { + _gc_par_phases[ScanHCC] = new WorkerDataArray(max_gc_threads, "Scan HCC (ms):"); + } else { + _gc_par_phases[ScanHCC] = NULL; + } + _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms):"); + _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms):"); + _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms):"); + _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination (ms):"); + _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total (ms):"); + _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End (ms):"); + _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other (ms):"); - _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:", true, 3); + _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:"); _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers); - _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:", true, 3); + _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:"); _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts); - _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup:", true, 2); - _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup:", true, 2); + if (UseStringDeduplication) { + _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup (ms):"); + _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup (ms):"); + } else { + _gc_par_phases[StringDedupQueueFixup] = NULL; + _gc_par_phases[StringDedupTableFixup] = NULL; + } - _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty:", true, 3); - _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:", true, 3); + _gc_par_phases[RedirtyCards] = new WorkerDataArray(max_gc_threads, "Parallel Redirty (ms):"); + _redirtied_cards = new WorkerDataArray(max_gc_threads, "Redirtied Cards:"); _gc_par_phases[RedirtyCards]->link_thread_work_items(_redirtied_cards); + + _gc_par_phases[PreserveCMReferents] = new WorkerDataArray(max_gc_threads, "Parallel Preserve CM Refs (ms):"); } void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { @@ -140,11 +103,10 @@ void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { _external_accounted_time_ms = 0.0; for (int i = 0; i < GCParPhasesSentinel; i++) { - _gc_par_phases[i]->reset(); + if (_gc_par_phases[i] != NULL) { + _gc_par_phases[i]->reset(); + } } - - _gc_par_phases[StringDedupQueueFixup]->set_enabled(G1StringDedup::is_enabled()); - _gc_par_phases[StringDedupTableFixup]->set_enabled(G1StringDedup::is_enabled()); } void G1GCPhaseTimes::note_gc_end() { @@ -166,43 +128,10 @@ void G1GCPhaseTimes::note_gc_end() { } for (int i = 0; i < GCParPhasesSentinel; i++) { - _gc_par_phases[i]->verify(_active_gc_threads); - } -} - -void G1GCPhaseTimes::print_stats(const char* indent, const char* str, double value) { - log_debug(gc, phases)("%s%s: %.1lf ms", indent, str, value); -} - -double G1GCPhaseTimes::accounted_time_ms() { - // First subtract any externally accounted time - double misc_time_ms = _external_accounted_time_ms; - - // Subtract the root region scanning wait time. It's initialized to - // zero at the start of the pause. - misc_time_ms += _root_region_scan_wait_time_ms; - - misc_time_ms += _cur_collection_par_time_ms; - - // Now subtract the time taken to fix up roots in generated code - misc_time_ms += _cur_collection_code_root_fixup_time_ms; - - // Strong code root purge time - misc_time_ms += _cur_strong_code_root_purge_time_ms; - - if (G1StringDedup::is_enabled()) { - // String dedup fixup time - misc_time_ms += _cur_string_dedup_fixup_time_ms; + if (_gc_par_phases[i] != NULL) { + _gc_par_phases[i]->verify(_active_gc_threads); } - - // Subtract the time taken to clean the card table from the - // current value of "other time" - misc_time_ms += _cur_clear_ct_time_ms; - - // Remove expand heap time from "other time" - misc_time_ms += _cur_expand_heap_time_ms; - - return misc_time_ms; + } } // record the time a phase took in seconds @@ -224,193 +153,144 @@ double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { return _gc_par_phases[phase]->average(_active_gc_threads) * 1000.0; } -double G1GCPhaseTimes::get_time_ms(GCParPhases phase, uint worker_i) { - return _gc_par_phases[phase]->get(worker_i) * 1000.0; -} - -double G1GCPhaseTimes::sum_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->sum(_active_gc_threads) * 1000.0; -} - -double G1GCPhaseTimes::min_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->minimum(_active_gc_threads) * 1000.0; -} - -double G1GCPhaseTimes::max_time_ms(GCParPhases phase) { - return _gc_par_phases[phase]->maximum(_active_gc_threads) * 1000.0; -} - -size_t G1GCPhaseTimes::get_thread_work_item(GCParPhases phase, uint worker_i) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->get(worker_i); -} - size_t G1GCPhaseTimes::sum_thread_work_items(GCParPhases phase) { assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); return _gc_par_phases[phase]->thread_work_items()->sum(_active_gc_threads); } -double G1GCPhaseTimes::average_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->average(_active_gc_threads); +template +void G1GCPhaseTimes::details(T* phase, const char* indent) { + LogHandle(gc, phases, task) log; + if (log.is_level(LogLevel::Trace)) { + outputStream* trace_out = log.trace_stream(); + trace_out->print("%s", indent); + phase->print_details_on(trace_out, _active_gc_threads); + } } -size_t G1GCPhaseTimes::min_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->minimum(_active_gc_threads); +void G1GCPhaseTimes::log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum) { + out->print("%s", Indents[indent]); + phase->print_summary_on(out, _active_gc_threads, print_sum); + details(phase, Indents[indent]); + + WorkerDataArray* work_items = phase->thread_work_items(); + if (work_items != NULL) { + out->print("%s", Indents[indent + 1]); + work_items->print_summary_on(out, _active_gc_threads, true); + details(work_items, Indents[indent + 1]); + } } -size_t G1GCPhaseTimes::max_thread_work_items(GCParPhases phase) { - assert(_gc_par_phases[phase]->thread_work_items() != NULL, "No sub count"); - return _gc_par_phases[phase]->thread_work_items()->maximum(_active_gc_threads); +void G1GCPhaseTimes::debug_phase(WorkerDataArray* phase) { + LogHandle(gc, phases) log; + if (log.is_level(LogLevel::Debug)) { + ResourceMark rm; + log_phase(phase, 2, log.debug_stream(), true); + } } -class G1GCParPhasePrinter : public StackObj { - G1GCPhaseTimes* _phase_times; - public: - G1GCParPhasePrinter(G1GCPhaseTimes* phase_times) : _phase_times(phase_times) {} - - void print(G1GCPhaseTimes::GCParPhases phase_id) { - WorkerDataArray* phase = _phase_times->_gc_par_phases[phase_id]; - - if (phase->_length == 1) { - print_single_length(phase_id, phase); - } else { - print_multi_length(phase_id, phase); - } +void G1GCPhaseTimes::trace_phase(WorkerDataArray* phase, bool print_sum) { + LogHandle(gc, phases) log; + if (log.is_level(LogLevel::Trace)) { + ResourceMark rm; + log_phase(phase, 3, log.trace_stream(), print_sum); } +} +#define PHASE_DOUBLE_FORMAT "%s%s: %.1lfms" +#define PHASE_SIZE_FORMAT "%s%s: " SIZE_FORMAT - private: - void print_single_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - // No need for min, max, average and sum for only one worker - log_debug(gc, phases)("%s%s: %.1lf", Indents[phase->_indent_level], phase->_title, _phase_times->get_time_ms(phase_id, 0)); +#define info_line(str, value) \ + log_info(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[1], str, value); - WorkerDataArray* work_items = phase->_thread_work_items; - if (work_items != NULL) { - log_debug(gc, phases)("%s%s: " SIZE_FORMAT, Indents[work_items->_indent_level], work_items->_title, _phase_times->sum_thread_work_items(phase_id)); - } - } +#define debug_line(str, value) \ + log_debug(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[2], str, value); - void print_time_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id) { - if (log_is_enabled(Trace, gc)) { - LineBuffer buf(0); - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" %4.1lf", _phase_times->get_time_ms(phase_id, i)); - } - const char* line = buf.to_string(); - log_trace(gc, phases)("%s%-25s%s", indent, "", line); - } - } +#define trace_line(str, value) \ + log_trace(gc, phases)(PHASE_DOUBLE_FORMAT, Indents[3], str, value); - void print_count_values(const char* indent, G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - if (log_is_enabled(Trace, gc)) { - LineBuffer buf(0); - uint active_length = _phase_times->_active_gc_threads; - for (uint i = 0; i < active_length; ++i) { - buf.append(" " SIZE_FORMAT, _phase_times->get_thread_work_item(phase_id, i)); - } - const char* line = buf.to_string(); - log_trace(gc, phases)("%s%-25s%s", indent, "", line); - } - } +#define trace_line_sz(str, value) \ + log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); - void print_thread_work_items(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* thread_work_items) { - const char* indent = Indents[thread_work_items->_indent_level]; +#define trace_line_ms(str, value) \ + log_trace(gc, phases)(PHASE_SIZE_FORMAT, Indents[3], str, value); - assert(thread_work_items->_print_sum, "%s does not have print sum true even though it is a count", thread_work_items->_title); - - log_debug(gc, phases)("%s%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT ", Sum: " SIZE_FORMAT, - indent, thread_work_items->_title, - _phase_times->min_thread_work_items(phase_id), _phase_times->average_thread_work_items(phase_id), _phase_times->max_thread_work_items(phase_id), - _phase_times->max_thread_work_items(phase_id) - _phase_times->min_thread_work_items(phase_id), _phase_times->sum_thread_work_items(phase_id)); - - print_count_values(indent, phase_id, thread_work_items); - } - - void print_multi_length(G1GCPhaseTimes::GCParPhases phase_id, WorkerDataArray* phase) { - const char* indent = Indents[phase->_indent_level]; - - if (phase->_print_sum) { - log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf, Sum: %4.1lf", - indent, phase->_title, - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id), _phase_times->sum_time_ms(phase_id)); - } else { - log_debug(gc, phases)("%s%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", - indent, phase->_title, - _phase_times->min_time_ms(phase_id), _phase_times->average_time_ms(phase_id), _phase_times->max_time_ms(phase_id), - _phase_times->max_time_ms(phase_id) - _phase_times->min_time_ms(phase_id)); - } - - print_time_values(indent, phase_id); - - if (phase->_thread_work_items != NULL) { - print_thread_work_items(phase_id, phase->_thread_work_items); - } - } -}; +#define info_line_and_account(str, value) \ + info_line(str, value); \ + accounted_time_ms += value; void G1GCPhaseTimes::print() { note_gc_end(); - G1GCParPhasePrinter par_phase_printer(this); - + double accounted_time_ms = _external_accounted_time_ms; if (_root_region_scan_wait_time_ms > 0.0) { - print_stats(Indents[1], "Root Region Scan Waiting", _root_region_scan_wait_time_ms); + info_line_and_account("Root Region Scan Waiting", _root_region_scan_wait_time_ms); } - print_stats(Indents[1], "Parallel Time", _cur_collection_par_time_ms); - for (int i = 0; i <= GCMainParPhasesLast; i++) { - par_phase_printer.print((GCParPhases) i); + info_line_and_account("Evacuate Collection Set", _cur_collection_par_time_ms); + trace_phase(_gc_par_phases[GCWorkerStart], false); + debug_phase(_gc_par_phases[ExtRootScan]); + for (int i = ThreadRoots; i <= SATBFiltering; i++) { + trace_phase(_gc_par_phases[i]); } + debug_phase(_gc_par_phases[UpdateRS]); + if (ConcurrentG1Refine::hot_card_cache_enabled()) { + trace_phase(_gc_par_phases[ScanHCC]); + } + debug_phase(_gc_par_phases[ScanRS]); + debug_phase(_gc_par_phases[CodeRoots]); + debug_phase(_gc_par_phases[ObjCopy]); + debug_phase(_gc_par_phases[Termination]); + debug_phase(_gc_par_phases[Other]); + debug_phase(_gc_par_phases[GCWorkerTotal]); + trace_phase(_gc_par_phases[GCWorkerEnd], false); + + info_line_and_account("Code Roots", _cur_collection_code_root_fixup_time_ms + _cur_strong_code_root_purge_time_ms); + debug_line("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms); + debug_line("Code Roots Purge", _cur_strong_code_root_purge_time_ms); - print_stats(Indents[1], "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); - print_stats(Indents[1], "Code Root Purge", _cur_strong_code_root_purge_time_ms); if (G1StringDedup::is_enabled()) { - print_stats(Indents[1], "String Dedup Fixup", _cur_string_dedup_fixup_time_ms); - for (int i = StringDedupPhasesFirst; i <= StringDedupPhasesLast; i++) { - par_phase_printer.print((GCParPhases) i); - } + info_line_and_account("String Dedup Fixup", _cur_string_dedup_fixup_time_ms); + debug_phase(_gc_par_phases[StringDedupQueueFixup]); + debug_phase(_gc_par_phases[StringDedupTableFixup]); } - print_stats(Indents[1], "Clear CT", _cur_clear_ct_time_ms); - print_stats(Indents[1], "Expand Heap After Collection", _cur_expand_heap_time_ms); - double misc_time_ms = _gc_pause_time_ms - accounted_time_ms(); - print_stats(Indents[1], "Other", misc_time_ms); + info_line_and_account("Clear Card Table", _cur_clear_ct_time_ms); + info_line_and_account("Expand Heap After Collection", _cur_expand_heap_time_ms); + + double free_cset_time = _recorded_young_free_cset_time_ms + _recorded_non_young_free_cset_time_ms; + info_line_and_account("Free Collection Set", free_cset_time); + debug_line("Young Free Collection Set", _recorded_young_free_cset_time_ms); + debug_line("Non-Young Free Collection Set", _recorded_non_young_free_cset_time_ms); + info_line_and_account("Merge Per-Thread State", _recorded_merge_pss_time_ms); + + info_line("Other", _gc_pause_time_ms - accounted_time_ms); if (_cur_verify_before_time_ms > 0.0) { - print_stats(Indents[2], "Verify Before", _cur_verify_before_time_ms); + debug_line("Verify Before", _cur_verify_before_time_ms); } if (G1CollectedHeap::heap()->evacuation_failed()) { double evac_fail_handling = _cur_evac_fail_recalc_used + _cur_evac_fail_remove_self_forwards + _cur_evac_fail_restore_remsets; - print_stats(Indents[2], "Evacuation Failure", evac_fail_handling); - log_trace(gc, phases)("%sRecalculate Used: %.1lf ms", Indents[3], _cur_evac_fail_recalc_used); - log_trace(gc, phases)("%sRemove Self Forwards: %.1lf ms", Indents[3], _cur_evac_fail_remove_self_forwards); - log_trace(gc, phases)("%sRestore RemSet: %.1lf ms", Indents[3], _cur_evac_fail_restore_remsets); + debug_line("Evacuation Failure", evac_fail_handling); + trace_line("Recalculate Used", _cur_evac_fail_recalc_used); + trace_line("Remove Self Forwards",_cur_evac_fail_remove_self_forwards); + trace_line("Restore RemSet", _cur_evac_fail_restore_remsets); } - print_stats(Indents[2], "Choose CSet", - (_recorded_young_cset_choice_time_ms + - _recorded_non_young_cset_choice_time_ms)); - print_stats(Indents[2], "Ref Proc", _cur_ref_proc_time_ms); - print_stats(Indents[2], "Ref Enq", _cur_ref_enq_time_ms); - print_stats(Indents[2], "Redirty Cards", _recorded_redirty_logged_cards_time_ms); - par_phase_printer.print(RedirtyCards); + debug_line("Choose CSet", (_recorded_young_cset_choice_time_ms + _recorded_non_young_cset_choice_time_ms)); + debug_line("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms); + debug_line("Reference Processing", _cur_ref_proc_time_ms); + debug_line("Reference Enqueuing", _cur_ref_enq_time_ms); + debug_line("Redirty Cards", _recorded_redirty_logged_cards_time_ms); + trace_phase(_gc_par_phases[RedirtyCards]); + trace_phase(_gc_par_phases[PreserveCMReferents]); if (G1EagerReclaimHumongousObjects) { - print_stats(Indents[2], "Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); - - log_trace(gc, phases)("%sHumongous Total: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_total); - log_trace(gc, phases)("%sHumongous Candidate: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_candidates); - print_stats(Indents[2], "Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); - log_trace(gc, phases)("%sHumongous Reclaimed: " SIZE_FORMAT, Indents[3], _cur_fast_reclaim_humongous_reclaimed); + debug_line("Humongous Register", _cur_fast_reclaim_humongous_register_time_ms); + trace_line_sz("Humongous Total", _cur_fast_reclaim_humongous_total); + trace_line_sz("Humongous Candidate", _cur_fast_reclaim_humongous_candidates); + debug_line("Humongous Reclaim", _cur_fast_reclaim_humongous_time_ms); + trace_line_sz("Humongous Reclaimed", _cur_fast_reclaim_humongous_reclaimed); } - print_stats(Indents[2], "Free CSet", - (_recorded_young_free_cset_time_ms + - _recorded_non_young_free_cset_time_ms)); - log_trace(gc, phases)("%sYoung Free CSet: %.1lf ms", Indents[3], _recorded_young_free_cset_time_ms); - log_trace(gc, phases)("%sNon-Young Free CSet: %.1lf ms", Indents[3], _recorded_non_young_free_cset_time_ms); if (_cur_verify_after_time_ms > 0.0) { - print_stats(Indents[2], "Verify After", _cur_verify_after_time_ms); + debug_line("Verify After", _cur_verify_after_time_ms); } } diff --git a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp index 5607c3f4ea0..e87075b5e93 100644 --- a/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc/g1/g1GCPhaseTimes.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 @@ -32,8 +32,6 @@ class LineBuffer; template class WorkerDataArray; class G1GCPhaseTimes : public CHeapObj { - friend class G1GCParPhasePrinter; - uint _active_gc_threads; uint _max_gc_threads; jlong _gc_start_counter; @@ -69,6 +67,7 @@ class G1GCPhaseTimes : public CHeapObj { StringDedupQueueFixup, StringDedupTableFixup, RedirtyCards, + PreserveCMReferents, GCParPhasesSentinel }; @@ -108,6 +107,10 @@ class G1GCPhaseTimes : public CHeapObj { double _recorded_redirty_logged_cards_time_ms; + double _recorded_preserve_cm_referents_time_ms; + + double _recorded_merge_pss_time_ms; + double _recorded_young_free_cset_time_ms; double _recorded_non_young_free_cset_time_ms; @@ -120,11 +123,14 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_verify_before_time_ms; double _cur_verify_after_time_ms; - // Helper methods for detailed logging - void print_stats(const char*, const char* str, double value); - void note_gc_end(); + template + void details(T* phase, const char* indent); + void log_phase(WorkerDataArray* phase, uint indent, outputStream* out, bool print_sum); + void debug_phase(WorkerDataArray* phase); + void trace_phase(WorkerDataArray* phase, bool print_sum = true); + public: G1GCPhaseTimes(uint max_gc_threads); void note_gc_start(uint active_gc_threads); @@ -143,16 +149,6 @@ class G1GCPhaseTimes : public CHeapObj { size_t sum_thread_work_items(GCParPhases phase); - private: - double get_time_ms(GCParPhases phase, uint worker_i); - double sum_time_ms(GCParPhases phase); - double min_time_ms(GCParPhases phase); - double max_time_ms(GCParPhases phase); - size_t get_thread_work_item(GCParPhases phase, uint worker_i); - double average_thread_work_items(GCParPhases phase); - size_t min_thread_work_items(GCParPhases phase); - size_t max_thread_work_items(GCParPhases phase); - public: void record_clear_ct_time(double ms) { @@ -234,6 +230,14 @@ class G1GCPhaseTimes : public CHeapObj { _recorded_redirty_logged_cards_time_ms = time_ms; } + void record_preserve_cm_referents_time_ms(double time_ms) { + _recorded_preserve_cm_referents_time_ms = time_ms; + } + + void record_merge_pss_time_ms(double time_ms) { + _recorded_merge_pss_time_ms = time_ms; + } + void record_cur_collection_start_sec(double time_ms) { _cur_collection_start_sec = time_ms; } @@ -250,8 +254,6 @@ class G1GCPhaseTimes : public CHeapObj { _external_accounted_time_ms += time_ms; } - double accounted_time_ms(); - double cur_collection_start_sec() { return _cur_collection_start_sec; } diff --git a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp index b7c176d632b..013be1a12f8 100644 --- a/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp +++ b/hotspot/src/share/vm/gc/g1/g1HotCardCache.cpp @@ -81,10 +81,7 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) { } void G1HotCardCache::drain(CardTableEntryClosure* cl, uint worker_i) { - if (!default_use_cache()) { - assert(_hot_cache == NULL, "Logic"); - return; - } + assert(default_use_cache(), "Drain only necessary if we use the hot card cache."); assert(_hot_cache != NULL, "Logic"); assert(!use_cache(), "cache should be disabled"); diff --git a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp index 0cf5dab9448..5759ed0c68f 100644 --- a/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp +++ b/hotspot/src/share/vm/gc/g1/g1IHOPControl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,14 +47,16 @@ void G1IHOPControl::update_allocation_info(double allocation_time_s, size_t allo void G1IHOPControl::print() { size_t cur_conc_mark_start_threshold = get_conc_mark_start_threshold(); - log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B," - " recent old gen allocation rate: %1.2f, recent marking phase length: %1.2f", + log_debug(gc, ihop)("Basic information (value update), threshold: " SIZE_FORMAT "B (%1.2f), target occupancy: " SIZE_FORMAT "B, current occupancy: " SIZE_FORMAT "B, " + "recent allocation size: " SIZE_FORMAT "B, recent allocation duration: %1.2fms, recent old gen allocation rate: %1.2fB/s, recent marking phase length: %1.2fms", cur_conc_mark_start_threshold, cur_conc_mark_start_threshold * 100.0 / _target_occupancy, _target_occupancy, G1CollectedHeap::heap()->used(), + _last_allocated_bytes, + _last_allocation_time_s * 1000.0, _last_allocation_time_s > 0.0 ? _last_allocated_bytes / _last_allocation_time_s : 0.0, - last_marking_length_s()); + last_marking_length_s() * 1000.0); } void G1IHOPControl::send_trace_event(G1NewTracer* tracer) { @@ -191,13 +193,16 @@ void G1AdaptiveIHOPControl::update_marking_length(double marking_length_s) { void G1AdaptiveIHOPControl::print() { G1IHOPControl::print(); size_t actual_target = actual_target_threshold(); - log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B," - " predicted old gen allocation rate: %1.2f, predicted marking phase length: %1.2f, prediction active: %s", + log_debug(gc, ihop)("Adaptive IHOP information (value update), threshold: " SIZE_FORMAT "B (%1.2f), internal target occupancy: " SIZE_FORMAT "B, " + "occupancy: " SIZE_FORMAT "B, additional buffer size: " SIZE_FORMAT "B, predicted old gen allocation rate: %1.2fB/s, " + "predicted marking phase length: %1.2fms, prediction active: %s", get_conc_mark_start_threshold(), percent_of(get_conc_mark_start_threshold(), actual_target), actual_target, + G1CollectedHeap::heap()->used(), + _last_unrestrained_young_size, _predictor->get_new_prediction(&_allocation_rate_s), - _predictor->get_new_prediction(&_marking_times_s), + _predictor->get_new_prediction(&_marking_times_s) * 1000.0, have_enough_data_for_prediction() ? "true" : "false"); } diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp index f22c6e2195c..b59fc203c6c 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -327,6 +327,9 @@ oop G1ParScanThreadState::copy_to_survivor_space(InCSetState const state, G1ParScanThreadState* G1ParScanThreadStateSet::state_for_worker(uint worker_id) { assert(worker_id < _n_workers, "out of bounds access"); + if (_states[worker_id] == NULL) { + _states[worker_id] = new_par_scan_state(worker_id, _young_cset_length); + } return _states[worker_id]; } @@ -352,6 +355,10 @@ void G1ParScanThreadStateSet::flush() { for (uint worker_index = 0; worker_index < _n_workers; ++worker_index) { G1ParScanThreadState* pss = _states[worker_index]; + if (pss == NULL) { + continue; + } + _total_cards_scanned += _cards_scanned[worker_index]; pss->flush(_surviving_young_words_total); diff --git a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp index 47c5328d2b9..6accb48c1de 100644 --- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp +++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -200,6 +200,7 @@ class G1ParScanThreadStateSet : public StackObj { size_t* _surviving_young_words_total; size_t* _cards_scanned; size_t _total_cards_scanned; + size_t _young_cset_length; uint _n_workers; bool _flushed; @@ -210,10 +211,11 @@ class G1ParScanThreadStateSet : public StackObj { _surviving_young_words_total(NEW_C_HEAP_ARRAY(size_t, young_cset_length, mtGC)), _cards_scanned(NEW_C_HEAP_ARRAY(size_t, n_workers, mtGC)), _total_cards_scanned(0), + _young_cset_length(young_cset_length), _n_workers(n_workers), _flushed(false) { for (uint i = 0; i < n_workers; ++i) { - _states[i] = new_par_scan_state(i, young_cset_length); + _states[i] = NULL; } memset(_surviving_young_words_total, 0, young_cset_length * sizeof(size_t)); memset(_cards_scanned, 0, n_workers * sizeof(size_t)); diff --git a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp index 40e3959c886..8c31430e185 100644 --- a/hotspot/src/share/vm/gc/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc/g1/g1RemSet.cpp @@ -238,7 +238,7 @@ void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i) { RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); G1GCParPhaseTimesTracker x(_g1p->phase_times(), G1GCPhaseTimes::UpdateRS, worker_i); - { + if (ConcurrentG1Refine::hot_card_cache_enabled()) { // Apply the closure to the entries of the hot card cache. G1GCParPhaseTimesTracker y(_g1p->phase_times(), G1GCPhaseTimes::ScanHCC, worker_i); _g1->iterate_hcc_closure(&into_cset_update_rs_cl, worker_i); @@ -291,7 +291,6 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() { _g1->cleanUpCardTable(); DirtyCardQueueSet& into_cset_dcqs = _into_cset_dirty_card_queue_set; - int into_cset_n_buffers = into_cset_dcqs.completed_buffers_num(); if (_g1->evacuation_failed()) { double restore_remembered_set_start = os::elapsedTime(); diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp index b511b04617f..8df01b58511 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.cpp @@ -26,6 +26,8 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" @@ -55,21 +57,21 @@ void G1YoungRemSetSamplingThread::stop() { } } -G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : ConcurrentGCThread() { - _monitor = new Monitor(Mutex::nonleaf, - "G1YoungRemSetSamplingThread monitor", - true, - Monitor::_safepoint_check_never); - +G1YoungRemSetSamplingThread::G1YoungRemSetSamplingThread() : + ConcurrentGCThread(), + _monitor(Mutex::nonleaf, + "G1YoungRemSetSamplingThread monitor", + true, + Monitor::_safepoint_check_never) { set_name("G1 Young RemSet Sampling"); create_and_start(); } void G1YoungRemSetSamplingThread::sleep_before_next_cycle() { - MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); + MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); if (!_should_terminate) { - intx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? - _monitor->wait(Mutex::_no_safepoint_check_flag, waitms); + uintx waitms = G1ConcRefinementServiceIntervalMillis; // 300, really should be? + _monitor.wait(Mutex::_no_safepoint_check_flag, waitms); } } @@ -90,8 +92,8 @@ void G1YoungRemSetSamplingThread::run_service() { } void G1YoungRemSetSamplingThread::stop_service() { - MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); - _monitor->notify(); + MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); + _monitor.notify(); } void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { @@ -100,22 +102,35 @@ void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { G1CollectorPolicy* g1p = g1h->g1_policy(); if (g1p->adaptive_young_list_length()) { int regions_visited = 0; - g1h->young_list()->rs_length_sampling_init(); - while (g1h->young_list()->rs_length_sampling_more()) { - g1h->young_list()->rs_length_sampling_next(); + HeapRegion* hr = g1h->young_list()->first_region(); + size_t sampled_rs_lengths = 0; + + while (hr != NULL) { + size_t rs_length = hr->rem_set()->occupied(); + sampled_rs_lengths += rs_length; + + // The current region may not yet have been added to the + // incremental collection set (it gets added when it is + // retired as the current allocation region). + if (hr->in_collection_set()) { + // Update the collection set policy information for this region + g1p->update_incremental_cset_info(hr, rs_length); + } + ++regions_visited; // we try to yield every time we visit 10 regions if (regions_visited == 10) { if (sts.should_yield()) { sts.yield(); - // we just abandon the iteration - break; + // A gc may have occurred and our sampling data is stale and further + // traversal of the young list is unsafe + return; } regions_visited = 0; } + hr = hr->get_next_young_region(); } - - g1p->revise_young_list_target_length_if_necessary(); + g1p->revise_young_list_target_length_if_necessary(sampled_rs_lengths); } } diff --git a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp index d5837e42aee..78e82e7e352 100644 --- a/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp +++ b/hotspot/src/share/vm/gc/g1/g1YoungRemSetSamplingThread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ // increase the young gen size to keep pause time length goal. class G1YoungRemSetSamplingThread: public ConcurrentGCThread { private: - Monitor* _monitor; + Monitor _monitor; void sample_young_list_rs_lengths(); diff --git a/hotspot/src/share/vm/gc/g1/g1_globals.hpp b/hotspot/src/share/vm/gc/g1/g1_globals.hpp index 086e27bd589..7bc980e0fee 100644 --- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -71,10 +71,6 @@ "draining concurrent marking work queues.") \ range(1, max_intx) \ \ - experimental(bool, G1UseConcMarkReferenceProcessing, true, \ - "If true, enable reference discovery during concurrent " \ - "marking and reference processing at the end of remark.") \ - \ experimental(double, G1LastPLABAverageOccupancy, 50.0, \ "The expected average occupancy of the last PLAB in " \ "percent.") \ @@ -107,35 +103,35 @@ "Size of an update buffer") \ range(1, NOT_LP64(32*M) LP64_ONLY(1*G)) \ \ - product(intx, G1ConcRefinementYellowZone, 0, \ + product(size_t, G1ConcRefinementYellowZone, 0, \ "Number of enqueued update buffers that will " \ "trigger concurrent processing. Will be selected ergonomically " \ "by default.") \ range(0, max_intx) \ \ - product(intx, G1ConcRefinementRedZone, 0, \ + product(size_t, G1ConcRefinementRedZone, 0, \ "Maximum number of enqueued update buffers before mutator " \ "threads start processing new ones instead of enqueueing them. " \ "Will be selected ergonomically by default. Zero will disable " \ "concurrent processing.") \ range(0, max_intx) \ \ - product(intx, G1ConcRefinementGreenZone, 0, \ + product(size_t, G1ConcRefinementGreenZone, 0, \ "The number of update buffers that are left in the queue by the " \ "concurrent processing threads. Will be selected ergonomically " \ "by default.") \ range(0, max_intx) \ \ - product(intx, G1ConcRefinementServiceIntervalMillis, 300, \ + product(uintx, G1ConcRefinementServiceIntervalMillis, 300, \ "The last concurrent refinement thread wakes up every " \ "specified number of milliseconds to do miscellaneous work.") \ range(0, max_jint) \ \ - product(intx, G1ConcRefinementThresholdStep, 0, \ + product(size_t, G1ConcRefinementThresholdStep, 0, \ "Each time the rset update queue increases by this amount " \ "activate the next refinement thread if available. " \ "Will be selected ergonomically by default.") \ - range(0, max_jint) \ + range(0, SIZE_MAX) \ \ product(intx, G1RSetUpdatingPauseTimePercent, 10, \ "A target percentage of time that is allowed to be spend on " \ diff --git a/hotspot/src/share/vm/gc/g1/heapRegion.cpp b/hotspot/src/share/vm/gc/g1/heapRegion.cpp index 1c332adcdf1..42cb7d5928a 100644 --- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp @@ -781,7 +781,9 @@ public: ResourceMark rm; _containing_obj->print_on(log.error_stream()); log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to)); - obj->print_on(log.error_stream()); + if (obj->is_oop()) { + obj->print_on(log.error_stream()); + } log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); log.error("----------"); _failures = true; diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp index 756b9599fb8..d6cf5c50e6a 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.cpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/thread.inline.hpp" +#include + PtrQueue::PtrQueue(PtrQueueSet* qset, bool permanent, bool active) : _qset(qset), _buf(NULL), _index(0), _sz(0), _active(active), _permanent(permanent), _lock(NULL) @@ -87,6 +89,19 @@ void PtrQueue::locking_enqueue_completed_buffer(void** buf) { } +BufferNode* BufferNode::allocate(size_t byte_size) { + assert(byte_size > 0, "precondition"); + assert(is_size_aligned(byte_size, sizeof(void**)), + "Invalid buffer size " SIZE_FORMAT, byte_size); + void* data = NEW_C_HEAP_ARRAY(char, buffer_offset() + byte_size, mtGC); + return new (data) BufferNode; +} + +void BufferNode::deallocate(BufferNode* node) { + node->~BufferNode(); + FREE_C_HEAP_ARRAY(char, node); +} + PtrQueueSet::PtrQueueSet(bool notify_when_complete) : _max_completed_queue(0), _cbl_mon(NULL), _fl_lock(NULL), @@ -123,17 +138,23 @@ void PtrQueueSet::initialize(Monitor* cbl_mon, void** PtrQueueSet::allocate_buffer() { assert(_sz > 0, "Didn't set a buffer size."); - MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); - if (_fl_owner->_buf_free_list != NULL) { - void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list); - _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next(); - _fl_owner->_buf_free_list_sz--; - return res; - } else { - // Allocate space for the BufferNode in front of the buffer. - char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC); - return BufferNode::make_buffer_from_block(b); + BufferNode* node = NULL; + { + MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag); + node = _fl_owner->_buf_free_list; + if (node != NULL) { + _fl_owner->_buf_free_list = node->next(); + _fl_owner->_buf_free_list_sz--; + } } + if (node == NULL) { + node = BufferNode::allocate(_sz); + } else { + // Reinitialize buffer obtained from free list. + node->set_index(0); + node->set_next(NULL); + } + return BufferNode::make_buffer_from_node(node); } void PtrQueueSet::deallocate_buffer(void** buf) { @@ -150,13 +171,13 @@ void PtrQueueSet::reduce_free_list() { // For now we'll adopt the strategy of deleting half. MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag); size_t n = _buf_free_list_sz / 2; - while (n > 0) { - assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong."); - void* b = BufferNode::make_block_from_node(_buf_free_list); - _buf_free_list = _buf_free_list->next(); - FREE_C_HEAP_ARRAY(char, b); - _buf_free_list_sz --; - n--; + for (size_t i = 0; i < n; ++i) { + assert(_buf_free_list != NULL, + "_buf_free_list_sz is wrong: " SIZE_FORMAT, _buf_free_list_sz); + BufferNode* node = _buf_free_list; + _buf_free_list = node->next(); + _buf_free_list_sz--; + BufferNode::deallocate(node); } } @@ -236,8 +257,9 @@ bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) { void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - BufferNode* cbn = BufferNode::new_from_buffer(buf); + BufferNode* cbn = BufferNode::make_node_from_buffer(buf); cbn->set_index(index); + cbn->set_next(NULL); if (_completed_buffers_tail == NULL) { assert(_completed_buffers_head == NULL, "Well-formedness"); _completed_buffers_head = cbn; @@ -249,16 +271,17 @@ void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { _n_completed_buffers++; if (!_process_completed && _process_completed_threshold >= 0 && - _n_completed_buffers >= _process_completed_threshold) { + _n_completed_buffers >= (size_t)_process_completed_threshold) { _process_completed = true; - if (_notify_when_complete) + if (_notify_when_complete) { _cbl_mon->notify(); + } } DEBUG_ONLY(assert_completed_buffer_list_len_correct_locked()); } -int PtrQueueSet::completed_buffers_list_length() { - int n = 0; +size_t PtrQueueSet::completed_buffers_list_length() { + size_t n = 0; BufferNode* cbn = _completed_buffers_head; while (cbn != NULL) { n++; @@ -312,7 +335,8 @@ void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) { void PtrQueueSet::notify_if_necessary() { MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); - if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) { + assert(_process_completed_threshold >= 0, "_process_completed is negative"); + if (_n_completed_buffers >= (size_t)_process_completed_threshold || _max_completed_queue == 0) { _process_completed = true; if (_notify_when_complete) _cbl_mon->notify(); diff --git a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp index 707d591c0c0..4d5c5e6c28a 100644 --- a/hotspot/src/share/vm/gc/g1/ptrQueue.hpp +++ b/hotspot/src/share/vm/gc/g1/ptrQueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,9 +33,6 @@ // the addresses of modified old-generation objects. This type supports // this operation. -// The definition of placement operator new(size_t, void*) in the . -#include - class PtrQueueSet; class PtrQueue VALUE_OBJ_CLASS_SPEC { friend class VMStructs; @@ -168,42 +165,38 @@ protected: class BufferNode { size_t _index; BufferNode* _next; -public: + void* _buffer[1]; // Pseudo flexible array member. + BufferNode() : _index(0), _next(NULL) { } + ~BufferNode() { } + + static size_t buffer_offset() { + return offset_of(BufferNode, _buffer); + } + +public: BufferNode* next() const { return _next; } void set_next(BufferNode* n) { _next = n; } size_t index() const { return _index; } void set_index(size_t i) { _index = i; } - // Align the size of the structure to the size of the pointer - static size_t aligned_size() { - static const size_t alignment = round_to(sizeof(BufferNode), sizeof(void*)); - return alignment; + // Allocate a new BufferNode with the "buffer" having size bytes. + static BufferNode* allocate(size_t byte_size); + + // Free a BufferNode. + static void deallocate(BufferNode* node); + + // Return the BufferNode containing the buffer. + static BufferNode* make_node_from_buffer(void** buffer) { + return reinterpret_cast( + reinterpret_cast(buffer) - buffer_offset()); } - // BufferNode is allocated before the buffer. - // The chunk of memory that holds both of them is a block. - - // Produce a new BufferNode given a buffer. - static BufferNode* new_from_buffer(void** buf) { - return new (make_block_from_buffer(buf)) BufferNode; - } - - // The following are the required conversion routines: - static BufferNode* make_node_from_buffer(void** buf) { - return (BufferNode*)make_block_from_buffer(buf); - } + // Return the buffer for node. static void** make_buffer_from_node(BufferNode *node) { - return make_buffer_from_block(node); - } - static void* make_block_from_node(BufferNode *node) { - return (void*)node; - } - static void** make_buffer_from_block(void* p) { - return (void**)((char*)p + aligned_size()); - } - static void* make_block_from_buffer(void** p) { - return (void*)((char*)p - aligned_size()); + // &_buffer[0] might lead to index out of bounds warnings. + return reinterpret_cast( + reinterpret_cast(node) + buffer_offset()); } }; @@ -216,7 +209,7 @@ protected: Monitor* _cbl_mon; // Protects the fields below. BufferNode* _completed_buffers_head; BufferNode* _completed_buffers_tail; - int _n_completed_buffers; + size_t _n_completed_buffers; int _process_completed_threshold; volatile bool _process_completed; @@ -240,9 +233,9 @@ protected: // Maximum number of elements allowed on completed queue: after that, // enqueuer does the work itself. Zero indicates no maximum. int _max_completed_queue; - int _completed_queue_padding; + size_t _completed_queue_padding; - int completed_buffers_list_length(); + size_t completed_buffers_list_length(); void assert_completed_buffer_list_len_correct_locked(); void assert_completed_buffer_list_len_correct(); @@ -306,15 +299,15 @@ public: // list size may be reduced, if that is deemed desirable. void reduce_free_list(); - int completed_buffers_num() { return _n_completed_buffers; } + size_t completed_buffers_num() { return _n_completed_buffers; } void merge_bufferlists(PtrQueueSet* src); void set_max_completed_queue(int m) { _max_completed_queue = m; } int max_completed_queue() { return _max_completed_queue; } - void set_completed_queue_padding(int padding) { _completed_queue_padding = padding; } - int completed_queue_padding() { return _completed_queue_padding; } + void set_completed_queue_padding(size_t padding) { _completed_queue_padding = padding; } + size_t completed_queue_padding() { return _completed_queue_padding; } // Notify the consumer if the number of buffers crossed the threshold void notify_if_necessary(); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp index 0e3305d5c2a..62b66559a53 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.cpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.cpp @@ -24,18 +24,53 @@ #include "precompiled.hpp" #include "gc/g1/workerDataArray.inline.hpp" +#include "utilities/ostream.hpp" + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum) { + out->print("%-25s Min: %4.1lf, Avg: %4.1lf, Max: %4.1lf, Diff: %4.1lf", title, min * MILLIUNITS, avg * MILLIUNITS, max * MILLIUNITS, diff* MILLIUNITS); + if (print_sum) { + out->print_cr(", Sum: %4.1lf", sum * MILLIUNITS); + } else { + out->cr(); + } +} + +template <> +void WorkerDataArray::WDAPrinter::summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum) { + out->print("%-25s Min: " SIZE_FORMAT ", Avg: %4.1lf, Max: " SIZE_FORMAT ", Diff: " SIZE_FORMAT, title, min, avg, max, diff); + if (print_sum) { + out->print_cr(", Sum: " SIZE_FORMAT, sum); + } else { + out->cr(); + } +} + +template <> +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { + out->print("%-25s", ""); + for (uint i = 0; i < active_threads; ++i) { + out->print(" %4.1lf", phase->get(i) * 1000.0); + } + out->cr(); +} + +template <> +void WorkerDataArray::WDAPrinter::details(const WorkerDataArray* phase, outputStream* out, uint active_threads) { + out->print("%-25s", ""); + for (uint i = 0; i < active_threads; ++i) { + out->print(" " SIZE_FORMAT, phase->get(i)); + } + out->cr(); +} #ifndef PRODUCT void WorkerDataArray_test() { const uint length = 3; const char* title = "Test array"; - const bool print_sum = false; - const uint indent_level = 2; - WorkerDataArray array(length, title, print_sum, indent_level); + WorkerDataArray array(length, title); assert(strncmp(array.title(), title, strlen(title)) == 0 , "Expected titles to match"); - assert(array.should_print_sum() == print_sum, "Expected should_print_sum to match print_sum"); - assert(array.indentation() == indent_level, "Expected indentation to match"); const size_t expected[length] = {5, 3, 7}; for (uint i = 0; i < length; i++) { @@ -46,10 +81,7 @@ void WorkerDataArray_test() { } assert(array.sum(length) == (5 + 3 + 7), "Expected sums to match"); - assert(array.minimum(length) == 3, "Expected mininum to match"); - assert(array.maximum(length) == 7, "Expected maximum to match"); - assert(array.diff(length) == (7 - 3), "Expected diffs to match"); - assert(array.average(length) == 5, "Expected averages to match"); + assert(array.average(length) == 5.0, "Expected averages to match"); for (uint i = 0; i < length; i++) { array.add(i, 1); diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp index 09f0b61a5f7..e1e972327ea 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.hpp @@ -22,18 +22,19 @@ * */ +#ifndef SHARE_VM_GC_G1_WORKERDATAARRAY_HPP +#define SHARE_VM_GC_G1_WORKERDATAARRAY_HPP + #include "memory/allocation.hpp" #include "utilities/debug.hpp" +class outputStream; + template class WorkerDataArray : public CHeapObj { - friend class G1GCParPhasePrinter; T* _data; uint _length; const char* _title; - bool _print_sum; - uint _indent_level; - bool _enabled; WorkerDataArray* _thread_work_items; @@ -42,11 +43,7 @@ class WorkerDataArray : public CHeapObj { void set_all(T value); public: - WorkerDataArray(uint length, - const char* title, - bool print_sum, - uint indent_level); - + WorkerDataArray(uint length, const char* title); ~WorkerDataArray(); void link_thread_work_items(WorkerDataArray* thread_work_items); @@ -62,27 +59,30 @@ class WorkerDataArray : public CHeapObj { double average(uint active_threads) const; T sum(uint active_threads) const; - T minimum(uint active_threads) const; - T maximum(uint active_threads) const; - T diff(uint active_threads) const; - - uint indentation() const { - return _indent_level; - } const char* title() const { return _title; } - bool should_print_sum() const { - return _print_sum; - } - void clear(); - void set_enabled(bool enabled) { - _enabled = enabled; - } void reset() PRODUCT_RETURN; void verify(uint active_threads) const PRODUCT_RETURN; + + + private: + class WDAPrinter { + public: + static void summary(outputStream* out, const char* title, double min, double avg, double max, double diff, double sum, bool print_sum); + static void summary(outputStream* out, const char* title, size_t min, double avg, size_t max, size_t diff, size_t sum, bool print_sum); + + static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + static void details(const WorkerDataArray* phase, outputStream* out, uint active_threads); + }; + + public: + void print_summary_on(outputStream* out, uint active_threads, bool print_sum = true) const; + void print_details_on(outputStream* out, uint active_threads) const; }; + +#endif // SHARE_VM_GC_G1_WORKERDATAARRAY_HPP diff --git a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp index 713eb125cff..7b4df8628b8 100644 --- a/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp +++ b/hotspot/src/share/vm/gc/g1/workerDataArray.inline.hpp @@ -22,20 +22,18 @@ * */ +#ifndef SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP +#define SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP + #include "gc/g1/workerDataArray.hpp" #include "memory/allocation.inline.hpp" +#include "utilities/ostream.hpp" template -WorkerDataArray::WorkerDataArray(uint length, - const char* title, - bool print_sum, - uint indent_level) : +WorkerDataArray::WorkerDataArray(uint length, const char* title) : _title(title), _length(0), - _print_sum(print_sum), - _indent_level(indent_level), - _thread_work_items(NULL), - _enabled(true) { + _thread_work_items(NULL) { assert(length > 0, "Must have some workers to store data for"); _length = length; _data = NEW_C_HEAP_ARRAY(T, _length, mtGC); @@ -93,29 +91,6 @@ T WorkerDataArray::sum(uint active_threads) const { return s; } -template -T WorkerDataArray::minimum(uint active_threads) const { - T min = get(0); - for (uint i = 1; i < active_threads; ++i) { - min = MIN2(min, get(i)); - } - return min; -} - -template -T WorkerDataArray::maximum(uint active_threads) const { - T max = get(0); - for (uint i = 1; i < active_threads; ++i) { - max = MAX2(max, get(i)); - } - return max; -} - -template -T WorkerDataArray::diff(uint active_threads) const { - return maximum(active_threads) - minimum(active_threads); -} - template void WorkerDataArray::clear() { set_all(0); @@ -128,6 +103,27 @@ void WorkerDataArray::set_all(T value) { } } +template +void WorkerDataArray::print_summary_on(outputStream* out, uint active_threads, bool print_sum) const { + T max = get(0); + T min = max; + T sum = 0; + for (uint i = 1; i < active_threads; ++i) { + T value = get(i); + max = MAX2(max, value); + min = MIN2(min, value); + sum += value; + } + T diff = max - min; + double avg = sum / (double) active_threads; + WDAPrinter::summary(out, title(), min, avg, max, diff, sum, print_sum); +} + +template +void WorkerDataArray::print_details_on(outputStream* out, uint active_threads) const { + WDAPrinter::details(this, out, active_threads); +} + #ifndef PRODUCT template void WorkerDataArray::reset() { @@ -139,10 +135,6 @@ void WorkerDataArray::reset() { template void WorkerDataArray::verify(uint active_threads) const { - if (!_enabled) { - return; - } - assert(active_threads <= _length, "Wrong number of active threads"); for (uint i = 0; i < active_threads; i++) { assert(_data[i] != uninitialized(), @@ -163,3 +155,5 @@ inline double WorkerDataArray::uninitialized() const { return -1.0; } #endif + +#endif // SHARE_VM_GC_G1_WORKERDATAARRAY_INLINE_HPP diff --git a/hotspot/src/share/vm/gc/g1/youngList.cpp b/hotspot/src/share/vm/gc/g1/youngList.cpp index 3d95e8ff93a..25b9d21d4fa 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.cpp +++ b/hotspot/src/share/vm/gc/g1/youngList.cpp @@ -33,9 +33,9 @@ #include "utilities/ostream.hpp" YoungList::YoungList(G1CollectedHeap* g1h) : - _g1h(g1h), _head(NULL), _length(0), _last_sampled_rs_lengths(0), + _g1h(g1h), _head(NULL), _length(0), _survivor_head(NULL), _survivor_tail(NULL), _survivor_length(0) { - guarantee(check_list_empty(false), "just making sure..."); + guarantee(check_list_empty(), "just making sure..."); } void YoungList::push_region(HeapRegion *hr) { @@ -86,9 +86,7 @@ void YoungList::empty_list() { _survivor_tail = NULL; _survivor_length = 0; - _last_sampled_rs_lengths = 0; - - assert(check_list_empty(false), "just making sure..."); + assert(check_list_empty(), "just making sure..."); } bool YoungList::check_list_well_formed() { @@ -119,17 +117,13 @@ bool YoungList::check_list_well_formed() { return ret; } -bool YoungList::check_list_empty(bool check_sample) { +bool YoungList::check_list_empty() { bool ret = true; if (_length != 0) { log_error(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length); ret = false; } - if (check_sample && _last_sampled_rs_lengths != 0) { - log_error(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths"); - ret = false; - } if (_head != NULL) { log_error(gc, verify)("### YOUNG LIST does not have a NULL head"); ret = false; @@ -141,38 +135,6 @@ bool YoungList::check_list_empty(bool check_sample) { return ret; } -void -YoungList::rs_length_sampling_init() { - _sampled_rs_lengths = 0; - _curr = _head; -} - -bool -YoungList::rs_length_sampling_more() { - return _curr != NULL; -} - -void -YoungList::rs_length_sampling_next() { - assert( _curr != NULL, "invariant" ); - size_t rs_length = _curr->rem_set()->occupied(); - - _sampled_rs_lengths += rs_length; - - // The current region may not yet have been added to the - // incremental collection set (it gets added when it is - // retired as the current allocation region). - if (_curr->in_collection_set()) { - // Update the collection set policy information for this region - _g1h->g1_policy()->update_incremental_cset_info(_curr, rs_length); - } - - _curr = _curr->get_next_young_region(); - if (_curr == NULL) { - _last_sampled_rs_lengths = _sampled_rs_lengths; - } -} - void YoungList::reset_auxilary_lists() { guarantee( is_empty(), "young list should be empty" ); diff --git a/hotspot/src/share/vm/gc/g1/youngList.hpp b/hotspot/src/share/vm/gc/g1/youngList.hpp index 36108b807db..1030b3f9c1c 100644 --- a/hotspot/src/share/vm/gc/g1/youngList.hpp +++ b/hotspot/src/share/vm/gc/g1/youngList.hpp @@ -37,14 +37,9 @@ private: HeapRegion* _survivor_head; HeapRegion* _survivor_tail; - HeapRegion* _curr; - uint _length; uint _survivor_length; - size_t _last_sampled_rs_lengths; - size_t _sampled_rs_lengths; - void empty_list(HeapRegion* list); public: @@ -72,15 +67,6 @@ public: return (size_t) survivor_length() * HeapRegion::GrainBytes; } - void rs_length_sampling_init(); - bool rs_length_sampling_more(); - void rs_length_sampling_next(); - - void reset_sampled_info() { - _last_sampled_rs_lengths = 0; - } - size_t sampled_rs_lengths() { return _last_sampled_rs_lengths; } - // for development purposes void reset_auxilary_lists(); void clear() { _head = NULL; _length = 0; } @@ -97,7 +83,7 @@ public: // debugging bool check_list_well_formed(); - bool check_list_empty(bool check_sample = true); + bool check_list_empty(); void print(); }; diff --git a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp index 9bba8daf55e..f132d75e860 100644 --- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp @@ -405,7 +405,9 @@ size_t CollectedHeap::max_tlab_size() const { oop CollectedHeap::new_store_pre_barrier(JavaThread* thread, oop new_obj) { // If a previous card-mark was deferred, flush it now. flush_deferred_store_barrier(thread); - if (can_elide_initializing_store_barrier(new_obj)) { + if (can_elide_initializing_store_barrier(new_obj) || + new_obj->is_typeArray()) { + // Arrays of non-references don't need a pre-barrier. // The deferred_card_mark region should be empty // following the flush above. assert(thread->deferred_card_mark().is_empty(), "Error"); diff --git a/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp b/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp index 6a6a64e31eb..b7e0bbe98b0 100644 --- a/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp +++ b/hotspot/src/share/vm/gc/shared/copyFailedInfo.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #define SHARE_VM_GC_SHARED_COPYFAILEDINFO_HPP #include "runtime/thread.hpp" +#include "trace/traceMacros.hpp" #include "utilities/globalDefinitions.hpp" class CopyFailedInfo : public CHeapObj { @@ -63,26 +64,28 @@ class CopyFailedInfo : public CHeapObj { }; class PromotionFailedInfo : public CopyFailedInfo { - OSThread* _thread; + traceid _thread_trace_id; public: - PromotionFailedInfo() : CopyFailedInfo(), _thread(NULL) {} + PromotionFailedInfo() : CopyFailedInfo(), _thread_trace_id(0) {} void register_copy_failure(size_t size) { CopyFailedInfo::register_copy_failure(size); - if (_thread == NULL) { - _thread = Thread::current()->osthread(); + if (_thread_trace_id == 0) { + _thread_trace_id = THREAD_TRACE_ID(Thread::current()); } else { - assert(_thread == Thread::current()->osthread(), "The PromotionFailedInfo should be thread local."); + assert(THREAD_TRACE_ID(Thread::current()) == _thread_trace_id, + "The PromotionFailedInfo should be thread local."); } } void reset() { CopyFailedInfo::reset(); - _thread = NULL; + _thread_trace_id = 0; } - OSThread* thread() const { return _thread; } + traceid thread_trace_id() const { return _thread_trace_id; } + }; class EvacuationFailedInfo : public CopyFailedInfo {}; diff --git a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp index 0bd6fef7471..db538eb4f41 100644 --- a/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp +++ b/hotspot/src/share/vm/gc/shared/gcTraceSend.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,7 +174,7 @@ void YoungGCTracer::send_promotion_failed_event(const PromotionFailedInfo& pf_in if (e.should_commit()) { e.set_gcId(GCId::current()); e.set_data(to_trace_struct(pf_info)); - e.set_thread(pf_info.thread()->thread_id()); + e.set_thread(pf_info.thread_trace_id()); e.commit(); } } diff --git a/hotspot/src/share/vm/gc/shared/plab.cpp b/hotspot/src/share/vm/gc/shared/plab.cpp index d8566523e7c..1743bffb089 100644 --- a/hotspot/src/share/vm/gc/shared/plab.cpp +++ b/hotspot/src/share/vm/gc/shared/plab.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -110,6 +110,30 @@ void PLAB::undo_allocation(HeapWord* obj, size_t word_sz) { } } +void PLABStats::log_plab_allocation() { + log_debug(gc, plab)("%s PLAB allocation: " + "allocated: " SIZE_FORMAT "B, " + "wasted: " SIZE_FORMAT "B, " + "unused: " SIZE_FORMAT "B, " + "used: " SIZE_FORMAT "B, " + "undo waste: " SIZE_FORMAT "B, ", + _description, + _allocated * HeapWordSize, + _wasted * HeapWordSize, + _unused * HeapWordSize, + used() * HeapWordSize, + _undo_wasted * HeapWordSize); +} + +void PLABStats::log_sizing(size_t calculated_words, size_t net_desired_words) { + log_debug(gc, plab)("%s sizing: " + "calculated: " SIZE_FORMAT "B, " + "actual: " SIZE_FORMAT "B", + _description, + calculated_words * HeapWordSize, + net_desired_words * HeapWordSize); +} + // Calculates plab size for current number of gc worker threads. size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) { return MAX2(min_size(), (size_t)align_object_size(_desired_net_plab_sz / no_of_gc_workers)); @@ -119,7 +143,13 @@ size_t PLABStats::desired_plab_sz(uint no_of_gc_workers) { // use. This should be called once at the end of parallel // scavenge; it clears the sensor accumulators. void PLABStats::adjust_desired_plab_sz() { - assert(ResizePLAB, "Not set"); + log_plab_allocation(); + + if (!ResizePLAB) { + // Clear accumulators for next round. + reset(); + return; + } assert(is_object_aligned(max_size()) && min_size() <= max_size(), "PLAB clipping computation may be incorrect"); @@ -150,8 +180,9 @@ void PLABStats::adjust_desired_plab_sz() { new_plab_sz = MIN2(max_size(), new_plab_sz); new_plab_sz = align_object_size(new_plab_sz); // Latch the result - log_trace(gc, plab)("plab_size = " SIZE_FORMAT " desired_net_plab_sz = " SIZE_FORMAT ") ", recent_plab_sz, new_plab_sz); _desired_net_plab_sz = new_plab_sz; + log_sizing(recent_plab_sz, new_plab_sz); + reset(); } diff --git a/hotspot/src/share/vm/gc/shared/plab.hpp b/hotspot/src/share/vm/gc/shared/plab.hpp index b684769ed61..e73562b301f 100644 --- a/hotspot/src/share/vm/gc/shared/plab.hpp +++ b/hotspot/src/share/vm/gc/shared/plab.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,8 @@ public: // PLAB book-keeping. class PLABStats : public CHeapObj { protected: + const char* _description; // Identifying string. + size_t _allocated; // Total allocated size_t _wasted; // of which wasted (internal fragmentation) size_t _undo_wasted; // of which wasted on undo (is not used for calculation of PLAB size) @@ -160,8 +162,12 @@ class PLABStats : public CHeapObj { _undo_wasted = 0; _unused = 0; } + + virtual void log_plab_allocation(); + virtual void log_sizing(size_t calculated, size_t net_desired); public: - PLABStats(size_t desired_net_plab_sz_, unsigned wt) : + PLABStats(const char* description, size_t desired_net_plab_sz_, unsigned wt) : + _description(description), _allocated(0), _wasted(0), _undo_wasted(0), @@ -172,6 +178,12 @@ class PLABStats : public CHeapObj { virtual ~PLABStats() { } + size_t allocated() const { return _allocated; } + size_t wasted() const { return _wasted; } + size_t unused() const { return _unused; } + size_t used() const { return allocated() - (wasted() + unused()); } + size_t undo_wasted() const { return _undo_wasted; } + static const size_t min_size() { return PLAB::min_size(); } diff --git a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp index 83e6a2146f7..983b0b71ad4 100644 --- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp +++ b/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp @@ -2258,10 +2258,8 @@ run: // Decrement counter at checkcast. BI_PROFILE_SUBTYPECHECK_FAILED(objKlass); ResourceMark rm(THREAD); - const char* objName = objKlass->external_name(); - const char* klassName = klassOf->external_name(); char* message = SharedRuntime::generate_class_cast_message( - objName, klassName); + objKlass, klassOf); VM_JAVA_ERROR(vmSymbols::java_lang_ClassCastException(), message, note_classCheck_trap); } // Profile checkcast with null_seen and receiver. diff --git a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp index 166390d8d6b..acc45335158 100644 --- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp +++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp @@ -384,7 +384,7 @@ IRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException( ResourceMark rm(thread); char* message = SharedRuntime::generate_class_cast_message( - thread, obj->klass()->external_name()); + thread, obj->klass()); if (ProfileTraps) { note_trap(thread, Deoptimization::Reason_class_check, CHECK); @@ -762,14 +762,6 @@ void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code byte ConstantPoolCacheEntry* cp_cache_entry = cache_entry(thread); if (cp_cache_entry->is_resolved(bytecode)) return; - if (bytecode == Bytecodes::_invokeinterface) { - if (log_develop_is_enabled(Trace, itables)) { - ResourceMark rm(thread); - log_develop_trace(itables)("Resolving: klass: %s to method: %s", - info.resolved_klass()->name()->as_C_string(), - info.resolved_method()->name()->as_C_string()); - } - } #ifdef ASSERT if (bytecode == Bytecodes::_invokeinterface) { if (info.resolved_method()->method_holder() == diff --git a/hotspot/src/share/vm/interpreter/linkResolver.cpp b/hotspot/src/share/vm/interpreter/linkResolver.cpp index 7e3c60b185d..5c7e9b13d35 100644 --- a/hotspot/src/share/vm/interpreter/linkResolver.cpp +++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp @@ -273,18 +273,25 @@ void LinkInfo::print() { // Klass resolution void LinkResolver::check_klass_accessability(KlassHandle ref_klass, KlassHandle sel_klass, TRAPS) { - if (!Reflection::verify_class_access(ref_klass(), - sel_klass(), - true)) { + Reflection::VerifyClassAccessResults vca_result = + Reflection::verify_class_access(ref_klass(), sel_klass(), true); + if (vca_result != Reflection::ACCESS_OK) { ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_IllegalAccessError(), - "tried to access class %s from class %s", - sel_klass->external_name(), - ref_klass->external_name() - ); - return; + char* msg = Reflection::verify_class_access_msg(ref_klass(), sel_klass(), vca_result); + if (msg == NULL) { + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "failed to access class %s from class %s", + sel_klass->external_name(), + ref_klass->external_name()); + } else { + // Use module specific message returned by verify_class_access_msg(). + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_IllegalAccessError(), + "%s", msg); + } } } diff --git a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp index cb06c34d4b6..2043b59d5e1 100644 --- a/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciCodeInstaller.cpp @@ -551,6 +551,14 @@ JVMCIEnv::CodeInstallResult CodeInstaller::install(JVMCICompiler* compiler, Hand compiler, _debug_recorder, _dependencies, env, id, has_unsafe_access, _has_wide_vector, installed_code, compiled_code, speculation_log); cb = nm; + if (nm != NULL && env == NULL) { + DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, compiler); + bool printnmethods = directive->PrintAssemblyOption || directive->PrintNMethodsOption; + if (printnmethods || PrintDebugInfo || PrintRelocations || PrintDependencies || PrintExceptionHandlers) { + nm->print_nmethod(printnmethods); + } + DirectivesStack::release(directive); + } } if (cb != NULL) { diff --git a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp index b19a39603fa..68d4a05bc7f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciEnv.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciEnv.cpp @@ -77,7 +77,9 @@ bool JVMCIEnv::check_klass_accessibility(KlassHandle accessing_klass, KlassHandl resolved_klass = ObjArrayKlass::cast(resolved_klass())->bottom_klass(); } if (resolved_klass->is_instance_klass()) { - return Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + Reflection::VerifyClassAccessResults result = + Reflection::verify_class_access(accessing_klass(), resolved_klass(), true); + return result == Reflection::ACCESS_OK; } return true; } diff --git a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp index 716f73c06b1..d5a10f4660f 100644 --- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp +++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp @@ -293,13 +293,11 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t // tracing if (log_is_enabled(Info, exceptions)) { ResourceMark rm; - log_info(exceptions)("Exception <%s> (" INTPTR_FORMAT ") thrown in" - " compiled method <%s> at PC " INTPTR_FORMAT - " for thread " INTPTR_FORMAT, - exception->print_value_string(), - p2i((address)exception()), - nm->method()->print_value_string(), p2i(pc), - p2i(thread)); + stringStream tempst; + tempst.print("compiled method <%s>\n" + " at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT, + nm->method()->print_value_string(), p2i(pc), p2i(thread)); + Exceptions::log_exception(exception, tempst); } // for AbortVMOnException flag NOT_PRODUCT(Exceptions::debug_check_abort(exception)); diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp index f555863ed0d..992746975f4 100644 --- a/hotspot/src/share/vm/jvmci/jvmci_globals.cpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "jvmci/jvmci_globals.hpp" +#include "utilities/defaultStream.hpp" +#include "runtime/globals_extension.hpp" JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_PD_DEVELOPER_FLAG, \ @@ -34,3 +36,185 @@ JVMCI_FLAGS(MATERIALIZE_DEVELOPER_FLAG, \ MATERIALIZE_NOTPRODUCT_FLAG, IGNORE_RANGE, \ IGNORE_CONSTRAINT) + +#define JVMCI_IGNORE_FLAG_FOUR_PARAM(type, name, value, doc) +#define JVMCI_IGNORE_FLAG_THREE_PARAM(type, name, doc) + +// Return true if jvmci flags are consistent. +bool JVMCIGlobals::check_jvmci_flags_are_consistent() { + if (EnableJVMCI) { + return true; + } + + // "FLAG_IS_DEFAULT" fail count. + int fail_count = 0; + // Number of "FLAG_IS_DEFAULT" fails that should be skipped before code + // detect real consistency failure. + int skip_fail_count; + + // EnableJVMCI flag is false here. + // If any other flag is changed, consistency check should fail. + // JVMCI_FLAGS macros added below can handle all JVMCI flags automatically. + // But it contains check for EnableJVMCI flag too, which is required to be + // skipped. This can't be handled easily! + // So the code looks for at-least two flag changes to detect consistency + // failure when EnableJVMCI flag is changed. + // Otherwise one flag change is sufficient to detect consistency failure. + // Set skip_fail_count to 0 if EnableJVMCI flag is default. + // Set skip_fail_count to 1 if EnableJVMCI flag is changed. + // This value will be used to skip fails in macro expanded code later. + if (!FLAG_IS_DEFAULT(EnableJVMCI)) { + skip_fail_count = 1; + } else { + skip_fail_count = 0; + } + +#define EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(FLAG) \ + if (!FLAG_IS_DEFAULT(FLAG)) { \ + fail_count++; \ + if (fail_count > skip_fail_count) { \ + return false; \ + } \ + } + +#define JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) + + // Check consistency of diagnostic flags if UnlockDiagnosticVMOptions is true + // or not default. UnlockDiagnosticVMOptions is default true in debug builds. + if (UnlockDiagnosticVMOptions || !FLAG_IS_DEFAULT(UnlockDiagnosticVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + + // Check consistency of experimental flags if UnlockExperimentalVMOptions is + // true or not default. + if (UnlockExperimentalVMOptions || !FLAG_IS_DEFAULT(UnlockExperimentalVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + +#ifndef PRODUCT +#define JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#else +#define JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) +#define JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) +#define JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) +#endif + +#define JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) +#define JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE(type, name, value, doc) EMIT_FLAG_VALUE_CHANGED_CHECK_CODE(name) + + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#undef EMIT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PD_DEVELOP_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_NOTPRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_DIAGNOSTIC_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PD_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_PRODUCT_FLAG_VALUE_CHANGED_CHECK_CODE +#undef JVMCI_EXPERIMENTAL_FLAG_VALUE_CHANGED_CHECK_CODE + + return true; +} + +// Print jvmci arguments inconsistency error message. +void JVMCIGlobals::print_jvmci_args_inconsistency_error_message() { + const char* error_msg = "Improperly specified VM option '%s'\n"; + jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); + +#define EMIT_CHECK_PRINT_ERR_MSG_CODE(FLAG) \ + if (!FLAG_IS_DEFAULT(FLAG)) { \ + if (strcmp(#FLAG, "EnableJVMCI")) { \ + jio_fprintf(defaultStream::error_stream(), error_msg, #FLAG); \ + } \ + } + +#define JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) + + if (UnlockDiagnosticVMOptions || !FLAG_IS_DEFAULT(UnlockDiagnosticVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + + if (UnlockExperimentalVMOptions || !FLAG_IS_DEFAULT(UnlockExperimentalVMOptions)) { + JVMCI_FLAGS(JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_THREE_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + } + +#ifndef PRODUCT +#define JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#else +#define JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) +#define JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) +#define JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) +#endif + +#define JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) +#define JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE(type, name, value, doc) EMIT_CHECK_PRINT_ERR_MSG_CODE(name) + + JVMCI_FLAGS(JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_IGNORE_FLAG_FOUR_PARAM, \ + JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE, \ + IGNORE_RANGE, \ + IGNORE_CONSTRAINT) + +#undef EMIT_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PD_DEVELOP_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_NOTPRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PD_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_PRODUCT_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_DIAGNOSTIC_FLAG_CHECK_PRINT_ERR_MSG_CODE +#undef JVMCI_EXPERIMENTAL_FLAG_CHECK_PRINT_ERR_MSG_CODE + +} + +#undef JVMCI_IGNORE_FLAG_FOUR_PARAM +#undef JVMCI_IGNORE_FLAG_THREE_PARAM diff --git a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp index ac1bfd119e6..03285e3bdfc 100644 --- a/hotspot/src/share/vm/jvmci/jvmci_globals.hpp +++ b/hotspot/src/share/vm/jvmci/jvmci_globals.hpp @@ -39,29 +39,23 @@ \ experimental(bool, UseJVMCICompiler, false, \ "Use JVMCI as the default compiler") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, BootstrapJVMCI, false, \ "Bootstrap JVMCI before running Java main method") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, PrintBootstrap, true, \ "Print JVMCI bootstrap progress and summary") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCIThreads, 1, \ "Force number of JVMCI compiler threads to use") \ range(1, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCIHostThreads, 1, \ "Force number of compiler threads for JVMCI host compiler") \ range(1, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, CodeInstallSafepointChecks, true, \ "Perform explicit safepoint checks while installing code") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ NOT_COMPILER2(product(intx, MaxVectorSize, 64, \ "Max vector size in bytes, " \ @@ -74,28 +68,22 @@ "Trace level for JVMCI: " \ "1 means emit a message for each CompilerToVM call," \ "levels greater than 1 provide progressively greater detail") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCICounterSize, 0, \ "Reserved size for benchmark counters") \ range(0, max_jint) \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(bool, JVMCICountersExcludeCompiler, true, \ "Exclude JVMCI compiler threads from benchmark counters") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ develop(bool, JVMCIUseFastLocking, true, \ "Use fast inlined locking code") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ experimental(intx, JVMCINMethodSizeLimit, (80*K)*wordSize, \ "Maximum size of a compiled method.") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ \ develop(bool, TraceUncollectedSpeculations, false, \ - "Print message when a failed speculation was not collected") \ - constraint(EnableJVMCIMustBeEnabledConstraintFunc,AtParse) \ + "Print message when a failed speculation was not collected") // Read default values for JVMCI globals @@ -110,4 +98,11 @@ JVMCI_FLAGS(DECLARE_DEVELOPER_FLAG, \ IGNORE_RANGE, \ IGNORE_CONSTRAINT) +class JVMCIGlobals { + public: + // Return true if jvmci flags are consistent. + static bool check_jvmci_flags_are_consistent(); + // Print jvmci arguments inconsistency error message. + static void print_jvmci_args_inconsistency_error_message(); +}; #endif // SHARE_VM_JVMCI_JVMCIGLOBALS_HPP diff --git a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp index 9456f34a0eb..99a7fbd3ac9 100644 --- a/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp +++ b/hotspot/src/share/vm/jvmci/vmStructs_jvmci.cpp @@ -592,6 +592,14 @@ #endif // TARGET_OS_FAMILY_bsd +#ifdef TARGET_ARCH_aarch64 + +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + +#endif // TARGET_ARCH_aarch64 + + #ifdef TARGET_ARCH_x86 #define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ diff --git a/hotspot/src/share/vm/logging/logPrefix.hpp b/hotspot/src/share/vm/logging/logPrefix.hpp index 039e5f44416..213fa7c2806 100644 --- a/hotspot/src/share/vm/logging/logPrefix.hpp +++ b/hotspot/src/share/vm/logging/logPrefix.hpp @@ -58,6 +58,7 @@ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, metaspace)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, start)) \ + LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, phases, task)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, plab)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, region)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, remset)) \ diff --git a/hotspot/src/share/vm/logging/logTag.hpp b/hotspot/src/share/vm/logging/logTag.hpp index 60e39f710f5..c7fb0a08325 100644 --- a/hotspot/src/share/vm/logging/logTag.hpp +++ b/hotspot/src/share/vm/logging/logTag.hpp @@ -43,6 +43,7 @@ LOG_TAG(classload) /* Trace all classes loaded */ \ LOG_TAG(classloaderdata) /* class loader loader_data lifetime */ \ LOG_TAG(classunload) /* Trace unloading of classes */ \ + LOG_TAG(classpath) \ LOG_TAG(compaction) \ LOG_TAG(cpu) \ LOG_TAG(cset) \ @@ -61,11 +62,13 @@ LOG_TAG(logging) \ LOG_TAG(marking) \ LOG_TAG(metaspace) \ + LOG_TAG(modules) \ LOG_TAG(monitorinflation) \ LOG_TAG(os) \ LOG_TAG(phases) \ LOG_TAG(plab) \ LOG_TAG(promotion) \ + LOG_TAG(protectiondomain) /* "Trace protection domain verification" */ \ LOG_TAG(ref) \ LOG_TAG(refine) \ LOG_TAG(region) \ @@ -81,6 +84,7 @@ LOG_TAG(survivor) \ LOG_TAG(sweep) \ LOG_TAG(task) \ + LOG_TAG(thread) \ LOG_TAG(tlab) \ LOG_TAG(time) \ LOG_TAG(verify) \ diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 2a82e60c063..0f6415e49e3 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -208,9 +208,7 @@ void FileMapInfo::allocate_classpath_entry_table() { count ++; bytes += (int)entry_size; bytes += name_bytes; - if (TraceClassPaths) { - tty->print_cr("[Add main shared path (%s) %s]", (cpe->is_jar_file() ? "jar" : "dir"), name); - } + log_info(classpath)("add main shared path (%s) %s", (cpe->is_jar_file() ? "jar" : "dir"), name); } else { SharedClassPathEntry* ent = shared_classpath(cur_entry); if (cpe->is_jar_file()) { @@ -228,12 +226,21 @@ void FileMapInfo::allocate_classpath_entry_table() { SharedClassUtil::update_shared_classpath(cpe, ent, st.st_mtime, st.st_size, THREAD); } else { struct stat st; - if ((os::stat(name, &st) == 0) && ((st.st_mode & S_IFDIR) == S_IFDIR)) { - if (!os::dir_is_empty(name)) { - ClassLoader::exit_with_path_failure("Cannot have non-empty directory in archived classpaths", name); + if (os::stat(name, &st) == 0) { + if (cpe->is_jrt()) { + // it's the "modules" jimage + ent->_timestamp = st.st_mtime; + ent->_filesize = st.st_size; + } else if ((st.st_mode & S_IFDIR) == S_IFDIR) { + if (!os::dir_is_empty(name)) { + ClassLoader::exit_with_path_failure( + "Cannot have non-empty directory in archived classpaths", name); + } + ent->_filesize = -1; } - ent->_filesize = -1; - } else { + } + if (ent->_filesize == 0) { + // unknown ent->_filesize = -2; } } @@ -275,9 +282,7 @@ bool FileMapInfo::validate_classpath_entry_table() { struct stat st; const char* name = ent->_name; bool ok = true; - if (TraceClassPaths) { - tty->print_cr("[Checking shared classpath entry: %s]", name); - } + log_info(classpath)("checking shared classpath entry: %s", name); if (os::stat(name, &st) != 0) { fail_continue("Required classpath entry does not exist: %s", name); ok = false; @@ -286,7 +291,7 @@ bool FileMapInfo::validate_classpath_entry_table() { fail_continue("directory is not empty: %s", name); ok = false; } - } else if (ent->is_jar()) { + } else if (ent->is_jar_or_bootimage()) { if (ent->_timestamp != st.st_mtime || ent->_filesize != st.st_size) { ok = false; @@ -295,15 +300,13 @@ bool FileMapInfo::validate_classpath_entry_table() { "Timestamp mismatch" : "File size mismatch"); } else { - fail_continue("A jar file is not the one used while building" + fail_continue("A jar/jimage file is not the one used while building" " the shared archive file: %s", name); } } } if (ok) { - if (TraceClassPaths) { - tty->print_cr("[ok]"); - } + log_info(classpath)("ok"); } else if (!PrintSharedArchiveAndExit) { _validating_classpath_entry_table = false; return false; @@ -877,6 +880,11 @@ bool FileMapInfo::FileMapHeader::validate() { return false; } + if (Arguments::patch_dirs() != NULL) { + FileMapInfo::fail_continue("The shared archive file cannot be used with -Xpatch."); + return false; + } + if (_version != current_version()) { FileMapInfo::fail_continue("The shared archive file is the wrong version."); return false; @@ -888,10 +896,8 @@ bool FileMapInfo::FileMapHeader::validate() { char header_version[JVM_IDENT_MAX]; get_header_version(header_version); if (strncmp(_jvm_ident, header_version, JVM_IDENT_MAX-1) != 0) { - if (TraceClassPaths) { - tty->print_cr("Expected: %s", header_version); - tty->print_cr("Actual: %s", _jvm_ident); - } + log_info(classpath)("expected: %s", header_version); + log_info(classpath)("actual: %s", _jvm_ident); FileMapInfo::fail_continue("The shared archive file was created by a different" " version or build of HotSpot"); return false; @@ -919,7 +925,7 @@ bool FileMapInfo::validate_header() { if (status) { if (!ClassLoader::check_shared_paths_misc_info(_paths_misc_info, _header->_paths_misc_info_size)) { if (!PrintSharedArchiveAndExit) { - fail_continue("shared class paths mismatch (hint: enable -XX:+TraceClassPaths to diagnose the failure)"); + fail_continue("shared class paths mismatch (hint: enable -Xlog:classpath=info to diagnose the failure)"); status = false; } } diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index 9752e5ddf75..7cb179434b9 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -44,14 +44,20 @@ class Metaspace; class SharedClassPathEntry VALUE_OBJ_CLASS_SPEC { public: const char *_name; - time_t _timestamp; // jar timestamp, 0 if is directory or other - long _filesize; // jar file size, -1 if is directory, -2 if other - bool is_jar() { + time_t _timestamp; // jar/jimage timestamp, 0 if is directory or other + long _filesize; // jar/jimage file size, -1 if is directory, -2 if other + + // The _timestamp only gets set for jar files and "modules" jimage. + bool is_jar_or_bootimage() { return _timestamp != 0; } bool is_dir() { return _filesize == -1; } + + bool is_jrt() { + return ClassLoader::is_jrt(_name); + } }; class FileMapInfo : public CHeapObj { diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index 3f10488bf7f..dc4fc082967 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -603,14 +603,7 @@ void VM_PopulateDumpSharedSpace::doit() { SystemDictionary::reverse(); SystemDictionary::copy_buckets(&md_top, md_end); - ClassLoader::verify(); - ClassLoader::copy_package_info_buckets(&md_top, md_end); - ClassLoader::verify(); - SystemDictionary::copy_table(&md_top, md_end); - ClassLoader::verify(); - ClassLoader::copy_package_info_table(&md_top, md_end); - ClassLoader::verify(); // Write the other data to the output array. WriteClosure wc(md_top, md_end); @@ -716,8 +709,7 @@ void VM_PopulateDumpSharedSpace::doit() { } -void MetaspaceShared::link_one_shared_class(Klass* obj, TRAPS) { - Klass* k = obj; +void MetaspaceShared::link_one_shared_class(Klass* k, TRAPS) { if (k->is_instance_klass()) { InstanceKlass* ik = InstanceKlass::cast(k); // Link the class to cause the bytecodes to be rewritten and the @@ -734,6 +726,16 @@ void MetaspaceShared::check_one_shared_class(Klass* k) { } } +void MetaspaceShared::check_shared_class_loader_type(Klass* k) { + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + u2 loader_type = ik->loader_type(); + ResourceMark rm; + guarantee(loader_type != 0, + "Class loader type is not set for this class %s", ik->name()->as_C_string()); + } +} + void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) { // We need to iterate because verification may cause additional classes // to be loaded. @@ -765,6 +767,7 @@ void MetaspaceShared::link_and_cleanup_shared_classes(TRAPS) { } void MetaspaceShared::prepare_for_dumping() { + Arguments::check_unsupported_dumping_properties(); ClassLoader::initialize_shared_path(); FileMapInfo::allocate_classpath_entry_table(); } @@ -901,7 +904,7 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { assert(DumpSharedSpaces, "should only be called during dumping"); if (ik->init_state() < InstanceKlass::linked) { bool saved = BytecodeVerificationLocal; - if (!SharedClassUtil::is_shared_boot_class(ik)) { + if (!(ik->is_shared_boot_class())) { // The verification decision is based on BytecodeVerificationRemote // for non-system classes. Since we are using the NULL classloader // to load non-system classes during dumping, we need to temporarily @@ -1089,36 +1092,14 @@ void MetaspaceShared::initialize_shared_spaces() { number_of_entries); buffer += sharedDictionaryLen; - // Create the package info table using the bucket array at this spot in - // the misc data space. Since the package info table is never - // modified, this region (of mapped pages) will be (effectively, if - // not explicitly) read-only. - - int pkgInfoLen = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - number_of_entries = *(intptr_t*)buffer; - buffer += sizeof(intptr_t); - ClassLoader::create_package_info_table((HashtableBucket*)buffer, pkgInfoLen, - number_of_entries); - buffer += pkgInfoLen; - ClassLoader::verify(); - // The following data in the shared misc data region are the linked // list elements (HashtableEntry objects) for the shared dictionary - // and package info table. + // table. int len = *(intptr_t*)buffer; // skip over shared dictionary entries buffer += sizeof(intptr_t); buffer += len; - len = *(intptr_t*)buffer; // skip over package info table entries - buffer += sizeof(intptr_t); - buffer += len; - - len = *(intptr_t*)buffer; // skip over package info table char[] arrays. - buffer += sizeof(intptr_t); - buffer += len; - intptr_t* array = (intptr_t*)buffer; ReadClosure rc(&array); serialize(&rc); diff --git a/hotspot/src/share/vm/memory/metaspaceShared.hpp b/hotspot/src/share/vm/memory/metaspaceShared.hpp index dac447c9e05..c78f78122cf 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.hpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp @@ -208,6 +208,7 @@ class MetaspaceShared : AllStatic { static bool try_link_class(InstanceKlass* ik, TRAPS); static void link_one_shared_class(Klass* obj, TRAPS); static void check_one_shared_class(Klass* obj); + static void check_shared_class_loader_type(Klass* obj); static void link_and_cleanup_shared_classes(TRAPS); static int count_class(const char* classlist_file); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 3a7945768e8..60a60e2feed 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -155,6 +155,7 @@ uintptr_t Universe::_verify_oop_bits = (uintptr_t) -1; int Universe::_base_vtable_size = 0; bool Universe::_bootstrapping = false; +bool Universe::_module_initialized = false; bool Universe::_fully_initialized = false; size_t Universe::_heap_capacity_at_last_gc; @@ -667,7 +668,6 @@ jint universe_init() { } else { SymbolTable::create_table(); StringTable::create_table(); - ClassLoader::create_package_info_table(); if (DumpSharedSpaces) { MetaspaceShared::prepare_for_dumping(); @@ -886,6 +886,10 @@ void universe2_init() { Universe::genesis(CATCH); } +// Set after initialization of the module runtime, call_initModuleRuntime +void universe_post_module_init() { + Universe::_module_initialized = true; +} bool universe_post_init() { assert(!is_init_completed(), "Error: initialization not yet completed!"); diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index fe10e849121..340e87fb706 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -111,6 +111,7 @@ class Universe: AllStatic { friend jint universe_init(); friend void universe2_init(); friend bool universe_post_init(); + friend void universe_post_module_init(); private: // Known classes in the VM @@ -205,6 +206,7 @@ class Universe: AllStatic { // Initialization static bool _bootstrapping; // true during genesis + static bool _module_initialized; // true after call_initPhase2 called static bool _fully_initialized; // true after universe_init and initialize_vtables called // the array of preallocated errors with backtraces @@ -436,6 +438,7 @@ class Universe: AllStatic { // Testers static bool is_bootstrapping() { return _bootstrapping; } + static bool is_module_initialized() { return _module_initialized; } static bool is_fully_initialized() { return _fully_initialized; } static inline bool element_type_should_be_aligned(BasicType type); diff --git a/hotspot/src/share/vm/oops/arrayKlass.cpp b/hotspot/src/share/vm/oops/arrayKlass.cpp index e92df43076f..50d5e041d84 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.cpp +++ b/hotspot/src/share/vm/oops/arrayKlass.cpp @@ -89,17 +89,24 @@ ArrayKlass::ArrayKlass(Symbol* name) : set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass()); set_layout_helper(Klass::_lh_neutral_value); set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5) - TRACE_INIT_ID(this); + TRACE_INIT_KLASS_ID(this); } // Initialization of vtables and mirror object is done separatly from base_create_array_klass, // since a GC can happen. At this point all instance variables of the ArrayKlass must be setup. -void ArrayKlass::complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, TRAPS) { +void ArrayKlass::complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, ModuleEntry* module_entry, TRAPS) { ResourceMark rm(THREAD); k->initialize_supers(super_klass(), CHECK); k->vtable()->initialize_vtable(false, CHECK); - java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(NULL), CHECK); + + // During bootstrapping, before java.base is defined, the module_entry may not be present yet. + // These classes will be put on a fixup list and their module fields will be patched once + // java.base is defined. + assert((module_entry != NULL) || ((module_entry == NULL) && !ModuleEntryTable::javabase_defined()), + "module entry not available post java.base definition"); + oop module = (module_entry != NULL) ? JNIHandles::resolve(module_entry->module()) : (oop)NULL; + java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), Handle(THREAD, module), Handle(NULL), CHECK); } GrowableArray* ArrayKlass::compute_secondary_supers(int num_extra_slots) { diff --git a/hotspot/src/share/vm/oops/arrayKlass.hpp b/hotspot/src/share/vm/oops/arrayKlass.hpp index b98a092f735..3761229a1ce 100644 --- a/hotspot/src/share/vm/oops/arrayKlass.hpp +++ b/hotspot/src/share/vm/oops/arrayKlass.hpp @@ -113,7 +113,7 @@ class ArrayKlass: public Klass { void array_klasses_do(void f(Klass* k, TRAPS), TRAPS); // Return a handle. - static void complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, TRAPS); + static void complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, ModuleEntry* module, TRAPS); // jvm support diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index 0ae310bdaf6..f526756a0ce 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1879,7 +1879,7 @@ inline DependencyContext InstanceKlass::dependencies() { return dep_context; } -int InstanceKlass::mark_dependent_nmethods(DepChange& changes) { +int InstanceKlass::mark_dependent_nmethods(KlassDepChange& changes) { return dependencies().mark_dependent_nmethods(changes); } @@ -1972,8 +1972,9 @@ static void restore_unshareable_in_class(Klass* k, TRAPS) { } void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { - Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); instanceKlassHandle ik(THREAD, this); + ik->set_package(loader_data, CHECK); + Klass::restore_unshareable_info(loader_data, protection_domain, CHECK); Array* methods = ik->methods(); int num_methods = methods->length(); @@ -2178,26 +2179,135 @@ const char* InstanceKlass::signature_name() const { return dest; } -// different verisons of is_same_class_package -bool InstanceKlass::is_same_class_package(const Klass* class2) const { - const Klass* const class1 = (const Klass* const)this; - oop classloader1 = InstanceKlass::cast(class1)->class_loader(); - const Symbol* const classname1 = class1->name(); +const jbyte* InstanceKlass::package_from_name(const Symbol* name, int& length) { + ResourceMark rm; + length = 0; + if (name == NULL) { + return NULL; + } else { + const jbyte* base_name = name->base(); + const jbyte* last_slash = UTF8::strrchr(base_name, name->utf8_length(), '/'); + if (last_slash == NULL) { + // No package name + return NULL; + } else { + // Skip over '['s + if (*base_name == '[') { + do { + base_name++; + } while (*base_name == '['); + if (*base_name != 'L') { + // Fully qualified class names should not contain a 'L'. + // Set length to -1 to indicate that the package name + // could not be obtained due to an error condition. + // In this situtation, is_same_class_package returns false. + length = -1; + return NULL; + } + } + + // Found the package name, look it up in the symbol table. + length = last_slash - base_name; + assert(length > 0, "Bad length for package name"); + return base_name; + } + } +} + +ModuleEntry* InstanceKlass::module() const { + if (!in_unnamed_package()) { + return _package_entry->module(); + } + const Klass* host = host_klass(); + if (host == NULL) { + return class_loader_data()->modules()->unnamed_module(); + } + return host->class_loader_data()->modules()->unnamed_module(); +} + +void InstanceKlass::set_package(ClassLoaderData* loader_data, TRAPS) { + int length = 0; + const jbyte* base_name = package_from_name(name(), length); + + if (base_name != NULL && loader_data != NULL) { + TempNewSymbol pkg_name = SymbolTable::new_symbol((const char*)base_name, length, CHECK); + + // Find in class loader's package entry table. + _package_entry = loader_data->packages()->lookup_only(pkg_name); + + // If the package name is not found in the loader's package + // entry table, it is an indication that the package has not + // been defined. Consider it defined within the unnamed module. + if (_package_entry == NULL) { + ResourceMark rm; + + if (!ModuleEntryTable::javabase_defined()) { + // Before java.base is defined during bootstrapping, define all packages in + // the java.base module. If a non-java.base package is erroneously placed + // in the java.base module it will be caught later when java.base + // is defined by ModuleEntryTable::verify_javabase_packages check. + assert(ModuleEntryTable::javabase_module() != NULL, "java.base module is NULL"); + _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_module()); + } else { + assert(loader_data->modules()->unnamed_module() != NULL, "unnamed module is NULL"); + _package_entry = loader_data->packages()->lookup(pkg_name, + loader_data->modules()->unnamed_module()); + } + + // A package should have been successfully created + assert(_package_entry != NULL, "Package entry for class %s not found, loader %s", + name()->as_C_string(), loader_data->loader_name()); + } + + if (log_is_enabled(Debug, modules)) { + ResourceMark rm; + ModuleEntry* m = _package_entry->module(); + log_trace(modules)("Setting package: class: %s, package: %s, loader: %s, module: %s", + external_name(), + pkg_name->as_C_string(), + loader_data->loader_name(), + (m->is_named() ? m->name()->as_C_string() : UNNAMED_MODULE)); + } + } else { + ResourceMark rm; + log_trace(modules)("Setting package: class: %s, package: unnamed, loader: %s, module: %s", + external_name(), + (loader_data != NULL) ? loader_data->loader_name() : "NULL", + UNNAMED_MODULE); + } +} + + +// different versions of is_same_class_package + +bool InstanceKlass::is_same_class_package(const Klass* class2) const { + oop classloader1 = this->class_loader(); + PackageEntry* classpkg1 = this->package(); if (class2->is_objArray_klass()) { class2 = ObjArrayKlass::cast(class2)->bottom_klass(); } + oop classloader2; + PackageEntry* classpkg2; if (class2->is_instance_klass()) { - classloader2 = InstanceKlass::cast(class2)->class_loader(); + classloader2 = class2->class_loader(); + classpkg2 = InstanceKlass::cast(class2)->package(); } else { assert(class2->is_typeArray_klass(), "should be type array"); classloader2 = NULL; + classpkg2 = NULL; } - const Symbol* classname2 = class2->name(); - return InstanceKlass::is_same_class_package(classloader1, classname1, - classloader2, classname2); + // Same package is determined by comparing class loader + // and package entries. Both must be the same. This rule + // applies even to classes that are defined in the unnamed + // package, they still must have the same class loader. + if ((classloader1 == classloader2) && (classpkg1 == classpkg2)) { + return true; + } + + return false; } bool InstanceKlass::is_same_class_package(oop other_class_loader, @@ -2225,43 +2335,24 @@ bool InstanceKlass::is_same_class_package(oop class_loader1, const Symbol* class // The Symbol*'s are in UTF8 encoding. Since we only need to check explicitly // for ASCII characters ('/', 'L', '['), we can keep them in UTF8 encoding. // Otherwise, we just compare jbyte values between the strings. - const jbyte *name1 = class_name1->base(); - const jbyte *name2 = class_name2->base(); + int length1 = 0; + int length2 = 0; + const jbyte *name1 = package_from_name(class_name1, length1); + const jbyte *name2 = package_from_name(class_name2, length2); - const jbyte *last_slash1 = UTF8::strrchr(name1, class_name1->utf8_length(), '/'); - const jbyte *last_slash2 = UTF8::strrchr(name2, class_name2->utf8_length(), '/'); + if ((length1 < 0) || (length2 < 0)) { + // error occurred parsing package name. + return false; + } - if ((last_slash1 == NULL) || (last_slash2 == NULL)) { + if ((name1 == NULL) || (name2 == NULL)) { // One of the two doesn't have a package. Only return true // if the other one also doesn't have a package. - return last_slash1 == last_slash2; - } else { - // Skip over '['s - if (*name1 == '[') { - do { - name1++; - } while (*name1 == '['); - if (*name1 != 'L') { - // Something is terribly wrong. Shouldn't be here. - return false; - } - } - if (*name2 == '[') { - do { - name2++; - } while (*name2 == '['); - if (*name2 != 'L') { - // Something is terribly wrong. Shouldn't be here. - return false; - } - } - - // Check that package part is identical - int length1 = last_slash1 - name1; - int length2 = last_slash2 - name2; - - return UTF8::equal(name1, length1, name2, length2); + return name1 == name2; } + + // Check that package part is identical + return UTF8::equal(name1, length1, name2, length2); } } @@ -2300,7 +2391,7 @@ bool InstanceKlass::is_same_package_member_impl(const InstanceKlass* class1, if (!class2->is_instance_klass()) return false; // must be in same package before we try anything else - if (!class1->is_same_class_package(class2->class_loader(), class2->name())) + if (!class1->is_same_class_package(class2)) return false; // As long as there is an outer1.getEnclosingClass, @@ -2908,6 +2999,7 @@ const char* InstanceKlass::internal_name() const { void InstanceKlass::print_loading_log(LogLevel::type type, ClassLoaderData* loader_data, + const char* module_name, const ClassFileStream* cfs) const { ResourceMark rm; outputStream* log; @@ -2928,7 +3020,11 @@ void InstanceKlass::print_loading_log(LogLevel::type type, // Source if (cfs != NULL) { if (cfs->source() != NULL) { - log->print(" source: %s", cfs->source()); + if (module_name != NULL) { + log->print(" source: jrt:/%s", module_name); + } else { + log->print(" source: %s", cfs->source()); + } } else if (loader_data == ClassLoaderData::the_null_class_loader_data()) { Thread* THREAD = Thread::current(); Klass* caller = diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index f7a3a24800f..4fdcc440e09 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,11 @@ #ifndef SHARE_VM_OOPS_INSTANCEKLASS_HPP #define SHARE_VM_OOPS_INSTANCEKLASS_HPP +#include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/packageEntry.hpp" #include "gc/shared/specialized_oop_closures.hpp" +#include "classfile/moduleEntry.hpp" #include "logging/logLevel.hpp" #include "memory/referenceType.hpp" #include "oops/annotations.hpp" @@ -56,7 +59,7 @@ // forward declaration for class -- see below for definition class BreakpointInfo; class ClassFileParser; -class DepChange; +class KlassDepChange; class DependencyContext; class fieldDescriptor; class jniIdMapBase; @@ -140,6 +143,8 @@ class InstanceKlass: public Klass { protected: // Annotations for this class Annotations* _annotations; + // Package this class is defined in + PackageEntry* _package_entry; // Array classes holding elements of this class. Klass* _array_klasses; // Constant pool for this class. @@ -199,16 +204,22 @@ class InstanceKlass: public Klass { // Start after _misc_kind field. enum { - _misc_rewritten = 1 << 2, // methods rewritten. - _misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops - _misc_should_verify_class = 1 << 4, // allow caching of preverification - _misc_is_anonymous = 1 << 5, // has embedded _host_klass field - _misc_is_contended = 1 << 6, // marked with contended annotation - _misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods - _misc_declares_default_methods = 1 << 8, // directly declares default methods (any access) - _misc_has_been_redefined = 1 << 9, // class has been redefined - _misc_is_scratch_class = 1 << 10 // class is the redefined scratch class + _misc_rewritten = 1 << 2, // methods rewritten. + _misc_has_nonstatic_fields = 1 << 3, // for sizing with UseCompressedOops + _misc_should_verify_class = 1 << 4, // allow caching of preverification + _misc_is_anonymous = 1 << 5, // has embedded _host_klass field + _misc_is_contended = 1 << 6, // marked with contended annotation + _misc_has_default_methods = 1 << 7, // class/superclass/implemented interfaces has default methods + _misc_declares_default_methods = 1 << 8, // directly declares default methods (any access) + _misc_has_been_redefined = 1 << 9, // class has been redefined + _misc_is_scratch_class = 1 << 10, // class is the redefined scratch class + _misc_is_shared_boot_class = 1 << 11, // defining class loader is boot class loader + _misc_is_shared_platform_class = 1 << 12, // defining class loader is platform class loader + _misc_is_shared_app_class = 1 << 13 // defining class loader is app class loader }; + u2 loader_type_bits() { + return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class; + } u2 _misc_flags; u2 _minor_version; // minor version number of class file u2 _major_version; // major version number of class file @@ -290,6 +301,39 @@ class InstanceKlass: public Klass { friend class SystemDictionary; public: + u2 loader_type() { + return _misc_flags & loader_type_bits(); + } + + bool is_shared_boot_class() const { + return (_misc_flags & _misc_is_shared_boot_class) != 0; + } + bool is_shared_platform_class() const { + return (_misc_flags & _misc_is_shared_platform_class) != 0; + } + bool is_shared_app_class() const { + return (_misc_flags & _misc_is_shared_app_class) != 0; + } + + void set_class_loader_type(jshort loader_type) { + assert(( _misc_flags & loader_type_bits()) == 0, + "Should only be called once for each class."); + switch (loader_type) { + case ClassLoader::BOOT_LOADER: + _misc_flags |= _misc_is_shared_boot_class; + break; + case ClassLoader::PLATFORM_LOADER: + _misc_flags |= _misc_is_shared_platform_class; + break; + case ClassLoader::APP_LOADER: + _misc_flags |= _misc_is_shared_app_class; + break; + default: + ShouldNotReachHere(); + break; + } + } + bool has_nonstatic_fields() const { return (_misc_flags & _misc_has_nonstatic_fields) != 0; } @@ -395,6 +439,11 @@ class InstanceKlass: public Klass { bool is_override(const methodHandle& super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS); // package + PackageEntry* package() const { return _package_entry; } + ModuleEntry* module() const; + bool in_unnamed_package() const { return (_package_entry == NULL); } + void set_package(PackageEntry* p) { _package_entry = p; } + void set_package(ClassLoaderData* loader_data, TRAPS); bool is_same_class_package(const Klass* class2) const; bool is_same_class_package(oop classloader2, const Symbol* classname2) const; static bool is_same_class_package(oop class_loader1, @@ -821,7 +870,7 @@ public: // maintenance of deoptimization dependencies inline DependencyContext dependencies(); - int mark_dependent_nmethods(DepChange& changes); + int mark_dependent_nmethods(KlassDepChange& changes); void add_dependent_nmethod(nmethod* nm); void remove_dependent_nmethod(nmethod* nm, bool delete_immediately); @@ -839,7 +888,7 @@ public: // support for stub routines static ByteSize init_state_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_state)); } - TRACE_DEFINE_OFFSET; + TRACE_DEFINE_KLASS_TRACE_ID_OFFSET; static ByteSize init_thread_offset() { return in_ByteSize(offset_of(InstanceKlass, _init_thread)); } // subclass/subinterface checks @@ -1030,6 +1079,7 @@ public: // Naming const char* signature_name() const; + static const jbyte* package_from_name(const Symbol* name, int& length); // GC specific object visitors // @@ -1247,7 +1297,8 @@ public: void oop_verify_on(oop obj, outputStream* st); // Logging - void print_loading_log(LogLevel::type type, ClassLoaderData* loader_data, const ClassFileStream* cfs) const; + void print_loading_log(LogLevel::type type, ClassLoaderData* loader_data, + const char* module_name, const ClassFileStream* cfs) const; }; // for adding methods diff --git a/hotspot/src/share/vm/oops/klass.cpp b/hotspot/src/share/vm/oops/klass.cpp index b391f222d6a..8e3267868b8 100644 --- a/hotspot/src/share/vm/oops/klass.cpp +++ b/hotspot/src/share/vm/oops/klass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -494,7 +494,7 @@ void Klass::remove_unshareable_info() { } void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) { - TRACE_INIT_ID(this); + TRACE_INIT_KLASS_ID(this); // If an exception happened during CDS restore, some of these fields may already be // set. We leave the class on the CLD list, even if incomplete so that we don't // modify the CLD list outside a safepoint. @@ -512,7 +512,21 @@ void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protec // gotten an OOM later but keep the mirror if it was created. if (java_mirror() == NULL) { Handle loader = loader_data->class_loader(); - java_lang_Class::create_mirror(this, loader, protection_domain, CHECK); + ModuleEntry* module_entry = NULL; + Klass* k = this; + if (k->is_objArray_klass()) { + k = ObjArrayKlass::cast(k)->bottom_klass(); + } + // Obtain klass' module. + if (k->is_instance_klass()) { + InstanceKlass* ik = (InstanceKlass*) k; + module_entry = ik->module(); + } else { + module_entry = ModuleEntryTable::javabase_module(); + } + // Obtain java.lang.reflect.Module, if available + Handle module_handle(THREAD, ((module_entry != NULL) ? JNIHandles::resolve(module_entry->module()) : (oop)NULL)); + java_lang_Class::create_mirror(this, loader, module_handle, protection_domain, CHECK); } } diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 00fe28d614b..cff1d74d6ef 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -132,7 +132,7 @@ class Klass : public Metadata { jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. - TRACE_DEFINE_KLASS_TRACE_ID; + TRACE_DEFINE_TRACE_ID_FIELD; // Biased locking implementation and statistics // (the 64-bit chunk goes first, to avoid some fragmentation) @@ -569,7 +569,7 @@ protected: jlong last_biased_lock_bulk_revocation_time() { return _last_biased_lock_bulk_revocation_time; } void set_last_biased_lock_bulk_revocation_time(jlong cur_time) { _last_biased_lock_bulk_revocation_time = cur_time; } - TRACE_DEFINE_KLASS_METHODS; + TRACE_DEFINE_TRACE_ID_METHODS; // garbage collection support void oops_do(OopClosure* cl); diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index 7620ea9f985..d309e9aaed8 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -1329,7 +1329,7 @@ vmSymbols::SID Method::klass_id_for_intrinsics(const Klass* holder) { // exception: the AES intrinsics come from lib/ext/sunjce_provider.jar // which does not use the class default class loader so we check for its loader here const InstanceKlass* ik = InstanceKlass::cast(holder); - if ((ik->class_loader() != NULL) && !SystemDictionary::is_ext_class_loader(ik->class_loader())) { + if ((ik->class_loader() != NULL) && !SystemDictionary::is_platform_class_loader(ik->class_loader())) { return vmSymbols::NO_SID; // regardless of name, no intrinsics here } diff --git a/hotspot/src/share/vm/oops/objArrayKlass.cpp b/hotspot/src/share/vm/oops/objArrayKlass.cpp index bd696d5cc0f..8750ac73736 100644 --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp @@ -135,8 +135,18 @@ Klass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data, // GC walks these as strong roots. loader_data->add_class(oak); + // The array is defined in the module of its bottom class + Klass* bottom_klass = oak->bottom_klass(); + ModuleEntry* module; + if (bottom_klass->is_instance_klass()) { + module = InstanceKlass::cast(bottom_klass)->module(); + } else { + module = ModuleEntryTable::javabase_module(); + } + assert(module != NULL, "No module entry for array"); + // Call complete_create_array_klass after all instance variables has been initialized. - ArrayKlass::complete_create_array_klass(oak, super_klass, CHECK_0); + ArrayKlass::complete_create_array_klass(oak, super_klass, module, CHECK_0); return oak; } diff --git a/hotspot/src/share/vm/oops/typeArrayKlass.cpp b/hotspot/src/share/vm/oops/typeArrayKlass.cpp index f8ec9ee822e..3fa977001a0 100644 --- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp +++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp @@ -70,7 +70,7 @@ TypeArrayKlass* TypeArrayKlass::create_klass(BasicType type, null_loader_data->add_class(ak); // Call complete_create_array_klass after all instance variables have been initialized. - complete_create_array_klass(ak, ak->super(), CHECK_NULL); + complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_module(), CHECK_NULL); return ak; } diff --git a/hotspot/src/share/vm/oops/typeArrayOop.hpp b/hotspot/src/share/vm/oops/typeArrayOop.hpp index e4670a8949b..8ab2f4d1f74 100644 --- a/hotspot/src/share/vm/oops/typeArrayOop.hpp +++ b/hotspot/src/share/vm/oops/typeArrayOop.hpp @@ -129,7 +129,7 @@ class typeArrayOopDesc : public arrayOopDesc { Metadata* metadata_at(int which) const { return (Metadata*)*long_at_addr(which); } void metadata_at_put(int which, Metadata* contents) { - *long_at_addr(which) = (long)contents; + *long_at_addr(which) = (jlong)contents; } #else Metadata* metadata_at(int which) const { diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp index 7068b5cfb1a..c9396fda2fa 100644 --- a/hotspot/src/share/vm/opto/c2compiler.cpp +++ b/hotspot/src/share/vm/opto/c2compiler.cpp @@ -243,14 +243,72 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_reverseBytes_l: if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false; break; + + /* CompareAndSwap, Object: */ case vmIntrinsics::_compareAndSwapObject: #ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapN)) return false; if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; +#else + if (!Matcher::match_rule_supported(Op_CompareAndSwapP)) return false; #endif break; + case vmIntrinsics::_weakCompareAndSwapObject: + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: + case vmIntrinsics::_weakCompareAndSwapObjectRelease: +#ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_WeakCompareAndSwapN)) return false; + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_WeakCompareAndSwapP)) return false; +#else + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapP)) return false; +#endif + break; + /* CompareAndSwap, Long: */ case vmIntrinsics::_compareAndSwapLong: if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return false; break; + case vmIntrinsics::_weakCompareAndSwapLong: + case vmIntrinsics::_weakCompareAndSwapLongAcquire: + case vmIntrinsics::_weakCompareAndSwapLongRelease: + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + break; + + /* CompareAndSwap, Int: */ + case vmIntrinsics::_compareAndSwapInt: + if (!Matcher::match_rule_supported(Op_CompareAndSwapI)) return false; + break; + case vmIntrinsics::_weakCompareAndSwapInt: + case vmIntrinsics::_weakCompareAndSwapIntAcquire: + case vmIntrinsics::_weakCompareAndSwapIntRelease: + if (!Matcher::match_rule_supported(Op_WeakCompareAndSwapL)) return false; + break; + + /* CompareAndExchange, Object: */ + case vmIntrinsics::_compareAndExchangeObjectVolatile: + case vmIntrinsics::_compareAndExchangeObjectAcquire: + case vmIntrinsics::_compareAndExchangeObjectRelease: +#ifdef _LP64 + if ( UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndExchangeN)) return false; + if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndExchangeP)) return false; +#else + if (!Matcher::match_rule_supported(Op_CompareAndExchangeP)) return false; +#endif + break; + + /* CompareAndExchange, Long: */ + case vmIntrinsics::_compareAndExchangeLongVolatile: + case vmIntrinsics::_compareAndExchangeLongAcquire: + case vmIntrinsics::_compareAndExchangeLongRelease: + if (!Matcher::match_rule_supported(Op_CompareAndExchangeL)) return false; + break; + + /* CompareAndExchange, Int: */ + case vmIntrinsics::_compareAndExchangeIntVolatile: + case vmIntrinsics::_compareAndExchangeIntAcquire: + case vmIntrinsics::_compareAndExchangeIntRelease: + if (!Matcher::match_rule_supported(Op_CompareAndExchangeI)) return false; + break; + case vmIntrinsics::_getAndAddInt: if (!Matcher::match_rule_supported(Op_GetAndAddI)) return false; break; @@ -382,6 +440,42 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_putLongVolatile: case vmIntrinsics::_putFloatVolatile: case vmIntrinsics::_putDoubleVolatile: + case vmIntrinsics::_getObjectAcquire: + case vmIntrinsics::_getBooleanAcquire: + case vmIntrinsics::_getByteAcquire: + case vmIntrinsics::_getShortAcquire: + case vmIntrinsics::_getCharAcquire: + case vmIntrinsics::_getIntAcquire: + case vmIntrinsics::_getLongAcquire: + case vmIntrinsics::_getFloatAcquire: + case vmIntrinsics::_getDoubleAcquire: + case vmIntrinsics::_putObjectRelease: + case vmIntrinsics::_putBooleanRelease: + case vmIntrinsics::_putByteRelease: + case vmIntrinsics::_putShortRelease: + case vmIntrinsics::_putCharRelease: + case vmIntrinsics::_putIntRelease: + case vmIntrinsics::_putLongRelease: + case vmIntrinsics::_putFloatRelease: + case vmIntrinsics::_putDoubleRelease: + case vmIntrinsics::_getObjectOpaque: + case vmIntrinsics::_getBooleanOpaque: + case vmIntrinsics::_getByteOpaque: + case vmIntrinsics::_getShortOpaque: + case vmIntrinsics::_getCharOpaque: + case vmIntrinsics::_getIntOpaque: + case vmIntrinsics::_getLongOpaque: + case vmIntrinsics::_getFloatOpaque: + case vmIntrinsics::_getDoubleOpaque: + case vmIntrinsics::_putObjectOpaque: + case vmIntrinsics::_putBooleanOpaque: + case vmIntrinsics::_putByteOpaque: + case vmIntrinsics::_putShortOpaque: + case vmIntrinsics::_putCharOpaque: + case vmIntrinsics::_putIntOpaque: + case vmIntrinsics::_putLongOpaque: + case vmIntrinsics::_putFloatOpaque: + case vmIntrinsics::_putDoubleOpaque: case vmIntrinsics::_getShortUnaligned: case vmIntrinsics::_getCharUnaligned: case vmIntrinsics::_getIntUnaligned: @@ -390,7 +484,6 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_putCharUnaligned: case vmIntrinsics::_putIntUnaligned: case vmIntrinsics::_putLongUnaligned: - case vmIntrinsics::_compareAndSwapInt: case vmIntrinsics::_putOrderedObject: case vmIntrinsics::_putOrderedInt: case vmIntrinsics::_putOrderedLong: @@ -400,8 +493,6 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_currentThread: case vmIntrinsics::_isInterrupted: #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: - case vmIntrinsics::_threadID: case vmIntrinsics::_counterTime: #endif case vmIntrinsics::_currentTimeMillis: diff --git a/hotspot/src/share/vm/opto/classes.hpp b/hotspot/src/share/vm/opto/classes.hpp index e101a9768a2..ee36282de38 100644 --- a/hotspot/src/share/vm/opto/classes.hpp +++ b/hotspot/src/share/vm/opto/classes.hpp @@ -85,6 +85,14 @@ macro(CompareAndSwapI) macro(CompareAndSwapL) macro(CompareAndSwapP) macro(CompareAndSwapN) +macro(WeakCompareAndSwapI) +macro(WeakCompareAndSwapL) +macro(WeakCompareAndSwapP) +macro(WeakCompareAndSwapN) +macro(CompareAndExchangeI) +macro(CompareAndExchangeL) +macro(CompareAndExchangeP) +macro(CompareAndExchangeN) macro(GetAndAddI) macro(GetAndAddL) macro(GetAndSetI) diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index bf5597753b6..ec737694e53 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -88,7 +88,27 @@ MachConstantBaseNode* Compile::mach_constant_base_node() { // Return the index at which m must be inserted (or already exists). // The sort order is by the address of the ciMethod, with is_virtual as minor key. -int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) { +class IntrinsicDescPair { + private: + ciMethod* _m; + bool _is_virtual; + public: + IntrinsicDescPair(ciMethod* m, bool is_virtual) : _m(m), _is_virtual(is_virtual) {} + static int compare(IntrinsicDescPair* const& key, CallGenerator* const& elt) { + ciMethod* m= elt->method(); + ciMethod* key_m = key->_m; + if (key_m < m) return -1; + else if (key_m > m) return 1; + else { + bool is_virtual = elt->is_virtual(); + bool key_virtual = key->_is_virtual; + if (key_virtual < is_virtual) return -1; + else if (key_virtual > is_virtual) return 1; + else return 0; + } + } +}; +int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found) { #ifdef ASSERT for (int i = 1; i < _intrinsics->length(); i++) { CallGenerator* cg1 = _intrinsics->at(i-1); @@ -99,63 +119,28 @@ int Compile::intrinsic_insertion_index(ciMethod* m, bool is_virtual) { "compiler intrinsics list must stay sorted"); } #endif - // Binary search sorted list, in decreasing intervals [lo, hi]. - int lo = 0, hi = _intrinsics->length()-1; - while (lo <= hi) { - int mid = (uint)(hi + lo) / 2; - ciMethod* mid_m = _intrinsics->at(mid)->method(); - if (m < mid_m) { - hi = mid-1; - } else if (m > mid_m) { - lo = mid+1; - } else { - // look at minor sort key - bool mid_virt = _intrinsics->at(mid)->is_virtual(); - if (is_virtual < mid_virt) { - hi = mid-1; - } else if (is_virtual > mid_virt) { - lo = mid+1; - } else { - return mid; // exact match - } - } - } - return lo; // inexact match + IntrinsicDescPair pair(m, is_virtual); + return _intrinsics->find_sorted(&pair, found); } void Compile::register_intrinsic(CallGenerator* cg) { if (_intrinsics == NULL) { _intrinsics = new (comp_arena())GrowableArray(comp_arena(), 60, 0, NULL); } - // This code is stolen from ciObjectFactory::insert. - // Really, GrowableArray should have methods for - // insert_at, remove_at, and binary_search. int len = _intrinsics->length(); - int index = intrinsic_insertion_index(cg->method(), cg->is_virtual()); - if (index == len) { - _intrinsics->append(cg); - } else { -#ifdef ASSERT - CallGenerator* oldcg = _intrinsics->at(index); - assert(oldcg->method() != cg->method() || oldcg->is_virtual() != cg->is_virtual(), "don't register twice"); -#endif - _intrinsics->append(_intrinsics->at(len-1)); - int pos; - for (pos = len-2; pos >= index; pos--) { - _intrinsics->at_put(pos+1,_intrinsics->at(pos)); - } - _intrinsics->at_put(index, cg); - } + bool found = false; + int index = intrinsic_insertion_index(cg->method(), cg->is_virtual(), found); + assert(!found, "registering twice"); + _intrinsics->insert_before(index, cg); assert(find_intrinsic(cg->method(), cg->is_virtual()) == cg, "registration worked"); } CallGenerator* Compile::find_intrinsic(ciMethod* m, bool is_virtual) { assert(m->is_loaded(), "don't try this on unloaded methods"); if (_intrinsics != NULL) { - int index = intrinsic_insertion_index(m, is_virtual); - if (index < _intrinsics->length() - && _intrinsics->at(index)->method() == m - && _intrinsics->at(index)->is_virtual() == is_virtual) { + bool found = false; + int index = intrinsic_insertion_index(m, is_virtual, found); + if (found) { return _intrinsics->at(index); } } @@ -2801,6 +2786,14 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { case Op_CompareAndSwapL: case Op_CompareAndSwapP: case Op_CompareAndSwapN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_GetAndAddI: case Op_GetAndAddL: case Op_GetAndSetI: diff --git a/hotspot/src/share/vm/opto/compile.hpp b/hotspot/src/share/vm/opto/compile.hpp index 871abe245a7..40724fbd6b7 100644 --- a/hotspot/src/share/vm/opto/compile.hpp +++ b/hotspot/src/share/vm/opto/compile.hpp @@ -1250,7 +1250,7 @@ class Compile : public Phase { // Intrinsic setup. void register_library_intrinsics(); // initializer CallGenerator* make_vm_intrinsic(ciMethod* m, bool is_virtual); // constructor - int intrinsic_insertion_index(ciMethod* m, bool is_virtual); // helper + int intrinsic_insertion_index(ciMethod* m, bool is_virtual, bool& found); // helper CallGenerator* find_intrinsic(ciMethod* m, bool is_virtual); // query fn void register_intrinsic(CallGenerator* cg); // update fn diff --git a/hotspot/src/share/vm/opto/escape.cpp b/hotspot/src/share/vm/opto/escape.cpp index 310ac7fa70e..d2641d2acca 100644 --- a/hotspot/src/share/vm/opto/escape.cpp +++ b/hotspot/src/share/vm/opto/escape.cpp @@ -490,6 +490,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de } break; } + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_GetAndSetP: case Op_GetAndSetN: { add_objload_to_connection_graph(n, delayed_worklist); @@ -499,6 +501,8 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de case Op_StoreN: case Op_StoreNKlass: case Op_StorePConditional: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_CompareAndSwapP: case Op_CompareAndSwapN: { Node* adr = n->in(MemNode::Address); @@ -698,8 +702,12 @@ void ConnectionGraph::add_final_edges(Node *n) { case Op_StoreN: case Op_StoreNKlass: case Op_StorePConditional: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: case Op_CompareAndSwapP: case Op_CompareAndSwapN: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_GetAndSetP: case Op_GetAndSetN: { Node* adr = n->in(MemNode::Address); diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp index f3389bd969b..73f7c3e1254 100644 --- a/hotspot/src/share/vm/opto/graphKit.cpp +++ b/hotspot/src/share/vm/opto/graphKit.cpp @@ -1179,8 +1179,10 @@ Node* GraphKit::load_array_length(Node* array) { // Helper function to do a NULL pointer check. Returned value is // the incoming address with NULL casted away. You are allowed to use the // not-null value only if you are control dependent on the test. +#ifndef PRODUCT extern int explicit_null_checks_inserted, explicit_null_checks_elided; +#endif Node* GraphKit::null_check_common(Node* value, BasicType type, // optional arguments for variations: bool assert_null, @@ -1193,7 +1195,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, value = cast_not_null(value); // Make it appear to be non-null (4962416). return value; } - explicit_null_checks_inserted++; + NOT_PRODUCT(explicit_null_checks_inserted++); // Construct NULL check Node *chk = NULL; @@ -1233,7 +1235,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // See if the type is contained in NULL_PTR. // If so, then the value is already null. if (t->higher_equal(TypePtr::NULL_PTR)) { - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return value; // Elided null assert quickly! } } else { @@ -1242,7 +1244,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, // type. In other words, "value" was not-null. if (t->meet(TypePtr::NULL_PTR) != t->remove_speculative()) { // same as: if (!TypePtr::NULL_PTR->higher_equal(t)) ... - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return value; // Elided null check quickly! } } @@ -1282,7 +1284,7 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, set_control(cfg); Node *res = cast_not_null(value); set_control(oldcontrol); - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); return res; } cfg = IfNode::up_one_dom(cfg, /*linear_only=*/ true); @@ -1326,15 +1328,18 @@ Node* GraphKit::null_check_common(Node* value, BasicType type, IfNode* iff = create_and_map_if(control(), tst, ok_prob, COUNT_UNKNOWN); Node* null_true = _gvn.transform( new IfFalseNode(iff)); set_control( _gvn.transform( new IfTrueNode(iff))); - if (null_true == top()) +#ifndef PRODUCT + if (null_true == top()) { explicit_null_checks_elided++; + } +#endif (*null_control) = null_true; } else { BuildCutout unless(this, tst, ok_prob); // Check for optimizer eliding test at parse time if (stopped()) { // Failure not possible; do not bother making uncommon trap. - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); } else if (assert_null) { uncommon_trap(reason, Deoptimization::Action_make_not_entrant, @@ -3149,6 +3154,19 @@ 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) { @@ -3840,7 +3858,7 @@ void GraphKit::write_barrier_post(Node* oop_store, BasicType bt = T_BYTE; if (UseConcMarkSweepGC && UseCondCardMark) { - insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier + insert_store_load_for_barrier(); __ sync_kit(this); } @@ -4280,8 +4298,7 @@ void GraphKit::g1_write_barrier_post(Node* oop_store, __ if_then(card_val, BoolTest::ne, young_card); { sync_kit(ideal); - // Use Op_MemBarVolatile to achieve the effect of a StoreLoad barrier. - insert_mem_bar(Op_MemBarVolatile, oop_store); + insert_store_load_for_barrier(); __ sync_kit(this); Node* card_val_reload = __ load(__ ctrl(), card_adr, TypeInt::INT, T_BYTE, Compile::AliasIdxRaw); diff --git a/hotspot/src/share/vm/opto/graphKit.hpp b/hotspot/src/share/vm/opto/graphKit.hpp index 7bb1f6946db..218e937818b 100644 --- a/hotspot/src/share/vm/opto/graphKit.hpp +++ b/hotspot/src/share/vm/opto/graphKit.hpp @@ -834,6 +834,7 @@ 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/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp index a2cea88273f..9e315739008 100644 --- a/hotspot/src/share/vm/opto/ifnode.cpp +++ b/hotspot/src/share/vm/opto/ifnode.cpp @@ -40,7 +40,9 @@ // Optimization - Graph Style +#ifndef PRODUCT extern int explicit_null_checks_elided; +#endif //============================================================================= //------------------------------Value------------------------------------------ @@ -1504,24 +1506,28 @@ Node* IfNode::search_identical(int dist) { Node* prev_dom = this; int op = Opcode(); // Search up the dominator tree for an If with an identical test - while( dom->Opcode() != op || // Not same opcode? + while (dom->Opcode() != op || // Not same opcode? dom->in(1) != in(1) || // Not same input 1? (req() == 3 && dom->in(2) != in(2)) || // Not same input 2? - prev_dom->in(0) != dom ) { // One path of test does not dominate? - if( dist < 0 ) return NULL; + prev_dom->in(0) != dom) { // One path of test does not dominate? + if (dist < 0) return NULL; dist--; prev_dom = dom; - dom = up_one_dom( dom ); - if( !dom ) return NULL; + dom = up_one_dom(dom); + if (!dom) return NULL; } // Check that we did not follow a loop back to ourselves - if( this == dom ) + if (this == dom) { return NULL; + } - if( dist > 2 ) // Add to count of NULL checks elided +#ifndef PRODUCT + if (dist > 2) { // Add to count of NULL checks elided explicit_null_checks_elided++; + } +#endif return prev_dom; } diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index 3edfc5e0ef0..431bba14c7e 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -348,8 +348,10 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo } // ---- Found an implicit null check +#ifndef PRODUCT extern int implicit_null_checks; implicit_null_checks++; +#endif if( is_decoden ) { // Check if we need to hoist decodeHeapOop_not_null first. diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index 753612c206f..cbcc5ae017d 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -49,7 +49,9 @@ #include "opto/subnode.hpp" #include "prims/nativeLookup.hpp" #include "runtime/sharedRuntime.hpp" +#ifdef TRACE_HAVE_INTRINSICS #include "trace/traceMacros.hpp" +#endif class LibraryIntrinsic : public InlineCallGenerator { // Extend the set of intrinsics known to the runtime: @@ -241,15 +243,14 @@ class LibraryCallKit : public GraphKit { // Generates the guards that check whether the result of // Unsafe.getObject should be recorded in an SATB log buffer. void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar); - bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool is_unaligned); + + typedef enum { Relaxed, Opaque, Volatile, Acquire, Release } AccessKind; + bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, AccessKind kind, bool is_unaligned); static bool klass_needs_init_guard(Node* kls); bool inline_unsafe_allocate(); bool inline_unsafe_copyMemory(); bool inline_native_currentThread(); -#ifdef TRACE_HAVE_INTRINSICS - bool inline_native_classID(); - bool inline_native_threadID(); -#endif + bool inline_native_time_funcs(address method, const char* funcName); bool inline_native_isInterrupted(); bool inline_native_Class_query(vmIntrinsics::ID id); @@ -274,9 +275,10 @@ class LibraryCallKit : public GraphKit { JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp); - typedef enum { LS_xadd, LS_xchg, LS_cmpxchg } LoadStoreKind; - bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind); - bool inline_unsafe_ordered_store(BasicType type); + typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; + MemNode::MemOrd access_kind_to_memord_LS(AccessKind access_kind, bool is_store); + MemNode::MemOrd access_kind_to_memord(AccessKind access_kind); + bool inline_unsafe_load_store(BasicType type, LoadStoreKind kind, AccessKind access_kind); bool inline_unsafe_fence(vmIntrinsics::ID id); bool inline_fp_conversions(vmIntrinsics::ID id); bool inline_number_methods(vmIntrinsics::ID id); @@ -317,8 +319,6 @@ class LibraryCallKit : public GraphKit { bool inline_profileBoolean(); bool inline_isCompileConstant(); - - bool inline_deoptimize(); }; //---------------------------make_vm_intrinsic---------------------------- @@ -553,86 +553,147 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_inflateStringC: case vmIntrinsics::_inflateStringB: return inline_string_copy(!is_compress); - case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, !is_volatile, false); - case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, !is_volatile, false); - case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, !is_volatile, false); - case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, !is_volatile, false); - case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); + case vmIntrinsics::_getObject: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Relaxed, false); + case vmIntrinsics::_getBoolean: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Relaxed, false); + case vmIntrinsics::_getByte: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_getShort: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_getChar: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_getInt: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Relaxed, false); + case vmIntrinsics::_getLong: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_getFloat: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_getDouble: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Relaxed, false); - case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, !is_volatile, false); + case vmIntrinsics::_putObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Relaxed, false); + case vmIntrinsics::_putBoolean: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Relaxed, false); + case vmIntrinsics::_putByte: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_putShort: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_putChar: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_putInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Relaxed, false); + case vmIntrinsics::_putLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_putFloat: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_putDouble: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Relaxed, false); - case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, !is_volatile, false); - case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, !is_volatile, false); - case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, !is_volatile, false); - case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, !is_volatile, false); - case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, !is_volatile, false); - case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, !is_volatile, false); - case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, !is_volatile, false); - case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, !is_volatile, false); + case vmIntrinsics::_getByte_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_getShort_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_getChar_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_getInt_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_INT, Relaxed, false); + case vmIntrinsics::_getLong_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_getFloat_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_getDouble_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_DOUBLE, Relaxed, false); + case vmIntrinsics::_getAddress_raw: return inline_unsafe_access( is_native_ptr, !is_store, T_ADDRESS, Relaxed, false); - case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, is_volatile, false); - case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, is_volatile, false); - case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, is_volatile, false); - case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, is_volatile, false); - case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, is_volatile, false); - case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, is_volatile, false); - case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, is_volatile, false); - case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, is_volatile, false); - case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, is_volatile, false); + case vmIntrinsics::_putByte_raw: return inline_unsafe_access( is_native_ptr, is_store, T_BYTE, Relaxed, false); + case vmIntrinsics::_putShort_raw: return inline_unsafe_access( is_native_ptr, is_store, T_SHORT, Relaxed, false); + case vmIntrinsics::_putChar_raw: return inline_unsafe_access( is_native_ptr, is_store, T_CHAR, Relaxed, false); + case vmIntrinsics::_putInt_raw: return inline_unsafe_access( is_native_ptr, is_store, T_INT, Relaxed, false); + case vmIntrinsics::_putLong_raw: return inline_unsafe_access( is_native_ptr, is_store, T_LONG, Relaxed, false); + case vmIntrinsics::_putFloat_raw: return inline_unsafe_access( is_native_ptr, is_store, T_FLOAT, Relaxed, false); + case vmIntrinsics::_putDouble_raw: return inline_unsafe_access( is_native_ptr, is_store, T_DOUBLE, Relaxed, false); + case vmIntrinsics::_putAddress_raw: return inline_unsafe_access( is_native_ptr, is_store, T_ADDRESS, Relaxed, false); - case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, is_volatile, false); - case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, is_volatile, false); - case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, is_volatile, false); - case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, is_volatile, false); - case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, is_volatile, false); - case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, is_volatile, false); - case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, is_volatile, false); - case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, is_volatile, false); - case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, is_volatile, false); + case vmIntrinsics::_getObjectVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Volatile, false); + case vmIntrinsics::_getBooleanVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Volatile, false); + case vmIntrinsics::_getByteVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Volatile, false); + case vmIntrinsics::_getShortVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Volatile, false); + case vmIntrinsics::_getCharVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Volatile, false); + case vmIntrinsics::_getIntVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Volatile, false); + case vmIntrinsics::_getLongVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Volatile, false); + case vmIntrinsics::_getFloatVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Volatile, false); + case vmIntrinsics::_getDoubleVolatile: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Volatile, false); - case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, !is_volatile, true); - case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, !is_volatile, true); - case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, !is_volatile, true); - case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, !is_volatile, true); + case vmIntrinsics::_putObjectVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Volatile, false); + case vmIntrinsics::_putBooleanVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Volatile, false); + case vmIntrinsics::_putByteVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Volatile, false); + case vmIntrinsics::_putShortVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Volatile, false); + case vmIntrinsics::_putCharVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Volatile, false); + case vmIntrinsics::_putIntVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Volatile, false); + case vmIntrinsics::_putLongVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Volatile, false); + case vmIntrinsics::_putFloatVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Volatile, false); + case vmIntrinsics::_putDoubleVolatile: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Volatile, false); - case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, !is_volatile, true); - case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, !is_volatile, true); - case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, !is_volatile, true); - case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, !is_volatile, true); + case vmIntrinsics::_getShortUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Relaxed, true); + case vmIntrinsics::_getCharUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Relaxed, true); + case vmIntrinsics::_getIntUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Relaxed, true); + case vmIntrinsics::_getLongUnaligned: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Relaxed, true); - case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmpxchg); - case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmpxchg); - case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmpxchg); + case vmIntrinsics::_putShortUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Relaxed, true); + case vmIntrinsics::_putCharUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Relaxed, true); + case vmIntrinsics::_putIntUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Relaxed, true); + case vmIntrinsics::_putLongUnaligned: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Relaxed, true); - case vmIntrinsics::_putOrderedObject: return inline_unsafe_ordered_store(T_OBJECT); - case vmIntrinsics::_putOrderedInt: return inline_unsafe_ordered_store(T_INT); - case vmIntrinsics::_putOrderedLong: return inline_unsafe_ordered_store(T_LONG); + case vmIntrinsics::_putOrderedObject: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Release, false); + case vmIntrinsics::_putOrderedInt: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Release, false); + case vmIntrinsics::_putOrderedLong: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Release, false); - case vmIntrinsics::_getAndAddInt: return inline_unsafe_load_store(T_INT, LS_xadd); - case vmIntrinsics::_getAndAddLong: return inline_unsafe_load_store(T_LONG, LS_xadd); - case vmIntrinsics::_getAndSetInt: return inline_unsafe_load_store(T_INT, LS_xchg); - case vmIntrinsics::_getAndSetLong: return inline_unsafe_load_store(T_LONG, LS_xchg); - case vmIntrinsics::_getAndSetObject: return inline_unsafe_load_store(T_OBJECT, LS_xchg); + case vmIntrinsics::_getObjectAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Acquire, false); + case vmIntrinsics::_getBooleanAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Acquire, false); + case vmIntrinsics::_getByteAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Acquire, false); + case vmIntrinsics::_getShortAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Acquire, false); + case vmIntrinsics::_getCharAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Acquire, false); + case vmIntrinsics::_getIntAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Acquire, false); + case vmIntrinsics::_getLongAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Acquire, false); + case vmIntrinsics::_getFloatAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Acquire, false); + case vmIntrinsics::_getDoubleAcquire: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Acquire, false); + + case vmIntrinsics::_putObjectRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Release, false); + case vmIntrinsics::_putBooleanRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Release, false); + case vmIntrinsics::_putByteRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Release, false); + case vmIntrinsics::_putShortRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Release, false); + case vmIntrinsics::_putCharRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Release, false); + case vmIntrinsics::_putIntRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Release, false); + case vmIntrinsics::_putLongRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Release, false); + case vmIntrinsics::_putFloatRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Release, false); + case vmIntrinsics::_putDoubleRelease: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Release, false); + + case vmIntrinsics::_getObjectOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_OBJECT, Opaque, false); + case vmIntrinsics::_getBooleanOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_BOOLEAN, Opaque, false); + case vmIntrinsics::_getByteOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_BYTE, Opaque, false); + case vmIntrinsics::_getShortOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_SHORT, Opaque, false); + case vmIntrinsics::_getCharOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_CHAR, Opaque, false); + case vmIntrinsics::_getIntOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_INT, Opaque, false); + case vmIntrinsics::_getLongOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_LONG, Opaque, false); + case vmIntrinsics::_getFloatOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_FLOAT, Opaque, false); + case vmIntrinsics::_getDoubleOpaque: return inline_unsafe_access(!is_native_ptr, !is_store, T_DOUBLE, Opaque, false); + + case vmIntrinsics::_putObjectOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_OBJECT, Opaque, false); + case vmIntrinsics::_putBooleanOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_BOOLEAN, Opaque, false); + case vmIntrinsics::_putByteOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_BYTE, Opaque, false); + case vmIntrinsics::_putShortOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_SHORT, Opaque, false); + case vmIntrinsics::_putCharOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_CHAR, Opaque, false); + case vmIntrinsics::_putIntOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_INT, Opaque, false); + case vmIntrinsics::_putLongOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_LONG, Opaque, false); + case vmIntrinsics::_putFloatOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_FLOAT, Opaque, false); + case vmIntrinsics::_putDoubleOpaque: return inline_unsafe_access(!is_native_ptr, is_store, T_DOUBLE, Opaque, false); + + case vmIntrinsics::_compareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap, Volatile); + case vmIntrinsics::_compareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmp_swap, Volatile); + case vmIntrinsics::_compareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmp_swap, Volatile); + + case vmIntrinsics::_weakCompareAndSwapObject: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapObjectAcquire: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapObjectRelease: return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Release); + case vmIntrinsics::_weakCompareAndSwapInt: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapIntAcquire: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapIntRelease: return inline_unsafe_load_store(T_INT, LS_cmp_swap_weak, Release); + case vmIntrinsics::_weakCompareAndSwapLong: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Relaxed); + case vmIntrinsics::_weakCompareAndSwapLongAcquire: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Acquire); + case vmIntrinsics::_weakCompareAndSwapLongRelease: return inline_unsafe_load_store(T_LONG, LS_cmp_swap_weak, Release); + + case vmIntrinsics::_compareAndExchangeObjectVolatile: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeObjectAcquire: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeObjectRelease: return inline_unsafe_load_store(T_OBJECT, LS_cmp_exchange, Release); + case vmIntrinsics::_compareAndExchangeIntVolatile: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeIntAcquire: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeIntRelease: return inline_unsafe_load_store(T_INT, LS_cmp_exchange, Release); + case vmIntrinsics::_compareAndExchangeLongVolatile: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Volatile); + case vmIntrinsics::_compareAndExchangeLongAcquire: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Acquire); + case vmIntrinsics::_compareAndExchangeLongRelease: return inline_unsafe_load_store(T_LONG, LS_cmp_exchange, Release); + + case vmIntrinsics::_getAndAddInt: return inline_unsafe_load_store(T_INT, LS_get_add, Volatile); + case vmIntrinsics::_getAndAddLong: return inline_unsafe_load_store(T_LONG, LS_get_add, Volatile); + case vmIntrinsics::_getAndSetInt: return inline_unsafe_load_store(T_INT, LS_get_set, Volatile); + case vmIntrinsics::_getAndSetLong: return inline_unsafe_load_store(T_LONG, LS_get_set, Volatile); + case vmIntrinsics::_getAndSetObject: return inline_unsafe_load_store(T_OBJECT, LS_get_set, Volatile); case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: @@ -642,8 +703,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_isInterrupted: return inline_native_isInterrupted(); #ifdef TRACE_HAVE_INTRINSICS - case vmIntrinsics::_classID: return inline_native_classID(); - case vmIntrinsics::_threadID: return inline_native_threadID(); case vmIntrinsics::_counterTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, TRACE_TIME_METHOD), "counterTime"); #endif case vmIntrinsics::_currentTimeMillis: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, os::javaTimeMillis), "currentTimeMillis"); @@ -760,9 +819,6 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_hasNegatives: return inline_hasNegatives(); - case vmIntrinsics::_deoptimize: - return inline_deoptimize(); - default: // If you get here, it may be that someone has added a new intrinsic // to the list in vmSymbols.hpp without implementing it here. @@ -1584,6 +1640,13 @@ bool LibraryCallKit::inline_string_char_access(bool is_store) { assert (type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2, "sanity: byte[] and char[] scales agree"); + // Bail when getChar over constants is requested: constant folding would + // reject folding mismatched char access over byte[]. A normal inlining for getChar + // Java method would constant fold nicely instead. + if (!is_store && value->is_Con() && index->is_Con()) { + return false; + } + Node* adr = array_element_address(value, index, T_CHAR); if (is_store) { (void) store_to_memory(control(), adr, ch, T_CHAR, TypeAryPtr::BYTES, MemNode::unordered, @@ -2277,8 +2340,10 @@ const TypeOopPtr* LibraryCallKit::sharpen_unsafe_type(Compile::AliasType* alias_ return NULL; } -bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile, bool unaligned) { +bool LibraryCallKit::inline_unsafe_access(const bool is_native_ptr, bool is_store, const BasicType type, const AccessKind kind, const bool unaligned) { if (callee()->is_static()) return false; // caller must have the capability! + guarantee(!is_store || kind != Acquire, "Acquire accesses can be produced only for loads"); + guarantee( is_store || kind != Release, "Release accesses can be produced only for stores"); #ifndef PRODUCT { @@ -2367,7 +2432,42 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // the barriers get omitted and the unsafe reference begins to "pollute" // the alias analysis of the rest of the graph, either Compile::can_alias // or Compile::must_alias will throw a diagnostic assert.) - bool need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM); + bool need_mem_bar; + switch (kind) { + case Relaxed: + need_mem_bar = (alias_type->adr_type() == TypeOopPtr::BOTTOM); + break; + case Opaque: + // Opaque uses CPUOrder membars for protection against code movement. + case Acquire: + case Release: + case Volatile: + need_mem_bar = true; + break; + default: + ShouldNotReachHere(); + } + + // Some accesses require access atomicity for all types, notably longs and doubles. + // When AlwaysAtomicAccesses is enabled, all accesses are atomic. + bool requires_atomic_access = false; + switch (kind) { + case Relaxed: + case Opaque: + requires_atomic_access = AlwaysAtomicAccesses; + break; + case Acquire: + case Release: + case Volatile: + requires_atomic_access = true; + break; + default: + ShouldNotReachHere(); + } + + // Figure out the memory ordering. + // Acquire/Release/Volatile accesses require marking the loads/stores with MemOrd + MemNode::MemOrd mo = access_kind_to_memord_LS(kind, is_store); // If we are reading the value of the referent field of a Reference // object (either by using Unsafe directly or through reflection) @@ -2394,22 +2494,30 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // and it is not possible to fully distinguish unintended nulls // from intended ones in this API. - if (is_volatile) { - // We need to emit leading and trailing CPU membars (see below) in - // addition to memory membars when is_volatile. This is a little - // too strong, but avoids the need to insert per-alias-type - // volatile membars (for stores; compare Parse::do_put_xxx), which - // we cannot do effectively here because we probably only have a - // rough approximation of type. - need_mem_bar = true; - // For Stores, place a memory ordering barrier now. - if (is_store) { - insert_mem_bar(Op_MemBarRelease); - } else { - if (support_IRIW_for_not_multiple_copy_atomic_cpu) { - insert_mem_bar(Op_MemBarVolatile); + // We need to emit leading and trailing CPU membars (see below) in + // addition to memory membars for special access modes. This is a little + // too strong, but avoids the need to insert per-alias-type + // volatile membars (for stores; compare Parse::do_put_xxx), which + // we cannot do effectively here because we probably only have a + // rough approximation of type. + + switch(kind) { + case Relaxed: + case Opaque: + case Acquire: + break; + case Release: + case Volatile: + if (is_store) { + insert_mem_bar(Op_MemBarRelease); + } else { + if (support_IRIW_for_not_multiple_copy_atomic_cpu) { + insert_mem_bar(Op_MemBarVolatile); + } } - } + break; + default: + ShouldNotReachHere(); } // Memory barrier to prevent normal and 'unsafe' accesses from @@ -2425,10 +2533,12 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas if (alias_type->element() != NULL || alias_type->field() != NULL) { BasicType bt; if (alias_type->element() != NULL) { - const Type* element = alias_type->element(); + // Use address type to get the element type. Alias type doesn't provide + // enough information (e.g., doesn't differentiate between byte[] and boolean[]). + const Type* element = adr_type->is_aryptr()->elem(); bt = element->isa_narrowoop() ? T_OBJECT : element->array_element_basic_type(); } else { - bt = alias_type->field()->type()->basic_type(); + bt = alias_type->field()->layout_type(); } if (bt == T_ARRAY) { // accessing an array field with getObject is not a mismatch @@ -2445,7 +2555,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // Try to constant fold a load from a constant field ciField* field = alias_type->field(); if (heap_base_oop != top() && - field != NULL && field->is_constant() && field->layout_type() == type) { + field != NULL && field->is_constant() && !mismatched) { // final or stable field const Type* con_type = Type::make_constant(alias_type->field(), heap_base_oop); if (con_type != NULL) { @@ -2453,10 +2563,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } } if (p == NULL) { - MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; // To be valid, unsafe loads may depend on other conditions than // the one that guards them: pin the Load node - p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, is_volatile, unaligned, mismatched); + p = make_load(control(), adr, value_type, type, adr_type, mo, LoadNode::Pinned, requires_atomic_access, unaligned, mismatched); // load value switch (type) { case T_BOOLEAN: @@ -2470,7 +2579,9 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; case T_OBJECT: if (need_read_barrier) { - insert_pre_barrier(heap_base_oop, offset, p, !(is_volatile || need_mem_bar)); + // We do not require a mem bar inside pre_barrier if need_mem_bar + // is set: the barriers would be emitted by us. + insert_pre_barrier(heap_base_oop, offset, p, !need_mem_bar); } break; case T_ADDRESS: @@ -2501,9 +2612,8 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas break; } - MemNode::MemOrd mo = is_volatile ? MemNode::release : MemNode::unordered; - if (type != T_OBJECT ) { - (void) store_to_memory(control(), adr, val, type, adr_type, mo, is_volatile, unaligned, mismatched); + if (type != T_OBJECT) { + (void) store_to_memory(control(), adr, val, type, adr_type, mo, requires_atomic_access, unaligned, mismatched); } else { // Possibly an oop being stored to Java heap or native memory if (!TypePtr::NULL_PTR->higher_equal(_gvn.type(heap_base_oop))) { @@ -2524,7 +2634,7 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas // Update IdealKit memory. __ sync_kit(this); } __ else_(); { - __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, is_volatile, mismatched); + __ store(__ ctrl(), adr, val, type, alias_type->index(), mo, requires_atomic_access, mismatched); } __ end_if(); // Final sync IdealKit and GraphKit. final_sync(ideal); @@ -2533,14 +2643,23 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas } } - if (is_volatile) { - if (!is_store) { - insert_mem_bar(Op_MemBarAcquire); - } else { - if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { - insert_mem_bar(Op_MemBarVolatile); + switch(kind) { + case Relaxed: + case Opaque: + case Release: + break; + case Acquire: + case Volatile: + if (!is_store) { + insert_mem_bar(Op_MemBarAcquire); + } else { + if (!support_IRIW_for_not_multiple_copy_atomic_cpu) { + insert_mem_bar(Op_MemBarVolatile); + } } - } + break; + default: + ShouldNotReachHere(); } if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); @@ -2551,21 +2670,52 @@ bool LibraryCallKit::inline_unsafe_access(bool is_native_ptr, bool is_store, Bas //----------------------------inline_unsafe_load_store---------------------------- // This method serves a couple of different customers (depending on LoadStoreKind): // -// LS_cmpxchg: -// public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); -// public final native boolean compareAndSwapInt( Object o, long offset, int expected, int x); -// public final native boolean compareAndSwapLong( Object o, long offset, long expected, long x); +// LS_cmp_swap: // -// LS_xadd: -// public int getAndAddInt( Object o, long offset, int delta) -// public long getAndAddLong(Object o, long offset, long delta) +// boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); +// boolean compareAndSwapInt( Object o, long offset, int expected, int x); +// boolean compareAndSwapLong( Object o, long offset, long expected, long x); +// +// LS_cmp_swap_weak: +// +// boolean weakCompareAndSwapObject( Object o, long offset, Object expected, Object x); +// boolean weakCompareAndSwapObjectAcquire(Object o, long offset, Object expected, Object x); +// boolean weakCompareAndSwapObjectRelease(Object o, long offset, Object expected, Object x); +// +// boolean weakCompareAndSwapInt( Object o, long offset, int expected, int x); +// boolean weakCompareAndSwapIntAcquire( Object o, long offset, int expected, int x); +// boolean weakCompareAndSwapIntRelease( Object o, long offset, int expected, int x); +// +// boolean weakCompareAndSwapLong( Object o, long offset, long expected, long x); +// boolean weakCompareAndSwapLongAcquire( Object o, long offset, long expected, long x); +// boolean weakCompareAndSwapLongRelease( Object o, long offset, long expected, long x); +// +// LS_cmp_exchange: +// +// Object compareAndExchangeObjectVolatile(Object o, long offset, Object expected, Object x); +// Object compareAndExchangeObjectAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeObjectRelease( Object o, long offset, Object expected, Object x); +// +// Object compareAndExchangeIntVolatile( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeIntAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeIntRelease( Object o, long offset, Object expected, Object x); +// +// Object compareAndExchangeLongVolatile( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeLongAcquire( Object o, long offset, Object expected, Object x); +// Object compareAndExchangeLongRelease( Object o, long offset, Object expected, Object x); +// +// LS_get_add: +// +// int getAndAddInt( Object o, long offset, int delta) +// long getAndAddLong(Object o, long offset, long delta) +// +// LS_get_set: // -// LS_xchg: // int getAndSet(Object o, long offset, int newValue) // long getAndSet(Object o, long offset, long newValue) // Object getAndSet(Object o, long offset, Object newValue) // -bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind) { +bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadStoreKind kind, const AccessKind access_kind) { // This basic scheme here is the same as inline_unsafe_access, but // differs in enough details that combining them would make the code // overly confusing. (This is a true fact! I originally combined @@ -2582,7 +2732,9 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // Check the signatures. ciSignature* sig = callee()->signature(); rtype = sig->return_type()->basic_type(); - if (kind == LS_xadd || kind == LS_xchg) { + switch(kind) { + case LS_get_add: + case LS_get_set: { // Check the signatures. #ifdef ASSERT assert(rtype == type, "get and set must return the expected type"); @@ -2591,7 +2743,10 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind assert(sig->type_at(1)->basic_type() == T_LONG, "get and set offset is long"); assert(sig->type_at(2)->basic_type() == type, "get and set must take expected type as new value/delta"); #endif // ASSERT - } else if (kind == LS_cmpxchg) { + break; + } + case LS_cmp_swap: + case LS_cmp_swap_weak: { // Check the signatures. #ifdef ASSERT assert(rtype == T_BOOLEAN, "CAS must return boolean"); @@ -2599,8 +2754,20 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object"); assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long"); #endif // ASSERT - } else { - ShouldNotReachHere(); + break; + } + case LS_cmp_exchange: { + // Check the signatures. +#ifdef ASSERT + assert(rtype == type, "CAS must return the expected type"); + assert(sig->count() == 4, "CAS has 4 arguments"); + assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object"); + assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long"); +#endif // ASSERT + break; + } + default: + ShouldNotReachHere(); } } #endif //PRODUCT @@ -2613,19 +2780,29 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* offset = NULL; Node* oldval = NULL; Node* newval = NULL; - if (kind == LS_cmpxchg) { - const bool two_slot_type = type2size[type] == 2; - receiver = argument(0); // type: oop - base = argument(1); // type: oop - offset = argument(2); // type: long - oldval = argument(4); // type: oop, int, or long - newval = argument(two_slot_type ? 6 : 5); // type: oop, int, or long - } else if (kind == LS_xadd || kind == LS_xchg){ - receiver = argument(0); // type: oop - base = argument(1); // type: oop - offset = argument(2); // type: long - oldval = NULL; - newval = argument(4); // type: oop, int, or long + switch(kind) { + case LS_cmp_swap: + case LS_cmp_swap_weak: + case LS_cmp_exchange: { + const bool two_slot_type = type2size[type] == 2; + receiver = argument(0); // type: oop + base = argument(1); // type: oop + offset = argument(2); // type: long + oldval = argument(4); // type: oop, int, or long + newval = argument(two_slot_type ? 6 : 5); // type: oop, int, or long + break; + } + case LS_get_add: + case LS_get_set: { + receiver = argument(0); // type: oop + base = argument(1); // type: oop + offset = argument(2); // type: long + oldval = NULL; + newval = argument(4); // type: oop, int, or long + break; + } + default: + ShouldNotReachHere(); } // Null check receiver. @@ -2650,11 +2827,23 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Compile::AliasType* alias_type = C->alias_type(adr_type); assert(alias_type->index() != Compile::AliasIdxBot, "no bare pointers here"); - if (kind == LS_xchg && type == T_OBJECT) { - const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); - if (tjp != NULL) { - value_type = tjp; + switch (kind) { + case LS_get_set: + case LS_cmp_exchange: { + if (type == T_OBJECT) { + const TypeOopPtr* tjp = sharpen_unsafe_type(alias_type, adr_type); + if (tjp != NULL) { + value_type = tjp; + } + } + break; } + case LS_cmp_swap: + case LS_cmp_swap_weak: + case LS_get_add: + break; + default: + ShouldNotReachHere(); } int alias_idx = C->get_alias_index(adr_type); @@ -2664,9 +2853,22 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // into actual barriers on most machines, but we still need rest of // compiler to respect ordering. - insert_mem_bar(Op_MemBarRelease); + switch (access_kind) { + case Relaxed: + case Acquire: + break; + case Release: + case Volatile: + insert_mem_bar(Op_MemBarRelease); + break; + default: + ShouldNotReachHere(); + } insert_mem_bar(Op_MemBarCPUOrder); + // Figure out the memory ordering. + MemNode::MemOrd mo = access_kind_to_memord(access_kind); + // 4984716: MemBars must be inserted before this // memory node in order to avoid a false // dependency which will confuse the scheduler. @@ -2677,25 +2879,45 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* load_store = NULL; switch(type) { case T_INT: - if (kind == LS_xadd) { - load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_cmpxchg) { - load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval)); - } else { - ShouldNotReachHere(); + switch(kind) { + case LS_get_add: + load_store = _gvn.transform(new GetAndAddINode(control(), mem, adr, newval, adr_type)); + break; + case LS_get_set: + load_store = _gvn.transform(new GetAndSetINode(control(), mem, adr, newval, adr_type)); + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapINode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapINode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangeINode(control(), mem, adr, newval, oldval, adr_type, mo)); + break; + default: + ShouldNotReachHere(); } break; case T_LONG: - if (kind == LS_xadd) { - load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type)); - } else if (kind == LS_cmpxchg) { - load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval)); - } else { - ShouldNotReachHere(); + switch(kind) { + case LS_get_add: + load_store = _gvn.transform(new GetAndAddLNode(control(), mem, adr, newval, adr_type)); + break; + case LS_get_set: + load_store = _gvn.transform(new GetAndSetLNode(control(), mem, adr, newval, adr_type)); + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapLNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapLNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangeLNode(control(), mem, adr, newval, oldval, adr_type, mo)); + break; + default: + ShouldNotReachHere(); } break; case T_OBJECT: @@ -2706,65 +2928,109 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind newval = _gvn.makecon(TypePtr::NULL_PTR); // Reference stores need a store barrier. - if (kind == LS_xchg) { - // If pre-barrier must execute before the oop store, old value will require do_load here. - if (!can_move_pre_barrier()) { - pre_barrier(true /* do_load*/, - control(), base, adr, alias_idx, newval, value_type->make_oopptr(), - NULL /* pre_val*/, - T_OBJECT); - } // Else move pre_barrier to use load_store value, see below. - } else if (kind == LS_cmpxchg) { - // Same as for newval above: - if (_gvn.type(oldval) == TypePtr::NULL_PTR) { - oldval = _gvn.makecon(TypePtr::NULL_PTR); + switch(kind) { + case LS_get_set: { + // If pre-barrier must execute before the oop store, old value will require do_load here. + if (!can_move_pre_barrier()) { + pre_barrier(true /* do_load*/, + control(), base, adr, alias_idx, newval, value_type->make_oopptr(), + NULL /* pre_val*/, + T_OBJECT); + } // Else move pre_barrier to use load_store value, see below. + break; } - // The only known value which might get overwritten is oldval. - pre_barrier(false /* do_load */, - control(), NULL, NULL, max_juint, NULL, NULL, - oldval /* pre_val */, - T_OBJECT); - } else { - ShouldNotReachHere(); + case LS_cmp_swap_weak: + case LS_cmp_swap: + case LS_cmp_exchange: { + // Same as for newval above: + if (_gvn.type(oldval) == TypePtr::NULL_PTR) { + oldval = _gvn.makecon(TypePtr::NULL_PTR); + } + // The only known value which might get overwritten is oldval. + pre_barrier(false /* do_load */, + control(), NULL, NULL, max_juint, NULL, NULL, + oldval /* pre_val */, + T_OBJECT); + break; + } + default: + ShouldNotReachHere(); } #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { Node *newval_enc = _gvn.transform(new EncodePNode(newval, newval->bottom_type()->make_narrowoop())); - if (kind == LS_xchg) { - load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, - newval_enc, adr_type, value_type->make_narrowoop())); - } else { - assert(kind == LS_cmpxchg, "wrong LoadStore operation"); - Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); - load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, - newval_enc, oldval_enc)); + + switch(kind) { + case LS_get_set: + load_store = _gvn.transform(new GetAndSetNNode(control(), mem, adr, newval_enc, adr_type, value_type->make_narrowoop())); + break; + case LS_cmp_swap_weak: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new WeakCompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo)); + break; + } + case LS_cmp_swap: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new CompareAndSwapNNode(control(), mem, adr, newval_enc, oldval_enc, mo)); + break; + } + case LS_cmp_exchange: { + Node *oldval_enc = _gvn.transform(new EncodePNode(oldval, oldval->bottom_type()->make_narrowoop())); + load_store = _gvn.transform(new CompareAndExchangeNNode(control(), mem, adr, newval_enc, oldval_enc, adr_type, value_type->make_narrowoop(), mo)); + break; + } + default: + ShouldNotReachHere(); } } else #endif - { - if (kind == LS_xchg) { + switch (kind) { + case LS_get_set: load_store = _gvn.transform(new GetAndSetPNode(control(), mem, adr, newval, adr_type, value_type->is_oopptr())); - } else { - assert(kind == LS_cmpxchg, "wrong LoadStore operation"); - load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval)); - } + break; + case LS_cmp_swap_weak: + load_store = _gvn.transform(new WeakCompareAndSwapPNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_swap: + load_store = _gvn.transform(new CompareAndSwapPNode(control(), mem, adr, newval, oldval, mo)); + break; + case LS_cmp_exchange: + load_store = _gvn.transform(new CompareAndExchangePNode(control(), mem, adr, newval, oldval, adr_type, value_type->is_oopptr(), mo)); + break; + default: + ShouldNotReachHere(); } - if (kind == LS_cmpxchg) { - // Emit the post barrier only when the actual store happened. - // This makes sense to check only for compareAndSet that can fail to set the value. - // CAS success path is marked more likely since we anticipate this is a performance - // critical path, while CAS failure path can use the penalty for going through unlikely - // path as backoff. Which is still better than doing a store barrier there. - IdealKit ideal(this); - ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); { - sync_kit(ideal); - post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); - ideal.sync_kit(this); - } ideal.end_if(); - final_sync(ideal); - } else { - post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + + // Emit the post barrier only when the actual store happened. This makes sense + // to check only for LS_cmp_* that can fail to set the value. + // LS_cmp_exchange does not produce any branches by default, so there is no + // boolean result to piggyback on. TODO: When we merge CompareAndSwap with + // CompareAndExchange and move branches here, it would make sense to conditionalize + // post_barriers for LS_cmp_exchange as well. + // + // CAS success path is marked more likely since we anticipate this is a performance + // critical path, while CAS failure path can use the penalty for going through unlikely + // path as backoff. Which is still better than doing a store barrier there. + switch (kind) { + case LS_get_set: + case LS_cmp_exchange: { + post_barrier(control(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + break; + } + case LS_cmp_swap_weak: + case LS_cmp_swap: { + IdealKit ideal(this); + ideal.if_then(load_store, BoolTest::ne, ideal.ConI(0), PROB_STATIC_FREQUENT); { + sync_kit(ideal); + post_barrier(ideal.ctrl(), load_store, base, adr, alias_idx, newval, T_OBJECT, true); + ideal.sync_kit(this); + } ideal.end_if(); + final_sync(ideal); + break; + } + default: + ShouldNotReachHere(); } break; default: @@ -2778,7 +3044,7 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind Node* proj = _gvn.transform(new SCMemProjNode(load_store)); set_memory(proj, alias_idx); - if (type == T_OBJECT && kind == LS_xchg) { + if (type == T_OBJECT && (kind == LS_get_set || kind == LS_cmp_exchange)) { #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { load_store = _gvn.transform(new DecodeNNode(load_store, load_store->get_ptr_type())); @@ -2797,74 +3063,52 @@ bool LibraryCallKit::inline_unsafe_load_store(BasicType type, LoadStoreKind kind // Add the trailing membar surrounding the access insert_mem_bar(Op_MemBarCPUOrder); - insert_mem_bar(Op_MemBarAcquire); + + switch (access_kind) { + case Relaxed: + case Release: + break; // do nothing + case Acquire: + case Volatile: + insert_mem_bar(Op_MemBarAcquire); + break; + default: + ShouldNotReachHere(); + } assert(type2size[load_store->bottom_type()->basic_type()] == type2size[rtype], "result type should match"); set_result(load_store); return true; } -//----------------------------inline_unsafe_ordered_store---------------------- -// public native void Unsafe.putOrderedObject(Object o, long offset, Object x); -// public native void Unsafe.putOrderedInt(Object o, long offset, int x); -// public native void Unsafe.putOrderedLong(Object o, long offset, long x); -bool LibraryCallKit::inline_unsafe_ordered_store(BasicType type) { - // This is another variant of inline_unsafe_access, differing in - // that it always issues store-store ("release") barrier and ensures - // store-atomicity (which only matters for "long"). - - if (callee()->is_static()) return false; // caller must have the capability! - -#ifndef PRODUCT - { - ResourceMark rm; - // Check the signatures. - ciSignature* sig = callee()->signature(); -#ifdef ASSERT - BasicType rtype = sig->return_type()->basic_type(); - assert(rtype == T_VOID, "must return void"); - assert(sig->count() == 3, "has 3 arguments"); - assert(sig->type_at(0)->basic_type() == T_OBJECT, "base is object"); - assert(sig->type_at(1)->basic_type() == T_LONG, "offset is long"); -#endif // ASSERT +MemNode::MemOrd LibraryCallKit::access_kind_to_memord_LS(AccessKind kind, bool is_store) { + MemNode::MemOrd mo = MemNode::unset; + switch(kind) { + case Opaque: + case Relaxed: mo = MemNode::unordered; break; + case Acquire: mo = MemNode::acquire; break; + case Release: mo = MemNode::release; break; + case Volatile: mo = is_store ? MemNode::release : MemNode::acquire; break; + default: + ShouldNotReachHere(); } -#endif //PRODUCT + guarantee(mo != MemNode::unset, "Should select memory ordering"); + return mo; +} - C->set_has_unsafe_access(true); // Mark eventual nmethod as "unsafe". - - // Get arguments: - Node* receiver = argument(0); // type: oop - Node* base = argument(1); // type: oop - Node* offset = argument(2); // type: long - Node* val = argument(4); // type: oop, int, or long - - // Null check receiver. - receiver = null_check(receiver); - if (stopped()) { - return true; +MemNode::MemOrd LibraryCallKit::access_kind_to_memord(AccessKind kind) { + MemNode::MemOrd mo = MemNode::unset; + switch(kind) { + case Opaque: + case Relaxed: mo = MemNode::unordered; break; + case Acquire: mo = MemNode::acquire; break; + case Release: mo = MemNode::release; break; + case Volatile: mo = MemNode::seqcst; break; + default: + ShouldNotReachHere(); } - - // Build field offset expression. - assert(Unsafe_field_offset_to_byte_offset(11) == 11, "fieldOffset must be byte-scaled"); - // 32-bit machines ignore the high half of long offsets - offset = ConvL2X(offset); - Node* adr = make_unsafe_address(base, offset); - const TypePtr *adr_type = _gvn.type(adr)->isa_ptr(); - const Type *value_type = Type::get_const_basic_type(type); - Compile::AliasType* alias_type = C->alias_type(adr_type); - - insert_mem_bar(Op_MemBarRelease); - insert_mem_bar(Op_MemBarCPUOrder); - // Ensure that the store is atomic for longs: - const bool require_atomic_access = true; - Node* store; - if (type == T_OBJECT) // reference stores need a store barrier. - store = store_oop_to_unknown(control(), base, adr, adr_type, val, type, MemNode::release); - else { - store = store_to_memory(control(), adr, val, type, adr_type, MemNode::release, require_atomic_access); - } - insert_mem_bar(Op_MemBarCPUOrder); - return true; + guarantee(mo != MemNode::unset, "Should select memory ordering"); + return mo; } bool LibraryCallKit::inline_unsafe_fence(vmIntrinsics::ID id) { @@ -2932,52 +3176,6 @@ bool LibraryCallKit::inline_unsafe_allocate() { return true; } -#ifdef TRACE_HAVE_INTRINSICS -/* - * oop -> myklass - * myklass->trace_id |= USED - * return myklass->trace_id & ~0x3 - */ -bool LibraryCallKit::inline_native_classID() { - null_check_receiver(); // null-check, then ignore - Node* cls = null_check(argument(1), T_OBJECT); - Node* kls = load_klass_from_mirror(cls, false, NULL, 0); - kls = null_check(kls, T_OBJECT); - ByteSize offset = TRACE_ID_OFFSET; - Node* insp = basic_plus_adr(kls, in_bytes(offset)); - Node* tvalue = make_load(NULL, insp, TypeLong::LONG, T_LONG, MemNode::unordered); - Node* bits = longcon(~0x03l); // ignore bit 0 & 1 - Node* andl = _gvn.transform(new AndLNode(tvalue, bits)); - Node* clsused = longcon(0x01l); // set the class bit - Node* orl = _gvn.transform(new OrLNode(tvalue, clsused)); - - const TypePtr *adr_type = _gvn.type(insp)->isa_ptr(); - store_to_memory(control(), insp, orl, T_LONG, adr_type, MemNode::unordered); - set_result(andl); - return true; -} - -bool LibraryCallKit::inline_native_threadID() { - Node* tls_ptr = NULL; - Node* cur_thr = generate_current_thread(tls_ptr); - Node* p = basic_plus_adr(top()/*!oop*/, tls_ptr, in_bytes(JavaThread::osthread_offset())); - Node* osthread = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered); - p = basic_plus_adr(top()/*!oop*/, osthread, in_bytes(OSThread::thread_id_offset())); - - Node* threadid = NULL; - size_t thread_id_size = OSThread::thread_id_size(); - if (thread_id_size == (size_t) BytesPerLong) { - threadid = ConvL2I(make_load(control(), p, TypeLong::LONG, T_LONG, MemNode::unordered)); - } else if (thread_id_size == (size_t) BytesPerInt) { - threadid = make_load(control(), p, TypeInt::INT, T_INT, MemNode::unordered); - } else { - ShouldNotReachHere(); - } - set_result(threadid); - return true; -} -#endif - //------------------------inline_native_time_funcs-------------- // inline code for System.currentTimeMillis() and System.nanoTime() // these have the same type and signature @@ -6551,12 +6749,3 @@ bool LibraryCallKit::inline_isCompileConstant() { set_result(n->is_Con() ? intcon(1) : intcon(0)); return true; } - -bool LibraryCallKit::inline_deoptimize() { - assert(WhiteBoxAPI, ""); - PreserveReexecuteState preexecs(this); - jvms()->set_should_reexecute(false); - uncommon_trap(Deoptimization::Reason_intrinsic, - Deoptimization::Action_none); - return true; -} diff --git a/hotspot/src/share/vm/opto/loopTransform.cpp b/hotspot/src/share/vm/opto/loopTransform.cpp index 57568819107..8c077f11d5f 100644 --- a/hotspot/src/share/vm/opto/loopTransform.cpp +++ b/hotspot/src/share/vm/opto/loopTransform.cpp @@ -2417,6 +2417,14 @@ void IdealLoopTree::adjust_loop_exit_prob( PhaseIdealLoop *phase ) { ((bol->in(1)->Opcode() == Op_StorePConditional ) || (bol->in(1)->Opcode() == Op_StoreIConditional ) || (bol->in(1)->Opcode() == Op_StoreLConditional ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeI ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeL ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeP ) || + (bol->in(1)->Opcode() == Op_CompareAndExchangeN ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapI ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapL ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapP ) || + (bol->in(1)->Opcode() == Op_WeakCompareAndSwapN ) || (bol->in(1)->Opcode() == Op_CompareAndSwapI ) || (bol->in(1)->Opcode() == Op_CompareAndSwapL ) || (bol->in(1)->Opcode() == Op_CompareAndSwapP ) || diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp index b0f3ad5d2a5..c853a2a6145 100644 --- a/hotspot/src/share/vm/opto/loopnode.hpp +++ b/hotspot/src/share/vm/opto/loopnode.hpp @@ -285,20 +285,29 @@ public: Node *incr() const { Node *tmp = cmp_node(); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } Node *limit() const { Node *tmp = cmp_node(); return (tmp && tmp->req()==3) ? tmp->in(2) : NULL; } Node *stride() const { Node *tmp = incr (); return (tmp && tmp->req()==3) ? tmp->in(2) : NULL; } - Node *phi() const { Node *tmp = incr (); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } Node *init_trip() const { Node *tmp = phi (); return (tmp && tmp->req()==3) ? tmp->in(1) : NULL; } int stride_con() const; bool stride_is_con() const { Node *tmp = stride (); return (tmp != NULL && tmp->is_Con()); } BoolTest::mask test_trip() const { return in(TestValue)->as_Bool()->_test._test; } + PhiNode *phi() const { + Node *tmp = incr(); + if (tmp && tmp->req() == 3) { + Node* phi = tmp->in(1); + if (phi->is_Phi()) { + return phi->as_Phi(); + } + } + return NULL; + } CountedLoopNode *loopnode() const { // The CountedLoopNode that goes with this CountedLoopEndNode may // have been optimized out by the IGVN so be cautious with the // pattern matching on the graph - if (phi() == NULL) { + PhiNode* iv_phi = phi(); + if (iv_phi == NULL) { return NULL; } - assert(phi()->is_Phi(), "should be PhiNode"); - Node *ln = phi()->in(0); + Node *ln = iv_phi->in(0); if (ln->is_CountedLoop() && ln->as_CountedLoop()->loopexit() == this) { return (CountedLoopNode*)ln; } diff --git a/hotspot/src/share/vm/opto/macroArrayCopy.cpp b/hotspot/src/share/vm/opto/macroArrayCopy.cpp index 82816b2462b..17065895bff 100644 --- a/hotspot/src/share/vm/opto/macroArrayCopy.cpp +++ b/hotspot/src/share/vm/opto/macroArrayCopy.cpp @@ -880,8 +880,14 @@ bool PhaseMacroExpand::generate_block_arraycopy(Node** ctrl, MergeMemNode** mem, Node* sptr = basic_plus_adr(src, src_off); Node* dptr = basic_plus_adr(dest, dest_off); uint alias_idx = C->get_alias_index(adr_type); - Node* sval = transform_later(LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, TypeInt::INT, T_INT, MemNode::unordered)); - Node* st = transform_later(StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, sval, T_INT, MemNode::unordered)); + bool is_mismatched = (basic_elem_type != T_INT); + Node* sval = transform_later( + LoadNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), sptr, adr_type, + TypeInt::INT, T_INT, MemNode::unordered, LoadNode::DependsOnlyOnTest, + false /*unaligned*/, is_mismatched)); + Node* st = transform_later( + StoreNode::make(_igvn, *ctrl, (*mem)->memory_at(alias_idx), dptr, adr_type, + sval, T_INT, MemNode::unordered)); (*mem)->set_memory_at(alias_idx, st); src_off += BytesPerInt; dest_off += BytesPerInt; diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index bb18a3da6d8..1df9f7ca1c0 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -2307,6 +2307,14 @@ void Matcher::find_shared( Node *n ) { case Op_StorePConditional: case Op_StoreIConditional: case Op_StoreLConditional: + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_CompareAndExchangeN: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: case Op_CompareAndSwapI: case Op_CompareAndSwapL: case Op_CompareAndSwapP: @@ -2407,8 +2415,10 @@ void Matcher::collect_null_checks( Node *proj, Node *orig_proj ) { bool push_it = false; if( proj->Opcode() == Op_IfTrue ) { +#ifndef PRODUCT extern int all_null_checks_found; all_null_checks_found++; +#endif if( b->_test._test == BoolTest::ne ) { push_it = true; } @@ -2522,6 +2532,14 @@ bool Matcher::post_store_load_barrier(const Node* vmb) { // that a monitor exit operation contains a serializing instruction. if (xop == Op_MemBarVolatile || + xop == Op_CompareAndExchangeI || + xop == Op_CompareAndExchangeL || + xop == Op_CompareAndExchangeP || + xop == Op_CompareAndExchangeN || + xop == Op_WeakCompareAndSwapL || + xop == Op_WeakCompareAndSwapP || + xop == Op_WeakCompareAndSwapN || + xop == Op_WeakCompareAndSwapI || xop == Op_CompareAndSwapL || xop == Op_CompareAndSwapP || xop == Op_CompareAndSwapN || diff --git a/hotspot/src/share/vm/opto/memnode.cpp b/hotspot/src/share/vm/opto/memnode.cpp index 75a699349f8..51733c8fa65 100644 --- a/hotspot/src/share/vm/opto/memnode.cpp +++ b/hotspot/src/share/vm/opto/memnode.cpp @@ -1582,6 +1582,21 @@ LoadNode::load_array_final_field(const TypeKlassPtr *tkls, return NULL; } +static bool is_mismatched_access(ciConstant con, BasicType loadbt) { + BasicType conbt = con.basic_type(); + switch (conbt) { + case T_BOOLEAN: conbt = T_BYTE; break; + case T_ARRAY: conbt = T_OBJECT; break; + } + switch (loadbt) { + case T_BOOLEAN: loadbt = T_BYTE; break; + case T_NARROWOOP: loadbt = T_OBJECT; break; + case T_ARRAY: loadbt = T_OBJECT; break; + case T_ADDRESS: loadbt = T_OBJECT; break; + } + return (conbt != loadbt); +} + // Try to constant-fold a stable array element. static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) { assert(ary->const_oop(), "array should be constant"); @@ -1590,10 +1605,12 @@ static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicTyp // Decode the results of GraphKit::array_element_address. ciArray* aobj = ary->const_oop()->as_array(); ciConstant con = aobj->element_value_by_offset(off); - if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) { + bool is_mismatched = is_mismatched_access(con, loadbt); + assert(!is_mismatched, "conbt=%s; loadbt=%s", type2name(con.basic_type()), type2name(loadbt)); const Type* con_type = Type::make_from_constant(con); - if (con_type != NULL) { + // Guard against erroneous constant folding. + if (!is_mismatched && con_type != NULL) { if (con_type->isa_aryptr()) { // Join with the array element type, in case it is also stable. int dim = ary->stable_dimension(); @@ -1642,7 +1659,7 @@ const Type* LoadNode::Value(PhaseGVN* phase) const { const bool off_beyond_header = ((uint)off >= (uint)min_base_off); // Try to constant-fold a stable array element. - if (FoldStableValues && ary->is_stable() && ary->const_oop() != NULL) { + if (FoldStableValues && !is_mismatched_access() && ary->is_stable() && ary->const_oop() != NULL) { // Make sure the reference is not into the header and the offset is constant if (off_beyond_header && adr->is_AddP() && off != Type::OffsetBot) { const Type* con_type = fold_stable_ary_elem(ary, off, memory_type()); diff --git a/hotspot/src/share/vm/opto/memnode.hpp b/hotspot/src/share/vm/opto/memnode.hpp index 994b782dfbb..8d9cd71bc0a 100644 --- a/hotspot/src/share/vm/opto/memnode.hpp +++ b/hotspot/src/share/vm/opto/memnode.hpp @@ -56,7 +56,9 @@ public: }; typedef enum { unordered = 0, acquire, // Load has to acquire or be succeeded by MemBarAcquire. - release // Store has to release or be preceded by MemBarRelease. + release, // Store has to release or be preceded by MemBarRelease. + seqcst, // LoadStore has to have both acquire and release semantics. + unset // The memory ordering is not set (used for testing) } MemOrd; protected: MemNode( Node *c0, Node *c1, Node *c2, const TypePtr* at ) @@ -848,34 +850,121 @@ public: virtual uint ideal_reg() const { return Op_RegFlags; } }; +class CompareAndSwapNode : public LoadStoreConditionalNode { +private: + const MemNode::MemOrd _mem_ord; +public: + CompareAndSwapNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : LoadStoreConditionalNode(c, mem, adr, val, ex), _mem_ord(mem_ord) {} + MemNode::MemOrd order() const { + return _mem_ord; + } +}; + +class CompareAndExchangeNode : public LoadStoreNode { +private: + const MemNode::MemOrd _mem_ord; +public: + enum { + ExpectedIn = MemNode::ValueIn+1 // One more input than MemNode + }; + CompareAndExchangeNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord, const TypePtr* at, const Type* t) : + LoadStoreNode(c, mem, adr, val, at, t, 5), _mem_ord(mem_ord) { + init_req(ExpectedIn, ex ); + } + + MemNode::MemOrd order() const { + return _mem_ord; + } +}; //------------------------------CompareAndSwapLNode--------------------------- -class CompareAndSwapLNode : public LoadStoreConditionalNode { +class CompareAndSwapLNode : public CompareAndSwapNode { public: - CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapINode--------------------------- -class CompareAndSwapINode : public LoadStoreConditionalNode { +class CompareAndSwapINode : public CompareAndSwapNode { public: - CompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapPNode--------------------------- -class CompareAndSwapPNode : public LoadStoreConditionalNode { +class CompareAndSwapPNode : public CompareAndSwapNode { public: - CompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } virtual int Opcode() const; }; //------------------------------CompareAndSwapNNode--------------------------- -class CompareAndSwapNNode : public LoadStoreConditionalNode { +class CompareAndSwapNNode : public CompareAndSwapNode { public: - CompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex) : LoadStoreConditionalNode(c, mem, adr, val, ex) { } + CompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapLNode--------------------------- +class WeakCompareAndSwapLNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapINode--------------------------- +class WeakCompareAndSwapINode : public CompareAndSwapNode { +public: + WeakCompareAndSwapINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + + +//------------------------------WeakCompareAndSwapPNode--------------------------- +class WeakCompareAndSwapPNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapPNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + +//------------------------------WeakCompareAndSwapNNode--------------------------- +class WeakCompareAndSwapNNode : public CompareAndSwapNode { +public: + WeakCompareAndSwapNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { } + virtual int Opcode() const; +}; + +//------------------------------CompareAndExchangeLNode--------------------------- +class CompareAndExchangeLNode : public CompareAndExchangeNode { +public: + CompareAndExchangeLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, TypeLong::LONG) { } + virtual int Opcode() const; +}; + + +//------------------------------CompareAndExchangeINode--------------------------- +class CompareAndExchangeINode : public CompareAndExchangeNode { +public: + CompareAndExchangeINode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, TypeInt::INT) { } + virtual int Opcode() const; +}; + + +//------------------------------CompareAndExchangePNode--------------------------- +class CompareAndExchangePNode : public CompareAndExchangeNode { +public: + CompareAndExchangePNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, t) { } + virtual int Opcode() const; +}; + +//------------------------------CompareAndExchangeNNode--------------------------- +class CompareAndExchangeNNode : public CompareAndExchangeNode { +public: + CompareAndExchangeNNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, const TypePtr* at, const Type* t, MemNode::MemOrd mem_ord) : CompareAndExchangeNode(c, mem, adr, val, ex, mem_ord, at, t) { } virtual int Opcode() const; }; diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp index 42ca23d212a..78dcacc550b 100644 --- a/hotspot/src/share/vm/opto/node.cpp +++ b/hotspot/src/share/vm/opto/node.cpp @@ -576,17 +576,11 @@ void Node::setup_is_top() { //------------------------------~Node------------------------------------------ // Fancy destructor; eagerly attempt to reclaim Node numberings and storage -extern int reclaim_idx ; -extern int reclaim_in ; -extern int reclaim_node; void Node::destruct() { // Eagerly reclaim unique Node numberings Compile* compile = Compile::current(); if ((uint)_idx+1 == compile->unique()) { compile->set_unique(compile->unique()-1); -#ifdef ASSERT - reclaim_idx++; -#endif } // Clear debug info: Node_Notes* nn = compile->node_notes_at(_idx); @@ -604,43 +598,25 @@ void Node::destruct() { int out_edge_size = _outmax*sizeof(void*); char *edge_end = ((char*)_in) + edge_size; char *out_array = (char*)(_out == NO_OUT_ARRAY? NULL: _out); - char *out_edge_end = out_array + out_edge_size; int node_size = size_of(); // Free the output edge array if (out_edge_size > 0) { -#ifdef ASSERT - if( out_edge_end == compile->node_arena()->hwm() ) - reclaim_in += out_edge_size; // count reclaimed out edges with in edges -#endif compile->node_arena()->Afree(out_array, out_edge_size); } // Free the input edge array and the node itself if( edge_end == (char*)this ) { -#ifdef ASSERT - if( edge_end+node_size == compile->node_arena()->hwm() ) { - reclaim_in += edge_size; - reclaim_node+= node_size; - } -#else // It was; free the input array and object all in one hit +#ifndef ASSERT compile->node_arena()->Afree(_in,edge_size+node_size); #endif } else { - // Free just the input array -#ifdef ASSERT - if( edge_end == compile->node_arena()->hwm() ) - reclaim_in += edge_size; -#endif compile->node_arena()->Afree(_in,edge_size); // Free just the object -#ifdef ASSERT - if( ((char*)this) + node_size == compile->node_arena()->hwm() ) - reclaim_node+= node_size; -#else +#ifndef ASSERT compile->node_arena()->Afree(this,node_size); #endif } diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp index b7900ad276d..b14505d3c4c 100644 --- a/hotspot/src/share/vm/opto/node.hpp +++ b/hotspot/src/share/vm/opto/node.hpp @@ -60,6 +60,8 @@ class CmpNode; class CodeBuffer; class ConstraintCastNode; class ConNode; +class CompareAndSwapNode; +class CompareAndExchangeNode; class CountedLoopNode; class CountedLoopEndNode; class DecodeNarrowPtrNode; @@ -679,6 +681,9 @@ public: DEFINE_CLASS_ID(Store, Mem, 1) DEFINE_CLASS_ID(StoreVector, Store, 0) DEFINE_CLASS_ID(LoadStore, Mem, 2) + DEFINE_CLASS_ID(LoadStoreConditional, LoadStore, 0) + DEFINE_CLASS_ID(CompareAndSwap, LoadStoreConditional, 0) + DEFINE_CLASS_ID(CompareAndExchangeNode, LoadStore, 1) DEFINE_CLASS_ID(Region, Node, 5) DEFINE_CLASS_ID(Loop, Region, 0) diff --git a/hotspot/src/share/vm/opto/parse.hpp b/hotspot/src/share/vm/opto/parse.hpp index c8a35c9ba53..b26a59f8497 100644 --- a/hotspot/src/share/vm/opto/parse.hpp +++ b/hotspot/src/share/vm/opto/parse.hpp @@ -104,13 +104,6 @@ public: // For temporary (stack-allocated, stateless) ilts: InlineTree(Compile* c, ciMethod* callee_method, JVMState* caller_jvms, float site_invoke_ratio, int max_inline_level); - // InlineTree enum - enum InlineStyle { - Inline_do_not_inline = 0, // - Inline_cha_is_monomorphic = 1, // - Inline_type_profile_monomorphic = 2 // - }; - // See if it is OK to inline. // The receiver is the inline tree for the caller. // @@ -349,9 +342,6 @@ class Parse : public GraphKit { Block* _block; // block currently getting parsed ciBytecodeStream _iter; // stream of this method's bytecodes - int _blocks_merged; // Progress meter: state merges from BB preds - int _blocks_parsed; // Progress meter: BBs actually parsed - const FastLockNode* _synch_lock; // FastLockNode for synchronized method #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/parse1.cpp b/hotspot/src/share/vm/opto/parse1.cpp index e051b5e1e5c..503f3c7f400 100644 --- a/hotspot/src/share/vm/opto/parse1.cpp +++ b/hotspot/src/share/vm/opto/parse1.cpp @@ -45,6 +45,7 @@ // the most. Some of the non-static variables are needed in bytecodeInfo.cpp // and eventually should be encapsulated in a proper class (gri 8/18/98). +#ifndef PRODUCT int nodes_created = 0; int methods_parsed = 0; int methods_seen = 0; @@ -53,42 +54,42 @@ int blocks_seen = 0; int explicit_null_checks_inserted = 0; int explicit_null_checks_elided = 0; -int all_null_checks_found = 0, implicit_null_checks = 0; -int implicit_null_throws = 0; +int all_null_checks_found = 0; +int implicit_null_checks = 0; -int reclaim_idx = 0; -int reclaim_in = 0; -int reclaim_node = 0; - -#ifndef PRODUCT bool Parse::BytecodeParseHistogram::_initialized = false; uint Parse::BytecodeParseHistogram::_bytecodes_parsed [Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_nodes_constructed[Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_nodes_transformed[Bytecodes::number_of_codes]; uint Parse::BytecodeParseHistogram::_new_values [Bytecodes::number_of_codes]; -#endif //------------------------------print_statistics------------------------------- -#ifndef PRODUCT void Parse::print_statistics() { tty->print_cr("--- Compiler Statistics ---"); tty->print("Methods seen: %d Methods parsed: %d", methods_seen, methods_parsed); tty->print(" Nodes created: %d", nodes_created); tty->cr(); - if (methods_seen != methods_parsed) + if (methods_seen != methods_parsed) { tty->print_cr("Reasons for parse failures (NOT cumulative):"); + } tty->print_cr("Blocks parsed: %d Blocks seen: %d", blocks_parsed, blocks_seen); - if( explicit_null_checks_inserted ) - tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", explicit_null_checks_inserted, explicit_null_checks_elided, (100*explicit_null_checks_elided)/explicit_null_checks_inserted, all_null_checks_found); - if( all_null_checks_found ) + if (explicit_null_checks_inserted) { + tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", + explicit_null_checks_inserted, explicit_null_checks_elided, + (100*explicit_null_checks_elided)/explicit_null_checks_inserted, + all_null_checks_found); + } + if (all_null_checks_found) { tty->print_cr("%d made implicit (%2d%%)", implicit_null_checks, (100*implicit_null_checks)/all_null_checks_found); - if( implicit_null_throws ) + } + if (SharedRuntime::_implicit_null_throws) { tty->print_cr("%d implicit null exceptions at runtime", - implicit_null_throws); + SharedRuntime::_implicit_null_throws); + } - if( PrintParseStatistics && BytecodeParseHistogram::initialized() ) { + if (PrintParseStatistics && BytecodeParseHistogram::initialized()) { BytecodeParseHistogram::print(); } } @@ -495,7 +496,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) C->dependencies()->assert_evol_method(method()); } - methods_seen++; + NOT_PRODUCT(methods_seen++); // Do some special top-level things. if (depth() == 1 && C->is_osr_compilation()) { @@ -530,8 +531,8 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) } #endif - methods_parsed++; #ifndef PRODUCT + methods_parsed++; // add method size here to guarantee that inlined methods are added too if (CITime) _total_bytes_compiled += method()->code_size(); @@ -652,7 +653,7 @@ void Parse::do_all_blocks() { continue; } - blocks_parsed++; + NOT_PRODUCT(blocks_parsed++); progress = true; if (block->is_loop_head() || block->is_handler() || has_irreducible && !block->is_ready()) { @@ -712,9 +713,9 @@ void Parse::do_all_blocks() { } } +#ifndef PRODUCT blocks_seen += block_count(); -#ifndef PRODUCT // Make sure there are no half-processed blocks remaining. // Every remaining unprocessed block is dead and may be ignored now. for (int rpo = 0; rpo < block_count(); rpo++) { @@ -1446,7 +1447,6 @@ void Parse::do_one_block() { assert(block()->is_merged(), "must be merged before being parsed"); block()->mark_parsed(); - ++_blocks_parsed; // Set iterator to start of block. iter().reset_to_bci(block()->start()); @@ -1596,9 +1596,6 @@ void Parse::merge_common(Parse::Block* target, int pnum) { return; } - // Record that a new block has been merged. - ++_blocks_merged; - // Make a region if we know there are multiple or unpredictable inputs. // (Also, if this is a plain fall-through, we might see another region, // which must not be allowed into this block's map.) diff --git a/hotspot/src/share/vm/opto/parse2.cpp b/hotspot/src/share/vm/opto/parse2.cpp index e03abd4f931..8004ef246e5 100644 --- a/hotspot/src/share/vm/opto/parse2.cpp +++ b/hotspot/src/share/vm/opto/parse2.cpp @@ -44,8 +44,10 @@ #include "runtime/deoptimization.hpp" #include "runtime/sharedRuntime.hpp" +#ifndef PRODUCT extern int explicit_null_checks_inserted, explicit_null_checks_elided; +#endif //---------------------------------array_load---------------------------------- void Parse::array_load(BasicType elem_type) { @@ -997,7 +999,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { return; } - explicit_null_checks_inserted++; + NOT_PRODUCT(explicit_null_checks_inserted++); // Generate real control flow Node *tst = _gvn.transform( new BoolNode( c, btest ) ); @@ -1013,7 +1015,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { set_control(iftrue); if (stopped()) { // Path is dead? - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); if (C->eliminate_boxing()) { // Mark the successor block as parsed branch_block->next_path_num(); @@ -1033,7 +1035,7 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { set_control(iffalse); if (stopped()) { // Path is dead? - explicit_null_checks_elided++; + NOT_PRODUCT(explicit_null_checks_elided++); if (C->eliminate_boxing()) { // Mark the successor block as parsed next_block->next_path_num(); diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index 1f6de0d1700..f925cd5ef27 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -1471,6 +1471,27 @@ void PhaseIterGVN::add_users_to_worklist0( Node *n ) { } } +// Return counted loop Phi if as a counted loop exit condition, cmp +// compares the the induction variable with n +static PhiNode* countedloop_phi_from_cmp(CmpINode* cmp, Node* n) { + for (DUIterator_Fast imax, i = cmp->fast_outs(imax); i < imax; i++) { + Node* bol = cmp->fast_out(i); + for (DUIterator_Fast i2max, i2 = bol->fast_outs(i2max); i2 < i2max; i2++) { + Node* iff = bol->fast_out(i2); + if (iff->is_CountedLoopEnd()) { + CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); + if (cle->limit() == n) { + PhiNode* phi = cle->phi(); + if (phi != NULL) { + return phi; + } + } + } + } + } + return NULL; +} + void PhaseIterGVN::add_users_to_worklist( Node *n ) { add_users_to_worklist0(n); @@ -1500,18 +1521,7 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { Node* bol = use->raw_out(0); if (bol->outcnt() > 0) { Node* iff = bol->raw_out(0); - if (use_op == Op_CmpI && - iff->is_CountedLoopEnd()) { - CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); - if (cle->limit() == n && cle->phi() != NULL) { - // If an opaque node feeds into the limit condition of a - // CountedLoop, we need to process the Phi node for the - // induction variable when the opaque node is removed: - // the range of values taken by the Phi is now known and - // so its type is also known. - _worklist.push(cle->phi()); - } - } else if (iff->outcnt() == 2) { + if (iff->outcnt() == 2) { // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the // phi merging either 0 or 1 onto the worklist Node* ifproj0 = iff->raw_out(0); @@ -1526,6 +1536,15 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { } } if (use_op == Op_CmpI) { + Node* phi = countedloop_phi_from_cmp((CmpINode*)use, n); + if (phi != NULL) { + // If an opaque node feeds into the limit condition of a + // CountedLoop, we need to process the Phi node for the + // induction variable when the opaque node is removed: + // the range of values taken by the Phi is now known and + // so its type is also known. + _worklist.push(phi); + } Node* in1 = use->in(1); for (uint i = 0; i < in1->outcnt(); i++) { if (in1->raw_out(i)->Opcode() == Op_CastII) { @@ -1714,6 +1733,15 @@ void PhaseCCP::analyze() { } } } + // If n is used in a counted loop exit condition then the type + // of the counted loop's Phi depends on the type of n. See + // PhiNode::Value(). + if (m_op == Op_CmpI) { + PhiNode* phi = countedloop_phi_from_cmp((CmpINode*)m, n); + if (phi != NULL) { + worklist.push(phi); + } + } } } } diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp index 837118d177a..6ef389e8649 100644 --- a/hotspot/src/share/vm/opto/phaseX.hpp +++ b/hotspot/src/share/vm/opto/phaseX.hpp @@ -431,7 +431,7 @@ public: // Phase for iteratively performing local, pessimistic GVN-style optimizations. // and ideal transformations on the graph. class PhaseIterGVN : public PhaseGVN { - private: +private: bool _delay_transform; // When true simply register the node when calling transform // instead of actually optimizing it diff --git a/hotspot/src/share/vm/precompiled/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp index bd79327acc2..f3e0fea113f 100644 --- a/hotspot/src/share/vm/precompiled/precompiled.hpp +++ b/hotspot/src/share/vm/precompiled/precompiled.hpp @@ -58,6 +58,9 @@ # include "classfile/classFileStream.hpp" # include "classfile/classLoader.hpp" # include "classfile/javaClasses.hpp" +# include "classfile/moduleEntry.hpp" +# include "classfile/modules.hpp" +# include "classfile/packageEntry.hpp" # include "classfile/symbolTable.hpp" # include "classfile/systemDictionary.hpp" # include "classfile/vmSymbols.hpp" diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 419963ef412..5f08fcd2c1f 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -28,7 +28,9 @@ #include "classfile/altHashing.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" +#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/modules.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -73,6 +75,7 @@ #include "runtime/vm_operations.hpp" #include "services/memTracker.hpp" #include "services/runtimeService.hpp" +#include "trace/traceMacros.hpp" #include "trace/tracing.hpp" #include "utilities/defaultStream.hpp" #include "utilities/dtrace.hpp" @@ -88,7 +91,7 @@ #include "jvmci/jvmciRuntime.hpp" #endif -static jint CurrentVersion = JNI_VERSION_1_8; +static jint CurrentVersion = JNI_VERSION_9; #ifdef _WIN32 extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); @@ -3442,6 +3445,47 @@ JNI_LEAF(jint, jni_GetJavaVM(JNIEnv *env, JavaVM **vm)) return JNI_OK; JNI_END + +JNI_ENTRY(jobject, jni_GetModule(JNIEnv* env, jclass clazz)) + JNIWrapper("GetModule"); + return Modules::get_module(clazz, THREAD); +JNI_END + + +JNI_ENTRY(void, jni_AddModuleReads(JNIEnv* env, jobject m1, jobject m2)) + JNIWrapper("AddModuleReads"); + if (m1 == NULL || m2 == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + JavaValue result(T_VOID); + Handle m1_h(THREAD, JNIHandles::resolve(m1)); + if (!java_lang_reflect_Module::is_instance(m1_h())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad m1 object"); + } + Handle m2_h(THREAD, JNIHandles::resolve(m2)); + if (!java_lang_reflect_Module::is_instance(m2_h())) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Bad m2 object"); + } + JavaCalls::call_static(&result, + KlassHandle(THREAD, SystemDictionary::module_Modules_klass()), + vmSymbols::addReads_name(), + vmSymbols::addReads_signature(), + m1_h, + m2_h, + THREAD); +JNI_END + + +JNI_ENTRY(jboolean, jni_CanReadModule(JNIEnv* env, jobject m1, jobject m2)) + JNIWrapper("CanReadModule"); + if (m1 == NULL || m2 == NULL) { + THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE); + } + jboolean res = Modules::can_read_module(m1, m2, CHECK_false); + return res; +JNI_END + + // Structure containing all jni functions struct JNINativeInterface_ jni_NativeInterface = { NULL, @@ -3721,7 +3765,13 @@ struct JNINativeInterface_ jni_NativeInterface = { // New 1_6 features - jni_GetObjectRefType + jni_GetObjectRefType, + + // Module features + + jni_GetModule, + jni_AddModuleReads, + jni_CanReadModule }; @@ -3929,7 +3979,7 @@ static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { EventThreadStart event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.set_thread(THREAD_TRACE_ID(thread)); event.commit(); } @@ -4149,7 +4199,7 @@ static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool dae EventThreadStart event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.set_thread(THREAD_TRACE_ID(thread)); event.commit(); } diff --git a/hotspot/src/share/vm/prims/jni.h b/hotspot/src/share/vm/prims/jni.h index 582f2c97024..96996885a07 100644 --- a/hotspot/src/share/vm/prims/jni.h +++ b/hotspot/src/share/vm/prims/jni.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -765,6 +765,17 @@ struct JNINativeInterface_ { jobjectRefType (JNICALL *GetObjectRefType) (JNIEnv* env, jobject obj); + + /* Module Features */ + + jobject (JNICALL *GetModule) + (JNIEnv* env, jclass clazz); + + void (JNICALL *AddModuleReads) + (JNIEnv* env, jobject m1, jobject m2); + + jboolean (JNICALL *CanReadModule) + (JNIEnv* env, jobject m1, jobject m2); }; /* @@ -1857,6 +1868,20 @@ struct JNIEnv_ { return functions->GetObjectRefType(this, obj); } + /* Module Features */ + + jobject GetModule(jclass clazz) { + return functions->GetModule(this, clazz); + } + + void AddModuleReads(jobject fromModule, jobject sourceModule) { + functions->AddModuleReads(this, fromModule, sourceModule); + } + + jboolean CanReadModule(jobject askingModule, jobject sourceModule) { + return functions->CanReadModule(this, askingModule, sourceModule); + } + #endif /* __cplusplus */ }; @@ -1952,6 +1977,7 @@ JNI_OnUnload(JavaVM *vm, void *reserved); #define JNI_VERSION_1_4 0x00010004 #define JNI_VERSION_1_6 0x00010006 #define JNI_VERSION_1_8 0x00010008 +#define JNI_VERSION_9 0x00090000 #ifdef __cplusplus } /* extern "C" */ diff --git a/hotspot/src/share/vm/prims/jniCheck.cpp b/hotspot/src/share/vm/prims/jniCheck.cpp index 8ba2212ac78..d6b703574d0 100644 --- a/hotspot/src/share/vm/prims/jniCheck.cpp +++ b/hotspot/src/share/vm/prims/jniCheck.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1989,7 +1989,48 @@ JNI_ENTRY_CHECKED(jint, return result; JNI_END +JNI_ENTRY_CHECKED(jobject, + checked_jni_GetModule(JNIEnv *env, + jclass clazz)) + functionEnter(thr); + IN_VM( + jniCheck::validate_class(thr, clazz, false); + ) + jobject result = UNCHECKED()->GetModule(env,clazz); + functionExit(thr); + return result; +JNI_END +JNI_ENTRY_CHECKED(void, + checked_jni_AddModuleReads(JNIEnv *env, + jobject fromModule, + jobject sourceModule)) + functionEnter(thr); + IN_VM( + jniCheck::validate_object(thr, fromModule); + if (sourceModule != NULL) { + jniCheck::validate_object(thr, sourceModule); + } + ) + UNCHECKED()->AddModuleReads(env,fromModule,sourceModule); + functionExit(thr); +JNI_END + +JNI_ENTRY_CHECKED(jboolean, + checked_jni_CanReadModule(JNIEnv *env, + jobject askingModule, + jobject sourceModule)) + functionEnter(thr); + IN_VM( + jniCheck::validate_object(thr, askingModule); + if (sourceModule != NULL) { + jniCheck::validate_object(thr, sourceModule); + } + ) + jboolean result = UNCHECKED()->CanReadModule(env,askingModule,sourceModule); + functionExit(thr); + return result; +JNI_END /* * Structure containing all checked jni functions @@ -2272,7 +2313,13 @@ struct JNINativeInterface_ checked_jni_NativeInterface = { // New 1.6 Features - checked_jni_GetObjectRefType + checked_jni_GetObjectRefType, + + // Module Features + + checked_jni_GetModule, + checked_jni_AddModuleReads, + checked_jni_CanReadModule }; diff --git a/hotspot/src/share/vm/prims/jvm.cpp b/hotspot/src/share/vm/prims/jvm.cpp index 2067afd58d5..093efe3bab1 100644 --- a/hotspot/src/share/vm/prims/jvm.cpp +++ b/hotspot/src/share/vm/prims/jvm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,12 @@ #include "precompiled.hpp" #include "classfile/classFileStream.hpp" #include "classfile/classLoader.hpp" +#include "classfile/classLoaderData.inline.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.inline.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/modules.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" @@ -1047,6 +1051,58 @@ JVM_ENTRY(jclass, JVM_FindLoadedClass(JNIEnv *env, jobject loader, jstring name) (jclass) JNIHandles::make_local(env, k->java_mirror()); JVM_END +// Module support ////////////////////////////////////////////////////////////////////////////// + +JVM_ENTRY(void, JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location, + jobjectArray packages)) + JVMWrapper("JVM_DefineModule"); + Modules::define_module(module, version, location, packages, CHECK); +JVM_END + +JVM_ENTRY(void, JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module)) + JVMWrapper("JVM_SetBootLoaderUnnamedModule"); + Modules::set_bootloader_unnamed_module(module, CHECK); +JVM_END + +JVM_ENTRY(void, JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring 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)) + 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)) + JVMWrapper("JVM_AddModuleExportsToAll"); + Modules::add_module_exports(from_module, package, NULL, CHECK); +JVM_END + +JVM_ENTRY (void, JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module)) + JVMWrapper("JVM_AddReadsModule"); + Modules::add_reads_module(from_module, source_module, CHECK); +JVM_END + +JVM_ENTRY(jboolean, JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module)) + JVMWrapper("JVM_CanReadModule"); + return Modules::can_read_module(asking_module, source_module, THREAD); +JVM_END + +JVM_ENTRY(jboolean, JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module)) + JVMWrapper("JVM_IsExportedToModule"); + return Modules::is_exported_to_module(from_module, package, to_module, THREAD); +JVM_END + +JVM_ENTRY (void, JVM_AddModulePackage(JNIEnv *env, jobject module, jstring 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 ////////////////////////////////////////////////////////////////////////////// diff --git a/hotspot/src/share/vm/prims/jvm.h b/hotspot/src/share/vm/prims/jvm.h index af12c25bf1d..31ff94c5743 100644 --- a/hotspot/src/share/vm/prims/jvm.h +++ b/hotspot/src/share/vm/prims/jvm.h @@ -416,6 +416,41 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source); +/* + * Module support funcions + */ + +JNIEXPORT void JNICALL +JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location, + jobjectArray packages); + +JNIEXPORT void JNICALL +JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); + +JNIEXPORT void JNICALL +JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + +JNIEXPORT void JNICALL +JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); + +JNIEXPORT void JNICALL +JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); + +JNIEXPORT void JNICALL +JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject source_module); + +JNIEXPORT jboolean JNICALL +JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module); + +JNIEXPORT jboolean JNICALL +JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + +JNIEXPORT void JNICALL +JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); + +JNIEXPORT jobject JNICALL +JVM_GetModuleByPackageName(JNIEnv* env, jobject loader, jstring package); + /* * Reflection support functions */ @@ -920,6 +955,7 @@ JVM_IsSameClassPackage(JNIEnv *env, jclass class1, jclass class2); #define JVM_ACC_SYNTHETIC 0x1000 /* compiler-generated class, method or field */ #define JVM_ACC_ANNOTATION 0x2000 /* annotation type */ #define JVM_ACC_ENUM 0x4000 /* field is declared as element of enum */ +#define JVM_ACC_MODULE 0x8000 /* module-info class file */ #define JVM_ACC_PUBLIC_BIT 0 #define JVM_ACC_PRIVATE_BIT 1 diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index 98a0a0640aa..f6a18c771ac 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@ + majorversion="9" + minorversion="0" + microversion="0"> <tm>JVM</tm> Tool Interface @@ -863,6 +863,23 @@ Agent_OnUnload_L(JavaVM *vm) to be instrumented by the use of wrapper methods. + + Agents that instrument code in named modules may need to arrange for those + modules to read other modules. If code is instrumented to invoke a method + in a support class in another module, then the module of the instrumented + code should read the module of the supporting class. Furthermore, the + supporting class will only be accessible to the instrumented code if + it is public and in a package that is exported by its module. + Agents can use the JNI functions CanReadModule and + AddModuleReads to test and update a module to read another. +

+ As an aid to agents that deploy supporting classes on the search path of + the bootstrap class loader, or the search path of the class loader that + loads the main class, the Java virtual machine arranges for the module + of classes transformed by the event to + read the unnamed module of both class loaders. + + uses modified UTF-8 to encode character strings. This is the same encoding used by JNI. @@ -1880,10 +1897,6 @@ jvmtiEnv *jvmti; jvmtiThreadInfo On return, filled with information describing the specified thread. -

- For JDK 1.1 implementations that don't - recognize context class loaders, - the context_class_loader field will be NULL. @@ -6460,6 +6473,43 @@ class C2 extends C1 implements I2 { + + + + + + + Get All Modules + + Return an array of all modules loaded in the virtual machine. + The number of modules in the array is returned via + module_count_ptr, and the array itself via + modules_ptr. +

+ + new + + + + + + + On return, points to the number of returned modules. + + + + + + On return, points to an array of references, one + for each module. + + + + + + + + @@ -6508,9 +6558,6 @@ class C2 extends C1 implements I2 { either by defining it directly or by delegation to another class loader. See .

- For JDK version 1.1 implementations that don't - recognize the distinction between initiating and defining class loaders, - this function should return all classes loaded in the virtual machine. The number of classes in the array is returned via class_count_ptr, and the array itself via classes_ptr. @@ -9941,6 +9988,12 @@ myInit() { See . + + + Can generate the VMStart event early. + See . + + @@ -12351,7 +12404,7 @@ myInit() { - This event is sent when the VM obtains class file data, @@ -12367,9 +12420,9 @@ myInit() { bytecode instrumentation for usage information.

- This event may be sent before the VM is initialized (the primordial - phase). During this time - no VM resources should be created. Some classes might not be compatible + This event may be sent before the VM is initialized (the start + phase). + Some classes might not be compatible with the function (eg. ROMized classes) and this event will not be generated for these classes.

@@ -12378,9 +12431,7 @@ myInit() { using the memory allocation function because the VM is responsible for freeing the new class file data buffer - using . - Note that - is permitted during the primordial phase. + using .

If the agent wishes to modify the class file, it must set new_class_data to point @@ -12427,8 +12478,6 @@ myInit() { The JNI environment of the event (current) thread. - Will be NULL if sent during the primordial - phase. @@ -12496,9 +12545,28 @@ myInit() { The VM initialization event signals the start of the VM. At this time JNI is live but the VM is not yet fully initialized. Once this event is generated, the agent is free to call any JNI function. - This event signals the beginning of the start phase, + This event signals the beginning of the start phase, functions permitted in the start phase may be called.

+ The timing of this event may depend on whether the agent has added the + + can_generate_early_vmstart capability or not. + If the capability has been added then the VM posts the event as early + as possible. The VM is capable of executing bytecode but it may not have + initialized to the point where it can load classes in modules other than + java.base. Agents that do load-time instrumentation in this + phase must take great care when instrumenting code that potentially + executes in this phase. Care should also be taken with JNI + FindClass as it may not be possible to load classes that are + not in the java.base module. + If the capability has not been added then the VM delays posting this + event until it is capable of loading classes in modules other than + java.base or the VM has completed its initialization. + Agents that create more than one JVM TI environment, where the + capability is added to some but not all environments, may observe the + start phase beginning earlier in the JVM TI environments that possess + the capabilty. +

In the case of VM start-up failure, this event will not be sent. jvmdi @@ -12576,7 +12644,7 @@ myInit() { - Sent when a method is compiled and loaded into memory by the VM. @@ -12667,7 +12735,7 @@ myInit() { - Sent when a compiled method is unloaded from memory. @@ -14340,6 +14408,17 @@ typedef void (JNICALL *jvmtiEventVMInit) Added support for statically linked agents. + + Support for modules: + - The majorversion is 9 now + - The ClassFileLoadHook events are not sent during the primordial phase anymore. + - Add new function GetAllModules + + + Support for modules: + - Add new capability can_generate_early_vmstart + - Allow CompiledMethodLoad events at start phase + diff --git a/hotspot/src/share/vm/prims/jvmti.xsl b/hotspot/src/share/vm/prims/jvmti.xsl index 1f975d2c1d4..00a1551d63d 100644 --- a/hotspot/src/share/vm/prims/jvmti.xsl +++ b/hotspot/src/share/vm/prims/jvmti.xsl @@ -1,6 +1,6 @@ - */ + */ - /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ + /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ - // AUTOMATICALLY GENERATED FILE - DO NOT EDIT + // AUTOMATICALLY GENERATED FILE - DO NOT EDIT diff --git a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp b/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp index b614b5acea0..a9ce01c93d1 100644 --- a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp +++ b/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -133,9 +133,7 @@ jvmtiCapabilities JvmtiManageCapabilities::init_onload_capabilities() { jc.can_get_owned_monitor_info = 1; jc.can_get_owned_monitor_stack_depth_info = 1; jc.can_get_current_contended_monitor = 1; - // jc.can_get_monitor_info = 1; - jc.can_tag_objects = 1; // TODO: this should have been removed - jc.can_generate_object_free_events = 1; // TODO: this should have been removed + jc.can_generate_early_vmstart = 1; return jc; } @@ -454,6 +452,8 @@ void JvmtiManageCapabilities:: print(const jvmtiCapabilities* cap) { tty->print_cr("can_generate_resource_exhaustion_heap_events"); if (cap->can_generate_resource_exhaustion_threads_events) tty->print_cr("can_generate_resource_exhaustion_threads_events"); + if (cap->can_generate_early_vmstart) + tty->print_cr("can_generate_early_vmstart"); } #endif diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index 8823e6670a6..6b176ec1f70 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3940,6 +3940,10 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass, scratch_class->set_methods(_old_methods); // To prevent potential GCing of the old methods, // and to be able to undo operation easily. + Array* old_ordering = the_class->method_ordering(); + the_class->set_method_ordering(scratch_class->method_ordering()); + scratch_class->set_method_ordering(old_ordering); + ConstantPool* old_constants = the_class->constants(); the_class->set_constants(scratch_class->constants()); scratch_class->set_constants(old_constants); // See the previous comment. diff --git a/hotspot/src/share/vm/prims/methodHandles.cpp b/hotspot/src/share/vm/prims/methodHandles.cpp index 38b68a40422..de66179e45b 100644 --- a/hotspot/src/share/vm/prims/methodHandles.cpp +++ b/hotspot/src/share/vm/prims/methodHandles.cpp @@ -1177,9 +1177,9 @@ JVM_ENTRY(jobject, MHN_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, if (reference_klass != NULL && reference_klass->is_instance_klass()) { // Emulate LinkResolver::check_klass_accessability. Klass* caller = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(caller_jh)); - if (!Reflection::verify_class_access(caller, - reference_klass, - true)) { + if (Reflection::verify_class_access(caller, + reference_klass, + true) != Reflection::ACCESS_OK) { THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), reference_klass->external_name()); } } diff --git a/hotspot/src/share/vm/prims/nativeLookup.cpp b/hotspot/src/share/vm/prims/nativeLookup.cpp index c89e4f10c32..1ebcaeef6ac 100644 --- a/hotspot/src/share/vm/prims/nativeLookup.cpp +++ b/hotspot/src/share/vm/prims/nativeLookup.cpp @@ -41,7 +41,9 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "utilities/macros.hpp" - +#if INCLUDE_TRACE +#include "trace/traceMacros.hpp" +#endif static void mangle_name_on(outputStream* st, Symbol* name, int begin, int end) { char* bytes = (char*)name->bytes() + begin; @@ -131,6 +133,9 @@ static JNINativeMethod lookup_special_native_methods[] = { { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", NULL, FN_PTR(JVM_GetJVMCIRuntime) }, { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", NULL, FN_PTR(JVM_RegisterJVMCINatives) }, #endif +#if INCLUDE_TRACE + { CC"Java_jdk_jfr_internal_JVM_registerNatives", NULL, TRACE_REGISTER_NATIVES }, +#endif }; static address lookup_special_native(char* jni_name) { diff --git a/hotspot/src/share/vm/prims/unsafe.cpp b/hotspot/src/share/vm/prims/unsafe.cpp index 84d24626a15..cdd4334e229 100644 --- a/hotspot/src/share/vm/prims/unsafe.cpp +++ b/hotspot/src/share/vm/prims/unsafe.cpp @@ -1117,6 +1117,44 @@ UNSAFE_END // JSR166 ------------------------------------------------------------------ +UNSAFE_ENTRY(jobject, Unsafe_CompareAndExchangeObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) + UnsafeWrapper("Unsafe_CompareAndExchangeObject"); + oop x = JNIHandles::resolve(x_h); + oop e = JNIHandles::resolve(e_h); + oop p = JNIHandles::resolve(obj); + HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset); + oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true); + if (res == e) + update_barrier_set((void*)addr, x); + return JNIHandles::make_local(env, res); +UNSAFE_END + +UNSAFE_ENTRY(jint, Unsafe_CompareAndExchangeInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) + UnsafeWrapper("Unsafe_CompareAndExchangeInt"); + oop p = JNIHandles::resolve(obj); + jint* addr = (jint *) index_oop_from_field_offset_long(p, offset); + return (jint)(Atomic::cmpxchg(x, addr, e)); +UNSAFE_END + +UNSAFE_ENTRY(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) + UnsafeWrapper("Unsafe_CompareAndExchangeLong"); + Handle p (THREAD, JNIHandles::resolve(obj)); + jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset)); +#ifdef SUPPORTS_NATIVE_CX8 + return (jlong)(Atomic::cmpxchg(x, addr, e)); +#else + if (VM_Version::supports_cx8()) + return (jlong)(Atomic::cmpxchg(x, addr, e)); + else { + MutexLockerEx mu(UnsafeJlong_lock, Mutex::_no_safepoint_check_flag); + jlong val = Atomic::load(addr); + if (val == e) + Atomic::store(x, addr); + return val; + } +#endif +UNSAFE_END + UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h)) UnsafeWrapper("Unsafe_CompareAndSwapObject"); oop x = JNIHandles::resolve(x_h); @@ -1384,6 +1422,10 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = { {CC "compareAndSwapObject", CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSwapObject)}, {CC "compareAndSwapInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSwapInt)}, {CC "compareAndSwapLong", CC "(" OBJ "J""J""J"")Z", FN_PTR(Unsafe_CompareAndSwapLong)}, + {CC "compareAndExchangeObjectVolatile", CC "(" OBJ "J" OBJ "" OBJ ")" OBJ, FN_PTR(Unsafe_CompareAndExchangeObject)}, + {CC "compareAndExchangeIntVolatile", CC "(" OBJ "J""I""I"")I", FN_PTR(Unsafe_CompareAndExchangeInt)}, + {CC "compareAndExchangeLongVolatile", CC "(" OBJ "J""J""J"")J", FN_PTR(Unsafe_CompareAndExchangeLong)}, + {CC "putOrderedObject", CC "(" OBJ "J" OBJ ")V", FN_PTR(Unsafe_SetOrderedObject)}, {CC "putOrderedInt", CC "(" OBJ "JI)V", FN_PTR(Unsafe_SetOrderedInt)}, {CC "putOrderedLong", CC "(" OBJ "JJ)V", FN_PTR(Unsafe_SetOrderedLong)}, diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 51750b8338e..c6d4c41163a 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -27,6 +27,7 @@ #include #include "classfile/classLoaderData.hpp" +#include "classfile/modules.hpp" #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" #include "compiler/methodMatcher.hpp" @@ -34,6 +35,7 @@ #include "memory/metadataFactory.hpp" #include "memory/metaspaceShared.hpp" #include "memory/universe.hpp" +#include "oops/constantPool.hpp" #include "oops/oop.inline.hpp" #include "prims/wbtestmethods/parserTests.hpp" #include "prims/whitebox.hpp" @@ -643,12 +645,12 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec return (mh->queued_for_compilation() || nm != NULL); WB_END -WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jboolean, WB_ShouldPrintAssembly(JNIEnv* env, jobject o, jobject method, jint comp_level)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, JNI_FALSE); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(CompLevel_simple)); + DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, CompileBroker::compiler(comp_level)); bool result = directive->PrintAssemblyOption; DirectivesStack::release(directive); @@ -1249,6 +1251,43 @@ WB_ENTRY(void, WB_FreeMetaspace(JNIEnv* env, jobject wb, jobject class_loader, j MetadataFactory::free_array(cld, (Array*)(uintptr_t)addr); WB_END +WB_ENTRY(void, WB_DefineModule(JNIEnv* env, jobject o, jobject module, jstring version, jstring location, + jobjectArray packages)) + Modules::define_module(module, version, location, packages, CHECK); +WB_END + +WB_ENTRY(void, WB_AddModuleExports(JNIEnv* env, jobject o, jobject from_module, jstring package, jobject to_module)) + Modules::add_module_exports_qualified(from_module, package, to_module, CHECK); +WB_END + +WB_ENTRY(void, WB_AddModuleExportsToAllUnnamed(JNIEnv* env, jobject o, jclass module, jstring package)) + Modules::add_module_exports_to_all_unnamed(module, package, CHECK); +WB_END + +WB_ENTRY(void, WB_AddModuleExportsToAll(JNIEnv* env, jobject o, jclass module, jstring package)) + Modules::add_module_exports(module, package, NULL, CHECK); +WB_END + +WB_ENTRY(void, WB_AddReadsModule(JNIEnv* env, jobject o, jobject from_module, jobject source_module)) + Modules::add_reads_module(from_module, source_module, CHECK); +WB_END + +WB_ENTRY(jboolean, WB_CanReadModule(JNIEnv* env, jobject o, jobject asking_module, jobject source_module)) + return Modules::can_read_module(asking_module, source_module, THREAD); +WB_END + +WB_ENTRY(jboolean, WB_IsExportedToModule(JNIEnv* env, jobject o, jobject from_module, jstring package, jobject to_module)) + return Modules::is_exported_to_module(from_module, package, to_module, THREAD); +WB_END + +WB_ENTRY(void, WB_AddModulePackage(JNIEnv* env, jobject o, jclass module, jstring package)) + Modules::add_module_package(module, package, CHECK); +WB_END + +WB_ENTRY(jobject, WB_GetModuleByPackageName(JNIEnv* env, jobject o, jobject loader, jstring package)) + return Modules::get_module_by_package_name(loader, package, THREAD); +WB_END + WB_ENTRY(jlong, WB_IncMetaspaceCapacityUntilGC(JNIEnv* env, jobject wb, jlong inc)) if (inc < 0) { THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), @@ -1277,7 +1316,6 @@ WB_ENTRY(jlong, WB_MetaspaceCapacityUntilGC(JNIEnv* env, jobject wb)) WB_END - WB_ENTRY(void, WB_AssertMatchingSafepointCalls(JNIEnv* env, jobject o, jboolean mutexSafepointValue, jboolean attemptedNoSafepointValue)) Monitor::SafepointCheckRequired sfpt_check_required = mutexSafepointValue ? Monitor::_safepoint_check_always : @@ -1286,10 +1324,6 @@ WB_ENTRY(void, WB_AssertMatchingSafepointCalls(JNIEnv* env, jobject o, jboolean attemptedNoSafepointValue == JNI_TRUE); WB_END -WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) - return (jboolean)MetaspaceShared::is_in_shared_space(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); -WB_END - WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj)) oop obj_oop = JNIHandles::resolve(obj); return (jboolean) obj_oop->mark()->has_monitor(); @@ -1305,6 +1339,38 @@ WB_ENTRY(jlong, WB_GetConstantPool(JNIEnv* env, jobject wb, jclass klass)) return (jlong) ikh->constants(); WB_END +WB_ENTRY(jint, WB_GetConstantPoolCacheIndexTag(JNIEnv* env, jobject wb)) + return ConstantPool::CPCACHE_INDEX_TAG; +WB_END + +WB_ENTRY(jint, WB_GetConstantPoolCacheLength(JNIEnv* env, jobject wb, jclass klass)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ikh->constants(); + if (cp->cache() == NULL) { + return -1; + } + return cp->cache()->length(); +WB_END + +WB_ENTRY(jint, WB_ConstantPoolRemapInstructionOperandFromCache(JNIEnv* env, jobject wb, jclass klass, jint index)) + instanceKlassHandle ikh(java_lang_Class::as_Klass(JNIHandles::resolve(klass))); + ConstantPool* cp = ikh->constants(); + if (cp->cache() == NULL) { + THROW_MSG_0(vmSymbols::java_lang_IllegalStateException(), "Constant pool does not have a cache"); + } + jint cpci = index; + jint cpciTag = ConstantPool::CPCACHE_INDEX_TAG; + if (cpciTag > cpci || cpci >= cp->cache()->length() + cpciTag) { + THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Constant pool cache index is out of range"); + } + jint cpi = cp->remap_instruction_operand_from_cache(cpci); + return cpi; +WB_END + +WB_ENTRY(jint, WB_ConstantPoolEncodeIndyIndex(JNIEnv* env, jobject wb, jint index)) + return ConstantPool::encode_invokedynamic_index(index); +WB_END + WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb)) VM_ClearICs clear_ics; VMThread::execute(&clear_ics); @@ -1384,6 +1450,10 @@ WB_ENTRY(jboolean, WB_IsShared(JNIEnv* env, jobject wb, jobject obj)) return MetaspaceShared::is_in_shared_space((void*)obj_oop); WB_END +WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz)) + return (jboolean)MetaspaceShared::is_in_shared_space(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); +WB_END + WB_ENTRY(jboolean, WB_AreSharedStringsIgnored(JNIEnv* env)) return StringTable::shared_string_ignored(); WB_END @@ -1495,10 +1565,9 @@ static JNINativeMethod methods[] = { {CC"runMemoryUnitTests", CC"()V", (void*)&WB_RunMemoryUnitTests}, {CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea}, {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize}, - {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass }, #if INCLUDE_ALL_GCS {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, - {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z",(void*)&WB_G1IsHumongous }, + {CC"g1IsHumongous0", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, {CC"g1BelongsToHumongousRegion0", CC"(J)Z", (void*)&WB_G1BelongsToHumongousRegion}, {CC"g1BelongsToFreeRegion0", CC"(J)Z", (void*)&WB_G1BelongsToFreeRegion}, {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions }, @@ -1523,8 +1592,8 @@ static JNINativeMethod methods[] = { #endif // INCLUDE_NMT {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", - (void*)&WB_DeoptimizeMethod }, + {CC"deoptimizeMethod0", CC"(Ljava/lang/reflect/Executable;Z)I", + (void*)&WB_DeoptimizeMethod }, {CC"isMethodCompiled0", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, {CC"isMethodCompilable0", CC"(Ljava/lang/reflect/Executable;IZ)Z", @@ -1559,7 +1628,7 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)I", (void*)&WB_MatchesInline}, {CC"shouldPrintAssembly", - CC"(Ljava/lang/reflect/Executable;)Z", + CC"(Ljava/lang/reflect/Executable;I)Z", (void*)&WB_ShouldPrintAssembly}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, @@ -1616,10 +1685,34 @@ static JNINativeMethod methods[] = { {CC"getCodeBlob", CC"(J)[Ljava/lang/Object;",(void*)&WB_GetCodeBlob }, {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, + {CC"DefineModule", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V", + (void*)&WB_DefineModule }, + {CC"AddModuleExports", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)V", + (void*)&WB_AddModuleExports }, + {CC"AddReadsModule", CC"(Ljava/lang/Object;Ljava/lang/Object;)V", + (void*)&WB_AddReadsModule }, + {CC"CanReadModule", CC"(Ljava/lang/Object;Ljava/lang/Object;)Z", + (void*)&WB_CanReadModule }, + {CC"IsExportedToModule", CC"(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;)Z", + (void*)&WB_IsExportedToModule }, + {CC"AddModulePackage", CC"(Ljava/lang/Object;Ljava/lang/String;)V", + (void*)&WB_AddModulePackage }, + {CC"GetModuleByPackageName", CC"(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", + (void*)&WB_GetModuleByPackageName }, + {CC"AddModuleExportsToAllUnnamed", CC"(Ljava/lang/Object;Ljava/lang/String;)V", + (void*)&WB_AddModuleExportsToAllUnnamed }, + {CC"AddModuleExportsToAll", CC"(Ljava/lang/Object;Ljava/lang/String;)V", + (void*)&WB_AddModuleExportsToAll }, {CC"assertMatchingSafepointCalls", CC"(ZZ)V", (void*)&WB_AssertMatchingSafepointCalls }, {CC"isMonitorInflated0", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated }, {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint }, {CC"getConstantPool0", CC"(Ljava/lang/Class;)J", (void*)&WB_GetConstantPool }, + {CC"getConstantPoolCacheIndexTag0", CC"()I", (void*)&WB_GetConstantPoolCacheIndexTag}, + {CC"getConstantPoolCacheLength0", CC"(Ljava/lang/Class;)I", (void*)&WB_GetConstantPoolCacheLength}, + {CC"remapInstructionOperandFromCPCache0", + CC"(Ljava/lang/Class;I)I", (void*)&WB_ConstantPoolRemapInstructionOperandFromCache}, + {CC"encodeConstantPoolIndyIndex0", + CC"(I)I", (void*)&WB_ConstantPoolEncodeIndyIndex}, {CC"getMethodBooleanOption", CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/Boolean;", (void*)&WB_GetMethodBooleaneOption}, @@ -1636,6 +1729,7 @@ static JNINativeMethod methods[] = { CC"(Ljava/lang/reflect/Executable;Ljava/lang/String;)Ljava/lang/String;", (void*)&WB_GetMethodStringOption}, {CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared }, + {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass }, {CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored }, {CC"clearInlineCaches", CC"()V", (void*)&WB_ClearInlineCaches }, }; diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index f43a7a1372f..e6f1f20a648 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -94,6 +94,9 @@ const char* Arguments::_java_vendor_url_bug = DEFAULT_VENDOR_URL_BUG; const char* Arguments::_sun_java_launcher = DEFAULT_JAVA_LAUNCHER; int Arguments::_sun_java_launcher_pid = -1; bool Arguments::_sun_java_launcher_is_altjvm = false; +int Arguments::_patch_dirs_count = 0; +char** Arguments::_patch_dirs = NULL; +int Arguments::_bootclassloader_append_index = -1; // These parameters are reset in method parse_vm_init_args() bool Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods; @@ -117,7 +120,9 @@ SystemProperty *Arguments::_sun_boot_library_path = NULL; SystemProperty *Arguments::_java_library_path = NULL; SystemProperty *Arguments::_java_home = NULL; SystemProperty *Arguments::_java_class_path = NULL; -SystemProperty *Arguments::_sun_boot_class_path = NULL; +SystemProperty *Arguments::_jdk_boot_class_path_append = NULL; + +PathString *Arguments::_system_boot_class_path = NULL; char* Arguments::_ext_dirs = NULL; @@ -195,6 +200,12 @@ void Arguments::process_sun_java_launcher_properties(JavaVMInitArgs* args) { // Initialize system properties key and value. void Arguments::init_system_properties() { + + // Set up _system_boot_class_path which is not a property but + // relies heavily on argument processing and the jdk.boot.class.path.append + // property. It is used to store the underlying system boot class path. + _system_boot_class_path = new PathString(NULL); + PropertyList_add(&_system_properties, new SystemProperty("java.vm.specification.name", "Java Virtual Machine Specification", false)); PropertyList_add(&_system_properties, new SystemProperty("java.vm.version", VM_Version::vm_release(), false)); @@ -208,16 +219,19 @@ void Arguments::init_system_properties() { _sun_boot_library_path = new SystemProperty("sun.boot.library.path", NULL, true); _java_library_path = new SystemProperty("java.library.path", NULL, true); _java_home = new SystemProperty("java.home", NULL, true); - _sun_boot_class_path = new SystemProperty("sun.boot.class.path", NULL, true); - _java_class_path = new SystemProperty("java.class.path", "", true); + // jdk.boot.class.path.append is a non-writeable, internal property. + // It can only be set by either: + // - -Xbootclasspath/a: + // - AddToBootstrapClassLoaderSearch during JVMTI OnLoad phase + _jdk_boot_class_path_append = new SystemProperty("jdk.boot.class.path.append", "", false, true); // Add to System Property list. PropertyList_add(&_system_properties, _sun_boot_library_path); PropertyList_add(&_system_properties, _java_library_path); PropertyList_add(&_system_properties, _java_home); PropertyList_add(&_system_properties, _java_class_path); - PropertyList_add(&_system_properties, _sun_boot_class_path); + PropertyList_add(&_system_properties, _jdk_boot_class_path_append); // Set OS specific system properties values os::init_system_properties_values(); @@ -372,6 +386,7 @@ static SpecialFlag const special_jvm_flags[] = { { "PreInflateSpin", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "JNIDetachReleasesMonitors", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, { "UseAltSigs", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, + { "SegmentedHeapDumpThreshold", JDK_Version::undefined(), JDK_Version::jdk(9), JDK_Version::jdk(10) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS { "dep > obs", JDK_Version::jdk(9), JDK_Version::jdk(8), JDK_Version::undefined() }, @@ -405,8 +420,9 @@ static AliasedFlag const aliased_jvm_flags[] = { static AliasedLoggingFlag const aliased_logging_flags[] = { { "TraceClassLoading", LogLevel::Info, true, LogTag::_classload }, - { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, + { "TraceClassPaths", LogLevel::Info, true, LogTag::_classpath }, { "TraceClassResolution", LogLevel::Info, true, LogTag::_classresolve }, + { "TraceClassUnloading", LogLevel::Info, true, LogTag::_classunload }, { "TraceExceptions", LogLevel::Info, true, LogTag::_exceptions }, { "TraceMonitorInflation", LogLevel::Debug, true, LogTag::_monitorinflation }, { "TraceBiasedLocking", LogLevel::Info, true, LogTag::_biasedlocking }, @@ -540,19 +556,19 @@ static bool verify_special_jvm_flags() { } #endif -// Constructs the system class path (aka boot class path) from the following -// components, in order: +// Constructs the system boot class path from the following components, in order: // -// prefix // from -Xbootclasspath/p:... -// base // from os::get_system_properties() or -Xbootclasspath= +// prefix // from -Xpatch:... +// base // from os::get_system_properties() // suffix // from -Xbootclasspath/a:... // // This could be AllStatic, but it isn't needed after argument processing is -// complete. -class SysClassPath: public StackObj { +// complete. After argument processing, the combined components are copied +// to Arguments::_system_boot_class_path via a call to Arguments::set_sysclasspath. +class ArgumentBootClassPath: public StackObj { public: - SysClassPath(const char* base); - ~SysClassPath(); + ArgumentBootClassPath(const char* base); + ~ArgumentBootClassPath(); inline void set_base(const char* base); inline void add_prefix(const char* prefix); @@ -560,9 +576,9 @@ public: inline void add_suffix(const char* suffix); inline void reset_path(const char* base); - inline const char* get_base() const { return _items[_scp_base]; } - inline const char* get_prefix() const { return _items[_scp_prefix]; } - inline const char* get_suffix() const { return _items[_scp_suffix]; } + inline const char* get_base() const { return _items[_bcp_base]; } + inline const char* get_prefix() const { return _items[_bcp_prefix]; } + inline const char* get_suffix() const { return _items[_bcp_suffix]; } // Combine all the components into a single c-heap-allocated string; caller // must free the string if/when no longer needed. @@ -578,55 +594,55 @@ private: // Array indices for the items that make up the sysclasspath. All except the // base are allocated in the C heap and freed by this class. enum { - _scp_prefix, // from -Xbootclasspath/p:... - _scp_base, // the default sysclasspath - _scp_suffix, // from -Xbootclasspath/a:... - _scp_nitems // the number of items, must be last. + _bcp_prefix, // was -Xpatch:... + _bcp_base, // the default system boot class path + _bcp_suffix, // from -Xbootclasspath/a:... + _bcp_nitems // the number of items, must be last. }; - const char* _items[_scp_nitems]; + const char* _items[_bcp_nitems]; }; -SysClassPath::SysClassPath(const char* base) { +ArgumentBootClassPath::ArgumentBootClassPath(const char* base) { memset(_items, 0, sizeof(_items)); - _items[_scp_base] = base; + _items[_bcp_base] = base; } -SysClassPath::~SysClassPath() { +ArgumentBootClassPath::~ArgumentBootClassPath() { // Free everything except the base. - for (int i = 0; i < _scp_nitems; ++i) { - if (i != _scp_base) reset_item_at(i); + for (int i = 0; i < _bcp_nitems; ++i) { + if (i != _bcp_base) reset_item_at(i); } } -inline void SysClassPath::set_base(const char* base) { - _items[_scp_base] = base; +inline void ArgumentBootClassPath::set_base(const char* base) { + _items[_bcp_base] = base; } -inline void SysClassPath::add_prefix(const char* prefix) { - _items[_scp_prefix] = add_to_path(_items[_scp_prefix], prefix, true); +inline void ArgumentBootClassPath::add_prefix(const char* prefix) { + _items[_bcp_prefix] = add_to_path(_items[_bcp_prefix], prefix, true); } -inline void SysClassPath::add_suffix_to_prefix(const char* suffix) { - _items[_scp_prefix] = add_to_path(_items[_scp_prefix], suffix, false); +inline void ArgumentBootClassPath::add_suffix_to_prefix(const char* suffix) { + _items[_bcp_prefix] = add_to_path(_items[_bcp_prefix], suffix, false); } -inline void SysClassPath::add_suffix(const char* suffix) { - _items[_scp_suffix] = add_to_path(_items[_scp_suffix], suffix, false); +inline void ArgumentBootClassPath::add_suffix(const char* suffix) { + _items[_bcp_suffix] = add_to_path(_items[_bcp_suffix], suffix, false); } -inline void SysClassPath::reset_item_at(int index) { - assert(index < _scp_nitems && index != _scp_base, "just checking"); +inline void ArgumentBootClassPath::reset_item_at(int index) { + assert(index < _bcp_nitems && index != _bcp_base, "just checking"); if (_items[index] != NULL) { FREE_C_HEAP_ARRAY(char, _items[index]); _items[index] = NULL; } } -inline void SysClassPath::reset_path(const char* base) { +inline void ArgumentBootClassPath::reset_path(const char* base) { // Clear the prefix and suffix. - reset_item_at(_scp_prefix); - reset_item_at(_scp_suffix); + reset_item_at(_bcp_prefix); + reset_item_at(_bcp_suffix); set_base(base); } @@ -635,17 +651,21 @@ inline void SysClassPath::reset_path(const char* base) { // Combine the bootclasspath elements, some of which may be null, into a single // c-heap-allocated string. -char* SysClassPath::combined_path() { - assert(_items[_scp_base] != NULL, "empty default sysclasspath"); +char* ArgumentBootClassPath::combined_path() { + assert(_items[_bcp_base] != NULL, "empty default sysclasspath"); - size_t lengths[_scp_nitems]; + size_t lengths[_bcp_nitems]; size_t total_len = 0; const char separator = *os::path_separator(); // Get the lengths. int i; - for (i = 0; i < _scp_nitems; ++i) { + for (i = 0; i < _bcp_nitems; ++i) { + if (i == _bcp_suffix) { + // Record index of boot loader's append path. + Arguments::set_bootclassloader_append_index((int)total_len); + } if (_items[i] != NULL) { lengths[i] = strlen(_items[i]); // Include space for the separator char (or a NULL for the last item). @@ -657,7 +677,7 @@ char* SysClassPath::combined_path() { // Copy the _items to a single string. char* cp = NEW_C_HEAP_ARRAY(char, total_len, mtInternal); char* cp_tmp = cp; - for (i = 0; i < _scp_nitems; ++i) { + for (i = 0; i < _bcp_nitems; ++i) { if (_items[i] != NULL) { memcpy(cp_tmp, _items[i], lengths[i]); cp_tmp += lengths[i]; @@ -670,7 +690,7 @@ char* SysClassPath::combined_path() { // Note: path must be c-heap-allocated (or NULL); it is freed if non-null. char* -SysClassPath::add_to_path(const char* path, const char* str, bool prepend) { +ArgumentBootClassPath::add_to_path(const char* path, const char* str, bool prepend) { char *cp; assert(str != NULL, "just checking"); @@ -704,7 +724,7 @@ SysClassPath::add_to_path(const char* path, const char* str, bool prepend) { // Scan the directory and append any jar or zip files found to path. // Note: path must be c-heap-allocated (or NULL); it is freed if non-null. -char* SysClassPath::add_jars_to_path(char* path, const char* directory) { +char* ArgumentBootClassPath::add_jars_to_path(char* path, const char* directory) { DIR* dir = os::opendir(directory); if (dir == NULL) return path; @@ -1373,6 +1393,54 @@ bool Arguments::add_property(const char* prop) { return true; } +// sets or adds a module name to the jdk.launcher.addmods property +bool Arguments::append_to_addmods_property(const char* module_name) { + const char* key = "jdk.launcher.addmods"; + const char* old_value = Arguments::get_property(key); + size_t buf_len = strlen(key) + strlen(module_name) + 2; + if (old_value != NULL) { + buf_len += strlen(old_value) + 1; + } + char* new_value = AllocateHeap(buf_len, mtInternal); + if (new_value == NULL) { + return false; + } + if (old_value == NULL) { + jio_snprintf(new_value, buf_len, "%s=%s", key, module_name); + } else { + jio_snprintf(new_value, buf_len, "%s=%s,%s", key, old_value, module_name); + } + bool added = add_property(new_value); + FreeHeap(new_value); + return added; +} + +#if INCLUDE_CDS +void Arguments::check_unsupported_dumping_properties() { + assert(DumpSharedSpaces, "this function is only used with -Xshare:dump"); + const char* unsupported_properties[5] = { "jdk.module.main", + "jdk.module.path", + "jdk.upgrade.module.path", + "jdk.launcher.addmods", + "jdk.launcher.limitmods" }; + const char* unsupported_options[5] = { "-m", + "-modulepath", + "-upgrademodulepath", + "-addmods", + "-limitmods" }; + SystemProperty* sp = system_properties(); + while (sp != NULL) { + for (int i = 0; i < 5; i++) { + if (strcmp(sp->key(), unsupported_properties[i]) == 0) { + vm_exit_during_initialization( + "Cannot use the following option when dumping the shared archive", unsupported_options[i]); + } + } + sp = sp->next(); + } +} +#endif + //=========================================================================================================== // Setting int/mixed/comp mode flags @@ -2315,6 +2383,17 @@ bool Arguments::sun_java_launcher_is_altjvm() { //=========================================================================================================== // Parsing of main arguments +#if INCLUDE_JVMCI +// Check consistency of jvmci vm argument settings. +bool Arguments::check_jvmci_args_consistency() { + if (!EnableJVMCI && !JVMCIGlobals::check_jvmci_flags_are_consistent()) { + JVMCIGlobals::print_jvmci_args_inconsistency_error_message(); + return false; + } + return true; +} +#endif //INCLUDE_JVMCI + // Check consistency of GC selection bool Arguments::check_gc_consistency() { // Ensure that the user has not selected conflicting sets @@ -2411,6 +2490,9 @@ bool Arguments::check_vm_args_consistency() { #endif } #if INCLUDE_JVMCI + + status = status && check_jvmci_args_consistency(); + if (EnableJVMCI) { if (!ScavengeRootsInCode) { warning("forcing ScavengeRootsInCode non-zero because JVMCI is enabled"); @@ -2537,8 +2619,8 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args) { // For components of the system classpath. - SysClassPath scp(Arguments::get_sysclasspath()); - bool scp_assembly_required = false; + ArgumentBootClassPath bcp(Arguments::get_sysclasspath()); + bool bcp_assembly_required = false; // Save default settings for some mode flags Arguments::_AlwaysCompileLoopMethods = AlwaysCompileLoopMethods; @@ -2556,13 +2638,13 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, // Parse args structure generated from JAVA_TOOL_OPTIONS environment // variable (if present). jint result = parse_each_vm_init_arg( - java_tool_options_args, &scp, &scp_assembly_required, Flag::ENVIRON_VAR); + java_tool_options_args, &bcp, &bcp_assembly_required, Flag::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Parse args structure generated from the command line flags. - result = parse_each_vm_init_arg(cmd_line_args, &scp, &scp_assembly_required, + result = parse_each_vm_init_arg(cmd_line_args, &bcp, &bcp_assembly_required, Flag::COMMAND_LINE); if (result != JNI_OK) { return result; @@ -2571,13 +2653,13 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, // Parse args structure generated from the _JAVA_OPTIONS environment // variable (if present) (mimics classic VM) result = parse_each_vm_init_arg( - java_options_args, &scp, &scp_assembly_required, Flag::ENVIRON_VAR); + java_options_args, &bcp, &bcp_assembly_required, Flag::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Do final processing now that all arguments have been parsed - result = finalize_vm_init_args(&scp, scp_assembly_required); + result = finalize_vm_init_args(&bcp, bcp_assembly_required); if (result != JNI_OK) { return result; } @@ -2631,8 +2713,8 @@ bool valid_jdwp_agent(char *name, bool is_path) { } jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, - SysClassPath* scp_p, - bool* scp_assembly_required_p, + ArgumentBootClassPath* bcp_p, + bool* bcp_assembly_required_p, Flag::Flags origin) { // For match_option to return remaining or value part of option string const char* tail; @@ -2684,16 +2766,18 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JavaAssertions::setSystemClassDefault(enable); // -bootclasspath: } else if (match_option(option, "-Xbootclasspath:", &tail)) { - scp_p->reset_path(tail); - *scp_assembly_required_p = true; + jio_fprintf(defaultStream::output_stream(), + "-Xbootclasspath is no longer a supported option.\n"); + return JNI_EINVAL; // -bootclasspath/a: } else if (match_option(option, "-Xbootclasspath/a:", &tail)) { - scp_p->add_suffix(tail); - *scp_assembly_required_p = true; + bcp_p->add_suffix(tail); + *bcp_assembly_required_p = true; // -bootclasspath/p: } else if (match_option(option, "-Xbootclasspath/p:", &tail)) { - scp_p->add_prefix(tail); - *scp_assembly_required_p = true; + jio_fprintf(defaultStream::output_stream(), + "-Xbootclasspath/p is no longer a supported option.\n"); + return JNI_EINVAL; // -Xrun } else if (match_option(option, "-Xrun", &tail)) { if (tail != NULL) { @@ -2745,9 +2829,14 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, "Instrumentation agents are not supported in this VM\n"); return JNI_ERR; #else - if(tail != NULL) { + if (tail != NULL) { char *options = strcpy(NEW_C_HEAP_ARRAY(char, strlen(tail) + 1, mtInternal), tail); add_init_agent("instrument", options, false); + // java agents need module java.instrument. Also -addmods ALL-SYSTEM because + // the java agent is in the unmamed module of the application class loader + if (!Arguments::append_to_addmods_property("java.instrument,ALL-SYSTEM")) { + return JNI_ENOMEM; + } } #endif // !INCLUDE_JVMTI // -Xnoclassgc @@ -3013,12 +3102,50 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, ManagementServer, true) != Flag::SUCCESS) { return JNI_EINVAL; } + // management agent in module java.management + if (!Arguments::append_to_addmods_property("java.management")) { + return JNI_ENOMEM; + } #else jio_fprintf(defaultStream::output_stream(), "-Dcom.sun.management is not supported in this VM.\n"); return JNI_ERR; #endif } + if (match_option(option, "-Djdk.launcher.patch.0=", &tail)) { + // -Xpatch + int dir_count; + char** patch_dirs = os::split_path(tail, &dir_count); + if (patch_dirs == NULL) { + jio_fprintf(defaultStream::output_stream(), + "Bad value for -Xpatch.\n"); + return JNI_ERR; + } + set_patch_dirs(patch_dirs); + set_patch_dirs_count(dir_count); + + // Create a path for each patch dir consisting of dir/java.base. + char file_sep = os::file_separator()[0]; + for (int x = 0; x < dir_count; x++) { + // Really shouldn't be NULL, but check can't hurt + if (patch_dirs[x] != NULL) { + size_t len = strlen(patch_dirs[x]); + if (len != 0) { // Ignore empty strings. + len += 11; // file_sep + "java.base" + null terminator. + char* dir = NEW_C_HEAP_ARRAY(char, len, mtInternal); + jio_snprintf(dir, len, "%s%cjava.base", patch_dirs[x], file_sep); + + // See if Xpatch module path exists. + struct stat st; + if ((os::stat(dir, &st) == 0)) { + bcp_p->add_prefix(dir); + *bcp_assembly_required_p = true; + } + FREE_C_HEAP_ARRAY(char, dir); + } + } + } + } // -Xint } else if (match_option(option, "-Xint")) { set_mode_flags(_int); @@ -3255,7 +3382,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, // PrintSharedArchiveAndExit will turn on // -Xshare:on - // -XX:+TraceClassPaths + // -Xlog:classpath=info if (PrintSharedArchiveAndExit) { if (FLAG_SET_CMDLINE(bool, UseSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; @@ -3263,9 +3390,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, if (FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true) != Flag::SUCCESS) { return JNI_EINVAL; } - if (FLAG_SET_CMDLINE(bool, TraceClassPaths, true) != Flag::SUCCESS) { - return JNI_EINVAL; - } + LogConfiguration::configure_stdout(LogLevel::Info, true, LOG_TAGS(classpath)); } // Change the default value for flags which have different default values @@ -3280,6 +3405,18 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, return JNI_OK; } +// Set property jdk.boot.class.path.append to the contents of the bootclasspath +// that follows either the jimage file or exploded module directories. The +// property will contain -Xbootclasspath/a and/or jvmti appended additions. +void Arguments::set_jdkbootclasspath_append() { + char *sysclasspath = get_sysclasspath(); + assert(sysclasspath != NULL, "NULL sysclasspath"); + int bcp_a_idx = bootclassloader_append_index(); + if (bcp_a_idx != -1 && bcp_a_idx < (int)strlen(sysclasspath)) { + _jdk_boot_class_path_append->set_value(sysclasspath + bcp_a_idx); + } +} + // Remove all empty paths from the app classpath (if IgnoreEmptyClassPaths is enabled) // // This is necessary because some apps like to specify classpath like -cp foo.jar:${XYZ}:bar.jar @@ -3315,13 +3452,9 @@ void Arguments::fix_appclasspath() { // Keep replacing ";;" -> ";" until we have no more ";;" (windows) } - _java_class_path->set_value(copy); + _java_class_path->set_writeable_value(copy); FreeHeap(copy); // a copy was made by set_value, so don't need this anymore } - - if (!PrintSharedArchiveAndExit) { - ClassLoader::trace_class_path(tty, "[classpath: ", _java_class_path->value()); - } } static bool has_jar_files(const char* directory) { @@ -3370,7 +3503,7 @@ static int check_non_empty_dirs(const char* path) { return nonEmptyDirs; } -jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required) { +jint Arguments::finalize_vm_init_args(ArgumentBootClassPath* bcp_p, bool bcp_assembly_required) { // check if the default lib/endorsed directory exists; if so, error char path[JVM_MAXPATHLEN]; const char* fileSep = os::file_separator(); @@ -3406,11 +3539,16 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req return JNI_ERR; } - if (scp_assembly_required) { + if (bcp_assembly_required) { // Assemble the bootclasspath elements into the final path. - char *combined_path = scp_p->combined_path(); + char *combined_path = bcp_p->combined_path(); Arguments::set_sysclasspath(combined_path); FREE_C_HEAP_ARRAY(char, combined_path); + } else { + // At this point in sysclasspath processing anything + // added would be considered in the boot loader's append path. + // Record this index, including +1 for the file separator character. + Arguments::set_bootclassloader_append_index(((int)strlen(Arguments::get_sysclasspath()))+1); } // This must be done after all arguments have been processed. @@ -3756,6 +3894,11 @@ jint Arguments::parse_options_buffer(const char* name, char* buffer, const size_ void Arguments::set_shared_spaces_flags() { if (DumpSharedSpaces) { + if (Arguments::patch_dirs() != NULL) { + vm_exit_during_initialization( + "Cannot use the following option when dumping the shared archive", "-Xpatch"); + } + if (RequireSharedSpaces) { warning("Cannot dump shared archive while using shared archive"); } @@ -4445,7 +4588,7 @@ void Arguments::PropertyList_unique_add(SystemProperty** plist, const char* k, c if (append) { prop->append_value(v); } else { - prop->set_value(v); + prop->set_writeable_value(v); } return; } diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index e7ce4f30cab..67a9661b8ae 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -43,37 +43,30 @@ extern "C" { } // Forward declarations +class ArgumentBootClassPath; -class SysClassPath; - -// Element describing System and User (-Dkey=value flags) defined property. - -class SystemProperty: public CHeapObj { - private: - char* _key; +// PathString is used as the underlying value container for a +// SystemProperty and for the string that represents the system +// boot class path, Arguments::_system_boot_class_path. +class PathString : public CHeapObj { + protected: char* _value; - SystemProperty* _next; - bool _writeable; - bool writeable() { return _writeable; } - public: - // Accessors - const char* key() const { return _key; } char* value() const { return _value; } - SystemProperty* next() const { return _next; } - void set_next(SystemProperty* next) { _next = next; } + bool set_value(const char *value) { - if (writeable()) { - if (_value != NULL) { - FreeHeap(_value); - } - _value = AllocateHeap(strlen(value)+1, mtInternal); - if (_value != NULL) { - strcpy(_value, value); - } - return true; + if (_value != NULL) { + FreeHeap(_value); } - return false; + _value = AllocateHeap(strlen(value)+1, mtInternal); + assert(_value != NULL, "Unable to allocate space for new path value"); + if (_value != NULL) { + strcpy(_value, value); + } else { + // not able to allocate + return false; + } + return true; } void append_value(const char *value) { @@ -85,6 +78,7 @@ class SystemProperty: public CHeapObj { len += strlen(_value); } sp = AllocateHeap(len+2, mtInternal); + assert(sp != NULL, "Unable to allocate space for new append path value"); if (sp != NULL) { if (_value != NULL) { strcpy(sp, _value); @@ -100,20 +94,61 @@ class SystemProperty: public CHeapObj { } // Constructor - SystemProperty(const char* key, const char* value, bool writeable) { - if (key == NULL) { - _key = NULL; - } else { - _key = AllocateHeap(strlen(key)+1, mtInternal); - strcpy(_key, key); - } + PathString(const char* value) { if (value == NULL) { _value = NULL; } else { _value = AllocateHeap(strlen(value)+1, mtInternal); strcpy(_value, value); } + } +}; + +// Element describing System and User (-Dkey=value flags) defined property. +// +// An internal SystemProperty is one that has been removed in +// jdk.internal.VM.saveAndRemoveProperties, like jdk.boot.class.path.append. +// +class SystemProperty : public PathString { + private: + char* _key; + SystemProperty* _next; + bool _internal; + bool _writeable; + bool writeable() { return _writeable; } + + public: + // Accessors + char* value() const { return PathString::value(); } + const char* key() const { return _key; } + bool internal() const { return _internal; } + SystemProperty* next() const { return _next; } + void set_next(SystemProperty* next) { _next = next; } + + // A system property should only have its value set + // via an external interface if it is a writeable property. + // The internal, non-writeable property jdk.boot.class.path.append + // is the only exception to this rule. It can be set externally + // via -Xbootclasspath/a or JVMTI OnLoad phase call to AddToBootstrapClassLoaderSearch. + // In those cases for jdk.boot.class.path.append, the base class + // set_value and append_value methods are called directly. + bool set_writeable_value(const char *value) { + if (writeable()) { + return set_value(value); + } + return false; + } + + // Constructor + SystemProperty(const char* key, const char* value, bool writeable, bool internal = false) : PathString(value) { + if (key == NULL) { + _key = NULL; + } else { + _key = AllocateHeap(strlen(key)+1, mtInternal); + strcpy(_key, key); + } _next = NULL; + _internal = internal; _writeable = writeable; } }; @@ -273,7 +308,13 @@ class Arguments : AllStatic { static SystemProperty *_java_library_path; static SystemProperty *_java_home; static SystemProperty *_java_class_path; - static SystemProperty *_sun_boot_class_path; + static SystemProperty *_jdk_boot_class_path_append; + + // The constructed value of the system class path after + // argument processing and JVMTI OnLoad additions via + // calls to AddToBootstrapClassLoaderSearch. This is the + // final form before ClassLoader::setup_bootstrap_search(). + static PathString *_system_boot_class_path; // temporary: to emit warning if the default ext dirs are not empty. // remove this variable when the warning is no longer needed. @@ -298,7 +339,7 @@ class Arguments : AllStatic { // Value of the conservative maximum heap alignment needed static size_t _conservative_max_heap_alignment; - static uintx _min_heap_size; + static uintx _min_heap_size; // -Xrun arguments static AgentLibraryList _libraryList; @@ -323,6 +364,17 @@ class Arguments : AllStatic { static void set_java_compiler(bool arg) { _java_compiler = arg; } static bool java_compiler() { return _java_compiler; } + // Capture the index location of -Xbootclasspath\a within sysclasspath. + // Used when setting up the bootstrap search path in order to + // mark the boot loader's append path observability boundary. + static int _bootclassloader_append_index; + + // -Xpatch flag + static char** _patch_dirs; + static int _patch_dirs_count; + static void set_patch_dirs(char** dirs) { _patch_dirs = dirs; } + static void set_patch_dirs_count(int count) { _patch_dirs_count = count; } + // -Xdebug flag static bool _xdebug_mode; static void set_xdebug_mode(bool arg) { _xdebug_mode = arg; } @@ -373,6 +425,9 @@ class Arguments : AllStatic { // System properties static bool add_property(const char* prop); + // Miscellaneous system property setter + static bool append_to_addmods_property(const char* module_name); + // Aggressive optimization flags. static jint set_aggressive_opts_flags(); @@ -406,8 +461,8 @@ class Arguments : AllStatic { static jint parse_vm_init_args(const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, SysClassPath* scp_p, bool* scp_assembly_required_p, Flag::Flags origin); - static jint finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, ArgumentBootClassPath* bcp_p, bool* bcp_assembly_required_p, Flag::Flags origin); + static jint finalize_vm_init_args(ArgumentBootClassPath* bcp_p, bool bcp_assembly_required); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); static bool is_bad_option(const JavaVMOption* option, jboolean ignore) { @@ -505,7 +560,10 @@ class Arguments : AllStatic { static void set_gc_specific_flags(); static inline bool gc_selected(); // whether a gc has been selected static void select_gc_ergonomically(); - +#if INCLUDE_JVMCI + // Check consistency of jvmci vm argument settings. + static bool check_jvmci_args_consistency(); +#endif // Check for consistency in the selection of the garbage collector. static bool check_gc_consistency(); // Check user-selected gc // Check consistency or otherwise of VM argument settings @@ -566,6 +624,18 @@ class Arguments : AllStatic { static size_t min_heap_size() { return _min_heap_size; } static void set_min_heap_size(size_t v) { _min_heap_size = v; } + // -Xbootclasspath/a + static int bootclassloader_append_index() { + return _bootclassloader_append_index; + } + static void set_bootclassloader_append_index(int value) { + _bootclassloader_append_index = value; + } + + // -Xpatch + static char** patch_dirs() { return _patch_dirs; } + static int patch_dirs_count() { return _patch_dirs_count; } + // -Xrun static AgentLibrary* libraries() { return _libraryList.first(); } static bool init_libraries_at_startup() { return !_libraryList.is_empty(); } @@ -622,24 +692,35 @@ class Arguments : AllStatic { static void set_java_home(const char *value) { _java_home->set_value(value); } static void set_library_path(const char *value) { _java_library_path->set_value(value); } static void set_ext_dirs(char *value) { _ext_dirs = os::strdup_check_oom(value); } - static void set_sysclasspath(const char *value) { _sun_boot_class_path->set_value(value); } - static void append_sysclasspath(const char *value) { _sun_boot_class_path->append_value(value); } + + // Set up of the underlying system boot class path + static void set_jdkbootclasspath_append(); + static void set_sysclasspath(const char *value) { + _system_boot_class_path->set_value(value); + set_jdkbootclasspath_append(); + } + static void append_sysclasspath(const char *value) { + _system_boot_class_path->append_value(value); + set_jdkbootclasspath_append(); + } static char* get_java_home() { return _java_home->value(); } static char* get_dll_dir() { return _sun_boot_library_path->value(); } - static char* get_sysclasspath() { return _sun_boot_class_path->value(); } + static char* get_sysclasspath() { return _system_boot_class_path->value(); } static char* get_ext_dirs() { return _ext_dirs; } static char* get_appclasspath() { return _java_class_path->value(); } static void fix_appclasspath(); // Operation modi - static Mode mode() { return _mode; } + static Mode mode() { return _mode; } static bool is_interpreter_only() { return mode() == _int; } // Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid. static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen); + + static void check_unsupported_dumping_properties() NOT_CDS_RETURN; }; bool Arguments::gc_selected() { diff --git a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp index 60cf0daecc1..2f96660c260 100644 --- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp +++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp @@ -33,9 +33,6 @@ #include "runtime/commandLineFlagConstraintsRuntime.hpp" #include "runtime/os.hpp" #include "utilities/macros.hpp" -#if INCLUDE_JVMCI -#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" -#endif class CommandLineFlagConstraint_bool : public CommandLineFlagConstraint { CommandLineFlagConstraintFunc_bool _constraint; @@ -254,17 +251,6 @@ void CommandLineFlagConstraintList::init(void) { IGNORE_RANGE, EMIT_CONSTRAINT_CHECK)); -#if INCLUDE_JVMCI - emit_constraint_no(NULL JVMCI_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, - EMIT_CONSTRAINT_PD_DEVELOPER_FLAG, - EMIT_CONSTRAINT_PRODUCT_FLAG, - EMIT_CONSTRAINT_PD_PRODUCT_FLAG, - EMIT_CONSTRAINT_DIAGNOSTIC_FLAG, - EMIT_CONSTRAINT_EXPERIMENTAL_FLAG, - EMIT_CONSTRAINT_NOTPRODUCT_FLAG, - IGNORE_RANGE, - EMIT_CONSTRAINT_CHECK)); -#endif // INCLUDE_JVMCI #ifdef COMPILER1 emit_constraint_no(NULL C1_FLAGS(EMIT_CONSTRAINT_DEVELOPER_FLAG, diff --git a/hotspot/src/share/vm/runtime/fprofiler.cpp b/hotspot/src/share/vm/runtime/fprofiler.cpp index fbc51b4047d..fc687618e03 100644 --- a/hotspot/src/share/vm/runtime/fprofiler.cpp +++ b/hotspot/src/share/vm/runtime/fprofiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -836,8 +836,7 @@ void FlatProfiler::record_vm_tick() { vm_thread_profiler->inc_thread_ticks(); // Get a snapshot of a current VMThread pc (and leave it running!) - // The call may fail if, for instance the VM thread is interrupted while - // holding the Interrupt_lock or for other reasons. + // The call may fail in some circumstances epc = os::get_thread_pc(VMThread::vm_thread()); if(epc.pc() != NULL) { if (os::dll_address_to_function_name(epc.pc(), buf, sizeof(buf), NULL)) { diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 3abf884cfbb..b2a321687b7 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -642,6 +642,13 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose m->name_and_sig_as_C_string(buf, buflen); st->print("j %s", buf); st->print("+%d", this->interpreter_frame_bci()); + ModuleEntry* module = m->method_holder()->module(); + if (module->is_named()) { + module->name()->as_C_string(buf, buflen); + st->print(" %s", buf); + module->version()->as_C_string(buf, buflen); + st->print("@%s", buf); + } } else { st->print("j " PTR_FORMAT, p2i(pc())); } @@ -662,14 +669,21 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print("J %d%s %s ", nm->compile_id(), (nm->is_osr_method() ? "%" : ""), ((nm->compiler() != NULL) ? nm->compiler()->name() : "")); + ModuleEntry* module = m->method_holder()->module(); + if (module->is_named()) { + module->name()->as_C_string(buf, buflen); + st->print(" %s", buf); + module->version()->as_C_string(buf, buflen); + st->print("@%s", buf); + } + st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", + buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); #if INCLUDE_JVMCI char* jvmciName = nm->jvmci_installed_code_name(buf, buflen); if (jvmciName != NULL) { st->print(" (%s)", jvmciName); } #endif - st->print("%s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", - buf, m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); } else { st->print("J " PTR_FORMAT, p2i(pc())); } diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index ce36ff1db49..28ecd890b5e 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1055,10 +1055,6 @@ public: "directory) of the dump file (defaults to java_pid.hprof " \ "in the working directory)") \ \ - develop(size_t, SegmentedHeapDumpThreshold, 2*G, \ - "Generate a segmented heap dump (JAVA PROFILE 1.0.2 format) " \ - "when the heap usage is larger than this") \ - \ develop(size_t, HeapDumpSegmentSize, 1*G, \ "Approximate segment size when generating a segmented heap dump") \ \ @@ -1437,9 +1433,6 @@ public: product(bool, VerifyMergedCPBytecodes, true, \ "Verify bytecodes after RedefineClasses constant pool merging") \ \ - develop(bool, TraceJNIHandleAllocation, false, \ - "Trace allocation/deallocation of JNI handle blocks") \ - \ develop(bool, TraceBytecodes, false, \ "Trace bytecode execution") \ \ @@ -1482,9 +1475,6 @@ public: develop(bool, TraceCompiledIC, false, \ "Trace changes of compiled IC") \ \ - develop(bool, TraceProtectionDomainVerification, false, \ - "Trace protection domain verification") \ - \ develop(bool, TraceClearedExceptions, false, \ "Print when an exception is forcibly cleared") \ \ @@ -2403,9 +2393,6 @@ public: product(bool, IgnoreEmptyClassPaths, false, \ "Ignore empty path elements in -classpath") \ \ - product(bool, TraceClassPaths, false, \ - "Trace processing of class paths") \ - \ product(bool, TraceClassLoadingPreorder, false, \ "Trace all classes loaded in order referenced (not loaded)") \ \ diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp index 84235d8803f..a30acc9a9bd 100644 --- a/hotspot/src/share/vm/runtime/java.cpp +++ b/hotspot/src/share/vm/runtime/java.cpp @@ -64,6 +64,7 @@ #include "runtime/timer.hpp" #include "runtime/vm_operations.hpp" #include "services/memTracker.hpp" +#include "trace/traceMacros.hpp" #include "trace/tracing.hpp" #include "utilities/dtrace.hpp" #include "utilities/globalDefinitions.hpp" @@ -485,7 +486,7 @@ void before_exit(JavaThread* thread) { EventThreadEnd event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(thread->threadObj())); + event.set_thread(THREAD_TRACE_ID(thread)); event.commit(); } diff --git a/hotspot/src/share/vm/runtime/jniHandles.cpp b/hotspot/src/share/vm/runtime/jniHandles.cpp index 3c4baed8e0e..3d44d322a4c 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.cpp +++ b/hotspot/src/share/vm/runtime/jniHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -278,10 +278,6 @@ JNIHandleBlock* JNIHandleBlock::allocate_block(Thread* thread) { // Allocate new block block = new JNIHandleBlock(); _blocks_allocated++; - if (TraceJNIHandleAllocation) { - tty->print_cr("JNIHandleBlock " INTPTR_FORMAT " allocated (%d total blocks)", - p2i(block), _blocks_allocated); - } if (ZapJNIHandleArea) block->zap(); #ifndef PRODUCT // Link new block to list of all allocated blocks @@ -471,6 +467,14 @@ jobject JNIHandleBlock::allocate_handle(oop obj) { return allocate_handle(obj); // retry } +void JNIHandleBlock::release_handle(jobject h) { + if (h != NULL) { + assert(chain_contains(h), "does not contain the JNI handle"); + // Mark the handle as deleted, allocate will reuse it + *((oop*)h) = JNIHandles::deleted_handle(); + } +} + void JNIHandleBlock::rebuild_free_list() { assert(_allocate_before_rebuild == 0 && _free_list == NULL, "just checking"); @@ -499,10 +503,6 @@ void JNIHandleBlock::rebuild_free_list() { // Not as many free handles as we would like - compute number of new blocks to append _allocate_before_rebuild = (extra + block_size_in_oops - 1) / block_size_in_oops; } - if (TraceJNIHandleAllocation) { - tty->print_cr("Rebuild free list JNIHandleBlock " INTPTR_FORMAT " blocks=%d used=%d free=%d add=%d", - p2i(this), blocks, total-free, free, _allocate_before_rebuild); - } } diff --git a/hotspot/src/share/vm/runtime/jniHandles.hpp b/hotspot/src/share/vm/runtime/jniHandles.hpp index 069a1f35cfa..7a39655bfae 100644 --- a/hotspot/src/share/vm/runtime/jniHandles.hpp +++ b/hotspot/src/share/vm/runtime/jniHandles.hpp @@ -138,6 +138,9 @@ class JNIHandleBlock : public CHeapObj { // Handle allocation jobject allocate_handle(oop obj); + // Release Handle + void release_handle(jobject); + // Block allocation and block free list management static JNIHandleBlock* allocate_block(Thread* thread = NULL); static void release_block(JNIHandleBlock* block, Thread* thread = NULL); diff --git a/hotspot/src/share/vm/runtime/mutex.cpp b/hotspot/src/share/vm/runtime/mutex.cpp index 81fa378d05c..ef6ac43b5d6 100644 --- a/hotspot/src/share/vm/runtime/mutex.cpp +++ b/hotspot/src/share/vm/runtime/mutex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -1320,15 +1320,12 @@ void Monitor::set_owner_implementation(Thread *new_owner) { // The rank Mutex::native is an exception in that it is not subject // to the verification rules. // Here are some further notes relating to mutex acquisition anomalies: - // . under Solaris, the interrupt lock gets acquired when doing - // profiling, so any lock could be held. // . it is also ok to acquire Safepoint_lock at the very end while we // already hold Terminator_lock - may happen because of periodic safepoints if (this->rank() != Mutex::native && this->rank() != Mutex::suspend_resume && locks != NULL && locks->rank() <= this->rank() && !SafepointSynchronize::is_at_safepoint() && - this != Interrupt_lock && this != ProfileVM_lock && !(this == Safepoint_lock && contains(locks, Terminator_lock) && SafepointSynchronize::is_synchronizing())) { new_owner->print_owned_locks(); diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index ae1d213b6e5..7066ae21c1d 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ Mutex* Patching_lock = NULL; Monitor* SystemDictionary_lock = NULL; -Mutex* PackageTable_lock = NULL; +Mutex* Module_lock = NULL; Mutex* CompiledIC_lock = NULL; Mutex* InlineCacheBuffer_lock = NULL; Mutex* VMStatistic_lock = NULL; @@ -50,7 +50,6 @@ Mutex* JmethodIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL; Monitor* JNICritical_lock = NULL; Mutex* JvmtiThreadState_lock = NULL; -Monitor* JvmtiPendingEvent_lock = NULL; Monitor* Heap_lock = NULL; Mutex* ExpandHeap_lock = NULL; Mutex* AdapterHandlerLibrary_lock = NULL; @@ -73,8 +72,6 @@ Monitor* CGC_lock = NULL; Monitor* STS_lock = NULL; Monitor* SLT_lock = NULL; Monitor* FullGCCount_lock = NULL; -Monitor* CMark_lock = NULL; -Mutex* CMRegionStack_lock = NULL; Mutex* SATB_Q_FL_lock = NULL; Monitor* SATB_Q_CBL_mon = NULL; Mutex* Shared_SATB_Q_lock = NULL; @@ -94,11 +91,8 @@ Mutex* MultiArray_lock = NULL; Monitor* Terminator_lock = NULL; Monitor* BeforeExit_lock = NULL; Monitor* Notify_lock = NULL; -Monitor* Interrupt_lock = NULL; -Monitor* ProfileVM_lock = NULL; Mutex* ProfilePrint_lock = NULL; Mutex* ExceptionCache_lock = NULL; -Monitor* ObjAllocPost_lock = NULL; Mutex* OsrList_lock = NULL; #ifndef PRODUCT @@ -184,8 +178,6 @@ void mutex_init() { } if (UseG1GC) { - def(CMark_lock , Monitor, nonleaf, true, Monitor::_safepoint_check_never); // coordinate concurrent mark thread - def(CMRegionStack_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); def(SATB_Q_FL_lock , Mutex , special, true, Monitor::_safepoint_check_never); def(SATB_Q_CBL_mon , Monitor, nonleaf, true, Monitor::_safepoint_check_never); def(Shared_SATB_Q_lock , Mutex, nonleaf, true, Monitor::_safepoint_check_never); @@ -206,17 +198,15 @@ void mutex_init() { def(ParGCRareEvent_lock , Mutex , leaf , true, Monitor::_safepoint_check_sometimes); def(DerivedPointerTableGC_lock , Mutex, leaf, true, Monitor::_safepoint_check_never); def(CodeCache_lock , Mutex , special, true, Monitor::_safepoint_check_never); - def(Interrupt_lock , Monitor, special, true, Monitor::_safepoint_check_never); // used for interrupt processing def(RawMonitor_lock , Mutex, special, true, Monitor::_safepoint_check_never); def(OopMapCacheAlloc_lock , Mutex, leaf, true, Monitor::_safepoint_check_always); // used for oop_map_cache allocation. def(Patching_lock , Mutex , special, true, Monitor::_safepoint_check_never); // used for safepointing and code patching. - def(ObjAllocPost_lock , Monitor, special, false, Monitor::_safepoint_check_never); def(Service_lock , Monitor, special, true, Monitor::_safepoint_check_never); // used for service thread operations def(JmethodIdCreation_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); // used for creating jmethodIDs. def(SystemDictionary_lock , Monitor, leaf, true, Monitor::_safepoint_check_always); // lookups done by VM thread - def(PackageTable_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); + def(Module_lock , Mutex , leaf+2, true, Monitor::_safepoint_check_always); def(InlineCacheBuffer_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); def(VMStatistic_lock , Mutex , leaf, false, Monitor::_safepoint_check_always); def(ExpandHeap_lock , Mutex , leaf, true, Monitor::_safepoint_check_always); // Used during compilation by VM thread @@ -267,7 +257,6 @@ void mutex_init() { def(MultiArray_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // locks SymbolTable_lock def(JvmtiThreadState_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // Used by JvmtiThreadState/JvmtiEventController - def(JvmtiPendingEvent_lock , Monitor, nonleaf, false, Monitor::_safepoint_check_never); // Used by JvmtiCodeBlobEvents def(Management_lock , Mutex , nonleaf+2, false, Monitor::_safepoint_check_always); // used for JVM management def(Compile_lock , Mutex , nonleaf+3, true, Monitor::_safepoint_check_sometimes); @@ -277,7 +266,6 @@ void mutex_init() { def(MethodCompileQueue_lock , Monitor, nonleaf+4, true, Monitor::_safepoint_check_always); def(Debug2_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never); def(Debug3_lock , Mutex , nonleaf+4, true, Monitor::_safepoint_check_never); - def(ProfileVM_lock , Monitor, special, false, Monitor::_safepoint_check_never); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false, Monitor::_safepoint_check_always); def(PeriodicTask_lock , Monitor, nonleaf+5, true, Monitor::_safepoint_check_sometimes); if (WhiteBoxAPI) { diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index bbf6f143312..f60329725cd 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code extern Monitor* SystemDictionary_lock; // a lock on the system dictionary -extern Mutex* PackageTable_lock; // a lock on the class loader package table +extern Mutex* Module_lock; // a lock on module and package related data structures extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment @@ -43,7 +43,6 @@ extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI metho extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data -extern Monitor* JvmtiPendingEvent_lock; // a lock on the JVMTI pending events list extern Monitor* Heap_lock; // a lock on the heap extern Mutex* ExpandHeap_lock; // a lock on expanding the heap extern Mutex* AdapterHandlerLibrary_lock; // a lock on the AdapterHandlerLibrary @@ -68,8 +67,6 @@ extern Monitor* CGC_lock; // used for coordination betwee extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet. extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc -extern Monitor* CMark_lock; // used for concurrent mark thread coordination -extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack extern Mutex* SATB_Q_FL_lock; // Protects SATB Q // buffer free list. extern Monitor* SATB_Q_CBL_mon; // Protects SATB Q @@ -98,8 +95,6 @@ extern Mutex* MultiArray_lock; // a lock used to guard allocat extern Monitor* Terminator_lock; // a lock used to guard termination of the vm extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm -extern Monitor* Interrupt_lock; // a lock used for condition variable mediated interrupt processing -extern Monitor* ProfileVM_lock; // a lock used for profiling the VMThread extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles extern Mutex* ExceptionCache_lock; // a lock used to synchronize exception cache updates extern Mutex* OsrList_lock; // a lock used to serialize access to OSR queues diff --git a/hotspot/src/share/vm/runtime/objectMonitor.cpp b/hotspot/src/share/vm/runtime/objectMonitor.cpp index 2f7937d4f3e..6258d64ad2f 100644 --- a/hotspot/src/share/vm/runtime/objectMonitor.cpp +++ b/hotspot/src/share/vm/runtime/objectMonitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -401,7 +401,7 @@ void NOINLINE ObjectMonitor::enter(TRAPS) { if (event.should_commit()) { event.set_klass(((oop)this->object())->klass()); - event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid); + event.set_previousOwner((TYPE_THREAD)_previous_owner_tid); event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); event.commit(); } @@ -937,7 +937,7 @@ void NOINLINE ObjectMonitor::exit(bool not_suspended, TRAPS) { // get the owner's thread id for the MonitorEnter event // if it is enabled and the thread isn't suspended if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) { - _previous_owner_tid = SharedRuntime::get_java_tid(Self); + _previous_owner_tid = THREAD_TRACE_ID(Self); } #endif @@ -1391,11 +1391,12 @@ void ObjectMonitor::post_monitor_wait_event(EventJavaMonitorWait* event, jlong notifier_tid, jlong timeout, bool timedout) { + assert(event != NULL, "invariant"); event->set_klass(((oop)this->object())->klass()); - event->set_timeout((TYPE_ULONG)timeout); - event->set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr())); - event->set_notifier((TYPE_OSTHREAD)notifier_tid); - event->set_timedOut((TYPE_BOOLEAN)timedout); + event->set_timeout(timeout); + event->set_address((TYPE_ADDRESS)this->object_addr()); + event->set_notifier(notifier_tid); + event->set_timedOut(timedout); event->commit(); } @@ -1655,7 +1656,7 @@ void ObjectMonitor::INotify(Thread * Self) { iterator->TState = ObjectWaiter::TS_ENTER; } iterator->_notified = 1; - iterator->_notifier_tid = Self->osthread()->thread_id(); + iterator->_notifier_tid = THREAD_TRACE_ID(Self); ObjectWaiter * list = _EntryList; if (list != NULL) { diff --git a/hotspot/src/share/vm/runtime/os.cpp b/hotspot/src/share/vm/runtime/os.cpp index c482d2135dd..016b6e3d84f 100644 --- a/hotspot/src/share/vm/runtime/os.cpp +++ b/hotspot/src/share/vm/runtime/os.cpp @@ -1193,67 +1193,14 @@ char* os::format_boot_path(const char* format_string, return formatted_path; } -// returns a PATH of all entries in the given directory that do not start with a '.' -static char* expand_entries_to_path(char* directory, char fileSep, char pathSep) { - DIR* dir = os::opendir(directory); - if (dir == NULL) return NULL; - - char* path = NULL; - size_t path_len = 0; // path length including \0 terminator - - size_t directory_len = strlen(directory); - struct dirent *entry; - char* dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal); - while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { - const char* name = entry->d_name; - if (name[0] == '.') continue; - - size_t name_len = strlen(name); - size_t needed = directory_len + name_len + 2; - size_t new_len = path_len + needed; - if (path == NULL) { - path = NEW_C_HEAP_ARRAY(char, new_len, mtInternal); - } else { - path = REALLOC_C_HEAP_ARRAY(char, path, new_len, mtInternal); - } - if (path == NULL) - break; - - // append directoryname - char* p = path; - if (path_len > 0) { - p += (path_len -1); - *p = pathSep; - p++; - } - - strcpy(p, directory); - p += directory_len; - - *p = fileSep; - p++; - - strcpy(p, name); - p += name_len; - - path_len = new_len; - } - - FREE_C_HEAP_ARRAY(char, dbuf); - os::closedir(dir); - - return path; -} - bool os::set_boot_path(char fileSep, char pathSep) { const char* home = Arguments::get_java_home(); int home_len = (int)strlen(home); - char* sysclasspath = NULL; struct stat st; - // modular image if bootmodules.jimage exists - char* jimage = format_boot_path("%/lib/modules/" BOOT_IMAGE_NAME, home, home_len, fileSep, pathSep); + // modular image if "modules" jimage exists + char* jimage = format_boot_path("%/lib/" MODULES_IMAGE_NAME, home, home_len, fileSep, pathSep); if (jimage == NULL) return false; bool has_jimage = (os::stat(jimage, &st) == 0); if (has_jimage) { @@ -1264,23 +1211,16 @@ bool os::set_boot_path(char fileSep, char pathSep) { FREE_C_HEAP_ARRAY(char, jimage); // check if developer build with exploded modules - char* modules_dir = format_boot_path("%/modules", home, home_len, fileSep, pathSep); - if (os::stat(modules_dir, &st) == 0) { - if ((st.st_mode & S_IFDIR) == S_IFDIR) { - sysclasspath = expand_entries_to_path(modules_dir, fileSep, pathSep); - } + char* base_classes = format_boot_path("%/modules/java.base", home, home_len, fileSep, pathSep); + if (base_classes == NULL) return false; + if (os::stat(base_classes, &st) == 0) { + Arguments::set_sysclasspath(base_classes); + FREE_C_HEAP_ARRAY(char, base_classes); + return true; } - FREE_C_HEAP_ARRAY(char, modules_dir); + FREE_C_HEAP_ARRAY(char, base_classes); - // fallback to classes - if (sysclasspath == NULL) - sysclasspath = format_boot_path("%/classes", home, home_len, fileSep, pathSep); - - if (sysclasspath == NULL) return false; - Arguments::set_sysclasspath(sysclasspath); - FREE_C_HEAP_ARRAY(char, sysclasspath); - - return true; + return false; } /* diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 128c73c3194..7b71ca5228d 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -778,6 +778,8 @@ class os: AllStatic { // Amount beyond the callee frame size that we bang the stack. static int extra_bang_size_in_bytes(); + static char** split_path(const char* path, int* n); + // Extensions #include "runtime/os_ext.hpp" @@ -993,7 +995,6 @@ class os: AllStatic { char fileSep, char pathSep); static bool set_boot_path(char fileSep, char pathSep); - static char** split_path(const char* path, int* n); }; diff --git a/hotspot/src/share/vm/runtime/reflection.cpp b/hotspot/src/share/vm/runtime/reflection.cpp index 7eda3c51393..b60c63a1ad8 100644 --- a/hotspot/src/share/vm/runtime/reflection.cpp +++ b/hotspot/src/share/vm/runtime/reflection.cpp @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" +#include "classfile/packageEntry.hpp" #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/verifier.hpp" @@ -452,25 +454,193 @@ static bool can_relax_access_check_for(const Klass* accessor, return false; } -bool Reflection::verify_class_access(const Klass* current_class, - const Klass* new_class, - bool classloader_only) { +/* + Type Accessibility check for public types: Callee Type T is accessible to Caller Type S if: + + Callee T in Callee T in package PT, + unnamed module runtime module MT + ------------------------------------------------------------------------------------------------ + + Caller S in package If MS is loose: YES If same classloader/package (PS == PT): YES + PS, runtime module MS If MS can read T's If same runtime module: (MS == MT): YES + unnamed module: YES + Else if (MS can read MT (Establish readability) && + MT exports PT to MS or to all modules): YES + + ------------------------------------------------------------------------------------------------ + Caller S in unnamed YES Readability exists because unnamed module + module UM "reads" all modules + if (MT exports PT to UM or to all modules): YES + + ------------------------------------------------------------------------------------------------ + + Note: a loose module is a module that can read all current and future unnamed modules. +*/ +Reflection::VerifyClassAccessResults Reflection::verify_class_access( + const Klass* current_class, const Klass* new_class, bool classloader_only) { + // Verify that current_class can access new_class. If the classloader_only // flag is set, we automatically allow any accesses in which current_class // doesn't have a classloader. if ((current_class == NULL) || (current_class == new_class) || - (new_class->is_public()) || is_same_class_package(current_class, new_class)) { - return true; + return ACCESS_OK; } // Allow all accesses from sun/reflect/MagicAccessorImpl subclasses to // succeed trivially. if (current_class->is_subclass_of(SystemDictionary::reflect_MagicAccessorImpl_klass())) { - return true; + return ACCESS_OK; } - return can_relax_access_check_for(current_class, new_class, classloader_only); + // module boundaries + if (new_class->is_public()) { + // Ignore modules for DumpSharedSpaces because we do not have any package + // or module information for modules other than java.base. + if (DumpSharedSpaces) { + return ACCESS_OK; + } + + // Find the module entry for current_class, the accessor + ModuleEntry* module_from = InstanceKlass::cast(current_class)->module(); + // Find the module entry for new_class, the accessee + if (new_class->is_objArray_klass()) { + new_class = ObjArrayKlass::cast(new_class)->bottom_klass(); + } + if (!new_class->is_instance_klass()) { + // Everyone can read a typearray. + assert (new_class->is_typeArray_klass(), "Unexpected klass type"); + return ACCESS_OK; + } + ModuleEntry* module_to = InstanceKlass::cast(new_class)->module(); + + // both in same (possibly unnamed) module + if (module_from == module_to) { + return ACCESS_OK; + } + + // Acceptable access to a type in an unamed module. Note that since + // unnamed modules can read all unnamed modules, this also handles the + // case where module_from is also unnamed but in a different class loader. + if (!module_to->is_named() && + (module_from->can_read_all_unnamed() || module_from->can_read(module_to))) { + return ACCESS_OK; + } + + // Establish readability, check if module_from is allowed to read module_to. + if (!module_from->can_read(module_to)) { + return MODULE_NOT_READABLE; + } + + PackageEntry* package_to = InstanceKlass::cast(new_class)->package(); + assert(package_to != NULL, "can not obtain new_class' package"); + + // Once readability is established, if module_to exports T unqualifiedly, + // (to all modules), than whether module_from is in the unnamed module + // or not does not matter, access is allowed. + if (package_to->is_unqual_exported()) { + return ACCESS_OK; + } + + // Access is allowed if both 1 & 2 hold: + // 1. Readability, module_from can read module_to (established above). + // 2. Either module_to exports T to module_from qualifiedly. + // or + // module_to exports T to all unnamed modules and module_from is unnamed. + // or + // module_to exports T unqualifiedly to all modules (checked above). + if (!package_to->is_qexported_to(module_from)) { + return TYPE_NOT_EXPORTED; + } + return ACCESS_OK; + } + + if (can_relax_access_check_for(current_class, new_class, classloader_only)) { + return ACCESS_OK; + } + return OTHER_PROBLEM; +} + +// Return an error message specific to the specified Klass*'s and result. +// This function must be called from within a block containing a ResourceMark. +char* Reflection::verify_class_access_msg(const Klass* current_class, + const Klass* new_class, + VerifyClassAccessResults result) { + assert(result != ACCESS_OK, "must be failure result"); + char * msg = NULL; + if (result != OTHER_PROBLEM && new_class != NULL && current_class != NULL) { + // Find the module entry for current_class, the accessor + ModuleEntry* module_from = InstanceKlass::cast(current_class)->module(); + const char * module_from_name = module_from->is_named() ? module_from->name()->as_C_string() : UNNAMED_MODULE; + const char * current_class_name = current_class->external_name(); + + // Find the module entry for new_class, the accessee + ModuleEntry* module_to = NULL; + if (new_class->is_objArray_klass()) { + new_class = ObjArrayKlass::cast(new_class)->bottom_klass(); + } + if (new_class->is_instance_klass()) { + module_to = InstanceKlass::cast(new_class)->module(); + } else { + module_to = ModuleEntryTable::javabase_module(); + } + const char * module_to_name = module_to->is_named() ? module_to->name()->as_C_string() : UNNAMED_MODULE; + const char * new_class_name = new_class->external_name(); + + if (result == MODULE_NOT_READABLE) { + assert(module_from->is_named(), "Unnamed modules can read all modules"); + if (module_to->is_named()) { + size_t len = 100 + strlen(current_class_name) + 2*strlen(module_from_name) + + strlen(new_class_name) + 2*strlen(module_to_name); + msg = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(msg, len - 1, + "class %s (in module %s) cannot access class %s (in module %s) because module %s does not read module %s", + current_class_name, module_from_name, new_class_name, + module_to_name, module_from_name, module_to_name); + } else { + jobject jlrm = module_to->module(); + assert(jlrm != NULL, "Null jlrm in module_to ModuleEntry"); + intptr_t identity_hash = JNIHandles::resolve(jlrm)->identity_hash(); + size_t len = 160 + strlen(current_class_name) + 2*strlen(module_from_name) + + strlen(new_class_name) + 2*sizeof(uintx); + msg = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(msg, len - 1, + "class %s (in module %s) cannot access class %s (in unnamed module @" SIZE_FORMAT_HEX ") because module %s does not read unnamed module @" SIZE_FORMAT_HEX, + current_class_name, module_from_name, new_class_name, uintx(identity_hash), + module_from_name, uintx(identity_hash)); + } + + } else if (result == TYPE_NOT_EXPORTED) { + assert(InstanceKlass::cast(new_class)->package() != NULL, + "Unnamed packages are always exported"); + const char * package_name = + InstanceKlass::cast(new_class)->package()->name()->as_klass_external_name(); + assert(module_to->is_named(), "Unnamed modules export all packages"); + if (module_from->is_named()) { + size_t len = 118 + strlen(current_class_name) + 2*strlen(module_from_name) + + strlen(new_class_name) + 2*strlen(module_to_name) + strlen(package_name); + msg = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(msg, len - 1, + "class %s (in module %s) cannot access class %s (in module %s) because module %s does not export %s to module %s", + current_class_name, module_from_name, new_class_name, + module_to_name, module_to_name, package_name, module_from_name); + } else { + jobject jlrm = module_from->module(); + assert(jlrm != NULL, "Null jlrm in module_from ModuleEntry"); + intptr_t identity_hash = JNIHandles::resolve(jlrm)->identity_hash(); + size_t len = 170 + strlen(current_class_name) + strlen(new_class_name) + + 2*strlen(module_to_name) + strlen(package_name) + 2*sizeof(uintx); + msg = NEW_RESOURCE_ARRAY(char, len); + jio_snprintf(msg, len - 1, + "class %s (in unnamed module @" SIZE_FORMAT_HEX ") cannot access class %s (in module %s) because module %s does not export %s to unnamed module @" SIZE_FORMAT_HEX, + current_class_name, uintx(identity_hash), new_class_name, module_to_name, + module_to_name, package_name, uintx(identity_hash)); + } + } else { + ShouldNotReachHere(); + } + } // result != OTHER_PROBLEM... + return msg; } bool Reflection::verify_field_access(const Klass* current_class, diff --git a/hotspot/src/share/vm/runtime/reflection.hpp b/hotspot/src/share/vm/runtime/reflection.hpp index 920cf4c22a3..736e21f9f6b 100644 --- a/hotspot/src/share/vm/runtime/reflection.hpp +++ b/hotspot/src/share/vm/runtime/reflection.hpp @@ -53,6 +53,14 @@ class Reflection: public AllStatic { MAX_DIM = 255 }; + // Results returned by verify_class_access() + enum VerifyClassAccessResults { + ACCESS_OK = 0, + MODULE_NOT_READABLE = 1, + TYPE_NOT_EXPORTED = 2, + OTHER_PROBLEM = 3 + }; + // Boxing. Returns boxed value of appropriate type. Throws IllegalArgumentException. static oop box(jvalue* v, BasicType type, TRAPS); // Unboxing. Returns type code and sets value. @@ -73,9 +81,14 @@ class Reflection: public AllStatic { static arrayOop reflect_new_multi_array(oop element_mirror, typeArrayOop dimensions, TRAPS); // Verification - static bool verify_class_access(const Klass* current_class, - const Klass* new_class, - bool classloader_only); + static VerifyClassAccessResults verify_class_access(const Klass* current_class, + const Klass* new_class, + bool classloader_only); + // Return an error message specific to the specified Klass*'s and result. + // This function must be called from within a block containing a ResourceMark. + static char* verify_class_access_msg(const Klass* current_class, + const Klass* new_class, + const VerifyClassAccessResults result); static bool verify_field_access(const Klass* current_class, const Klass* resolved_class, diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.cpp b/hotspot/src/share/vm/runtime/sharedRuntime.cpp index 5b862a01fab..fe697685022 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp @@ -39,6 +39,8 @@ #include "interpreter/interpreterRuntime.hpp" #include "logging/log.hpp" #include "memory/universe.inline.hpp" +#include "oops/klass.hpp" +#include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/forte.hpp" #include "prims/jvmtiExport.hpp" @@ -1134,12 +1136,19 @@ Handle SharedRuntime::find_callee_info_helper(JavaThread* thread, MethodHandles::is_signature_polymorphic_intrinsic(id)) { bc = MethodHandles::signature_polymorphic_intrinsic_bytecode(id); - // Need to adjust invokehandle since inlining through signature-polymorphic - // method happened. - if (bc == Bytecodes::_invokehandle && - !MethodHandles::is_signature_polymorphic_method(attached_method())) { - bc = attached_method->is_static() ? Bytecodes::_invokestatic - : Bytecodes::_invokevirtual; + // Adjust invocation mode according to the attached method. + switch (bc) { + case Bytecodes::_invokeinterface: + if (!attached_method->method_holder()->is_interface()) { + bc = Bytecodes::_invokevirtual; + } + break; + case Bytecodes::_invokehandle: + if (!MethodHandles::is_signature_polymorphic_method(attached_method())) { + bc = attached_method->is_static() ? Bytecodes::_invokestatic + : Bytecodes::_invokevirtual; + } + break; } } } else { @@ -1908,28 +1917,58 @@ JRT_ENTRY(void, SharedRuntime::slow_arraycopy_C(oopDesc* src, jint src_pos, } JRT_END +// The caller of generate_class_cast_message() (or one of its callers) +// must use a ResourceMark in order to correctly free the result. char* SharedRuntime::generate_class_cast_message( - JavaThread* thread, const char* objName) { + JavaThread* thread, Klass* caster_klass) { // Get target class name from the checkcast instruction vframeStream vfst(thread, true); assert(!vfst.at_end(), "Java frame must exist"); Bytecode_checkcast cc(vfst.method(), vfst.method()->bcp_from(vfst.bci())); - Klass* targetKlass = vfst.method()->constants()->klass_at( + Klass* target_klass = vfst.method()->constants()->klass_at( cc.index(), thread); - return generate_class_cast_message(objName, targetKlass->external_name()); + return generate_class_cast_message(caster_klass, target_klass); } char* SharedRuntime::generate_class_cast_message( - const char* objName, const char* targetKlassName, const char* desc) { - size_t msglen = strlen(objName) + strlen(desc) + strlen(targetKlassName) + 1; + Klass* caster_klass, Klass* target_klass) { + + const char* caster_klass_name = caster_klass->external_name(); + Klass* c_klass = caster_klass->is_objArray_klass() ? + ObjArrayKlass::cast(caster_klass)->bottom_klass() : caster_klass; + ModuleEntry* caster_module; + const char* caster_module_name; + if (c_klass->is_instance_klass()) { + caster_module = InstanceKlass::cast(c_klass)->module(); + caster_module_name = caster_module->is_named() ? + caster_module->name()->as_C_string() : UNNAMED_MODULE; + } else { + caster_module_name = "java.base"; + } + const char* target_klass_name = target_klass->external_name(); + Klass* t_klass = target_klass->is_objArray_klass() ? + ObjArrayKlass::cast(target_klass)->bottom_klass() : target_klass; + ModuleEntry* target_module; + const char* target_module_name; + if (t_klass->is_instance_klass()) { + target_module = InstanceKlass::cast(t_klass)->module(); + target_module_name = target_module->is_named() ? + target_module->name()->as_C_string(): UNNAMED_MODULE; + } else { + target_module_name = "java.base"; + } + + size_t msglen = strlen(caster_klass_name) + strlen(caster_module_name) + + strlen(target_klass_name) + strlen(target_module_name) + 50; char* message = NEW_RESOURCE_ARRAY(char, msglen); if (NULL == message) { // Shouldn't happen, but don't cause even more problems if it does - message = const_cast(objName); + message = const_cast(caster_klass_name); } else { - jio_snprintf(message, msglen, "%s%s%s", objName, desc, targetKlassName); + jio_snprintf(message, msglen, "%s (in module: %s) cannot be cast to %s (in module: %s)", + caster_klass_name, caster_module_name, target_klass_name, target_module_name); } return message; } diff --git a/hotspot/src/share/vm/runtime/sharedRuntime.hpp b/hotspot/src/share/vm/runtime/sharedRuntime.hpp index f00b911d048..10c94e6c366 100644 --- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp +++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp @@ -293,22 +293,21 @@ class SharedRuntime: AllStatic { // Fill in the "X cannot be cast to a Y" message for ClassCastException // // @param thr the current thread - // @param name the name of the class of the object attempted to be cast + // @param caster_klass the class of the object we are casting // @return the dynamically allocated exception message (must be freed // by the caller using a resource mark) // // BCP must refer to the current 'checkcast' opcode for the frame // on top of the stack. - // The caller (or one of it's callers) must use a ResourceMark + // The caller (or one of its callers) must use a ResourceMark // in order to correctly free the result. // - static char* generate_class_cast_message(JavaThread* thr, const char* name); + static char* generate_class_cast_message(JavaThread* thr, Klass* caster_klass); // Fill in the "X cannot be cast to a Y" message for ClassCastException // - // @param name the name of the class of the object attempted to be cast - // @param klass the name of the target klass attempt - // @param gripe the specific kind of problem being reported + // @param caster_klass the class of the object we are casting + // @param target_klass the target klass attempt // @return the dynamically allocated exception message (must be freed // by the caller using a resource mark) // @@ -317,8 +316,7 @@ class SharedRuntime: AllStatic { // The caller (or one of it's callers) must use a ResourceMark // in order to correctly free the result. // - static char* generate_class_cast_message(const char* name, const char* klass, - const char* gripe = " cannot be cast to "); + static char* generate_class_cast_message(Klass* caster_klass, Klass* target_klass); // Resolves a call site- may patch in the destination of the call into the // compiled code. diff --git a/hotspot/src/share/vm/runtime/statSampler.cpp b/hotspot/src/share/vm/runtime/statSampler.cpp index 3e693d997da..cc88f88bead 100644 --- a/hotspot/src/share/vm/runtime/statSampler.cpp +++ b/hotspot/src/share/vm/runtime/statSampler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -238,7 +238,6 @@ static const char* property_counters_us[] = { // unstable interface, unsupported counters static const char* property_counters_uu[] = { - "sun.boot.class.path", "sun.boot.library.path", NULL }; diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp index 5b9adc09776..db440291575 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.cpp @@ -36,19 +36,13 @@ // Implementation of StubCodeDesc StubCodeDesc* StubCodeDesc::_list = NULL; -int StubCodeDesc::_count = 0; bool StubCodeDesc::_frozen = false; StubCodeDesc* StubCodeDesc::desc_for(address pc) { StubCodeDesc* p = _list; - while (p != NULL && !p->contains(pc)) p = p->_next; - // p == NULL || p->contains(pc) - return p; -} - -StubCodeDesc* StubCodeDesc::desc_for_index(int index) { - StubCodeDesc* p = _list; - while (p != NULL && p->index() != index) p = p->_next; + while (p != NULL && !p->contains(pc)) { + p = p->_next; + } return p; } @@ -73,43 +67,17 @@ void StubCodeDesc::print_on(outputStream* st) const { // Implementation of StubCodeGenerator StubCodeGenerator::StubCodeGenerator(CodeBuffer* code, bool print_code) { - _masm = new MacroAssembler(code); - _first_stub = _last_stub = NULL; - _print_code = print_code; -} - -extern "C" { - static int compare_cdesc(const void* void_a, const void* void_b) { - int ai = (*((StubCodeDesc**) void_a))->index(); - int bi = (*((StubCodeDesc**) void_b))->index(); - return ai - bi; - } + _masm = new MacroAssembler(code ); + _print_code = PrintStubCode || print_code; } StubCodeGenerator::~StubCodeGenerator() { - if (PrintStubCode || _print_code) { + if (_print_code) { CodeBuffer* cbuf = _masm->code(); CodeBlob* blob = CodeCache::find_blob_unsafe(cbuf->insts()->start()); if (blob != NULL) { blob->set_strings(cbuf->strings()); } - bool saw_first = false; - StubCodeDesc* toprint[1000]; - int toprint_len = 0; - for (StubCodeDesc* cdesc = _last_stub; cdesc != NULL; cdesc = cdesc->_next) { - toprint[toprint_len++] = cdesc; - if (cdesc == _first_stub) { saw_first = true; break; } - } - assert(toprint_len == 0 || saw_first, "must get both first & last"); - // Print in reverse order: - qsort(toprint, toprint_len, sizeof(toprint[0]), compare_cdesc); - for (int i = 0; i < toprint_len; i++) { - StubCodeDesc* cdesc = toprint[i]; - cdesc->print(); - tty->cr(); - Disassembler::decode(cdesc->begin(), cdesc->end()); - tty->cr(); - } } } @@ -118,9 +86,12 @@ void StubCodeGenerator::stub_prolog(StubCodeDesc* cdesc) { } void StubCodeGenerator::stub_epilog(StubCodeDesc* cdesc) { - // default implementation - record the cdesc - if (_first_stub == NULL) _first_stub = cdesc; - _last_stub = cdesc; + if (_print_code) { + cdesc->print(); + tty->cr(); + Disassembler::decode(cdesc->begin(), cdesc->end()); + tty->cr(); + } } diff --git a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp index 13bb86e6396..4571e3ae667 100644 --- a/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp +++ b/hotspot/src/share/vm/runtime/stubCodeGenerator.hpp @@ -39,13 +39,11 @@ class StubCodeDesc: public CHeapObj { private: static StubCodeDesc* _list; // the list of all descriptors - static int _count; // length of list static bool _frozen; // determines whether _list modifications are allowed StubCodeDesc* _next; // the next element in the linked list const char* _group; // the group to which the stub code belongs const char* _name; // the name assigned to the stub code - int _index; // serial number assigned to the stub address _begin; // points to the first byte of the stub code (included) address _end; // points to the first byte after the stub code (excluded) @@ -64,8 +62,10 @@ class StubCodeDesc: public CHeapObj { friend class StubCodeGenerator; public: + static StubCodeDesc* first() { return _list; } + static StubCodeDesc* next(StubCodeDesc* desc) { return desc->_next; } + static StubCodeDesc* desc_for(address pc); // returns the code descriptor for the code containing pc or NULL - static StubCodeDesc* desc_for_index(int); // returns the code descriptor for the index or NULL static const char* name_for(address pc); // returns the name of the code containing pc or NULL StubCodeDesc(const char* group, const char* name, address begin, address end = NULL) { @@ -74,7 +74,6 @@ class StubCodeDesc: public CHeapObj { _next = _list; _group = group; _name = name; - _index = ++_count; // (never zero) _begin = begin; _end = end; _list = this; @@ -84,7 +83,6 @@ class StubCodeDesc: public CHeapObj { const char* group() const { return _group; } const char* name() const { return _name; } - int index() const { return _index; } address begin() const { return _begin; } address end() const { return _end; } int size_in_bytes() const { return _end - _begin; } @@ -97,13 +95,12 @@ class StubCodeDesc: public CHeapObj { // Provides utility functions. class StubCodeGenerator: public StackObj { + private: + bool _print_code; + protected: MacroAssembler* _masm; - StubCodeDesc* _first_stub; - StubCodeDesc* _last_stub; - bool _print_code; - public: StubCodeGenerator(CodeBuffer* code, bool print_code = false); ~StubCodeGenerator(); diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp index 5e1c4a31445..a7b9f41f9b1 100644 --- a/hotspot/src/share/vm/runtime/thread.cpp +++ b/hotspot/src/share/vm/runtime/thread.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "classfile/classLoader.hpp" #include "classfile/javaClasses.hpp" +#include "classfile/moduleEntry.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" @@ -118,6 +119,9 @@ #include "runtime/rtmLocking.hpp" #endif +// Initialization after module runtime initialization +void universe_post_module_init(); // must happen after call_initPhase2 + #ifdef DTRACE_ENABLED // Only bother with this argument setup if dtrace is available @@ -324,6 +328,10 @@ void Thread::record_stack_base_and_size() { // record thread's native stack, stack grows downward MemTracker::record_thread_stack(stack_end(), stack_size()); #endif // INCLUDE_NMT + log_debug(os, thread)("Thread " UINTX_FORMAT " stack dimensions: " + PTR_FORMAT "-" PTR_FORMAT " (" SIZE_FORMAT "k).", + os::current_thread_id(), p2i(stack_base() - stack_size()), + p2i(stack_base()), stack_size()/1024); } @@ -993,15 +1001,6 @@ static oop create_initial_thread(Handle thread_group, JavaThread* thread, return thread_oop(); } -static void call_initializeSystemClass(TRAPS) { - Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); - instanceKlassHandle klass (THREAD, k); - - JavaValue result(T_VOID); - JavaCalls::call_static(&result, klass, vmSymbols::initializeSystemClass_name(), - vmSymbols::void_method_signature(), CHECK); -} - char java_runtime_name[128] = ""; char java_runtime_version[128] = ""; @@ -1690,7 +1689,7 @@ void JavaThread::run() { EventThreadStart event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); + event.set_thread(THREAD_TRACE_ID(this)); event.commit(); } @@ -1795,7 +1794,7 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { // from java_lang_Thread object EventThreadEnd event; if (event.should_commit()) { - event.set_javalangthread(java_lang_Thread::thread_id(this->threadObj())); + event.set_thread(THREAD_TRACE_ID(this)); event.commit(); } @@ -1924,6 +1923,10 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { } #endif // INCLUDE_ALL_GCS + log_info(os, thread)("JavaThread %s (tid: " UINTX_FORMAT ").", + exit_type == JavaThread::normal_exit ? "exiting" : "detaching", + os::current_thread_id()); + // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread Threads::remove(this); } @@ -2491,18 +2494,25 @@ void JavaThread::create_stack_guard_pages() { // warning("Guarding at " PTR_FORMAT " for len " SIZE_FORMAT "\n", low_addr, len); if (allocate && !os::create_stack_guard_pages((char *) low_addr, len)) { - warning("Attempt to allocate stack guard pages failed."); + log_warning(os, thread)("Attempt to allocate stack guard pages failed."); return; } if (os::guard_memory((char *) low_addr, len)) { _stack_guard_state = stack_guard_enabled; } else { - warning("Attempt to protect stack guard pages failed."); + log_warning(os, thread)("Attempt to protect stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); if (os::uncommit_memory((char *) low_addr, len)) { - warning("Attempt to deallocate stack guard pages failed."); + log_warning(os, thread)("Attempt to deallocate stack guard pages failed."); } + return; } + + log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages activated: " + PTR_FORMAT "-" PTR_FORMAT ".", + os::current_thread_id(), p2i(low_addr), p2i(low_addr + len)); + } void JavaThread::remove_stack_guard_pages() { @@ -2515,16 +2525,25 @@ void JavaThread::remove_stack_guard_pages() { if (os::remove_stack_guard_pages((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { - warning("Attempt to deallocate stack guard pages failed."); + log_warning(os, thread)("Attempt to deallocate stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); + return; } } else { if (_stack_guard_state == stack_guard_unused) return; if (os::unguard_memory((char *) low_addr, len)) { _stack_guard_state = stack_guard_unused; } else { - warning("Attempt to unprotect stack guard pages failed."); + log_warning(os, thread)("Attempt to unprotect stack guard pages failed (" + PTR_FORMAT "-" PTR_FORMAT ").", p2i(low_addr), p2i(low_addr + len)); + return; } } + + log_debug(os, thread)("Thread " UINTX_FORMAT " stack guard pages removed: " + PTR_FORMAT "-" PTR_FORMAT ".", + os::current_thread_id(), p2i(low_addr), p2i(low_addr + len)); + } void JavaThread::enable_stack_reserved_zone() { @@ -3340,6 +3359,62 @@ void Threads::threads_do(ThreadClosure* tc) { // If CompilerThreads ever become non-JavaThreads, add them here } +// The system initialization in the library has three phases. +// +// Phase 1: java.lang.System class initialization +// java.lang.System is a primordial class loaded and initialized +// by the VM early during startup. java.lang.System. +// only does registerNatives and keeps the rest of the class +// initialization work later until thread initialization completes. +// +// System.initPhase1 initializes the system properties, the static +// fields in, out, and err. Set up java signal handlers, OS-specific +// system settings, and thread group of the main thread. +static void call_initPhase1(TRAPS) { + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); + instanceKlassHandle klass (THREAD, k); + + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbols::initPhase1_name(), + vmSymbols::void_method_signature(), CHECK); +} + +// Phase 2. Module system initialization +// This will initialize the module system. Only java.base classes +// can be loaded until phase 2 completes. +// +// Call System.initPhase2 after the compiler initialization and jsr292 +// classes get initialized because module initialization runs a lot of java +// code, that for performance reasons, should be compiled. Also, this will +// enable the startup code to use lambda and other language features in this +// phase and onward. +// +// After phase 2, The VM will begin search classes from -Xbootclasspath/a. +static void call_initPhase2(TRAPS) { + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); + instanceKlassHandle klass (THREAD, k); + + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbols::initPhase2_name(), + vmSymbols::void_method_signature(), CHECK); + universe_post_module_init(); +} + +// Phase 3. final setup - set security manager, system class loader and TCCL +// +// This will instantiate and set the security manager, set the system class +// loader as well as the thread context class loader. The security manager +// and system class loader may be a custom class loaded from -Xbootclasspath/a, +// other modules or the application's classpath. +static void call_initPhase3(TRAPS) { + Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), true, CHECK); + instanceKlassHandle klass (THREAD, k); + + JavaValue result(T_VOID); + JavaCalls::call_static(&result, klass, vmSymbols::initPhase3_name(), + vmSymbols::void_method_signature(), CHECK); +} + void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { TraceStartupTime timer("Initialize java.lang classes"); @@ -3367,10 +3442,15 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { java_lang_Thread::set_thread_status(thread_object, java_lang_Thread::RUNNABLE); + // The VM creates objects of this class. + initialize_class(vmSymbols::java_lang_reflect_Module(), CHECK); + // The VM preresolves methods to these classes. Make sure that they get initialized initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK); initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK); - call_initializeSystemClass(CHECK); + + // Phase 1 of the system initialization in the library, java.lang.System class initialization + call_initPhase1(CHECK); // get the Java runtime name after java.lang.System is initialized JDK_Version::set_runtime_name(get_java_runtime_name(THREAD)); @@ -3530,6 +3610,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { return status; } + if (TRACE_INITIALIZE() != JNI_OK) { + vm_exit_during_initialization("Failed to initialize tracing backend"); + } + // Should be done after the heap is fully created main_thread->cache_global_variables(); @@ -3584,10 +3668,10 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // Always call even when there are not JVMTI environments yet, since environments // may be attached late and JVMTI must track phases of VM execution - JvmtiExport::enter_start_phase(); + JvmtiExport::enter_early_start_phase(); // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. - JvmtiExport::post_vm_start(); + JvmtiExport::post_early_vm_start(); initialize_java_lang_classes(main_thread, CHECK_JNI_ERR); @@ -3598,11 +3682,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { quicken_jni_functions(); - // Must be run after init_ft which initializes ft_enabled - if (TRACE_INITIALIZE() != JNI_OK) { - vm_exit_during_initialization("Failed to initialize tracing backend"); - } - // No more stub generation allowed after that point. StubCodeDesc::freeze(); @@ -3620,12 +3699,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { Management::record_vm_init_completed(); #endif // INCLUDE_MANAGEMENT - // Compute system loader. Note that this has to occur after set_init_completed, since - // valid exceptions may be thrown in the process. // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and // set_init_completed has just been called, causing exceptions not to be shortcut // anymore. We call vm_exit_during_initialization directly instead. - SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); #if INCLUDE_ALL_GCS // Support for ConcurrentMarkSweep. This should be cleaned up @@ -3640,10 +3716,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { } #endif // INCLUDE_ALL_GCS - // Always call even when there are not JVMTI environments yet, since environments - // may be attached late and JVMTI must track phases of VM execution - JvmtiExport::enter_live_phase(); - // Signal Dispatcher needs to be started before VMInit event is posted os::signal_init(); @@ -3662,13 +3734,6 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { create_vm_init_libraries(); } - // Notify JVMTI agents that VM initialization is complete - nop if no agents. - JvmtiExport::post_vm_initialized(); - - if (TRACE_START() != JNI_OK) { - vm_exit_during_initialization("Failed to start tracing backend."); - } - if (CleanChunkPoolAsync) { Chunk::start_chunk_pool_cleaner_task(); } @@ -3693,6 +3758,34 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // (see SystemDictionary::find_method_handle_intrinsic). initialize_jsr292_core_classes(CHECK_JNI_ERR); + // This will initialize the module system. Only java.base classes can be + // loaded until phase 2 completes + call_initPhase2(CHECK_JNI_ERR); + + // Always call even when there are not JVMTI environments yet, since environments + // may be attached late and JVMTI must track phases of VM execution + JvmtiExport::enter_start_phase(); + + // Notify JVMTI agents that VM has started (JNI is up) - nop if no agents. + JvmtiExport::post_vm_start(); + + // Final system initialization including security manager and system class loader + call_initPhase3(CHECK_JNI_ERR); + + // cache the system class loader + SystemDictionary::compute_java_system_loader(CHECK_(JNI_ERR)); + + // Always call even when there are not JVMTI environments yet, since environments + // may be attached late and JVMTI must track phases of VM execution + JvmtiExport::enter_live_phase(); + + // Notify JVMTI agents that VM initialization is complete - nop if no agents. + JvmtiExport::post_vm_initialized(); + + if (TRACE_START() != JNI_OK) { + vm_exit_during_initialization("Failed to start tracing backend."); + } + #if INCLUDE_MANAGEMENT Management::initialize(THREAD); @@ -4110,6 +4203,7 @@ jboolean Threads::is_supported_jni_version(jint version) { if (version == JNI_VERSION_1_4) return JNI_TRUE; if (version == JNI_VERSION_1_6) return JNI_TRUE; if (version == JNI_VERSION_1_8) return JNI_TRUE; + if (version == JNI_VERSION_9) return JNI_TRUE; return JNI_FALSE; } diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp index 4d94026e313..eed983d3841 100644 --- a/hotspot/src/share/vm/runtime/thread.hpp +++ b/hotspot/src/share/vm/runtime/thread.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -448,7 +448,8 @@ class Thread: public ThreadShadow { void incr_allocated_bytes(jlong size) { _allocated_bytes += size; } inline jlong cooked_allocated_bytes(); - TRACE_DATA* trace_data() { return &_trace_data; } + TRACE_DEFINE_THREAD_TRACE_DATA_OFFSET; + TRACE_DATA* trace_data() const { return &_trace_data; } const ThreadExt& ext() const { return _ext; } ThreadExt& ext() { return _ext; } diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index c6519c03600..84d2c6ebd3b 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -960,7 +960,6 @@ typedef CompactHashtable SymbolCompactHashTable; nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, int) \ nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ - nonstatic_field(nmethod, _marked_for_deoptimization, bool) \ \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ \ @@ -2006,10 +2005,20 @@ typedef CompactHashtable SymbolCompactHashTable; declare_c2_type(LoadStoreNode, Node) \ declare_c2_type(StorePConditionalNode, LoadStoreNode) \ declare_c2_type(StoreLConditionalNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapLNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapINode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapPNode, LoadStoreNode) \ - declare_c2_type(CompareAndSwapNNode, LoadStoreNode) \ + declare_c2_type(CompareAndSwapNode, LoadStoreConditionalNode) \ + declare_c2_type(CompareAndSwapLNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapINode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapPNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndSwapNNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapLNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapINode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapPNode, CompareAndSwapNode) \ + declare_c2_type(WeakCompareAndSwapNNode, CompareAndSwapNode) \ + declare_c2_type(CompareAndExchangeNode, LoadStoreNode) \ + declare_c2_type(CompareAndExchangeLNode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangeINode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangePNode, CompareAndExchangeNode) \ + declare_c2_type(CompareAndExchangeNNode, CompareAndExchangeNode) \ declare_c2_type(MulNode, Node) \ declare_c2_type(MulINode, MulNode) \ declare_c2_type(MulLNode, MulNode) \ diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp index 77935603075..f4584b1fc9b 100644 --- a/hotspot/src/share/vm/runtime/vmThread.cpp +++ b/hotspot/src/share/vm/runtime/vmThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -359,7 +359,7 @@ void VMThread::evaluate_operation(VM_Operation* op) { // Only write caller thread information for non-concurrent vm operations. // For concurrent vm operations, the thread id is set to 0 indicating thread is unknown. // This is because the caller thread could have exited already. - event.set_caller(is_concurrent ? 0 : op->calling_thread()->osthread()->thread_id()); + event.set_caller(is_concurrent ? 0 : THREAD_TRACE_ID(op->calling_thread())); event.commit(); } diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp index 80def983a56..db7341d869f 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.cpp +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp @@ -485,6 +485,10 @@ void VM_Exit::wait_if_vm_exited() { } } +void VM_PrintCompileQueue::doit() { + CompileBroker::print_compile_queues(_out); +} + #if INCLUDE_SERVICES void VM_PrintClassHierarchy::doit() { KlassHierarchy::print_class_hierarchy(_out, _print_interfaces, _print_subclasses, _classname); diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp index 03392091aee..a5b0ddbf47b 100644 --- a/hotspot/src/share/vm/runtime/vm_operations.hpp +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp @@ -105,6 +105,7 @@ template(DumpHashtable) \ template(DumpTouchedMethods) \ template(MarkActiveNMethods) \ + template(PrintCompileQueue) \ template(PrintClassHierarchy) \ class VM_Operation: public CHeapObj { @@ -421,6 +422,17 @@ class VM_Exit: public VM_Operation { void doit(); }; +class VM_PrintCompileQueue: public VM_Operation { + private: + outputStream* _out; + + public: + VM_PrintCompileQueue(outputStream* st) : _out(st) {} + VMOp_Type type() const { return VMOp_PrintCompileQueue; } + Mode evaluation_mode() const { return _safepoint; } + void doit(); +}; + #if INCLUDE_SERVICES class VM_PrintClassHierarchy: public VM_Operation { private: diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp index 2a81ae7bfad..1b745b091c0 100644 --- a/hotspot/src/share/vm/services/diagnosticCommand.cpp +++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp @@ -893,7 +893,8 @@ void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) { } void CompileQueueDCmd::execute(DCmdSource source, TRAPS) { - CompileBroker::print_compile_queues(output()); + VM_PrintCompileQueue printCompileQueueOp(output()); + VMThread::execute(&printCompileQueueOp); } void CodeListDCmd::execute(DCmdSource source, TRAPS) { diff --git a/hotspot/src/share/vm/services/heapDumper.cpp b/hotspot/src/share/vm/services/heapDumper.cpp index 2f01fab4cc9..986855894d2 100644 --- a/hotspot/src/share/vm/services/heapDumper.cpp +++ b/hotspot/src/share/vm/services/heapDumper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,8 +53,7 @@ * src/share/demo/jvmti/hprof/hprof_io.c * * - * header "JAVA PROFILE 1.0.1" or "JAVA PROFILE 1.0.2" - * (0-terminated) + * header "JAVA PROFILE 1.0.2" (0-terminated) * * u4 size of identifiers. Identifiers are used to represent * UTF8 strings, objects, stack traces, etc. They usually @@ -385,6 +384,8 @@ class DumpWriter : public StackObj { size_t _size; size_t _pos; + jlong _dump_start; + char* _error; // error message when I/O fails void set_file_descriptor(int fd) { _fd = fd; } @@ -408,6 +409,10 @@ class DumpWriter : public StackObj { bool is_open() const { return file_descriptor() >= 0; } void flush(); + jlong dump_start() const { return _dump_start; } + void set_dump_start(jlong pos); + julong current_record_length(); + // total number of bytes written to the disk julong bytes_written() const { return _bytes_written; } @@ -449,6 +454,7 @@ DumpWriter::DumpWriter(const char* path) { _pos = 0; _error = NULL; _bytes_written = 0L; + _dump_start = (jlong)-1; _fd = os::create_binary_file(path, false); // don't replace existing file // if the open failed we record the error @@ -476,6 +482,22 @@ void DumpWriter::close() { } } +// sets the dump starting position +void DumpWriter::set_dump_start(jlong pos) { + _dump_start = pos; +} + +julong DumpWriter::current_record_length() { + if (is_open()) { + // calculate the size of the dump record + julong dump_end = bytes_written() + bytes_unwritten(); + assert(dump_end == (size_t)current_offset(), "checking"); + julong dump_len = dump_end - dump_start() - 4; + return dump_len; + } + return 0; +} + // write directly to the file void DumpWriter::write_internal(void* s, size_t len) { if (is_open()) { @@ -645,6 +667,18 @@ class DumperSupport : AllStatic { static void dump_prim_array(DumpWriter* writer, typeArrayOop array); // create HPROF_FRAME record for the given method and bci static void dump_stack_frame(DumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci); + + // check if we need to truncate an array + static int calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size); + + // writes a HPROF_HEAP_DUMP_SEGMENT record + static void write_dump_header(DumpWriter* writer); + + // fixes up the length of the current dump record + static void write_current_dump_record_length(DumpWriter* writer); + + // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record + static void end_of_dump(DumpWriter* writer); }; // write a header of the given type @@ -1005,50 +1039,102 @@ void DumperSupport::dump_basic_type_array_class(DumpWriter* writer, Klass* k) { } } +// Hprof uses an u4 as record length field, +// which means we need to truncate arrays that are too long. +int DumperSupport::calculate_array_max_length(DumpWriter* writer, arrayOop array, short header_size) { + BasicType type = ArrayKlass::cast(array->klass())->element_type(); + assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type"); + + int length = array->length(); + + int type_size; + if (type == T_OBJECT) { + type_size = sizeof(address); + } else { + type_size = type2aelembytes(type); + } + + size_t length_in_bytes = (size_t)length * type_size; + + // Create a new record if the current record is non-empty and the array can't fit. + julong current_record_length = writer->current_record_length(); + if (current_record_length > 0 && + (current_record_length + header_size + length_in_bytes) > max_juint) { + write_current_dump_record_length(writer); + write_dump_header(writer); + + // We now have an empty record. + current_record_length = 0; + } + + // Calculate max bytes we can use. + uint max_bytes = max_juint - (header_size + current_record_length); + + // Array too long for the record? + // Calculate max length and return it. + if (length_in_bytes > max_bytes) { + length = max_bytes / type_size; + length_in_bytes = (size_t)length * type_size; + + warning("cannot dump array of type %s[] with length %d; truncating to length %d", + type2name_tab[type], array->length(), length); + } + return length; +} + // creates HPROF_GC_OBJ_ARRAY_DUMP record for the given object array void DumperSupport::dump_object_array(DumpWriter* writer, objArrayOop array) { + // sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + sizeof(classID) + short header_size = 1 + 2 * 4 + 2 * sizeof(address); + + int length = calculate_array_max_length(writer, array, header_size); writer->write_u1(HPROF_GC_OBJ_ARRAY_DUMP); writer->write_objectID(array); writer->write_u4(STACK_TRACE_ID); - writer->write_u4((u4)array->length()); + writer->write_u4(length); // array class ID writer->write_classID(array->klass()); // [id]* elements - for (int index=0; indexlength(); index++) { + for (int index = 0; index < length; index++) { oop o = array->obj_at(index); writer->write_objectID(o); } } -#define WRITE_ARRAY(Array, Type, Size) \ - for (int i=0; ilength(); i++) { writer->write_##Size((Size)array->Type##_at(i)); } - +#define WRITE_ARRAY(Array, Type, Size, Length) \ + for (int i = 0; i < Length; i++) { writer->write_##Size((Size)Array->Type##_at(i)); } // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { BasicType type = TypeArrayKlass::cast(array->klass())->element_type(); + // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID) + short header_size = 2 * 1 + 2 * 4 + sizeof(address); + + int length = calculate_array_max_length(writer, array, header_size); + int type_size = type2aelembytes(type); + u4 length_in_bytes = (u4)length * type_size; + writer->write_u1(HPROF_GC_PRIM_ARRAY_DUMP); writer->write_objectID(array); writer->write_u4(STACK_TRACE_ID); - writer->write_u4((u4)array->length()); + writer->write_u4(length); writer->write_u1(type2tag(type)); // nothing to copy - if (array->length() == 0) { + if (length == 0) { return; } // If the byte ordering is big endian then we can copy most types directly - u4 length_in_bytes = (u4)array->length() * type2aelembytes(type); switch (type) { case T_INT : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, int, u4); + WRITE_ARRAY(array, int, u4, length); } else { writer->write_raw((void*)(array->int_at_addr(0)), length_in_bytes); } @@ -1060,7 +1146,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_CHAR : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, char, u2); + WRITE_ARRAY(array, char, u2, length); } else { writer->write_raw((void*)(array->char_at_addr(0)), length_in_bytes); } @@ -1068,7 +1154,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_SHORT : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, short, u2); + WRITE_ARRAY(array, short, u2, length); } else { writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes); } @@ -1076,7 +1162,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_BOOLEAN : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, bool, u1); + WRITE_ARRAY(array, bool, u1, length); } else { writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes); } @@ -1084,7 +1170,7 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { } case T_LONG : { if (Bytes::is_Java_byte_ordering_different()) { - WRITE_ARRAY(array, long, u8); + WRITE_ARRAY(array, long, u8, length); } else { writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes); } @@ -1096,14 +1182,14 @@ void DumperSupport::dump_prim_array(DumpWriter* writer, typeArrayOop array) { // use IEEE 754. case T_FLOAT : { - for (int i=0; ilength(); i++) { - dump_float( writer, array->float_at(i) ); + for (int i = 0; i < length; i++) { + dump_float(writer, array->float_at(i)); } break; } case T_DOUBLE : { - for (int i=0; ilength(); i++) { - dump_double( writer, array->double_at(i) ); + for (int i = 0; i < length; i++) { + dump_double(writer, array->double_at(i)); } break; } @@ -1320,8 +1406,6 @@ class VM_HeapDumper : public VM_GC_Operation { JavaThread* _oome_thread; Method* _oome_constructor; bool _gc_before_heap_dump; - bool _is_segmented_dump; - jlong _dump_start; GrowableArray* _klass_map; ThreadStackTrace** _stack_traces; int _num_threads; @@ -1340,11 +1424,6 @@ class VM_HeapDumper : public VM_GC_Operation { void clear_global_dumper() { _global_dumper = NULL; } void clear_global_writer() { _global_writer = NULL; } - bool is_segmented_dump() const { return _is_segmented_dump; } - void set_segmented_dump() { _is_segmented_dump = true; } - jlong dump_start() const { return _dump_start; } - void set_dump_start(jlong pos); - bool skip_operation() const; // writes a HPROF_LOAD_CLASS record @@ -1369,16 +1448,6 @@ class VM_HeapDumper : public VM_GC_Operation { // HPROF_TRACE and HPROF_FRAME records void dump_stack_traces(); - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record - void write_dump_header(); - - // fixes up the length of the current dump record - void write_current_dump_record_length(); - - // fixes up the current dump record )and writes HPROF_HEAP_DUMP_END - // record in the case of a segmented heap dump) - void end_of_dump(); - public: VM_HeapDumper(DumpWriter* writer, bool gc_before_heap_dump, bool oome) : VM_GC_Operation(0 /* total collections, dummy, ignored */, @@ -1387,8 +1456,6 @@ class VM_HeapDumper : public VM_GC_Operation { gc_before_heap_dump) { _local_writer = writer; _gc_before_heap_dump = gc_before_heap_dump; - _is_segmented_dump = false; - _dump_start = (jlong)-1; _klass_map = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(INITIAL_CLASS_COUNT, true); _stack_traces = NULL; _num_threads = 0; @@ -1428,35 +1495,23 @@ bool VM_HeapDumper::skip_operation() const { return false; } -// sets the dump starting position -void VM_HeapDumper::set_dump_start(jlong pos) { - _dump_start = pos; -} - - // writes a HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT record -void VM_HeapDumper::write_dump_header() { - if (writer()->is_open()) { - if (is_segmented_dump()) { - writer()->write_u1(HPROF_HEAP_DUMP_SEGMENT); - } else { - writer()->write_u1(HPROF_HEAP_DUMP); - } - writer()->write_u4(0); // current ticks + // writes a HPROF_HEAP_DUMP_SEGMENT record +void DumperSupport::write_dump_header(DumpWriter* writer) { + if (writer->is_open()) { + writer->write_u1(HPROF_HEAP_DUMP_SEGMENT); + writer->write_u4(0); // current ticks // record the starting position for the dump (its length will be fixed up later) - set_dump_start(writer()->current_offset()); - writer()->write_u4(0); + writer->set_dump_start(writer->current_offset()); + writer->write_u4(0); } } // fixes up the length of the current dump record -void VM_HeapDumper::write_current_dump_record_length() { - if (writer()->is_open()) { - assert(dump_start() >= 0, "no dump start recorded"); - - // calculate the size of the dump record - julong dump_end = writer()->current_offset(); - julong dump_len = (dump_end - dump_start() - 4); +void DumperSupport::write_current_dump_record_length(DumpWriter* writer) { + if (writer->is_open()) { + julong dump_end = writer->bytes_written() + writer->bytes_unwritten(); + julong dump_len = writer->current_record_length(); // record length must fit in a u4 if (dump_len > max_juint) { @@ -1464,17 +1519,18 @@ void VM_HeapDumper::write_current_dump_record_length() { } // seek to the dump start and fix-up the length - writer()->seek_to_offset(dump_start()); - writer()->write_u4((u4)dump_len); + assert(writer->dump_start() >= 0, "no dump start recorded"); + writer->seek_to_offset(writer->dump_start()); + writer->write_u4((u4)dump_len); // adjust the total size written to keep the bytes written correct. - writer()->adjust_bytes_written(-((jlong) sizeof(u4))); + writer->adjust_bytes_written(-((jlong) sizeof(u4))); // seek to dump end so we can continue - writer()->seek_to_offset(dump_end); + writer->seek_to_offset(dump_end); // no current dump record - set_dump_start((jlong)-1); + writer->set_dump_start((jlong)-1); } } @@ -1482,33 +1538,23 @@ void VM_HeapDumper::write_current_dump_record_length() { // new segment. void VM_HeapDumper::check_segment_length() { if (writer()->is_open()) { - if (is_segmented_dump()) { - // don't use current_offset that would be too expensive on a per record basis - julong dump_end = writer()->bytes_written() + writer()->bytes_unwritten(); - assert(dump_end == (julong)writer()->current_offset(), "checking"); - julong dump_len = (dump_end - dump_start() - 4); - assert(dump_len <= max_juint, "bad dump length"); + julong dump_len = writer()->current_record_length(); - if (dump_len > HeapDumpSegmentSize) { - write_current_dump_record_length(); - write_dump_header(); - } + if (dump_len > 2UL*G) { + DumperSupport::write_current_dump_record_length(writer()); + DumperSupport::write_dump_header(writer()); } } } -// fixes up the current dump record )and writes HPROF_HEAP_DUMP_END -// record in the case of a segmented heap dump) -void VM_HeapDumper::end_of_dump() { - if (writer()->is_open()) { - write_current_dump_record_length(); +// fixes up the current dump record and writes HPROF_HEAP_DUMP_END record +void DumperSupport::end_of_dump(DumpWriter* writer) { + if (writer->is_open()) { + write_current_dump_record_length(writer); - // for segmented dump we write the end record - if (is_segmented_dump()) { - writer()->write_u1(HPROF_HEAP_DUMP_END); - writer()->write_u4(0); - writer()->write_u4(0); - } + writer->write_u1(HPROF_HEAP_DUMP_END); + writer->write_u4(0); + writer->write_u4(0); } } @@ -1686,16 +1732,17 @@ void VM_HeapDumper::do_threads() { // [HPROF_LOAD_CLASS]* // [[HPROF_FRAME]*|HPROF_TRACE]* // [HPROF_GC_CLASS_DUMP]* -// HPROF_HEAP_DUMP +// [HPROF_HEAP_DUMP_SEGMENT]* +// HPROF_HEAP_DUMP_END // // The HPROF_TRACE records represent the stack traces where the heap dump // is generated and a "dummy trace" record which does not include // any frames. The dummy trace record is used to be referenced as the // unknown object alloc site. // -// The HPROF_HEAP_DUMP record has a length following by sub-records. To allow -// the heap dump be generated in a single pass we remember the position of -// the dump length and fix it up after all sub-records have been written. +// Each HPROF_HEAP_DUMP_SEGMENT record has a length followed by sub-records. +// To allow the heap dump be generated in a single pass we remember the position +// of the dump length and fix it up after all sub-records have been written. // To generate the sub-records we iterate over the heap, writing // HPROF_GC_INSTANCE_DUMP, HPROF_GC_OBJ_ARRAY_DUMP, and HPROF_GC_PRIM_ARRAY_DUMP // records as we go. Once that is done we write records for some of the GC @@ -1722,15 +1769,9 @@ void VM_HeapDumper::doit() { set_global_dumper(); set_global_writer(); - // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1 + // Write the file header - we always use 1.0.2 size_t used = ch->used(); - const char* header; - if (used > SegmentedHeapDumpThreshold) { - set_segmented_dump(); - header = "JAVA PROFILE 1.0.2"; - } else { - header = "JAVA PROFILE 1.0.1"; - } + const char* header = "JAVA PROFILE 1.0.2"; // header is few bytes long - no chance to overflow int writer()->write_raw((void*)header, (int)strlen(header)); @@ -1750,8 +1791,8 @@ void VM_HeapDumper::doit() { // this must be called after _klass_map is built when iterating the classes above. dump_stack_traces(); - // write HPROF_HEAP_DUMP or HPROF_HEAP_DUMP_SEGMENT - write_dump_header(); + // write HPROF_HEAP_DUMP_SEGMENT + DumperSupport::write_dump_header(writer()); // Writes HPROF_GC_CLASS_DUMP records ClassLoaderDataGraph::classes_do(&do_class_dump); @@ -1759,9 +1800,9 @@ void VM_HeapDumper::doit() { check_segment_length(); // writes HPROF_GC_INSTANCE_DUMP records. - // After each sub-record is written check_segment_length will be invoked. When - // generated a segmented heap dump this allows us to check if the current - // segment exceeds a threshold and if so, then a new segment is started. + // After each sub-record is written check_segment_length will be invoked + // to check if the current segment exceeds a threshold. If so, a new + // segment is started. // The HPROF_GC_CLASS_DUMP and HPROF_GC_INSTANCE_DUMP are the vast bulk // of the heap dump. HeapObjectDumper obj_dumper(this, writer()); @@ -1785,9 +1826,8 @@ void VM_HeapDumper::doit() { StickyClassDumper class_dumper(writer()); SystemDictionary::always_strong_classes_do(&class_dumper); - // fixes up the length of the dump record. In the case of a segmented - // heap then the HPROF_HEAP_DUMP_END record is also written. - end_of_dump(); + // fixes up the length of the dump record and writes the HPROF_HEAP_DUMP_END record. + DumperSupport::end_of_dump(writer()); // Now we clear the global variables, so that a future dumper might run. clear_global_dumper(); diff --git a/hotspot/src/share/vm/services/jmm.h b/hotspot/src/share/vm/services/jmm.h index 0362e794d10..b6497cd8982 100644 --- a/hotspot/src/share/vm/services/jmm.h +++ b/hotspot/src/share/vm/services/jmm.h @@ -59,7 +59,6 @@ typedef struct { unsigned int isThreadContentionMonitoringSupported : 1; unsigned int isCurrentThreadCpuTimeSupported : 1; unsigned int isOtherThreadCpuTimeSupported : 1; - unsigned int isBootClassPathSupported : 1; unsigned int isObjectMonitorUsageSupported : 1; unsigned int isSynchronizerUsageSupported : 1; unsigned int isThreadAllocatedMemorySupported : 1; diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index 892ce92fe7e..6de924a21ab 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -121,7 +121,6 @@ void Management::init() { _optional_support.isOtherThreadCpuTimeSupported = 0; } - _optional_support.isBootClassPathSupported = 1; _optional_support.isObjectMonitorUsageSupported = 1; #if INCLUDE_SERVICES // This depends on the heap inspector diff --git a/hotspot/src/share/vm/trace/trace.xml b/hotspot/src/share/vm/trace/trace.xml index 7e357f4c106..d6d76d9398f 100644 --- a/hotspot/src/share/vm/trace/trace.xml +++ b/hotspot/src/share/vm/trace/trace.xml @@ -1,6 +1,6 @@ - + diff --git a/hotspot/src/share/vm/trace/traceBackend.cpp b/hotspot/src/share/vm/trace/traceBackend.cpp new file mode 100644 index 00000000000..a93077405e2 --- /dev/null +++ b/hotspot/src/share/vm/trace/traceBackend.cpp @@ -0,0 +1,28 @@ +/* +* 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. +* +*/ + +#include "precompiled.hpp" +#include "prims/jni.h" + +extern "C" void JNICALL trace_register_natives(JNIEnv*, jclass) {} diff --git a/hotspot/src/share/vm/trace/traceBackend.hpp b/hotspot/src/share/vm/trace/traceBackend.hpp index c65d89e41d8..36635321ad6 100644 --- a/hotspot/src/share/vm/trace/traceBackend.hpp +++ b/hotspot/src/share/vm/trace/traceBackend.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,6 +47,10 @@ public: static void on_unloading_classes(void) { } + + static void on_vm_error(bool) { + } + }; class TraceThreadData { diff --git a/hotspot/src/share/vm/trace/traceDataTypes.hpp b/hotspot/src/share/vm/trace/traceDataTypes.hpp index 31004d934b5..5df07eb1bbe 100644 --- a/hotspot/src/share/vm/trace/traceDataTypes.hpp +++ b/hotspot/src/share/vm/trace/traceDataTypes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,39 +31,36 @@ enum { CONTENT_TYPE_NONE = 0, - CONTENT_TYPE_BYTES = 1, - CONTENT_TYPE_EPOCHMILLIS = 2, - CONTENT_TYPE_MILLIS = 3, - CONTENT_TYPE_NANOS = 4, - CONTENT_TYPE_TICKS = 5, - CONTENT_TYPE_ADDRESS = 6, + CONTENT_TYPE_CLASS = 20, + CONTENT_TYPE_UTF8 = 21, + CONTENT_TYPE_THREAD = 22, + CONTENT_TYPE_STACKTRACE = 23, + CONTENT_TYPE_BYTES = 24, + CONTENT_TYPE_EPOCHMILLIS = 25, + CONTENT_TYPE_MILLIS = 26, + CONTENT_TYPE_NANOS = 27, + CONTENT_TYPE_TICKS = 28, + CONTENT_TYPE_ADDRESS = 29, + CONTENT_TYPE_PERCENTAGE = 30, - CONTENT_TYPE_OSTHREAD, - CONTENT_TYPE_JAVALANGTHREAD, - CONTENT_TYPE_STACKTRACE, - CONTENT_TYPE_CLASS, - CONTENT_TYPE_PERCENTAGE, - - JVM_CONTENT_TYPES_START = 30, - JVM_CONTENT_TYPES_END = 100 + JVM_CONTENT_TYPES_START = 33, + JVM_CONTENT_TYPES_END = 255 }; enum ReservedEvent { - EVENT_PRODUCERS, + EVENT_METADATA, EVENT_CHECKPOINT, EVENT_BUFFERLOST, - NUM_RESERVED_EVENTS + NUM_RESERVED_EVENTS = JVM_CONTENT_TYPES_END }; typedef enum ReservedEvent ReservedEvent; -typedef u8 classid; -typedef u8 stacktraceid; -typedef u8 methodid; -typedef u8 fieldid; +typedef u8 traceid; -class TraceUnicodeString; +class ModuleEntry; +class PackageEntry; +class Symbol; #endif // SHARE_VM_TRACE_TRACEDATATYPES_HPP - diff --git a/hotspot/src/share/vm/trace/traceEvent.hpp b/hotspot/src/share/vm/trace/traceEvent.hpp index a0548d76513..3a083c402ce 100644 --- a/hotspot/src/share/vm/trace/traceEvent.hpp +++ b/hotspot/src/share/vm/trace/traceEvent.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,6 @@ class TraceEvent : public StackObj { _endTime = time; } - public: TraceEvent(EventStartTime timing=TIMED) : _startTime(0), _endTime(0), @@ -76,12 +75,21 @@ class TraceEvent : public StackObj { { if (T::is_enabled()) { _started = true; - if (timing == TIMED && !T::isInstant) { - static_cast(this)->set_starttime(Tracing::time()); + if (TIMED == timing && !T::isInstant) { + static_cast(this)->set_starttime(Tracing::time()); } } } + public: + void set_starttime(const Ticks& time) { + _startTime = time.value(); + } + + void set_endtime(const Ticks& time) { + _endTime = time.value(); + } + static bool is_enabled() { return Tracing::is_event_enabled(T::eventId); } @@ -90,67 +98,68 @@ class TraceEvent : public StackObj { return _started; } - void ignoreCheck() { - DEBUG_ONLY(_ignore_check = true); - } - void commit() { if (!should_commit()) { - cancel(); - return; + DEBUG_ONLY(cancel()); + return; } - if (_endTime == 0) { + assert(!_cancelled, "Committing an event that has already been cancelled"); + if (_startTime == 0) { + static_cast(this)->set_starttime(Tracing::time()); + } else if (_endTime == 0) { static_cast(this)->set_endtime(Tracing::time()); } if (static_cast(this)->should_write()) { static_cast(this)->writeEvent(); } - set_commited(); + DEBUG_ONLY(set_commited()); } - void set_starttime(const Ticks& time) { - _startTime = time.value(); - } - - void set_endtime(const Ticks& time) { - _endTime = time.value(); - } - - TraceEventId id() const { + static TraceEventId id() { return T::eventId; } - bool is_instant() const { + static bool is_instant() { return T::isInstant; } - bool is_requestable() const { + static bool is_requestable() { return T::isRequestable; } - bool has_thread() const { + static bool has_thread() { return T::hasThread; } - bool has_stacktrace() const { + static bool has_stacktrace() { return T::hasStackTrace; } void cancel() { - assert(!_committed && !_cancelled, "event was already committed/cancelled"); + assert(!_committed && !_cancelled, + "event was already committed/cancelled"); DEBUG_ONLY(_cancelled = true); } - void set_commited() { - assert(!_committed, "event has already been committed"); - DEBUG_ONLY(_committed = true); - } - ~TraceEvent() { if (_started) { - assert(_ignore_check || _committed || _cancelled, "event was not committed/cancelled"); + assert(_ignore_check || _committed || _cancelled, + "event was not committed/cancelled"); } } + +#ifdef ASSERT + protected: + void ignoreCheck() { + _ignore_check = true; + } + + private: + void set_commited() { + assert(!_committed, "event has already been committed"); + _committed = true; + } +#endif // ASSERT }; #endif // INCLUDE_TRACE diff --git a/hotspot/src/share/vm/trace/traceEventClasses.xsl b/hotspot/src/share/vm/trace/traceEventClasses.xsl index 41d3a446a9e..16b30c7b909 100644 --- a/hotspot/src/share/vm/trace/traceEventClasses.xsl +++ b/hotspot/src/share/vm/trace/traceEventClasses.xsl @@ -1,6 +1,6 @@ - + - + - - + - - - + type="const char*" sizeop="sizeof_utf(%)"/> + type="const Symbol*" sizeop="sizeof(u8)"/> + type="const Klass*" sizeop="sizeof(u8)"/> + + + + + type="const Method*" sizeop="sizeof(u8)"/> - - - - - - - - + + - + sizeop="sizeof(u8)"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp index 8d6a9398764..f0aa8371f17 100644 --- a/hotspot/src/share/vm/utilities/debug.cpp +++ b/hotspot/src/share/vm/utilities/debug.cpp @@ -51,9 +51,14 @@ #include "services/heapDumper.hpp" #include "utilities/defaultStream.hpp" #include "utilities/events.hpp" +#include "utilities/macros.hpp" #include "utilities/top.hpp" #include "utilities/vmError.hpp" +#if INCLUDE_TRACE +#include "trace/tracing.hpp" +#endif + #ifndef ASSERT # ifdef _DEBUG // NOTE: don't turn the lines below into a comment -- if you're getting @@ -280,6 +285,12 @@ void report_out_of_shared_space(SharedSpaceType shared_space) { exit(2); } +static void notify_tracing() { +#if INCLUDE_TRACE + Tracing::on_vm_error(true); +#endif +} + void report_insufficient_metaspace(size_t required_size) { warning("\nThe MaxMetaspaceSize of " SIZE_FORMAT " bytes is not large enough.\n" "Either don't specify the -XX:MaxMetaspaceSize=\n" @@ -302,6 +313,8 @@ void report_java_out_of_memory(const char* message) { HeapDumper::dump_heap_from_oome(); } + notify_tracing(); + if (OnOutOfMemoryError && OnOutOfMemoryError[0]) { VMError::report_java_out_of_memory(message); } diff --git a/hotspot/src/share/vm/utilities/dtrace_disabled.hpp b/hotspot/src/share/vm/utilities/dtrace_disabled.hpp index 40093592791..44f49f63afe 100644 --- a/hotspot/src/share/vm/utilities/dtrace_disabled.hpp +++ b/hotspot/src/share/vm/utilities/dtrace_disabled.hpp @@ -1084,6 +1084,12 @@ #define HOTSPOT_JNI_UNREGISTERNATIVES_RETURN(arg0) #define HOTSPOT_JNI_UNREGISTERNATIVES_RETURN_ENABLED() 0 +/* Modules */ +#define HOTSPOT_JNI_GETMODULE_ENTRY(arg0, arg1) +#define HOTSPOT_JNI_GETMODULE_ENTRY_ENABLED() 0 +#define HOTSPOT_JNI_GETMODULE_RETURN(arg0) +#define HOTSPOT_JNI_GETMODULE_RETURN_ENABLED() + #else /* !defined(DTRACE_ENABLED) */ #error This file should only be included when dtrace is not enabled #endif /* !defined(DTRACE_ENABLED) */ diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp index 933cf339661..a2780fecca5 100644 --- a/hotspot/src/share/vm/utilities/growableArray.hpp +++ b/hotspot/src/share/vm/utilities/growableArray.hpp @@ -396,7 +396,7 @@ template class GrowableArray : public GenericGrowableArray { int max = length() - 1; while (max >= min) { - int mid = (max + min) / 2; + int mid = (int)(((uint)max + min) / 2); E value = at(mid); int diff = compare(key, value); if (diff > 0) { diff --git a/hotspot/src/share/vm/utilities/hashtable.cpp b/hotspot/src/share/vm/utilities/hashtable.cpp index 10f4456274a..8af6156ed45 100644 --- a/hotspot/src/share/vm/utilities/hashtable.cpp +++ b/hotspot/src/share/vm/utilities/hashtable.cpp @@ -383,4 +383,9 @@ template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; template class BasicHashtable; +#if INCLUDE_TRACE +template class Hashtable; +template class HashtableEntry; +template class BasicHashtable; +#endif template class BasicHashtable; diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp index 3bafaec300a..de62ba3a6be 100644 --- a/hotspot/src/share/vm/utilities/ostream.cpp +++ b/hotspot/src/share/vm/utilities/ostream.cpp @@ -706,8 +706,10 @@ void defaultStream::start_log() { for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) { // Print in two stages to avoid problems with long // keys/values. + assert(p->key() != NULL, "p->key() is NULL"); text->print_raw(p->key()); text->put('='); + assert(p->value() != NULL, "p->value() is NULL"); text->print_raw_cr(p->value()); } xs->tail("properties"); diff --git a/hotspot/src/share/vm/utilities/utf8.cpp b/hotspot/src/share/vm/utilities/utf8.cpp index d7a6043097a..93ad3e23d89 100644 --- a/hotspot/src/share/vm/utilities/utf8.cpp +++ b/hotspot/src/share/vm/utilities/utf8.cpp @@ -333,6 +333,68 @@ jint UTF8::get_supplementary_character(const unsigned char* str) { + ((str[4] & 0x0f) << 6) + (str[5] & 0x3f); } +bool UTF8::is_legal_utf8(const unsigned char* buffer, int length, + bool version_leq_47) { + int i = 0; + int count = length >> 2; + for (int k=0; k= 128 (highest bit 1) for v == 0 or v >= 128. + unsigned char res = b0 | b0 - 1 | + b1 | b1 - 1 | + b2 | b2 - 1 | + b3 | b3 - 1; + if (res >= 128) break; + i += 4; + } + for(; i < length; i++) { + unsigned short c; + // no embedded zeros + if (buffer[i] == 0) return false; + if(buffer[i] < 128) { + continue; + } + if ((i + 5) < length) { // see if it's legal supplementary character + if (UTF8::is_supplementary_character(&buffer[i])) { + c = UTF8::get_supplementary_character(&buffer[i]); + i += 5; + continue; + } + } + switch (buffer[i] >> 4) { + default: break; + case 0x8: case 0x9: case 0xA: case 0xB: case 0xF: + return false; + case 0xC: case 0xD: // 110xxxxx 10xxxxxx + c = (buffer[i] & 0x1F) << 6; + i++; + if ((i < length) && ((buffer[i] & 0xC0) == 0x80)) { + c += buffer[i] & 0x3F; + if (version_leq_47 || c == 0 || c >= 0x80) { + break; + } + } + return false; + case 0xE: // 1110xxxx 10xxxxxx 10xxxxxx + c = (buffer[i] & 0xF) << 12; + i += 2; + if ((i < length) && ((buffer[i-1] & 0xC0) == 0x80) && ((buffer[i] & 0xC0) == 0x80)) { + c += ((buffer[i-1] & 0x3F) << 6) + (buffer[i] & 0x3F); + if (version_leq_47 || c >= 0x800) { + break; + } + } + return false; + } // end of switch + } // end of for + return true; +} + //------------------------------------------------------------------------------------- bool UNICODE::is_latin1(jchar c) { diff --git a/hotspot/src/share/vm/utilities/utf8.hpp b/hotspot/src/share/vm/utilities/utf8.hpp index 161eb410f40..1a30cb456fc 100644 --- a/hotspot/src/share/vm/utilities/utf8.hpp +++ b/hotspot/src/share/vm/utilities/utf8.hpp @@ -73,6 +73,9 @@ class UTF8 : AllStatic { static bool equal(const jbyte* base1, int length1, const jbyte* base2,int length2); static bool is_supplementary_character(const unsigned char* str); static jint get_supplementary_character(const unsigned char* str); + + static bool is_legal_utf8(const unsigned char* buffer, int length, + bool version_leq_47); }; diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index ee6ad0e5ddb..2d0942349be 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -1121,6 +1121,10 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt if (first_error_tid == -1 && Atomic::cmpxchg_ptr(mytid, &first_error_tid, -1) == -1) { + // Initialize time stamps to use the same base. + out.time_stamp().update_to(1); + log.time_stamp().update_to(1); + _id = id; _message = message; _thread = thread; diff --git a/hotspot/test/TEST.ROOT b/hotspot/test/TEST.ROOT index 8dd7c84e9ee..55979b0a554 100644 --- a/hotspot/test/TEST.ROOT +++ b/hotspot/test/TEST.ROOT @@ -32,8 +32,8 @@ keys=cte_test jcmd nmt regression gc stress groups=TEST.groups [closed/TEST.groups] requires.properties=sun.arch.data.model -# Tests using jtreg 4.1 b12 features -requiredVersion=4.1 b12 +# Tests using jtreg 4.2 b01 features +requiredVersion=4.2 b01 # Path to libraries in the topmost test directory. This is needed so @library # does not need ../../ notation to reach them diff --git a/hotspot/test/TEST.groups b/hotspot/test/TEST.groups index f7d983f5a8f..11b95da776b 100644 --- a/hotspot/test/TEST.groups +++ b/hotspot/test/TEST.groups @@ -297,7 +297,8 @@ hotspot_compiler_3 = \ compiler/types/ \ compiler/uncommontrap/ \ compiler/unsafe/ \ - -compiler/intrinsics/bmi/verifycode \ + -compiler/intrinsics/adler32 \ + -compiler/intrinsics/bmi \ -compiler/intrinsics/mathexact \ -compiler/intrinsics/multiplytolen \ -compiler/intrinsics/sha \ diff --git a/hotspot/test/compiler/c1/CanonicalizeArrayLength.java b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java new file mode 100644 index 00000000000..ee2649a3b3a --- /dev/null +++ b/hotspot/test/compiler/c1/CanonicalizeArrayLength.java @@ -0,0 +1,155 @@ +/* + * 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 8150102 8150514 8150534 + * @summary C1 crashes in Canonicalizer::do_ArrayLength() after fix for JDK-8150102 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:+PatchALot CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=0 CanonicalizeArrayLength + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:CompileThreshold=100 -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -XX:-BackgroundCompilation -XX:ScavengeRootsInCode=1 CanonicalizeArrayLength + */ +public class CanonicalizeArrayLength { + int[] arr = new int[42]; + int[] arrNull = null; + + final int[] finalArr = new int[42]; + final int[] finalArrNull = null; + + static int[] staticArr = new int[42]; + static int[] staticArrNull = null; + + static final int[] staticFinalArr = new int[42]; + static final int[] staticFinalArrNull = null; + + public static void main(String... args) { + CanonicalizeArrayLength t = new CanonicalizeArrayLength(); + for (int i = 0; i < 20000; i++) { + if (t.testLocal() != 42) + throw new IllegalStateException(); + if (t.testLocalNull() != 42) + throw new IllegalStateException(); + if (t.testField() != 42) + throw new IllegalStateException(); + if (t.testFieldNull() != 42) + throw new IllegalStateException(); + if (t.testFinalField() != 42) + throw new IllegalStateException(); + if (t.testFinalFieldNull() != 42) + throw new IllegalStateException(); + if (t.testStaticField() != 42) + throw new IllegalStateException(); + if (t.testStaticFieldNull() != 42) + throw new IllegalStateException(); + if (t.testStaticFinalField() != 42) + throw new IllegalStateException(); + if (t.testStaticFinalFieldNull() != 42) + throw new IllegalStateException(); + } + } + + int testField() { + try { + return arr.length; + } catch (Throwable t) { + return -1; + } + } + + int testFieldNull() { + try { + return arrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testFinalField() { + try { + return finalArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testFinalFieldNull() { + try { + return finalArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testStaticField() { + try { + return staticArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testStaticFieldNull() { + try { + return staticArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testStaticFinalField() { + try { + return staticFinalArr.length; + } catch (Throwable t) { + return -1; + } + } + + int testStaticFinalFieldNull() { + try { + return staticFinalArrNull.length; + } catch (Throwable t) { + return 42; + } + } + + int testLocal() { + int[] arr = new int[42]; + try { + return arr.length; + } catch (Throwable t) { + return -1; + } + } + + int testLocalNull() { + int[] arrNull = null; + try { + return arrNull.length; + } catch (Throwable t) { + return 42; + } + } + + +} diff --git a/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java b/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java new file mode 100644 index 00000000000..3c8f153a17c --- /dev/null +++ b/hotspot/test/compiler/c2/TestDominatingDeadCheckCast.java @@ -0,0 +1,91 @@ +/* + * 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 8149797 + * @summary node replaced by dominating dead cast during parsing + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:TypeProfileLevel=200 -XX:CompileCommand=dontinline,TestDominatingDeadCheckCast::not_inlined TestDominatingDeadCheckCast + * + */ + +public class TestDominatingDeadCheckCast { + + static class A { + int f; + } + + static class B extends A { + } + + static A not_inlined() { + return new A(); + } + + static void inlined(A param) { + param.f = 42; + } + + static A field; + + static void test(boolean flag1, boolean flag2, boolean flag3, boolean flag4, boolean flag5) { + // Go through memory rather than through a local to defeat C2's replace_in_map + field = not_inlined(); + // Speculation adds a CheckCast on entry of this inlined + // method for the parameter + inlined(field); + // Walk up the dominators is depth limited, make the CheckCast + // above unreachable from the last inlined call + if (flag1) { + if (flag2) { + if (flag3) { + // Speculation adds a CheckCast on entry of this + // inlined method for the parameter. This + // CheckCast is replaced by the CheckCast of the + // first inlined method call but the replaced + // CheckCast is still around during parsing. + inlined(field); + // Same as above, some useless control + if (flag4) { + if (flag5) { + // Speculation adds a CheckCast on entry + // of this inlined method for the + // parameter. This CheckCast is replaced + // by the dead CheckCast of the previous + // inlined() call. + inlined(field); + } + } + } + } + } + } + + static public void main(String[] args) { + field = new A(); + for (int i = 0; i < 20000; i++) { + test(true, true, true, true, true); + } + } +} diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java index 283003afde6..ff5f70eceaa 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityBase.java @@ -24,25 +24,26 @@ /* * @test TestCompilerDirectivesCompatibilityBase * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityBase * @summary Test compiler control compatibility with compile command */ +import compiler.testlibrary.CompilerUtils; +import compiler.whitebox.CompilerWhiteBoxTest; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; - import org.testng.annotations.Test; import org.testng.Assert; - import sun.hotspot.WhiteBox; import java.io.BufferedReader; @@ -64,32 +65,38 @@ public class TestCompilerDirectivesCompatibilityBase { method = getMethod(TestCompilerDirectivesCompatibilityBase.class, "helper"); nomatch = getMethod(TestCompilerDirectivesCompatibilityBase.class, "another"); - testCompatibility(executor); + int[] levels = CompilerUtils.getAvailableCompilationLevels(); + for (int complevel : levels) { + // Only test the major compilers, ignore profiling levels + if (complevel == CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE || complevel == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION){ + testCompatibility(executor, complevel); + } + } } - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default off expect(!WB.getBooleanVMFlag("PrintAssembly")); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it on executor.execute("Compiler.directives_add " + control_on); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); } public void expect(boolean test) throws Exception { diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java index a2922c8a2d9..661b06036c0 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOff.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityCommandOff * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:-PrintAssembly -XX:CompileCommand=option,*.helper,bool,PrintAssembly,false * -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityCommandOff * @summary Test compiler control compatibility with compile command @@ -55,27 +56,27 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityCommandOff extends TestCompilerDirectivesCompatibilityBase { - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default off - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it on executor.execute("Compiler.directives_add " + control_on); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is false again executor.execute("Compiler.directives_remove"); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(!WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(!WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java index 0123c282b11..8fd0eec6d53 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityCommandOn.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityCommandOn * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:-PrintAssembly -XX:CompileCommand=print,*.* -XX:+WhiteBoxAPI * TestCompilerDirectivesCompatibilityCommandOn * @summary Test compiler control compatibility with compile command @@ -55,27 +56,27 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityCommandOn extends TestCompilerDirectivesCompatibilityBase{ - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default on - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it off executor.execute("Compiler.directives_add " + control_off); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java index 37c8d2b0181..8ec1fc9ee4e 100644 --- a/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java +++ b/hotspot/test/compiler/compilercontrol/TestCompilerDirectivesCompatibilityFlag.java @@ -24,16 +24,17 @@ /* * @test TestCompilerDirectivesCompatibilityFlag * @bug 8137167 - * @library /testlibrary /test/lib + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @build sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions * -XX:+PrintAssembly -XX:+WhiteBoxAPI TestCompilerDirectivesCompatibilityFlag * @summary Test compiler control compatibility with compile command */ @@ -54,28 +55,28 @@ import java.util.Objects; public class TestCompilerDirectivesCompatibilityFlag extends TestCompilerDirectivesCompatibilityBase { - public void testCompatibility(CommandExecutor executor) throws Exception { + public void testCompatibility(CommandExecutor executor, int comp_level) throws Exception { // Call all validation twice to catch error when overwriting a directive // Flag is default on expect(WB.getBooleanVMFlag("PrintAssembly")); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // load directives that turn it off executor.execute("Compiler.directives_add " + control_off); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(!WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(!WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); // remove and see that it is true again executor.execute("Compiler.directives_remove"); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); - expect(WB.shouldPrintAssembly(method)); - expect(WB.shouldPrintAssembly(nomatch)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); + expect(WB.shouldPrintAssembly(method, comp_level)); + expect(WB.shouldPrintAssembly(nomatch, comp_level)); } } diff --git a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java index 2e1c2013b43..04d8ada9319 100644 --- a/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java +++ b/hotspot/test/compiler/compilercontrol/share/AbstractTestBase.java @@ -51,8 +51,9 @@ public abstract class AbstractTestBase { for (int i = 0; !md.isValid() && i < ATTEMPTS; i++) { md = METHOD_GEN.generateRandomDescriptor(exec); } - if (!md.isValid()) { - System.out.println("WARN: Using predefined pattern"); + if (!md.isValid() || "any.method()".matches(md.getRegexp())) { + /* if we haven't got a valid pattern or it matches any method + leading to timeouts, then use plain standard descriptor */ md = MethodGenerator.commandDescriptor(exec); } return md; diff --git a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java index f4109d65810..24a8222f23f 100644 --- a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java +++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java @@ -22,6 +22,8 @@ */ import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; @@ -35,11 +37,11 @@ import jdk.test.lib.*; * @modules java.base/sun.misc * java.management * java.base/jdk.internal + * @ignore 8132924 * @compile -XDignore.symbol.file java/lang/Object.java TestMonomorphicObjectCall.java * @run main TestMonomorphicObjectCall */ public class TestMonomorphicObjectCall { - final static String testClasses = System.getProperty("test.classes") + File.separator; private static void callFinalize(Object object) throws Throwable { // Call modified version of java.lang.Object::finalize() that is @@ -50,6 +52,9 @@ public class TestMonomorphicObjectCall { public static void main(String[] args) throws Throwable { if (args.length == 0) { + byte[] bytecode = Files.readAllBytes(Paths.get(System.getProperty("test.classes") + File.separator + + "java" + File.separator + "lang" + File.separator + "Object.class")); + ClassFileInstaller.writeClassToDisk("java.lang.Object", bytecode, "mods/java.base"); // Execute new instance with modified java.lang.Object executeTestJvm(); } else { @@ -62,7 +67,7 @@ public class TestMonomorphicObjectCall { // Execute test with modified version of java.lang.Object // in -Xbootclasspath. String[] vmOpts = new String[] { - "-Xbootclasspath/p:" + testClasses, + "-Xpatch:mods", "-Xcomp", "-XX:+IgnoreUnrecognizedVMOptions", "-XX:-VerifyDependencies", diff --git a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java index a59e412bc96..7bba5308971 100644 --- a/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java +++ b/hotspot/test/compiler/intrinsics/string/TestStringIntrinsics2.java @@ -494,6 +494,29 @@ public class TestStringIntrinsics2 { return s.indexOf("1"); } + static String text1UTF16 = "A" + "\u05d0" + "\u05d1" + "B"; + + @Test(role = Role.TEST_ENTRY) + public static void test_indexOf_immUTF16() { + assertEquals( 3, indexOf_imm1Latin1_needle(text1UTF16), "test_indexOf_immUTF16"); + assertEquals( 1, indexOf_imm1UTF16_needle(text1UTF16), "test_indexOf_immUTF16"); + assertEquals( 1, indexOf_immUTF16_needle(text1UTF16), "test_indexOf_immUTF16"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_imm1Latin1_needle(String s) { + return s.indexOf("B"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_imm1UTF16_needle(String s) { + return s.indexOf("\u05d0"); + } + + @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "A" + "\u05d0" + "\u05d1" + "B" }) + static int indexOf_immUTF16_needle(String s) { + return s.indexOf("\u05d0" + "\u05d1"); + } @Test(role = Role.TEST_HELPER, compileAt = 4, warmup = 1, warmupArgs = { "abc", "abcd" }) public static int asmStringCompareTo(String a, String b) { diff --git a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java index e650aa558c1..78ee7131476 100644 --- a/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java +++ b/hotspot/test/compiler/jsr292/CallSiteDepContextTest.java @@ -24,13 +24,25 @@ /** * @test * @bug 8057967 + * @modules java.base/jdk.internal.org.objectweb.asm + * @library patches + * @build java.base/java.lang.invoke.MethodHandleHelper * @run main/bootclasspath -Xbatch -XX:+IgnoreUnrecognizedVMOptions -Xlog:classunload * -XX:+PrintCompilation -XX:+TraceDependencies -XX:+TraceReferenceGC - * -verbose:gc java.lang.invoke.CallSiteDepContextTest + * -verbose:gc compiler.jsr292.CallSiteDepContextTest */ -package java.lang.invoke; -import java.lang.ref.*; +package compiler.jsr292; + +import java.lang.invoke.CallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.MutableCallSite; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; import java.lang.reflect.Field; import jdk.internal.org.objectweb.asm.*; @@ -40,10 +52,10 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; public class CallSiteDepContextTest { static final Unsafe UNSAFE = Unsafe.getUnsafe(); - static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP; static final String CLASS_NAME = "java/lang/invoke/Test"; static final String METHOD_NAME = "m"; - static final MethodType TYPE = MethodType.methodType(int.class); + static final MethodType TYPE = MethodType.methodType(int.class); static MutableCallSite mcs; static MethodHandle bsmMH; @@ -77,7 +89,8 @@ public class CallSiteDepContextTest { mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, METHOD_NAME, TYPE.toMethodDescriptorString(), null, null); mv.visitCode(); Handle bsm = new Handle(H_INVOKESTATIC, - "java/lang/invoke/CallSiteDepContextTest", "bootstrap", + CallSiteDepContextTest.class.getName().replace(".", "/"), + "bootstrap", bsmMH.type().toMethodDescriptorString()); mv.visitInvokeDynamicInsn("methodName", TYPE.toMethodDescriptorString(), bsm); mv.visitInsn(IRETURN); @@ -99,9 +112,9 @@ public class CallSiteDepContextTest { } } - public static void testHiddenDepField() throws Exception { + public static void testHiddenDepField() { try { - Field f = MethodHandleNatives.CallSiteContext.class.getDeclaredField("vmdependencies"); + Field f = MethodHandleHelper.MHN_CALL_SITE_CONTEXT_CLASS.getDeclaredField("vmdependencies"); throw new AssertionError("Context.dependencies field should be hidden"); } catch(NoSuchFieldException e) { /* expected */ } } @@ -111,8 +124,8 @@ public class CallSiteDepContextTest { Class cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null); MethodHandle[] mhs = new MethodHandle[] { - LOOKUP.findStatic(cls1, METHOD_NAME, TYPE), - LOOKUP.findStatic(cls2, METHOD_NAME, TYPE) + LOOKUP.findStatic(cls1, METHOD_NAME, TYPE), + LOOKUP.findStatic(cls2, METHOD_NAME, TYPE) }; mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE)); @@ -198,3 +211,4 @@ public class CallSiteDepContextTest { System.out.println("TEST PASSED"); } } + diff --git a/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java b/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java new file mode 100644 index 00000000000..a59f962fd22 --- /dev/null +++ b/hotspot/test/compiler/jsr292/ContinuousCallSiteTargetChange.java @@ -0,0 +1,103 @@ +/* + * 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 + * @library /testlibrary + * @run main ContinuousCallSiteTargetChange + */ +import java.lang.invoke.*; +import jdk.test.lib.*; + +public class ContinuousCallSiteTargetChange { + static void testServer() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-server", "-XX:-TieredCompilation", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "ContinuousCallSiteTargetChange$Test", "100"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("made not compilable"); + analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff"); + } + + static void testClient() throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-client", "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "ContinuousCallSiteTargetChange$Test", "100"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("made not compilable"); + analyzer.shouldNotContain("decompile_count > PerMethodRecompilationCutoff"); + } + + public static void main(String[] args) throws Exception { + testServer(); + testClient(); + } + + static class Test { + static final MethodType mt = MethodType.methodType(void.class); + static final CallSite cs = new MutableCallSite(mt); + + static final MethodHandle mh = cs.dynamicInvoker(); + + static void f() { + } + + static void test1() throws Throwable { + mh.invokeExact(); + } + + static void test2() throws Throwable { + cs.getTarget().invokeExact(); + } + + static void iteration() throws Throwable { + MethodHandle mh1 = MethodHandles.lookup().findStatic(ContinuousCallSiteTargetChange.Test.class, "f", mt); + cs.setTarget(mh1); + for (int i = 0; i < 20_000; i++) { + test1(); + test2(); + } + } + + public static void main(String[] args) throws Throwable { + int iterations = Integer.parseInt(args[0]); + for (int i = 0; i < iterations; i++) { + iteration(); + } + } + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java index 70665d5f604..e9f2f46a8f4 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/Agent.java @@ -20,28 +20,39 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + +package compiler.jsr292.NonInlinedCall; + import java.io.File; import java.io.PrintStream; import java.util.Arrays; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.OutputAnalyzer; + public class Agent { public static void main(String[] args) throws Exception { String jarName = args[0]; String className = args[1]; String manifestName = "manifest.mf"; - System.out.println("Creating "+manifestName); + System.out.println("Creating " + manifestName); try (PrintStream out = new PrintStream(new File(manifestName))) { out.println("Premain-Class: " + className); out.println("Can-Redefine-Classes: true"); } - System.out.println("Building "+jarName); - String[] jarArgs = new String[] {"-cfm", jarName, manifestName }; - System.out.println("Running jar " + Arrays.toString(jarArgs)); - sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar"); - if (!jarTool.run(jarArgs)) { - throw new Error("jar failed: args=" + Arrays.toString(args)); - } + System.out.println("Building " + jarName); + JDKToolLauncher jar = JDKToolLauncher + .create("jar") + .addToolArg("-cfm") + .addToolArg(jarName) + .addToolArg(manifestName); + + System.out.println("Running jar " + Arrays.toString(jar.getCommand())); + + ProcessBuilder pb = new ProcessBuilder(jar.getCommand()); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); } } diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java index 49ce05490fd..fc705850e00 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/GCTest.java @@ -24,29 +24,38 @@ /* * @test * @bug 8072008 - * @library /testlibrary /test/lib - * @compile GCTest.java NonInlinedReinvoker.java - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * java.lang.invoke.GCTest - * java.lang.invoke.GCTest$T - * java.lang.invoke.NonInlinedReinvoker - * jdk.test.lib.Asserts - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 - * java.lang.invoke.GCTest + * @library /testlibrary /test/lib ../patches + * @modules java.base/jdk.internal.vm.annotation + * @build java.base/java.lang.invoke.MethodHandleHelper + * @build sun.hotspot.WhiteBox + * @run main/bootclasspath -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * -XX:+FoldStableValues + * compiler.jsr292.NonInlinedCall.GCTest */ -package java.lang.invoke; -import sun.hotspot.WhiteBox; +package compiler.jsr292.NonInlinedCall; + +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodHandleHelper.NonInlinedReinvoker; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandle; + +import java.lang.invoke.MethodType; +import java.lang.ref.PhantomReference; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; + import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.Stable; -import java.lang.ref.*; + +import sun.hotspot.WhiteBox; + import static jdk.test.lib.Asserts.*; public class GCTest { - static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP; static class T { static int f1() { return 0; } @@ -54,15 +63,15 @@ public class GCTest { } static @Stable MethodHandle mh; - static PhantomReference lform; + static PhantomReference lform; - static final ReferenceQueue rq = new ReferenceQueue<>(); + static final ReferenceQueue rq = new ReferenceQueue<>(); static final WhiteBox WB = WhiteBox.getWhiteBox(); @DontInline static int invokeBasic() { try { - return (int) mh.invokeBasic(); + return MethodHandleHelper.invokeBasicI(mh); } catch (Throwable e) { throw new Error(e); } @@ -80,7 +89,7 @@ public class GCTest { LOOKUP.findStatic(T.class, "f1", MethodType.methodType(int.class))); // Monitor LambdaForm GC - lform = new PhantomReference<>(mh.form, rq); + lform = new PhantomReference<>(MethodHandleHelper.getLambdaForm(mh), rq); test(0); WB.clearInlineCaches(); diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java index 02bdef91a10..225db6018ce 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/InvokeTest.java @@ -24,30 +24,33 @@ /* * @test * @bug 8072008 - * @library /testlibrary /test/lib - * @compile InvokeTest.java NonInlinedReinvoker.java - * @run main ClassFileInstaller sun.hotspot.WhiteBox - * sun.hotspot.WhiteBox$WhiteBoxPermission - * java.lang.invoke.InvokeTest - * java.lang.invoke.InvokeTest$T - * java.lang.invoke.InvokeTest$P1 - * java.lang.invoke.InvokeTest$P2 - * java.lang.invoke.InvokeTest$I - * java.lang.invoke.NonInlinedReinvoker - * jdk.test.lib.Asserts - * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 - * java.lang.invoke.InvokeTest + * @library /testlibrary /test/lib / ../patches + * @modules java.base/jdk.internal.vm.annotation + * @build java.base/java.lang.invoke.MethodHandleHelper + * @build sun.hotspot.WhiteBox + * @build compiler.jsr292.NonInlinedCall.InvokeTest + * @run main/bootclasspath -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * compiler.jsr292.NonInlinedCall.InvokeTest */ -package java.lang.invoke; + +package compiler.jsr292.NonInlinedCall; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodHandleHelper.NonInlinedReinvoker; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; + +import jdk.internal.vm.annotation.DontInline; import sun.hotspot.WhiteBox; -import jdk.internal.vm.annotation.DontInline; + import static jdk.test.lib.Asserts.*; public class InvokeTest { - static MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP; static final MethodHandle virtualMH; // invokevirtual T.f1 static final MethodHandle staticMH; // invokestatic T.f2 @@ -136,7 +139,7 @@ public class InvokeTest { @DontInline static void invokeBasic() { try { - Class cls = (Class)basicMH.invokeBasic(); + Class cls = (Class)MethodHandleHelper.invokeBasicL(basicMH); assertEquals(cls, T.class); } catch (Throwable e) { throw new Error(e); @@ -180,7 +183,10 @@ public class InvokeTest { static void testInterface() { System.out.println("linkToInterface"); - // Monomorphic case (optimized virtual call) + // Monomorphic case (optimized virtual call), concrete target method + run(() -> linkToInterface(new P1(), P1.class)); + + // Monomorphic case (optimized virtual call), default target method run(() -> linkToInterface(new T(), I.class)); // Megamorphic case (virtual call) diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java index 51481e87bb4..6607ec19c6c 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java +++ b/hotspot/test/compiler/jsr292/NonInlinedCall/RedefineTest.java @@ -24,35 +24,46 @@ /* * @test * @bug 8072008 - * @library /testlibrary /test/lib - * @compile -XDignore.symbol.file RedefineTest.java Agent.java + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.misc + * java.base/jdk.internal.vm.annotation + * @library /testlibrary /test/lib / ../patches + * @build sun.hotspot.WhiteBox + * @build java.base/java.lang.invoke.MethodHandleHelper + * @build compiler.jsr292.NonInlinedCall.RedefineTest + * @run main compiler.jsr292.NonInlinedCall.Agent agent.jar compiler.jsr292.NonInlinedCall.RedefineTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * java.lang.invoke.RedefineTest - * Agent - * @run main Agent agent.jar java.lang.invoke.RedefineTest - * @run main/othervm -Xbootclasspath/a:. -javaagent:agent.jar - * -XX:+IgnoreUnrecognizedVMOptions - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 - * java.lang.invoke.RedefineTest + * compiler.jsr292.NonInlinedCall.RedefineTest + * @run main/bootclasspath -javaagent:agent.jar + * -XX:+IgnoreUnrecognizedVMOptions + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -Xbatch -XX:-TieredCompilation -XX:CICompilerCount=1 + * compiler.jsr292.NonInlinedCall.RedefineTest */ -package java.lang.invoke; + +package compiler.jsr292.NonInlinedCall; import sun.hotspot.WhiteBox; -import sun.misc.Unsafe; -import jdk.internal.org.objectweb.asm.*; -import jdk.internal.vm.annotation.DontInline; + import java.lang.instrument.ClassDefinition; import java.lang.instrument.Instrumentation; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodType; + +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.org.objectweb.asm.*; import static jdk.internal.org.objectweb.asm.Opcodes.*; public class RedefineTest { - static final MethodHandles.Lookup LOOKUP = MethodHandles.Lookup.IMPL_LOOKUP; + static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP; static final Unsafe UNSAFE = Unsafe.getUnsafe(); - static final String NAME = "java/lang/invoke/RedefineTest$T"; + static final String NAME = "compiler/jsr292/NonInlinedCall/RedefineTest$T"; static Class getClass(int r) { byte[] classFile = getClassFile(r); diff --git a/hotspot/test/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java b/hotspot/test/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java new file mode 100644 index 00000000000..a4732624a3a --- /dev/null +++ b/hotspot/test/compiler/jsr292/patches/java.base/java/lang/invoke/MethodHandleHelper.java @@ -0,0 +1,92 @@ +/* + * 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 java.lang.invoke; + +import java.lang.invoke.MethodHandles.Lookup; +import jdk.internal.vm.annotation.DontInline; +import jdk.internal.vm.annotation.ForceInline; +/** + * Helper class to inject into java.lang.invoke that provides access to + * package-private methods in this package. + */ + +public class MethodHandleHelper { + + private MethodHandleHelper() { } + + public static final Lookup IMPL_LOOKUP = Lookup.IMPL_LOOKUP; + public static final Class MHN_CALL_SITE_CONTEXT_CLASS + = MethodHandleNatives.CallSiteContext.class; + + public static void customize(MethodHandle mh) { + mh.customize(); + } + + @ForceInline + public static Object invokeBasicL(MethodHandle mh) throws Throwable { + return mh.invokeBasic(); + } + + @ForceInline + public static int invokeBasicI(MethodHandle mh) throws Throwable { + return (int) mh.invokeBasic(); + } + + public static MethodHandle varargsArray(int nargs) { + return MethodHandleImpl.varargsArray(nargs); + } + + public static MethodHandle varargsArray(Class arrayType, int nargs) { + return MethodHandleImpl.varargsArray(arrayType, nargs); + } + + public static LambdaForm getLambdaForm(MethodHandle mh) { + return mh.form; + } + + public static class NonInlinedReinvoker extends DelegatingMethodHandle { + private final MethodHandle target; + + private NonInlinedReinvoker(MethodHandle target, LambdaForm lf) { + super(target.type(), lf); + this.target = target; + } + @Override + public MethodHandle getTarget() { + return target; + } + + @Override + public MethodHandle asTypeUncached(MethodType newType) { + return asTypeCache = target.asType(newType); + } + + public static MethodHandle make(MethodHandle target) { + LambdaForm lform = DelegatingMethodHandle.makeReinvokerForm( + target, -1, DelegatingMethodHandle.class, "reinvoker.dontInline", + /*forceInline=*/false, DelegatingMethodHandle.NF_getTarget, null); + return new NonInlinedReinvoker(target, lform); + } + } +} diff --git a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java index e74fc43ca01..993cbba8a18 100644 --- a/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java +++ b/hotspot/test/compiler/jvmci/SecurityRestrictionsTest.java @@ -27,25 +27,26 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ./common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xbootclasspath/a:. + * @library common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @run main/othervm -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI * compiler.jvmci.SecurityRestrictionsTest * NO_SEC_MAN - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI * compiler.jvmci.SecurityRestrictionsTest * NO_PERM - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI * compiler.jvmci.SecurityRestrictionsTest * ALL_PERM - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockExperimentalVMOptions * -XX:+EnableJVMCI * compiler.jvmci.SecurityRestrictionsTest * NO_JVMCI_ACCESS_PERM - * @run main/othervm -XX:+UnlockExperimentalVMOptions -Xbootclasspath/a:. + * @run main/othervm -XX:+UnlockExperimentalVMOptions * -XX:-EnableJVMCI * compiler.jvmci.SecurityRestrictionsTest * NO_JVMCI diff --git a/hotspot/test/compiler/jvmci/code/DataPatchTest.java b/hotspot/test/compiler/jvmci/code/DataPatchTest.java index af438a306bf..60e46915202 100644 --- a/hotspot/test/compiler/jvmci/code/DataPatchTest.java +++ b/hotspot/test/compiler/jvmci/code/DataPatchTest.java @@ -24,7 +24,14 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" - * @compile CodeInstallationTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @library / + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.code.site + * jdk.vm.ci/jdk.vm.ci.runtime + * jdk.vm.ci/jdk.vm.ci.amd64 + * jdk.vm.ci/jdk.vm.ci.sparc * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.DataPatchTest */ diff --git a/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java b/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java index 60def019ad1..6c1377c8935 100644 --- a/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java +++ b/hotspot/test/compiler/jvmci/code/SimpleCodeInstallationTest.java @@ -24,7 +24,14 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" - * @compile CodeInstallationTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @library / + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.code.site + * jdk.vm.ci/jdk.vm.ci.runtime + * jdk.vm.ci/jdk.vm.ci.amd64 + * jdk.vm.ci/jdk.vm.ci.sparc * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.SimpleCodeInstallationTest */ diff --git a/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java b/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java index 041a184bc16..b27802ce47a 100644 --- a/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java +++ b/hotspot/test/compiler/jvmci/code/SimpleDebugInfoTest.java @@ -24,7 +24,14 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" - * @compile CodeInstallationTest.java DebugInfoTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @library / + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.code.site + * jdk.vm.ci/jdk.vm.ci.runtime + * jdk.vm.ci/jdk.vm.ci.amd64 + * jdk.vm.ci/jdk.vm.ci.sparc * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.SimpleDebugInfoTest */ diff --git a/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java b/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java index 2f1061adfd0..c06c5076eae 100644 --- a/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java +++ b/hotspot/test/compiler/jvmci/code/VirtualObjectDebugInfoTest.java @@ -24,7 +24,14 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9") & os.arch != "aarch64" - * @compile CodeInstallationTest.java DebugInfoTest.java TestAssembler.java amd64/AMD64TestAssembler.java sparc/SPARCTestAssembler.java + * @library / + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.code.site + * jdk.vm.ci/jdk.vm.ci.runtime + * jdk.vm.ci/jdk.vm.ci.amd64 + * jdk.vm.ci/jdk.vm.ci.sparc * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI compiler.jvmci.code.VirtualObjectDebugInfoTest */ diff --git a/hotspot/test/compiler/jvmci/common/CTVMUtilities.java b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java index 67a1aef7a19..6c3301631a5 100644 --- a/hotspot/test/compiler/jvmci/common/CTVMUtilities.java +++ b/hotspot/test/compiler/jvmci/common/CTVMUtilities.java @@ -24,6 +24,7 @@ package compiler.jvmci.common; import java.io.IOException; +import java.lang.reflect.Module; import java.lang.reflect.Field; import java.lang.reflect.Executable; import java.lang.reflect.Constructor; @@ -88,20 +89,24 @@ public class CTVMUtilities { } public static Map getBciToLineNumber(Executable method) { Map lineNumbers = new TreeMap<>(); + Class aClass = method.getDeclaringClass(); + ClassReader cr; try { - ClassReader cr = new ClassReader(method.getDeclaringClass() - .getName()); - ClassNode cn = new ClassNode(); - cr.accept(cn, ClassReader.EXPAND_FRAMES); - - Map labels = new HashMap<>(); - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - ClassVisitor cv = new ClassVisitorForLabels(cw, labels, method); - cr.accept(cv, ClassReader.EXPAND_FRAMES); - labels.forEach((k, v) -> lineNumbers.put(k.getOffset(), v)); + Module aModule = aClass.getModule(); + String name = aClass.getName(); + cr = new ClassReader(aModule.getResourceAsStream( + name.replace('.', '/') + ".class")); } catch (IOException e) { - throw new Error("TEST BUG " + e, e); + throw new Error("TEST BUG: can read " + aClass.getName() + " : " + e, e); } + ClassNode cn = new ClassNode(); + cr.accept(cn, ClassReader.EXPAND_FRAMES); + + Map labels = new HashMap<>(); + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + ClassVisitor cv = new ClassVisitorForLabels(cw, labels, method); + cr.accept(cv, ClassReader.EXPAND_FRAMES); + labels.forEach((k, v) -> lineNumbers.put(k.getOffset(), v)); boolean isEmptyMethod = Modifier.isAbstract(method.getModifiers()) || Modifier.isNative(method.getModifiers()); if (lineNumbers.isEmpty() && !isEmptyMethod) { diff --git a/hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java b/hotspot/test/compiler/jvmci/common/patches/jdk.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java similarity index 100% rename from hotspot/test/compiler/jvmci/common/CompilerToVMHelper.java rename to hotspot/test/compiler/jvmci/common/patches/jdk.vm.ci/jdk/vm/ci/hotspot/CompilerToVMHelper.java diff --git a/hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java b/hotspot/test/compiler/jvmci/common/patches/jdk.vm.ci/jdk/vm/ci/hotspot/MetaAccessWrapper.java similarity index 100% rename from hotspot/test/compiler/jvmci/events/MetaAccessWrapper.java rename to hotspot/test/compiler/jvmci/common/patches/jdk.vm.ci/jdk/vm/ci/hotspot/MetaAccessWrapper.java diff --git a/hotspot/test/compiler/jvmci/common/PublicMetaspaceWrapperObject.java b/hotspot/test/compiler/jvmci/common/patches/jdk.vm.ci/jdk/vm/ci/hotspot/PublicMetaspaceWrapperObject.java similarity index 100% rename from hotspot/test/compiler/jvmci/common/PublicMetaspaceWrapperObject.java rename to hotspot/test/compiler/jvmci/common/patches/jdk.vm.ci/jdk/vm/ci/hotspot/PublicMetaspaceWrapperObject.java diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java index d90b5285c02..3e090394bbc 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleAbstractImplementer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,93 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public abstract class MultipleAbstractImplementer implements MultipleImplementersInterface { + // Different access levels on the fields of this class are used on purpose. + // It is needed to verify jdk.vm.ci.CompilerToVM constant pool related + // methods, e.g. resolveFieldInPool. + + private static int intStaticField = INT_CONSTANT; + final static long longStaticField = LONG_CONSTANT; + volatile static float floatStaticField = FLOAT_CONSTANT; + static double doubleStaticField = DOUBLE_CONSTANT; + public static String stringStaticField = STRING_CONSTANT; + protected static Object objectStaticField = OBJECT_CONSTANT; + + public int intField = INT_CONSTANT; + private long longField = LONG_CONSTANT; + protected float floatField = FLOAT_CONSTANT; + transient double doubleField = DOUBLE_CONSTANT; + volatile String stringField = STRING_CONSTANT; + String stringFieldEmpty = ""; + final Object objectField; + + public MultipleAbstractImplementer() { + intField = Integer.MAX_VALUE; + longField = Long.MAX_VALUE; + floatField = Float.MAX_VALUE; + doubleField = Double.MAX_VALUE; + stringField = "Message"; + objectField = new Object(); + } + public abstract void abstractMethod(); @Override public void finalize() throws Throwable { super.finalize(); } + + public void lambdaUsingMethod2() { + Thread t = new Thread(this::testMethod); + t.start(); + } + + /** + * This method is needed to have "getstatic" and "getfield" instructions + * in the class. These instructions are needed to test + * resolveFieldInPool method, because it needs a bytecode as one of its arguments. + */ + public void printFileds() { + System.out.println(intStaticField); + System.out.println(longStaticField); + System.out.println(floatStaticField); + System.out.println(doubleStaticField); + System.out.println(stringStaticField); + System.out.println(objectStaticField); + System.out.println(intField); + System.out.println(longField); + System.out.println(floatField); + System.out.println(doubleField); + System.out.println(stringField); + System.out.println(stringFieldEmpty); + System.out.println(objectField); + } + + public static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + @Override + public void instanceMethod() { + toString(); // calling some virtual method + super.toString(); // calling some special method + } + + @Override + public void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java index 274df6b5c0f..e7a7b3cc0c3 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementer2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,18 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public class MultipleImplementer2 implements MultipleImplementersInterface { + // Different access levels on the fields of this class are used on purpose. + // It is needed to verify jdk.vm.ci.CompilerToVM constant pool related + // methods, e.g. resolveFieldInPool. + private static int intStaticField = INT_CONSTANT; - static long longStaticField = LONG_CONSTANT; - static float floatStaticField = FLOAT_CONSTANT; + final static long longStaticField = LONG_CONSTANT; + volatile static float floatStaticField = FLOAT_CONSTANT; static double doubleStaticField = DOUBLE_CONSTANT; public static String stringStaticField = STRING_CONSTANT; protected static Object objectStaticField = OBJECT_CONSTANT; @@ -35,9 +42,10 @@ public class MultipleImplementer2 implements MultipleImplementersInterface { public int intField = INT_CONSTANT; private long longField = LONG_CONSTANT; protected float floatField = FLOAT_CONSTANT; - double doubleField = DOUBLE_CONSTANT; - String stringField = STRING_CONSTANT; - Object objectField = OBJECT_CONSTANT; + transient double doubleField = DOUBLE_CONSTANT; + volatile String stringField = STRING_CONSTANT; + String stringFieldEmpty = ""; + final Object objectField; public MultipleImplementer2() { intField = Integer.MAX_VALUE; @@ -58,12 +66,52 @@ public class MultipleImplementer2 implements MultipleImplementersInterface { super.finalize(); } - public void interfaceMethodReferral2(MultipleImplementersInterface obj) { - obj.interfaceMethodReferral(obj); - } - public void lambdaUsingMethod2() { Thread t = new Thread(this::testMethod); t.start(); } + + /** + * This method is needed to have "getstatic" and "getfield" instructions + * in the class. These instructions are needed to test + * resolveFieldInPool method, because it needs a bytecode as one of its arguments. + */ + public void printFileds() { + System.out.println(intStaticField); + System.out.println(longStaticField); + System.out.println(floatStaticField); + System.out.println(doubleStaticField); + System.out.println(stringStaticField); + System.out.println(objectStaticField); + System.out.println(intField); + System.out.println(longField); + System.out.println(floatField); + System.out.println(doubleField); + System.out.println(stringField); + System.out.println(stringFieldEmpty); + System.out.println(objectField); + } + + public static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + @Override + public void instanceMethod() { + toString(); // calling some virtual method + super.toString(); // calling some special method + } + + @Override + public void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java index 9ce4e792bc6..5257e592c6e 100644 --- a/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java +++ b/hotspot/test/compiler/jvmci/common/testcases/MultipleImplementersInterface.java @@ -23,6 +23,9 @@ package compiler.jvmci.common.testcases; +import java.util.HashMap; +import java.util.Map; + public interface MultipleImplementersInterface { int INT_CONSTANT = Integer.MAX_VALUE; @@ -42,12 +45,34 @@ public interface MultipleImplementersInterface { // empty } - default void interfaceMethodReferral(MultipleImplementersInterface obj) { - obj.defaultMethod(); - } - default void lambdaUsingMethod() { Thread t = new Thread(this::defaultMethod); t.start(); } + + default void printFields() { + System.out.println(OBJECT_CONSTANT); + String s = ""; + System.out.println(s); + } + + static void staticMethod() { + System.getProperties(); // calling some static method + Map map = new HashMap(); // calling some constructor + map.put(OBJECT_CONSTANT, OBJECT_CONSTANT); // calling some interface method + map.remove(OBJECT_CONSTANT); // calling some default interface method + } + + default void instanceMethod() { + toString(); // calling some virtual method + } + + default void anonClassMethod() { + new Runnable() { + @Override + public void run() { + System.out.println("Running"); + } + }.run(); + } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java index 63c009c3df3..3902acf2388 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/AllocateCompileIdTest.java @@ -26,15 +26,21 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.AllocateCompileIdTest * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * -XX:-BackgroundCompilation - * compiler.jvmci.compilerToVM.AllocateCompileIdTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:-BackgroundCompilation + * compiler.jvmci.compilerToVM.AllocateCompileIdTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java index 64dca91cfb5..b24d25ca005 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/CanInlineMethodTest.java @@ -27,14 +27,20 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.CanInlineMethodTest * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.CanInlineMethodTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.CanInlineMethodTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java index be1d594bbd4..81b7bd47d7b 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/CollectCountersTest.java @@ -26,20 +26,20 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.CollectCountersTest * @run main/othervm -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI -Xbootclasspath/a:. - * -XX:JVMCICounterSize=0 - * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=0 - * compiler.jvmci.compilerToVM.CollectCountersTest + * -XX:+EnableJVMCI + * -XX:JVMCICounterSize=0 + * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=0 + * compiler.jvmci.compilerToVM.CollectCountersTest * @run main/othervm -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI -Xbootclasspath/a:. - * -XX:JVMCICounterSize=11 - * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=11 - * compiler.jvmci.compilerToVM.CollectCountersTest + * -XX:+EnableJVMCI + * -XX:JVMCICounterSize=11 + * -Dcompiler.jvmci.compilerToVM.CollectCountersTest.expected=11 + * compiler.jvmci.compilerToVM.CollectCountersTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java index b9716cca2a2..df4046d889f 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,118 +27,214 @@ package compiler.jvmci.compilerToVM; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import jdk.internal.misc.SharedSecrets; +import sun.hotspot.WhiteBox; import sun.reflect.ConstantPool; +import sun.reflect.ConstantPool.Tag; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; /** * Common class for jdk.vm.ci.hotspot.CompilerToVM constant pool tests */ public class ConstantPoolTestCase { - private final Map typeTests; + + private static final Map TAG_TO_TYPE_MAP; + static { + TAG_TO_TYPE_MAP = new HashMap<>(); + TAG_TO_TYPE_MAP.put(Tag.CLASS, CONSTANT_CLASS); + TAG_TO_TYPE_MAP.put(Tag.FIELDREF, CONSTANT_FIELDREF); + TAG_TO_TYPE_MAP.put(Tag.METHODREF, CONSTANT_METHODREF); + TAG_TO_TYPE_MAP.put(Tag.INTERFACEMETHODREF, CONSTANT_INTERFACEMETHODREF); + TAG_TO_TYPE_MAP.put(Tag.STRING, CONSTANT_STRING); + TAG_TO_TYPE_MAP.put(Tag.INTEGER, CONSTANT_INTEGER); + TAG_TO_TYPE_MAP.put(Tag.FLOAT, CONSTANT_FLOAT); + TAG_TO_TYPE_MAP.put(Tag.LONG, CONSTANT_LONG); + TAG_TO_TYPE_MAP.put(Tag.DOUBLE, CONSTANT_DOUBLE); + TAG_TO_TYPE_MAP.put(Tag.NAMEANDTYPE, CONSTANT_NAMEANDTYPE); + TAG_TO_TYPE_MAP.put(Tag.UTF8, CONSTANT_UTF8); + TAG_TO_TYPE_MAP.put(Tag.METHODHANDLE, CONSTANT_METHODHANDLE); + TAG_TO_TYPE_MAP.put(Tag.METHODTYPE, CONSTANT_METHODTYPE); + TAG_TO_TYPE_MAP.put(Tag.INVOKEDYNAMIC, CONSTANT_INVOKEDYNAMIC); + TAG_TO_TYPE_MAP.put(Tag.INVALID, CONSTANT_INVALID); + } + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private final Map typeTests; + + public static enum ConstantTypes { + CONSTANT_CLASS { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + Class klass = constantPoolSS.getClassAt(index); + String klassName = klass.getName(); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (entry.klass.replaceAll("/", "\\.").equals(klassName)) { + return entry; + } + } + return null; + } + }, + CONSTANT_FIELDREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_METHODREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_INTERFACEMETHODREF { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return this.getTestedCPEntryForMethodAndField(dummyClass, index); + } + }, + CONSTANT_STRING { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + String value = constantPoolSS.getStringAt(index); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (entry.name.equals(value)) { + return entry; + } + } + return null; + } + }, + CONSTANT_INTEGER, + CONSTANT_FLOAT, + CONSTANT_LONG, + CONSTANT_DOUBLE, + CONSTANT_NAMEANDTYPE, + CONSTANT_UTF8, + CONSTANT_METHODHANDLE, + CONSTANT_METHODTYPE, + CONSTANT_INVOKEDYNAMIC { + @Override + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + int nameAndTypeIndex = constantPoolSS.getNameAndTypeRefIndexAt(index); + String[] info = constantPoolSS.getNameAndTypeRefInfoAt(nameAndTypeIndex); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (info[0].equals(entry.name) && info[1].equals(entry.type)) { + return entry; + } + } + return null; + } + }, + CONSTANT_INVALID; + + public TestedCPEntry getTestedCPEntry(DummyClasses dummyClass, int index) { + return null; // returning null by default + } + + public TestedCPEntry[] getAllCPEntriesForType(DummyClasses dummyClass) { + TestedCPEntry[] toReturn = dummyClass.testedCP.get(this); + if (toReturn == null) { + return new TestedCPEntry[0]; + } + return dummyClass.testedCP.get(this); + } + + protected TestedCPEntry getTestedCPEntryForMethodAndField(DummyClasses dummyClass, int index) { + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + checkIndex(constantPoolSS, index); + String[] info = constantPoolSS.getMemberRefInfoAt(index); + TestedCPEntry[] testedEntries = dummyClass.testedCP.get(this); + for (TestedCPEntry entry : testedEntries) { + if (info[0].equals(entry.klass) && info[1].equals(entry.name) && info[2].equals(entry.type)) { + return entry; + } + } + return null; + } + + protected void checkIndex(ConstantPool constantPoolSS, int index) { + ConstantPool.Tag tag = constantPoolSS.getTagAt(index); + ConstantTypes type = mapTagToCPType(tag); + if (!this.equals(type)) { + String msg = String.format("TESTBUG: CP tag should be a %s, but is %s", + this.name(), + type.name()); + throw new Error(msg); + } + } + } public static interface Validator { void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index); + ConstantTypes cpType, + DummyClasses dummyClass, + int index); } - public ConstantPoolTestCase(Map typeTests) { + public static class TestedCPEntry { + public final String klass; + public final String name; + public final String type; + public final byte[] opcodes; + public final long accFlags; + + public TestedCPEntry(String klass, String name, String type, byte[] opcodes, long accFlags) { + this.klass = klass; + this.name = name; + this.type = type; + if (opcodes != null) { + this.opcodes = new byte[opcodes.length]; + System.arraycopy(opcodes, 0, this.opcodes, 0, opcodes.length); + } else { + this.opcodes = null; + } + this.accFlags = accFlags; + } + + public TestedCPEntry(String klass, String name, String type, byte[] opcodes) { + this(klass, name, type, opcodes, 0); + } + + public TestedCPEntry(String klass, String name, String type) { + this(klass, name, type, null, 0); + } + } + + public static ConstantTypes mapTagToCPType(Tag tag) { + return TAG_TO_TYPE_MAP.get(tag); + } + + public ConstantPoolTestCase(Map typeTests) { this.typeTests = new HashMap<>(); this.typeTests.putAll(typeTests); } - private void messageOnFail(Throwable t, - ConstantPoolTestsHelper.ConstantTypes cpType, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). - getConstantPool(dummyClass.klass); - String msg = String.format("Test for %s constant pool entry of" - + " type %s", - dummyClass.klass, cpType.name()); - switch (cpType) { - case CONSTANT_CLASS: - case CONSTANT_STRING: - case CONSTANT_METHODTYPE: - String utf8 = constantPoolSS - .getUTF8At((int) dummyClass.cp.get(index).value); - msg = String.format("%s (%s) failed with %s", msg, utf8, t); - break; - case CONSTANT_INTEGER: - int intValue = constantPoolSS.getIntAt(index); - msg = String.format("%s (%d) failed with %s", msg, intValue, t); - break; - case CONSTANT_LONG: - long longValue = constantPoolSS.getLongAt(index); - msg = String.format("%s (%d) failed with %s", msg, longValue, t); - break; - case CONSTANT_FLOAT: - float floatValue = constantPoolSS.getFloatAt(index); - msg = String.format("%s (%E) failed with %s", msg, floatValue, t); - break; - case CONSTANT_DOUBLE: - double doubleValue = constantPoolSS.getDoubleAt(index); - msg = String.format("%s (%E) failed with %s", msg, doubleValue, t); - break; - case CONSTANT_UTF8: - String utf8Value = constantPoolSS.getUTF8At(index); - msg = String.format("%s (%s) failed with %s", msg, utf8Value, t); - break; - case CONSTANT_INVOKEDYNAMIC: - index = ((int[]) dummyClass.cp.get(index).value)[1]; - case CONSTANT_NAMEANDTYPE: - String name = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(index).value)[0]); - String type = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(index).value)[1]); - msg = String.format("%s (%s:%s) failed with %s", - msg, name, type, t); - break; - case CONSTANT_METHODHANDLE: - index = ((int[]) dummyClass.cp.get(index).value)[1]; - case CONSTANT_METHODREF: - case CONSTANT_INTERFACEMETHODREF: - case CONSTANT_FIELDREF: - int classIndex = ((int[]) dummyClass.cp.get(index).value)[0]; - int nameAndTypeIndex = ((int[]) dummyClass.cp.get(index).value)[1]; - String cName = constantPoolSS - .getUTF8At((int) dummyClass.cp.get(classIndex).value); - String mName = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[0]); - String mType = constantPoolSS - .getUTF8At(((int[]) dummyClass.cp.get(nameAndTypeIndex).value)[1]); - msg = String.format("%s (%s.%s:%s) failed with %s ", - msg, cName, mName, mType, t); - break; - default: - msg = String.format("Test bug: unknown constant type %s ", cpType); - } - throw new Error(msg + t.getMessage(), t); - } - public void test() { - for (ConstantPoolTestsHelper.DummyClasses dummyClass - : ConstantPoolTestsHelper.DummyClasses.values()) { - System.out.printf("%nTesting dummy %s%n", dummyClass.klass); - HotSpotResolvedObjectType holder = HotSpotResolvedObjectType - .fromObjectClass(dummyClass.klass); - jdk.vm.ci.meta.ConstantPool constantPoolCTVM - = holder.getConstantPool(); - ConstantPool constantPoolSS = SharedSecrets.getJavaLangAccess(). - getConstantPool(dummyClass.klass); - for (Integer i : dummyClass.cp.keySet()) { - ConstantPoolTestsHelper.ConstantTypes cpType - = dummyClass.cp.get(i).type; + for (DummyClasses dummyClass : DummyClasses.values()) { + boolean isCPCached = WB.getConstantPoolCacheLength(dummyClass.klass) > -1; + System.out.printf("Testing dummy %s with constant pool cached = %b%n", + dummyClass.klass, + isCPCached); + HotSpotResolvedObjectType holder = HotSpotResolvedObjectType.fromObjectClass(dummyClass.klass); + jdk.vm.ci.meta.ConstantPool constantPoolCTVM = holder.getConstantPool(); + ConstantPool constantPoolSS = dummyClass.constantPoolSS; + for (int i = 0; i < constantPoolSS.getSize(); i++) { + Tag tag = constantPoolSS.getTagAt(i); + ConstantTypes cpType = mapTagToCPType(tag); if (!typeTests.keySet().contains(cpType)) { continue; } - try { - typeTests.get(cpType).validate(constantPoolCTVM, - constantPoolSS, dummyClass, i); - } catch (Throwable t) { - messageOnFail(t, cpType, dummyClass, i); - } + typeTests.get(cpType).validate(constantPoolCTVM, cpType, dummyClass, i); } } } } - diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java index 777b848fd8b..783b26188e9 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ConstantPoolTestsHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,19 @@ */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.common.testcases.MultipleAbstractImplementer; import compiler.jvmci.common.testcases.MultipleImplementer2; import compiler.jvmci.common.testcases.MultipleImplementersInterface; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; import java.util.HashMap; import java.util.Map; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.org.objectweb.asm.Opcodes; +import sun.hotspot.WhiteBox; +import sun.reflect.ConstantPool; +import sun.reflect.ConstantPool.Tag; /** * Class contains hard-coded constant pool tables for dummy classes used for @@ -34,104 +43,437 @@ import java.util.Map; */ public class ConstantPoolTestsHelper { - public enum ConstantTypes { - CONSTANT_CLASS, - CONSTANT_FIELDREF, - CONSTANT_METHODREF, - CONSTANT_INTERFACEMETHODREF, - CONSTANT_STRING, - CONSTANT_INTEGER, - CONSTANT_FLOAT, - CONSTANT_LONG, - CONSTANT_DOUBLE, - CONSTANT_NAMEANDTYPE, - CONSTANT_UTF8, - CONSTANT_METHODHANDLE, - CONSTANT_METHODTYPE, - CONSTANT_INVOKEDYNAMIC; - } + public static final int NO_CP_CACHE_PRESENT = Integer.MAX_VALUE; public enum DummyClasses { DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS), + DUMMY_ABS_CLASS(MultipleAbstractImplementer.class, CP_MAP_FOR_ABS_CLASS), DUMMY_INTERFACE(MultipleImplementersInterface.class, CP_MAP_FOR_INTERFACE); + private static final WhiteBox WB = WhiteBox.getWhiteBox(); public final Class klass; - public final Map cp; + public final ConstantPool constantPoolSS; + public final Map testedCP; - DummyClasses(Class klass, Map cp) { + DummyClasses(Class klass, Map testedCP) { this.klass = klass; - this.cp = cp; + this.constantPoolSS = SharedSecrets.getJavaLangAccess().getConstantPool(klass); + this.testedCP = testedCP; + } + + public int getCPCacheIndex(int cpi) { + int cacheLength = WB.getConstantPoolCacheLength(this.klass); + int indexTag = WB.getConstantPoolCacheIndexTag(); + for (int cpci = indexTag; cpci < cacheLength + indexTag; cpci++) { + if (WB.remapInstructionOperandFromCPCache(this.klass, cpci) == cpi) { + if (constantPoolSS.getTagAt(cpi).equals(Tag.INVOKEDYNAMIC)) { + return WB.encodeConstantPoolIndyIndex(cpci) + indexTag; + } + return cpci; + } + } + return NO_CP_CACHE_PRESENT; } } - public static class ConstantPoolEntry { - - public final ConstantTypes type; - public final Object value; - - public ConstantPoolEntry(ConstantTypes type, Object value) { - this.type = type; - this.value = value; - } + private static final Map CP_MAP_FOR_CLASS = new HashMap<>(); + static { + CP_MAP_FOR_CLASS.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2$1", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "intStaticField", + "I", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "longStaticField", + "J", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_FINAL | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "floatStaticField", + "F", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_VOLATILE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "doubleStaticField", + "D", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringStaticField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "objectStaticField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "intField", + "I", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PUBLIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "longField", + "J", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PRIVATE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "floatField", + "F", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PROTECTED), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "doubleField", + "D", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_TRANSIENT), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "objectField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_FINAL), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_VOLATILE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "stringFieldEmpty", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + 0L), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKESPECIAL, + (byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleImplementer2;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Message", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;", + null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2", + "testMethod", + "()V"), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_CLASS.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleImplementer2;)" + + "Ljava/lang/Runnable;"), + } + ); } - private static final Map CP_MAP_FOR_CLASS + private static final Map CP_MAP_FOR_ABS_CLASS = new HashMap<>(); static { - CP_MAP_FOR_CLASS.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 68})); - CP_MAP_FOR_CLASS.put(2, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 69)); - CP_MAP_FOR_CLASS.put(3, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); - CP_MAP_FOR_CLASS.put(4, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 70})); - CP_MAP_FOR_CLASS.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807L)); - CP_MAP_FOR_CLASS.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38F)); - CP_MAP_FOR_CLASS.put(10, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308D)); - CP_MAP_FOR_CLASS.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 74)); - CP_MAP_FOR_CLASS.put(22, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 83)); - CP_MAP_FOR_CLASS.put(23, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{22, 84})); - CP_MAP_FOR_CLASS.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{2, 85})); - CP_MAP_FOR_CLASS.put(26, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 91})); - CP_MAP_FOR_CLASS.put(29, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{35, 94})); - CP_MAP_FOR_CLASS.put(35, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 100)); - CP_MAP_FOR_CLASS.put(68, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{54, 55})); - CP_MAP_FOR_CLASS.put(70, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{48, 37})); - CP_MAP_FOR_CLASS.put(84, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{59, 55})); - CP_MAP_FOR_CLASS.put(85, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{103, 63})); - CP_MAP_FOR_CLASS.put(91, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{106, 107})); - CP_MAP_FOR_CLASS.put(94, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{36, 37})); - CP_MAP_FOR_CLASS.put(104, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{110, 111})); - CP_MAP_FOR_CLASS.put(105, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{35, 112})); - CP_MAP_FOR_CLASS.put(110, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 113)); - CP_MAP_FOR_CLASS.put(111, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{114, 118})); - CP_MAP_FOR_CLASS.put(112, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{58, 55})); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "intStaticField", + "I", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "longStaticField", + "J", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_FINAL | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "floatStaticField", + "F", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_VOLATILE | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "doubleStaticField", + "D", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringStaticField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "objectStaticField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "intField", + "I", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PUBLIC), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "longField", + "J", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PRIVATE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "floatField", + "F", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_PROTECTED), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "doubleField", + "D", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_TRANSIENT), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "objectField", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_FINAL), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringField", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + Opcodes.ACC_VOLATILE), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "stringFieldEmpty", + "Ljava/lang/String;", + new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD}, + 0L), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKESPECIAL, + (byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Message", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;", + null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer", + "testMethod", + "()V"), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_ABS_CLASS.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)" + + "Ljava/lang/Runnable;"), + } + ); } - private static final Map CP_MAP_FOR_INTERFACE + private static final Map CP_MAP_FOR_INTERFACE = new HashMap<>(); static { - CP_MAP_FOR_INTERFACE.put(1, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 48)); - CP_MAP_FOR_INTERFACE.put(5, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTERFACEMETHODREF, new int[]{13, 52})); - CP_MAP_FOR_INTERFACE.put(6, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 53)); - CP_MAP_FOR_INTERFACE.put(7, new ConstantPoolEntry(ConstantTypes.CONSTANT_INVOKEDYNAMIC, new int[]{0, 58})); - CP_MAP_FOR_INTERFACE.put(8, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 59})); - CP_MAP_FOR_INTERFACE.put(9, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{6, 60})); - CP_MAP_FOR_INTERFACE.put(12, new ConstantPoolEntry(ConstantTypes.CONSTANT_FIELDREF, new int[]{13, 63})); - CP_MAP_FOR_INTERFACE.put(13, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 64)); - CP_MAP_FOR_INTERFACE.put(17, new ConstantPoolEntry(ConstantTypes.CONSTANT_INTEGER, 2147483647)); - CP_MAP_FOR_INTERFACE.put(20, new ConstantPoolEntry(ConstantTypes.CONSTANT_LONG, 9223372036854775807l)); - CP_MAP_FOR_INTERFACE.put(24, new ConstantPoolEntry(ConstantTypes.CONSTANT_FLOAT, 3.4028235E38f)); - CP_MAP_FOR_INTERFACE.put(27, new ConstantPoolEntry(ConstantTypes.CONSTANT_DOUBLE, 1.7976931348623157E308d)); - CP_MAP_FOR_INTERFACE.put(31, new ConstantPoolEntry(ConstantTypes.CONSTANT_STRING, 65)); - CP_MAP_FOR_INTERFACE.put(52, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{34, 35})); - CP_MAP_FOR_INTERFACE.put(55, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{6, 67})); - CP_MAP_FOR_INTERFACE.put(56, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODTYPE, 35)); - CP_MAP_FOR_INTERFACE.put(57, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODHANDLE, new int[]{9, 5})); - CP_MAP_FOR_INTERFACE.put(58, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{68, 69})); - CP_MAP_FOR_INTERFACE.put(59, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{70, 71})); - CP_MAP_FOR_INTERFACE.put(60, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{72, 35})); - CP_MAP_FOR_INTERFACE.put(63, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{32, 33})); - CP_MAP_FOR_INTERFACE.put(67, new ConstantPoolEntry(ConstantTypes.CONSTANT_METHODREF, new int[]{73, 74})); - CP_MAP_FOR_INTERFACE.put(73, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 75)); - CP_MAP_FOR_INTERFACE.put(74, new ConstantPoolEntry(ConstantTypes.CONSTANT_NAMEANDTYPE, new int[]{76, 80})); - CP_MAP_FOR_INTERFACE.put(77, new ConstantPoolEntry(ConstantTypes.CONSTANT_CLASS, 82)); + CP_MAP_FOR_INTERFACE.put(CONSTANT_CLASS, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", null, null), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface$1", null, null), + new TestedCPEntry("java/lang/Object", null, null), + new TestedCPEntry("java/lang/invoke/MethodHandles$Lookup", null, null), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_FIELDREF, + new TestedCPEntry[] { + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", + "OBJECT_CONSTANT", + "Ljava/lang/Object;", + new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC}, + Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/System", + "getProperties", + "()Ljava/util/Properties;", + new byte[] {(byte) Opcodes.INVOKESTATIC}), + new TestedCPEntry("java/util/HashMap", + "", + "()V", + new byte[] {(byte) Opcodes.INVOKESPECIAL}), + new TestedCPEntry("java/lang/Object", + "toString", + "()Ljava/lang/String;", + new byte[] {(byte) Opcodes.INVOKEVIRTUAL}), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "", + "(Lcompiler/jvmci/common/testcases/MultipleAbstractImplementer;)V", + new byte[0]), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer$1", + "run", + "()V", + new byte[0]), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_INTERFACEMETHODREF, + new TestedCPEntry[] { + new TestedCPEntry("java/util/Map", + "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + new TestedCPEntry("java/util/Map", + "remove", + "(Ljava/lang/Object;)Ljava/lang/Object;", + new byte[] {(byte) Opcodes.INVOKEINTERFACE}), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_STRING, + new TestedCPEntry[] { + new TestedCPEntry(null, "Hello", null), + new TestedCPEntry(null, "", null), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODHANDLE, + new TestedCPEntry[] { + new TestedCPEntry("java/lang/invoke/LambdaMetafactory", + "metafactory", + "(Ljava/lang/invoke/MethodHandles$Lookup;" + + "Ljava/lang/String;Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodType;" + + "Ljava/lang/invoke/MethodHandle;" + + "Ljava/lang/invoke/MethodType;)" + + "Ljava/lang/invoke/CallSite;"), + new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface", + "defaultMethod", + "()V"), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_METHODTYPE, + new TestedCPEntry[] { + new TestedCPEntry(null, null, "()V"), + } + ); + CP_MAP_FOR_INTERFACE.put(CONSTANT_INVOKEDYNAMIC, + new TestedCPEntry[] { + new TestedCPEntry(null, + "run", + "(Lcompiler/jvmci/common/testcases/MultipleImplementersInterface;)" + + "Ljava/lang/Runnable;"), + } + ); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java index d6c22fc5ee1..fe251871e07 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/DebugOutputTest.java @@ -26,12 +26,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run driver compiler.jvmci.compilerToVM.DebugOutputTest + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.DebugOutputTest + * @run main/othervm compiler.jvmci.compilerToVM.DebugOutputTest */ + // as soon as CODETOOLS-7901589 fixed, '@run main/othervm' should be replaced w/ '@run driver' + package compiler.jvmci.compilerToVM; import jdk.vm.ci.hotspot.CompilerToVMHelper; @@ -50,15 +53,13 @@ public class DebugOutputTest { System.out.println(testCase); OutputAnalyzer oa; try { - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( - /* use test options = */ true, + oa = ProcessTools.executeTestJvmAllArgs( "-XX:+UnlockExperimentalVMOptions", "-XX:+EnableJVMCI", "-Xbootclasspath/a:.", DebugOutputTest.Worker.class.getName(), testCase.name()); - oa = ProcessTools.executeProcess(pb); - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); throw new Error("Problems running child process", e); } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java index 60a734d68a5..bd39a56e2e5 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java @@ -27,16 +27,21 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code * @ignore 8139700 - * @compile ../common/CompilerToVMHelper.java + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.DisassembleCodeBlobTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java index a87cab4a386..747a9cf6123 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/DoNotInlineOrCompileTest.java @@ -27,14 +27,20 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.DoNotInlineOrCompileTest * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.DoNotInlineOrCompileTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.DoNotInlineOrCompileTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java index 839b509af15..fb89c4e5428 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java @@ -23,16 +23,21 @@ import java.util.Map; * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / + * @library ../common/patches * @ignore 8139383 - * @compile ../common/CompilerToVMHelper.java + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest * @build sun.hotspot.WhiteBox - * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ExecuteInstalledCodeTest */ public class ExecuteInstalledCodeTest { diff --git a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java index 2b39757975c..0cca017515d 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/FindUniqueConcreteMethodTest.java @@ -26,12 +26,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.FindUniqueConcreteMethodTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java index 586160f58fc..472bc379cb5 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetBytecodeTest.java @@ -27,11 +27,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetBytecodeTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.GetBytecodeTest + * compiler.jvmci.compilerToVM.GetBytecodeTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java index 6c731a4540f..1b0eacdf3c6 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetClassInitializerTest.java @@ -26,11 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.GetClassInitializerTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetClassInitializerTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetClassInitializerTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java index 4c347964800..3e14a684644 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetConstantPoolTest.java @@ -27,16 +27,19 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java ../common/PublicMetaspaceWrapperObject.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build jdk.vm.ci/jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject + * @build compiler.jvmci.compilerToVM.GetConstantPoolTest * @build sun.hotspot.WhiteBox - * compiler.jvmci.compilerToVM.GetConstantPoolTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetConstantPoolTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetConstantPoolTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java index e8630c10d0f..63f44334e4e 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetExceptionTableTest.java @@ -27,11 +27,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetExceptionTableTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.GetExceptionTableTest + * compiler.jvmci.compilerToVM.GetExceptionTableTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java index fd88f772cba..1b03ef2e79e 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetImplementorTest.java @@ -26,12 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.GetImplementorTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetImplementorTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetImplementorTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java index 8ca2f535bbc..99fcd9fae21 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLineNumberTableTest.java @@ -27,11 +27,16 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetLineNumberTableTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.GetLineNumberTableTest + * compiler.jvmci.compilerToVM.GetLineNumberTableTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java index d967e60a7d1..958b2e48fe4 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetLocalVariableTableTest.java @@ -27,15 +27,19 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code * @clean compiler.jvmci.compilerToVM.* * @compile -g DummyInterface.java * @compile -g DummyAbstractClass.java * @compile -g DummyClass.java - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetLocalVariableTableTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.GetLocalVariableTableTest + * compiler.jvmci.compilerToVM.GetLocalVariableTableTest * @clean compiler.jvmci.compilerToVM.* */ diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java index b803f550600..c180d41d548 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetMaxCallTargetOffsetTest.java @@ -26,12 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetMaxCallTargetOffsetTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java index 830ff7b066a..44fbb4cdaef 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetNextStackFrameTest.java @@ -26,11 +26,16 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetNextStackFrameTest + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetNextStackFrameTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetNextStackFrameTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java index 3f578e9883d..87afff2df3b 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodAtSlotTest.java @@ -27,11 +27,16 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetNextStackFrameTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.GetResolvedJavaMethodAtSlotTest + * compiler.jvmci.compilerToVM.GetResolvedJavaMethodAtSlotTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java index 5a98e880f9c..4735af3ee3e 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaMethodTest.java @@ -26,17 +26,18 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java - * ../common/PublicMetaspaceWrapperObject.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * jdk.vm.ci/jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject * @build compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest * @run main ClassFileInstaller * sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetResolvedJavaMethodTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java index 50b1a60acb8..0ddc246aec3 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetResolvedJavaTypeTest.java @@ -26,22 +26,26 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java - * ../common/PublicMetaspaceWrapperObject.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * jdk.vm.ci/jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject * @build compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller * sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * jdk.vm.ci.hotspot.PublicMetaspaceWrapperObject - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UseCompressedOops - * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:-UseCompressedOops - * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UseCompressedOops + * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:-UseCompressedOops + * compiler.jvmci.compilerToVM.GetResolvedJavaTypeTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java index 5554bc3914b..a6feb931eb0 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetStackTraceElementTest.java @@ -27,10 +27,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.GetStackTraceElementTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. compiler.jvmci.compilerToVM.GetStackTraceElementTest + * compiler.jvmci.compilerToVM.GetStackTraceElementTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java index e550282d5b0..9e1f82998ca 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetSymbolTest.java @@ -26,17 +26,16 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.GetSymbolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * compiler.jvmci.common.testcases.SingleImplementer - * compiler.jvmci.common.testcases.SingleImplementerInterface - * compiler.jvmci.compilerToVM.GetSymbolTest - * compiler.jvmci.common.CTVMUtilities - * jdk.test.lib.Utils - * jdk.test.lib.Asserts * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. compiler.jvmci.compilerToVM.GetSymbolTest + * compiler.jvmci.compilerToVM.GetSymbolTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java index f97a44750a6..49fd32128df 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/GetVtableIndexForInterfaceTest.java @@ -26,12 +26,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.GetVtableIndexForInterfaceTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java index cf839d71059..e45940e3e6a 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasCompiledCodeForOSRTest.java @@ -27,15 +27,21 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.HasCompiledCodeForOSRTest * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * -XX:-BackgroundCompilation - * compiler.jvmci.compilerToVM.HasCompiledCodeForOSRTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:-BackgroundCompilation + * compiler.jvmci.compilerToVM.HasCompiledCodeForOSRTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java index ce6f1a830f9..066e78448de 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/HasFinalizableSubclassTest.java @@ -26,11 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.HasFinalizableSubclassTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.HasFinalizableSubclassTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.HasFinalizableSubclassTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java index 2a2268ab38c..3de8ec56166 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/InitializeConfigurationTest.java @@ -26,13 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.InitializeConfigurationTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * compiler.jvmci.compilerToVM.InitializeConfigurationTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.InitializeConfigurationTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java index a8eac1de6cd..b7a0cfd0c19 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/InvalidateInstalledCodeTest.java @@ -27,16 +27,22 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.runtime * @ignore 8139700 - * @compile ../common/CompilerToVMHelper.java + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest * @build sun.hotspot.WhiteBox - * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.InvalidateInstalledCodeTest */ package compiler.jvmci.compilerToVM; @@ -86,6 +92,7 @@ public class InvalidateInstalledCodeTest { CompilationResult compResult = new CompilationResult(name); // to pass sanity check of default -1 compResult.setTotalFrameSize(0); + compResult.close(); InstalledCode installedCode = CACHE_PROVIDER.installCode( compRequest, compResult, new InstalledCode(name), /* speculationLog = */ null, diff --git a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java index a8004268fd2..f6ebb8303a6 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/IsMatureTest.java @@ -26,14 +26,17 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java - * @build sun.hotspot.WhiteBox IsMatureTest + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.IsMatureTest + * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * compiler.jvmci.compilerToVM.IsMatureTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.IsMatureTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java index b3fb21028af..21be817e7db 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,59 +28,80 @@ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @summary Testing compiler.jvmci.CompilerToVM.lookupKlassInPool method * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.common.testcases.MultipleImplementersInterface - * compiler.jvmci.common.testcases.MultipleImplementer2 - * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper - * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.LookupKlassInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupKlassInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.jvmci.compilerToVM.LookupKlassInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import sun.reflect.ConstantPool; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.lookupKlassInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupKlassInPool} method */ public class LookupKlassInPoolTest { - public static void main(String[] args) { - Map typeTests = new HashMap<>(1); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, - LookupKlassInPoolTest::validate); + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_CLASS, LookupKlassInPoolTest::validate); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - public static void validate(jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { - Object classToVerify = CompilerToVMHelper - .lookupKlassInPool(constantPoolCTVM, i); - if (!(classToVerify instanceof HotSpotResolvedObjectType) - && !(classToVerify instanceof String)) { - String msg = String.format("Output of method" - + " CTVM.lookupKlassInPool is neither" - + " a HotSpotResolvedObjectType, nor a String"); + public static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int i) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, i); + if (entry == null) { + return; + } + Object classToVerify = CompilerToVMHelper.lookupKlassInPool(constantPoolCTVM, i); + if (!(classToVerify instanceof HotSpotResolvedObjectType) && !(classToVerify instanceof String)) { + String msg = String.format("Output of method CTVM.lookupKlassInPool is neither" + + " a HotSpotResolvedObjectType, nor a String"); throw new AssertionError(msg); } - int classNameIndex = (int) dummyClass.cp.get(i).value; - String classNameToRefer - = constantPoolSS.getUTF8At(classNameIndex); + String classNameToRefer = entry.klass; String outputToVerify = classToVerify.toString(); if (!outputToVerify.contains(classNameToRefer)) { - String msg = String.format("Wrong class accessed by constant" - + " pool index %d: %s, but should be %s", - i, outputToVerify, classNameToRefer); + String msg = String.format("Wrong class accessed by constant pool index %d: %s, but should be %s", + i, + outputToVerify, + classNameToRefer); throw new AssertionError(msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java new file mode 100644 index 00000000000..b17763bd3ac --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupKlassRefIndexInPoolTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupKlassRefIndexInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupKlassRefIndexInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupKlassRefIndexInPool} method + */ +public class LookupKlassRefIndexInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupKlassRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupKlassRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupKlassRefIndexInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + int indexToVerify = CompilerToVMHelper.lookupKlassRefIndexInPool(constantPoolCTVM, index); + int indexToRefer = dummyClass.constantPoolSS.getClassRefIndexAt(cpi); + String msg = String.format("Wrong class index returned by lookupKlassRefIndexInPool method " + + "applied to %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(indexToRefer, indexToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java new file mode 100644 index 00000000000..1c23c7458c1 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupMethodInPoolTest.java @@ -0,0 +1,125 @@ +/* + * 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 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupMethodInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupMethodInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupMethodInPool} method + */ +public class LookupMethodInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupMethodInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupMethodInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + for (int j = 0; j < entry.opcodes.length; j++) { + HotSpotResolvedJavaMethod methodToVerify = CompilerToVMHelper + .lookupMethodInPool(constantPoolCTVM, index, entry.opcodes[j]); + String msg = String.format("Object returned by lookupMethodInPool method" + + " for %sindex %d should not be null", + cached, + index); + Asserts.assertNotNull(methodToVerify, msg); + String[] classNameSplit = entry.klass.split("/"); + String classNameToRefer = classNameSplit[classNameSplit.length - 1]; + String methodNameToRefer = entry.name; + String methodToVerifyToString = methodToVerify.toString(); + if (!methodToVerifyToString.contains(classNameToRefer) + || !methodToVerifyToString.contains(methodNameToRefer)) { + msg = String.format("String representation \"%s\" of the object" + + " returned by lookupMethodInPool method" + + " for index %d does not contain a method's class name" + + " or method's name, should contain %s.%s", + methodToVerifyToString, + index, + classNameToRefer, + methodNameToRefer); + throw new AssertionError(msg); + } + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java new file mode 100644 index 00000000000..16add7012e0 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameAndTypeRefIndexInPoolTest.java @@ -0,0 +1,108 @@ +/* + * 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 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupNameAndTypeRefIndexInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupNameAndTypeRefIndexInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupNameAndTypeRefIndexInPool} method + */ +public class LookupNameAndTypeRefIndexInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupNameAndTypeRefIndexInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupNameAndTypeRefIndexInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + int indexToVerify = CompilerToVMHelper.lookupNameAndTypeRefIndexInPool(constantPoolCTVM, index); + int indexToRefer = dummyClass.constantPoolSS.getNameAndTypeRefIndexAt(cpi); + String msg = String.format("Wrong nameAndType index returned by lookupNameAndTypeRefIndexInPool" + + " method applied to %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(indexToRefer, indexToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java new file mode 100644 index 00000000000..9dc255210fb --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupNameInPoolTest.java @@ -0,0 +1,105 @@ +/* + * 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 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupNameInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupNameInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Asserts; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupNameInPool} method + */ +public class LookupNameInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupNameInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupNameInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + String nameToVerify = CompilerToVMHelper.lookupNameInPool(constantPoolCTVM, index); + String nameToRefer = entry.name; + String msg = String.format("Wrong name accessed by %sconstant pool index %d", cached, index); + Asserts.assertEQ(nameToVerify, nameToRefer, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java new file mode 100644 index 00000000000..adcf6cb85f4 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupSignatureInPoolTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @bug 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.LookupSignatureInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupSignatureInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.lookupSignatureInPool} method + */ +public class LookupSignatureInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_INTERFACEMETHODREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_FIELDREF, LookupSignatureInPoolTest::validate); + typeTests.put(CONSTANT_INVOKEDYNAMIC, LookupSignatureInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + String sigToVerify = CompilerToVMHelper.lookupSignatureInPool(constantPoolCTVM, index); + String sigToRefer = entry.type; + String msg = String.format("Wrong signature accessed by %sconstant pool index %d", + cached, + index); + Asserts.assertEQ(sigToVerify, sigToRefer, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java index 2f6efe1795f..269c5a7d39c 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/LookupTypeTest.java @@ -26,12 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.LookupTypeTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.LookupTypeTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.LookupTypeTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java index 326f24e92fb..e28174905a2 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java @@ -26,22 +26,34 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta * @ignore 8139703 - * @compile ../common/CompilerToVMHelper.java - * @build sun.hotspot.WhiteBox MaterializeVirtualObjectTest + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:CompileCommand=exclude,*::check -XX:+DoEscapeAnalysis -Xbatch - * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=false - * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:CompileCommand=exclude,*::check -XX:+DoEscapeAnalysis -Xbatch - * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=true - * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:CompileCommand=exclude,*::check + * -XX:+DoEscapeAnalysis + * -Xbatch + * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=false + * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:CompileCommand=exclude,*::check + * -XX:+DoEscapeAnalysis + * -Xbatch + * -Dcompiler.jvmci.compilerToVM.MaterializeVirtualObjectTest.invalidate=true + * compiler.jvmci.compilerToVM.MaterializeVirtualObjectTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java index 3d00dae0cd7..b63fa7af5ee 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/MethodIsIgnoredBySecurityStackWalkTest.java @@ -27,11 +27,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.MethodIsIgnoredBySecurityStackWalkTest * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.MethodIsIgnoredBySecurityStackWalkTest + * compiler.jvmci.compilerToVM.MethodIsIgnoredBySecurityStackWalkTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java index 5ff5913d6fe..4ec17c2e71a 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReadUncompressedOopTest.java @@ -26,22 +26,24 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller * sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:-UseCompressedOops - * compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:-UseCompressedOops + * compiler.jvmci.compilerToVM.ReadUncompressedOopTest * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI - * -XX:+UseCompressedOops - * compiler.jvmci.compilerToVM.ReadUncompressedOopTest + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UseCompressedOops + * compiler.jvmci.compilerToVM.ReadUncompressedOopTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java index bc3e781086d..1e8cb12dd89 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ReprofileTest.java @@ -27,16 +27,23 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build sun.hotspot.WhiteBox + * @build compiler.jvmci.compilerToVM.ReprofileTest * @run main ClassFileInstaller * sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * -Xmixed - * compiler.jvmci.compilerToVM.ReprofileTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -Xmixed + * compiler.jvmci.compilerToVM.ReprofileTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java index e72240e0316..285f0ff77af 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveConstantInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,67 +27,92 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.compilerToVM.ResolveConstantInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * compiler.jvmci.compilerToVM.ResolveConstantInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.HashMap; import java.util.Map; -import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.test.lib.Asserts; -import sun.reflect.ConstantPool; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.resolveConstantInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveConstantInPool} method */ public class ResolveConstantInPoolTest { + private static final String NOT_NULL_MSG + = "Object returned by resolveConstantInPool method should not be null"; + public static void main(String[] args) throws Exception { - Map typeTests = new HashMap<>(2); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODHANDLE, - ResolveConstantInPoolTest::validateMethodHandle); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_METHODTYPE, - ResolveConstantInPoolTest::validateMethodType); + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_METHODHANDLE, ResolveConstantInPoolTest::validateMethodHandle); + typeTests.put(CONSTANT_METHODTYPE, ResolveConstantInPoolTest::validateMethodType); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - private static void validateMethodHandle( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - Object constantInPool = CompilerToVMHelper - .resolveConstantInPool(constantPoolCTVM, index); + private static void validateMethodHandle(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int index) { + Object constantInPool = CompilerToVMHelper.resolveConstantInPool(constantPoolCTVM, index); + String msg = String.format("%s for index %d", NOT_NULL_MSG, index); + Asserts.assertNotNull(constantInPool, msg); if (!(constantInPool instanceof MethodHandle)) { - String msg = String.format( - "Wrong constant pool entry accessed by index" - + " %d: %s, but should be subclass of %s", - index + 1, constantInPool.getClass(), - MethodHandle.class.getName()); + msg = String.format("Wrong constant pool entry accessed by index" + + " %d: %s, but should be subclass of %s", + index, + constantInPool.getClass(), + MethodHandle.class.getName()); throw new AssertionError(msg); } } - private static void validateMethodType( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int index) { - Object constantInPool = CompilerToVMHelper - .resolveConstantInPool(constantPoolCTVM, index); + private static void validateMethodType(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int index) { + Object constantInPool = CompilerToVMHelper.resolveConstantInPool(constantPoolCTVM, index); + String msg = String.format("%s for index %d", NOT_NULL_MSG, index); + Asserts.assertNotNull(constantInPool, msg); Class mtToVerify = constantInPool.getClass(); Class mtToRefer = MethodType.class; - String msg = String.format("Wrong %s accessed by constant pool index" - + " %d: %s, but should be %s", "method type class", - index, mtToVerify, mtToRefer); + msg = String.format("Wrong method type class accessed by" + + " constant pool index %d", + index); Asserts.assertEQ(mtToRefer, mtToVerify, msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java new file mode 100644 index 00000000000..2d7145dec15 --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveFieldInPoolTest.java @@ -0,0 +1,164 @@ +/* + * 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 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolveFieldInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolveFieldInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.ConstantPool; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.misc.Unsafe; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveFieldInPool} method + */ +public class ResolveFieldInPoolTest { + + private static final Unsafe UNSAFE = Utils.getUnsafe(); + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_FIELDREF, ResolveFieldInPoolTest::validate); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + for (int j = 0; j < entry.opcodes.length; j++) { + long[] info = new long[2]; + HotSpotResolvedObjectType fieldToVerify + = CompilerToVMHelper.resolveFieldInPool(constantPoolCTVM, + index, + entry.opcodes[j], + info); + String msg = String.format("Object returned by resolveFieldInPool method" + + " for %sindex %d should not be null", + cached, + index); + Asserts.assertNotNull(fieldToVerify, msg); + String classNameToRefer = entry.klass; + String fieldToVerifyKlassToString = fieldToVerify.klass().toValueString(); + if (!fieldToVerifyKlassToString.contains(classNameToRefer)) { + msg = String.format("String representation \"%s\" of the object" + + " returned by resolveFieldInPool method" + + " for index %d does not contain a field's class name," + + " should contain %s", + fieldToVerifyKlassToString, + index, + classNameToRefer); + throw new AssertionError(msg); + } + msg = String.format("Access flags returned by resolveFieldInPool" + + " method are wrong for the field %s.%s" + + " at %sindex %d", + entry.klass, + entry.name, + cached, + index); + Asserts.assertEQ(info[0], entry.accFlags, msg); + if (cpci == -1) { + return; + } + Class classOfTheField = null; + Field fieldToRefer = null; + try { + classOfTheField = Class.forName(classNameToRefer.replaceAll("/", "\\.")); + fieldToRefer = classOfTheField.getDeclaredField(entry.name); + fieldToRefer.setAccessible(true); + } catch (Exception ex) { + throw new Error("Unexpected exception", ex); + } + long offsetToRefer; + if ((entry.accFlags & Opcodes.ACC_STATIC) != 0) { + offsetToRefer = UNSAFE.staticFieldOffset(fieldToRefer); + } else { + offsetToRefer = UNSAFE.objectFieldOffset(fieldToRefer); + } + msg = String.format("Field offset returned by resolveFieldInPool" + + " method is wrong for the field %s.%s" + + " at %sindex %d", + entry.klass, + entry.name, + cached, + index); + Asserts.assertEQ(info[1], offsetToRefer, msg); + } + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java index ba43e6b08ff..ff08b7e53bf 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveMethodTest.java @@ -26,12 +26,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.ResolveMethodTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveMethodTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolveMethodTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java new file mode 100644 index 00000000000..1e0f269e8cd --- /dev/null +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolvePossiblyCachedConstantInPoolTest.java @@ -0,0 +1,101 @@ +/* + * 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 8138708 + * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") + * @library /testlibrary /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox + * compiler.jvmci.compilerToVM.ResolvePossiblyCachedConstantInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ResolvePossiblyCachedConstantInPoolTest + */ + +package compiler.jvmci.compilerToVM; + +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; +import java.util.HashMap; +import java.util.Map; +import jdk.test.lib.Asserts; +import jdk.vm.ci.hotspot.CompilerToVMHelper; +import jdk.vm.ci.meta.ConstantPool; + +/** + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolvePossiblyCachedConstantInPool} method + */ +public class ResolvePossiblyCachedConstantInPoolTest { + + public static void main(String[] args) throws Exception { + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_STRING, ResolvePossiblyCachedConstantInPoolTest::validateString); + ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); + // The next "Class.forName" is here for the following reason. + // When class is initialized, constant pool cache is available. + // This method works only with cached constant pool. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); + } + + private static void validateString(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int cpi) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, cpi); + if (entry == null) { + return; + } + int index = cpi; + String cached = ""; + int cpci = dummyClass.getCPCacheIndex(cpi); + if (cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + index = cpci; + cached = "cached "; + } + Object constantInPool = CompilerToVMHelper.resolvePossiblyCachedConstantInPool(constantPoolCTVM, index); + String stringToVerify = (String) constantInPool; + String stringToRefer = entry.name; + if (stringToRefer.equals("") && cpci != ConstantPoolTestsHelper.NO_CP_CACHE_PRESENT) { + stringToRefer = null; // tested method returns null for cached empty strings + } + String msg = String.format("Wrong string accessed by %sconstant pool index %d", cached, index); + Asserts.assertEQ(stringToRefer, stringToVerify, msg); + } +} diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java index 9b205e347ad..cad8ccd9f31 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ResolveTypeInPoolTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,52 +28,75 @@ * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @summary Testing compiler.jvmci.CompilerToVM.resolveTypeInPool method * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java - * @build compiler.jvmci.common.testcases.MultipleImplementersInterface - * compiler.jvmci.common.testcases.MultipleImplementer2 - * compiler.jvmci.compilerToVM.ConstantPoolTestsHelper - * compiler.jvmci.compilerToVM.ConstantPoolTestCase + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.org.objectweb.asm + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.meta + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build sun.hotspot.WhiteBox * compiler.jvmci.compilerToVM.ResolveTypeInPoolTest - * @run main ClassFileInstaller jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockExperimentalVMOptions - * -XX:+EnableJVMCI compiler.jvmci.compilerToVM.ResolveTypeInPoolTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * compiler.jvmci.compilerToVM.ResolveTypeInPoolTest */ package compiler.jvmci.compilerToVM; +import compiler.jvmci.compilerToVM.ConstantPoolTestsHelper.DummyClasses; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes; +import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry; +import compiler.jvmci.compilerToVM.ConstantPoolTestCase.Validator; import java.util.HashMap; import java.util.Map; import jdk.vm.ci.hotspot.CompilerToVMHelper; import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; -import sun.reflect.ConstantPool; +import jdk.vm.ci.meta.ConstantPool; /** - * Test for {@code compiler.jvmci.CompilerToVM.resolveTypeInPool} method + * Test for {@code jdk.vm.ci.hotspot.CompilerToVM.resolveTypeInPool} method */ public class ResolveTypeInPoolTest { public static void main(String[] args) throws Exception { - Map typeTests = new HashMap<>(1); - typeTests.put(ConstantPoolTestsHelper.ConstantTypes.CONSTANT_CLASS, - ResolveTypeInPoolTest::validate); + Map typeTests = new HashMap<>(); + typeTests.put(CONSTANT_CLASS, ResolveTypeInPoolTest::validate); ConstantPoolTestCase testCase = new ConstantPoolTestCase(typeTests); testCase.test(); + // The next "Class.forName" and repeating "testCase.test()" + // are here for the following reason. + // The first test run is without dummy class initialization, + // which means no constant pool cache exists. + // The second run is with initialized class (with constant pool cache available). + // Some CompilerToVM methods require different input + // depending on whether CP cache exists or not. + for (DummyClasses dummy : DummyClasses.values()) { + Class.forName(dummy.klass.getName()); + } + testCase.test(); } - public static void validate( - jdk.vm.ci.meta.ConstantPool constantPoolCTVM, - ConstantPool constantPoolSS, - ConstantPoolTestsHelper.DummyClasses dummyClass, int i) { - HotSpotResolvedObjectType typeToVerify = CompilerToVMHelper - .resolveTypeInPool(constantPoolCTVM, i); - int classNameIndex = (int) dummyClass.cp.get(i).value; - String classNameToRefer = constantPoolSS.getUTF8At(classNameIndex); + public static void validate(ConstantPool constantPoolCTVM, + ConstantTypes cpType, + DummyClasses dummyClass, + int i) { + TestedCPEntry entry = cpType.getTestedCPEntry(dummyClass, i); + if (entry == null) { + return; + } + HotSpotResolvedObjectType typeToVerify = CompilerToVMHelper.resolveTypeInPool(constantPoolCTVM, i); + String classNameToRefer = entry.klass; String outputToVerify = typeToVerify.toString(); if (!outputToVerify.contains(classNameToRefer)) { String msg = String.format("Wrong class accessed by constant" - + " pool index %d: %s, but should be %s", - i, outputToVerify, classNameToRefer); + + " pool index %d: %s, but should be %s", + i, + outputToVerify, + classNameToRefer); throw new AssertionError(msg); } } diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java index 86f9cef8ec0..69ceeffdf7d 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldDebugNonSafepointsTest.java @@ -26,22 +26,20 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary /test/lib/ - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest - * @run main ClassFileInstaller - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions - * -XX:+DebugNonSafepoints - * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=true - * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest - * @run main/othervm - * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions - * -XX:-DebugNonSafepoints - * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=false - * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions + * -XX:+DebugNonSafepoints + * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=true + * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest + * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * -XX:+UnlockDiagnosticVMOptions + * -XX:-DebugNonSafepoints + * -Dcompiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest.expected=false + * compiler.jvmci.compilerToVM.ShouldDebugNonSafepointsTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java index a034166604a..615b5859df6 100644 --- a/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java +++ b/hotspot/test/compiler/jvmci/compilerToVM/ShouldInlineMethodTest.java @@ -27,14 +27,20 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library /testlibrary /test/lib / - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper + * @build compiler.jvmci.compilerToVM.ShouldInlineMethodTest * @build sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * sun.hotspot.WhiteBox$WhiteBoxPermission - * jdk.vm.ci.hotspot.CompilerToVMHelper - * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. - * compiler.jvmci.compilerToVM.ShouldInlineMethodTest + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + * compiler.jvmci.compilerToVM.ShouldInlineMethodTest */ package compiler.jvmci.compilerToVM; diff --git a/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java index 810404bf8ef..c8bfbff88d1 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciCreateMetaAccessContextTest.java @@ -26,7 +26,12 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary - * @compile ./MetaAccessWrapper.java + * @library ../common/patches + * @modules jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci/jdk.vm.ci.hotspot.MetaAccessWrapper * @build compiler.jvmci.common.JVMCIHelpers * compiler.jvmci.events.JvmciCreateMetaAccessContextTest * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ @@ -37,7 +42,6 @@ * compiler.jvmci.common.JVMCIHelpers$EmptyHotspotCompiler * compiler.jvmci.common.JVMCIHelpers$EmptyCompilerFactory * compiler.jvmci.events.JvmciCreateMetaAccessContextTest - * jdk.vm.ci.hotspot.MetaAccessWrapper * jdk.test.lib.Asserts * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI * -Xbootclasspath/a:. diff --git a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java index 75c808e34cc..5e6f972a883 100644 --- a/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java +++ b/hotspot/test/compiler/jvmci/events/JvmciNotifyInstallEventTest.java @@ -26,7 +26,15 @@ * @bug 8136421 * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") * @library / /testlibrary - * @compile ../common/CompilerToVMHelper.java + * @library ../common/patches + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.vm.ci/jdk.vm.ci.hotspot + * jdk.vm.ci/jdk.vm.ci.code + * jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @ignore 8144964 + * @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper * @build compiler.jvmci.common.JVMCIHelpers * compiler.jvmci.events.JvmciNotifyInstallEventTest * @run main jdk.test.lib.FileInstaller ../common/services/ ./META-INF/services/ @@ -38,7 +46,6 @@ * compiler.jvmci.events.JvmciNotifyInstallEventTest * compiler.jvmci.common.CTVMUtilities * compiler.jvmci.common.testcases.SimpleClass - * jdk.vm.ci.hotspot.CompilerToVMHelper * jdk.test.lib.Asserts * @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI * -Djvmci.compiler=EmptyCompiler -Xbootclasspath/a:. -Xmixed diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java index 5be56d0c33a..761db0e7a06 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/ConstantTest.java @@ -24,10 +24,13 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile ConstantTest.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.ConstantTest * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.ConstantTest */ - +// * @compile ConstantTest.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java package jdk.vm.ci.runtime.test; import jdk.vm.ci.meta.JavaConstant; diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java index 11392414300..038efdcb2d2 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/RedefineClassTest.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile RedefineClassTest.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.RedefineClassTest * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.RedefineClassTest */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java index dbde990b71c..fe31f5907be 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestConstantReflectionProvider.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestConstantReflectionProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestConstantReflectionProvider * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestConstantReflectionProvider */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java index d4c3a58db5d..46f4e80ac89 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaField.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestJavaField * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaField */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java index 50e7b2ed3ee..460abd992af 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaMethod.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestJavaMethod * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaMethod */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java index 311c96ac5af..72506cf0933 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestJavaType.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestJavaType.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestJavaType * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestJavaType */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java index 9c1974035cf..10b2e70c334 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestMetaAccessProvider.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestMetaAccessProvider.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestMetaAccessProvider * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestMetaAccessProvider */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java index fb960c00af7..71e9f188c43 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaField.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestResolvedJavaField.java FieldUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestResolvedJavaField * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaField */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 13dd0999fee..c60a7d45e42 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -24,7 +24,10 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestResolvedJavaMethod.java MethodUniverse.java TypeUniverse.java TestMetaAccessProvider.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * @build jdk.vm.ci.runtime.test.TestResolvedJavaMethod * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaMethod */ diff --git a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java index 8c869808338..2011bc0c863 100644 --- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java +++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java @@ -24,7 +24,11 @@ /** * @test * @requires (os.simpleArch == "x64" | os.simpleArch == "sparcv9" | os.simpleArch == "aarch64") - * @compile TestResolvedJavaType.java TypeUniverse.java TestMetaAccessProvider.java NameAndSignature.java + * @library ../../../../../ + * @modules jdk.vm.ci/jdk.vm.ci.meta + * jdk.vm.ci/jdk.vm.ci.runtime + * jdk.vm.ci/jdk.vm.ci.common + * @build jdk.vm.ci.runtime.test.TestResolvedJavaType * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI jdk.vm.ci.runtime.test.TestResolvedJavaType */ diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg2/Class1Pkg2.java b/hotspot/test/compiler/native/TestDirtyInt.java similarity index 64% rename from langtools/test/com/sun/javadoc/testProfiles/pkg2/Class1Pkg2.java rename to hotspot/test/compiler/native/TestDirtyInt.java index 935bd3643ae..607fd2d491c 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg2/Class1Pkg2.java +++ b/hotspot/test/compiler/native/TestDirtyInt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,31 +21,26 @@ * questions. */ -package pkg2; - -/** - * @deprecated Class1Pkg2. This class is deprecated - * - * @author Bhavesh Patel +/* @test + * @run main/native TestDirtyInt */ -public class Class1Pkg2 { +public class TestDirtyInt { + static { + System.loadLibrary("TestDirtyInt"); + } - /** - * A sample enum. - */ - public static enum ModalExclusionType { - /** - * Test comment. - */ - NO_EXCLUDE, - /** - * Another comment. - */ - APPLICATION_EXCLUDE - }; + native static int test(int v); - /** - * A string constant. - */ - public static final String CONSTANT1 = "C2"; + static int compiled(int v) { + return test(v<<2); + } + + static public void main(String[] args) { + for (int i = 0; i < 20000; i++) { + int res = compiled(Integer.MAX_VALUE); + if (res != 0x42) { + throw new RuntimeException("Test failed"); + } + } + } } diff --git a/hotspot/test/compiler/native/libTestDirtyInt.c b/hotspot/test/compiler/native/libTestDirtyInt.c new file mode 100644 index 00000000000..b688a369398 --- /dev/null +++ b/hotspot/test/compiler/native/libTestDirtyInt.c @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#include "jni.h" +#include + +static int array = 0x42; + +JNIEXPORT jint JNICALL Java_TestDirtyInt_test(JNIEnv* env, jclass jclazz, jint v) +{ + int* ptr = &array + v + 4; + return *ptr; +} diff --git a/hotspot/test/compiler/stable/StableConfiguration.java b/hotspot/test/compiler/stable/StableConfiguration.java index be69081640c..db7e9a0f742 100644 --- a/hotspot/test/compiler/stable/StableConfiguration.java +++ b/hotspot/test/compiler/stable/StableConfiguration.java @@ -22,16 +22,17 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package java.lang.invoke; + +package compiler.stable; + +import sun.hotspot.WhiteBox; import java.lang.reflect.Method; -import java.util.Properties; -import sun.hotspot.WhiteBox; public class StableConfiguration { static final WhiteBox WB = WhiteBox.getWhiteBox(); - static final boolean isStableEnabled; - static final boolean isServerWithStable; + public static final boolean isStableEnabled; + public static final boolean isServerWithStable; static { Boolean value = WB.getBooleanVMFlag("FoldStableValues"); @@ -60,8 +61,6 @@ public class StableConfiguration { static void get1() { } - - // ::get() is among immediately compiled methods. static boolean get() { try { @@ -80,5 +79,4 @@ public class StableConfiguration { throw new Error(e); } } - } diff --git a/hotspot/test/compiler/stable/TestStableBoolean.java b/hotspot/test/compiler/stable/TestStableBoolean.java index 168ddf48da7..ed8d18b18fa 100644 --- a/hotspot/test/compiler/stable/TestStableBoolean.java +++ b/hotspot/test/compiler/stable/TestStableBoolean.java @@ -26,64 +26,37 @@ /* * @test TestStableBoolean * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableBoolean StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableBoolean - * java/lang/invoke/TestStableBoolean$BooleanStable - * java/lang/invoke/TestStableBoolean$StaticBooleanStable - * java/lang/invoke/TestStableBoolean$VolatileBooleanStable - * java/lang/invoke/TestStableBoolean$BooleanArrayDim1 - * java/lang/invoke/TestStableBoolean$BooleanArrayDim2 - * java/lang/invoke/TestStableBoolean$BooleanArrayDim3 - * java/lang/invoke/TestStableBoolean$BooleanArrayDim4 - * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableBoolean$NestedStableField - * java/lang/invoke/TestStableBoolean$NestedStableField$A - * java/lang/invoke/TestStableBoolean$NestedStableField1 - * java/lang/invoke/TestStableBoolean$NestedStableField1$A - * java/lang/invoke/TestStableBoolean$NestedStableField2 - * java/lang/invoke/TestStableBoolean$NestedStableField2$A - * java/lang/invoke/TestStableBoolean$NestedStableField3 - * java/lang/invoke/TestStableBoolean$NestedStableField3$A - * java/lang/invoke/TestStableBoolean$DefaultValue - * java/lang/invoke/TestStableBoolean$DefaultStaticValue - * java/lang/invoke/TestStableBoolean$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableBoolean * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableBoolean - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableBoolean - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableBoolean - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableBoolean + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableBoolean + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:-FoldStableValues + * compiler.stable.TestStableBoolean * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:+FoldStableValues + * compiler.stable.TestStableBoolean + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 + * -XX:-FoldStableValues + * compiler.stable.TestStableBoolean */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableBoolean { @@ -122,12 +95,13 @@ public class TestStableBoolean { /* ==================================================== */ static class DefaultValue { - public @Stable boolean v; + public @Stable + boolean v; public static final DefaultValue c = new DefaultValue(); public static boolean get() { return c.v; } public static void test() throws Exception { - boolean val1 = get(); + boolean val1 = get(); c.v = true; boolean val2 = get(); assertEquals(val1, false); assertEquals(val2, true); @@ -157,7 +131,7 @@ public class TestStableBoolean { public static final DefaultStaticValue c = new DefaultStaticValue(); public static boolean get() { return c.v; } public static void test() throws Exception { - boolean val1 = get(); + boolean val1 = get(); c.v = true; boolean val2 = get(); assertEquals(val1, false); assertEquals(val2, true); @@ -207,14 +181,14 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1]; c.v[0] = true; boolean val1 = get(); - c.v[0] = false; boolean val2 = get(); + c.v[0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, (isServerWithStable ? true : false)); } { c.v = new boolean[20]; c.v[10] = true; boolean val1 = get1(); - c.v[10] = false; boolean val2 = get1(); + c.v[10] = false; boolean val2 = get1(); assertEquals(val1, true); assertEquals(val2, (isServerWithStable ? true : false)); } @@ -239,7 +213,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1][1]; c.v[0][0] = true; boolean val1 = get(); - c.v[0][0] = false; boolean val2 = get(); + c.v[0][0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, (isServerWithStable ? true : false)); @@ -277,7 +251,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1][1][1]; c.v[0][0][0] = true; boolean val1 = get(); - c.v[0][0][0] = false; boolean val2 = get(); + c.v[0][0][0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, (isServerWithStable ? true : false)); @@ -325,7 +299,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1][1][1][1]; c.v[0][0][0][0] = true; boolean val1 = get(); - c.v[0][0][0][0] = false; boolean val2 = get(); + c.v[0][0][0][0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, (isServerWithStable ? true : false)); @@ -383,7 +357,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1]; ((boolean[])c.v)[0] = true; boolean val1 = get(); - ((boolean[])c.v)[0] = false; boolean val2 = get(); + ((boolean[])c.v)[0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, false); @@ -410,7 +384,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1][1]; ((boolean[][])c.v)[0][0] = true; boolean val1 = get(); - ((boolean[][])c.v)[0][0] = false; boolean val2 = get(); + ((boolean[][])c.v)[0][0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, false); @@ -418,7 +392,7 @@ public class TestStableBoolean { { c.v = new boolean[1][1]; c.v[0] = new boolean[0]; boolean[] val1 = get1(); - c.v[0] = new boolean[0]; boolean[] val2 = get1(); + c.v[0] = new boolean[0]; boolean[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -446,7 +420,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new boolean[1][1][1]; ((boolean[][][])c.v)[0][0][0] = true; boolean val1 = get(); - ((boolean[][][])c.v)[0][0][0] = false; boolean val2 = get(); + ((boolean[][][])c.v)[0][0][0] = false; boolean val2 = get(); assertEquals(val1, true); assertEquals(val2, false); @@ -454,14 +428,14 @@ public class TestStableBoolean { { c.v = new boolean[1][1][1]; c.v[0][0] = new boolean[0]; boolean[] val1 = get1(); - c.v[0][0] = new boolean[0]; boolean[] val2 = get1(); + c.v[0][0] = new boolean[0]; boolean[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new boolean[1][1][1]; c.v[0] = new boolean[0][0]; boolean[][] val1 = get2(); - c.v[0] = new boolean[0][0]; boolean[][] val2 = get2(); + c.v[0] = new boolean[0][0]; boolean[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -491,7 +465,7 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new A(); c.v.a = true; A val1 = get(); - c.v.a = false; A val2 = get(); + c.v.a = false; A val2 = get(); assertEquals(val1.a, false); assertEquals(val2.a, false); @@ -499,7 +473,7 @@ public class TestStableBoolean { { c.v = new A(); c.v.a = true; boolean val1 = get1(); - c.v.a = false; boolean val2 = get1(); + c.v.a = false; boolean val2 = get1(); c.v = new A(); c.v.a = false; boolean val3 = get1(); assertEquals(val1, true); @@ -525,8 +499,8 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = true; c.v.next.a = true; A val1 = get(); - c.v.a = false; c.v.next.a = false; A val2 = get(); + c.v.a = true; c.v.next.a = true; A val1 = get(); + c.v.a = false; c.v.next.a = false; A val2 = get(); assertEquals(val1.a, false); assertEquals(val2.a, false); @@ -534,10 +508,10 @@ public class TestStableBoolean { { c.v = new A(); c.v.next = c.v; - c.v.a = true; boolean val1 = get1(); - c.v.a = false; boolean val2 = get1(); + c.v.a = true; boolean val1 = get1(); + c.v.a = false; boolean val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = false; boolean val3 = get1(); + c.v.a = false; boolean val3 = get1(); assertEquals(val1, true); assertEquals(val2, (isStableEnabled ? true : false)); @@ -563,8 +537,8 @@ public class TestStableBoolean { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = true; boolean val1 = get(); boolean val2 = get1(); - c.v.a = false; boolean val3 = get(); boolean val4 = get1(); + c.v.a = true; boolean val1 = get(); boolean val2 = get1(); + c.v.a = false; boolean val3 = get(); boolean val4 = get1(); assertEquals(val1, true); assertEquals(val3, (isStableEnabled ? true : false)); @@ -594,8 +568,8 @@ public class TestStableBoolean { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = true; boolean val1 = get(); boolean val2 = get1(); - elem.a = false; boolean val3 = get(); boolean val4 = get1(); + elem.a = true; boolean val1 = get(); boolean val2 = get1(); + elem.a = false; boolean val3 = get(); boolean val4 = get1(); assertEquals(val1, true); assertEquals(val3, (isServerWithStable ? true : false)); @@ -632,4 +606,5 @@ public class TestStableBoolean { } } } + } diff --git a/hotspot/test/compiler/stable/TestStableByte.java b/hotspot/test/compiler/stable/TestStableByte.java index 694205e8e55..14ce6e40135 100644 --- a/hotspot/test/compiler/stable/TestStableByte.java +++ b/hotspot/test/compiler/stable/TestStableByte.java @@ -26,64 +26,37 @@ /* * @test TestStableByte * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableByte StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableByte - * java/lang/invoke/TestStableByte$ByteStable - * java/lang/invoke/TestStableByte$StaticByteStable - * java/lang/invoke/TestStableByte$VolatileByteStable - * java/lang/invoke/TestStableByte$ByteArrayDim1 - * java/lang/invoke/TestStableByte$ByteArrayDim2 - * java/lang/invoke/TestStableByte$ByteArrayDim3 - * java/lang/invoke/TestStableByte$ByteArrayDim4 - * java/lang/invoke/TestStableByte$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableByte$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableByte$NestedStableField - * java/lang/invoke/TestStableByte$NestedStableField$A - * java/lang/invoke/TestStableByte$NestedStableField1 - * java/lang/invoke/TestStableByte$NestedStableField1$A - * java/lang/invoke/TestStableByte$NestedStableField2 - * java/lang/invoke/TestStableByte$NestedStableField2$A - * java/lang/invoke/TestStableByte$NestedStableField3 - * java/lang/invoke/TestStableByte$NestedStableField3$A - * java/lang/invoke/TestStableByte$DefaultValue - * java/lang/invoke/TestStableByte$DefaultStaticValue - * java/lang/invoke/TestStableByte$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableByte * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableByte - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableByte - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableByte - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableByte + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableByte + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableByte * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableByte + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableByte */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableByte { @@ -127,7 +100,7 @@ public class TestStableByte { public static final DefaultValue c = new DefaultValue(); public static byte get() { return c.v; } public static void test() throws Exception { - byte val1 = get(); + byte val1 = get(); c.v = 1; byte val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1); @@ -157,7 +130,7 @@ public class TestStableByte { public static final DefaultStaticValue c = new DefaultStaticValue(); public static byte get() { return c.v; } public static void test() throws Exception { - byte val1 = get(); + byte val1 = get(); c.v = 1; byte val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1); @@ -207,24 +180,24 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1]; c.v[0] = 1; byte val1 = get(); - c.v[0] = 2; byte val2 = get(); + c.v[0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new byte[1]; c.v[0] = 3; byte val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { c.v = new byte[20]; c.v[10] = 1; byte val1 = get1(); - c.v[10] = 2; byte val2 = get1(); + c.v[10] = 2; byte val2 = get1(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new byte[20]; c.v[10] = 3; byte val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { @@ -247,17 +220,17 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1][1]; c.v[0][0] = 1; byte val1 = get(); - c.v[0][0] = 2; byte val2 = get(); + c.v[0][0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new byte[1][1]; c.v[0][0] = 3; byte val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new byte[1]; c.v[0][0] = 4; byte val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); } { @@ -287,21 +260,21 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1][1][1]; c.v[0][0][0] = 1; byte val1 = get(); - c.v[0][0][0] = 2; byte val2 = get(); + c.v[0][0][0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new byte[1][1][1]; c.v[0][0][0] = 3; byte val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new byte[1][1]; c.v[0][0][0] = 4; byte val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new byte[1]; c.v[0][0][0] = 5; byte val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); } { @@ -338,25 +311,25 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 1; byte val1 = get(); - c.v[0][0][0][0] = 2; byte val2 = get(); + c.v[0][0][0][0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new byte[1][1][1][1]; c.v[0][0][0][0] = 3; byte val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new byte[1][1][1]; c.v[0][0][0][0] = 4; byte val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new byte[1][1]; c.v[0][0][0][0] = 5; byte val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); c.v[0][0][0] = new byte[1]; c.v[0][0][0][0] = 6; byte val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 6)); + : 6)); } { @@ -399,7 +372,7 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1]; ((byte[])c.v)[0] = 1; byte val1 = get(); - ((byte[])c.v)[0] = 2; byte val2 = get(); + ((byte[])c.v)[0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -426,7 +399,7 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1][1]; ((byte[][])c.v)[0][0] = 1; byte val1 = get(); - ((byte[][])c.v)[0][0] = 2; byte val2 = get(); + ((byte[][])c.v)[0][0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -434,7 +407,7 @@ public class TestStableByte { { c.v = new byte[1][1]; c.v[0] = new byte[0]; byte[] val1 = get1(); - c.v[0] = new byte[0]; byte[] val2 = get1(); + c.v[0] = new byte[0]; byte[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -462,7 +435,7 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new byte[1][1][1]; ((byte[][][])c.v)[0][0][0] = 1; byte val1 = get(); - ((byte[][][])c.v)[0][0][0] = 2; byte val2 = get(); + ((byte[][][])c.v)[0][0][0] = 2; byte val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -470,14 +443,14 @@ public class TestStableByte { { c.v = new byte[1][1][1]; c.v[0][0] = new byte[0]; byte[] val1 = get1(); - c.v[0][0] = new byte[0]; byte[] val2 = get1(); + c.v[0][0] = new byte[0]; byte[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new byte[1][1][1]; c.v[0] = new byte[0][0]; byte[][] val1 = get2(); - c.v[0] = new byte[0][0]; byte[][] val2 = get2(); + c.v[0] = new byte[0][0]; byte[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -507,7 +480,7 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new A(); c.v.a = 1; A val1 = get(); - c.v.a = 2; A val2 = get(); + c.v.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -515,7 +488,7 @@ public class TestStableByte { { c.v = new A(); c.v.a = 1; byte val1 = get1(); - c.v.a = 2; byte val2 = get1(); + c.v.a = 2; byte val2 = get1(); c.v = new A(); c.v.a = 3; byte val3 = get1(); assertEquals(val1, 1); @@ -541,8 +514,8 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 1; c.v.next.a = 1; A val1 = get(); - c.v.a = 2; c.v.next.a = 2; A val2 = get(); + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -550,10 +523,10 @@ public class TestStableByte { { c.v = new A(); c.v.next = c.v; - c.v.a = 1; byte val1 = get1(); - c.v.a = 2; byte val2 = get1(); + c.v.a = 1; byte val1 = get1(); + c.v.a = 2; byte val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 3; byte val3 = get1(); + c.v.a = 3; byte val3 = get1(); assertEquals(val1, 1); assertEquals(val2, (isStableEnabled ? 1 : 2)); @@ -579,8 +552,8 @@ public class TestStableByte { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 1; byte val1 = get(); byte val2 = get1(); - c.v.a = 2; byte val3 = get(); byte val4 = get1(); + c.v.a = 1; byte val1 = get(); byte val2 = get1(); + c.v.a = 2; byte val3 = get(); byte val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isStableEnabled ? 1 : 2)); @@ -610,8 +583,8 @@ public class TestStableByte { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 1; byte val1 = get(); byte val2 = get1(); - elem.a = 2; byte val3 = get(); byte val4 = get1(); + elem.a = 1; byte val1 = get(); byte val2 = get1(); + elem.a = 2; byte val3 = get(); byte val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isServerWithStable ? 1 : 2)); diff --git a/hotspot/test/compiler/stable/TestStableChar.java b/hotspot/test/compiler/stable/TestStableChar.java index d92dfb67c73..ba8e935fd35 100644 --- a/hotspot/test/compiler/stable/TestStableChar.java +++ b/hotspot/test/compiler/stable/TestStableChar.java @@ -26,65 +26,38 @@ /* * @test TestStableChar * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableChar StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableChar - * java/lang/invoke/TestStableChar$CharStable - * java/lang/invoke/TestStableChar$StaticCharStable - * java/lang/invoke/TestStableChar$VolatileCharStable - * java/lang/invoke/TestStableChar$CharArrayDim1 - * java/lang/invoke/TestStableChar$CharArrayDim2 - * java/lang/invoke/TestStableChar$CharArrayDim3 - * java/lang/invoke/TestStableChar$CharArrayDim4 - * java/lang/invoke/TestStableChar$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableChar$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableChar$NestedStableField - * java/lang/invoke/TestStableChar$NestedStableField$A - * java/lang/invoke/TestStableChar$NestedStableField1 - * java/lang/invoke/TestStableChar$NestedStableField1$A - * java/lang/invoke/TestStableChar$NestedStableField2 - * java/lang/invoke/TestStableChar$NestedStableField2$A - * java/lang/invoke/TestStableChar$NestedStableField3 - * java/lang/invoke/TestStableChar$NestedStableField3$A - * java/lang/invoke/TestStableChar$DefaultValue - * java/lang/invoke/TestStableChar$DefaultStaticValue - * java/lang/invoke/TestStableChar$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableChar * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableChar - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableChar - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableChar - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableChar + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableChar + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableChar * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableChar + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableChar */ -package java.lang.invoke; -import jdk.internal.vm.annotation.Stable; +package compiler.stable; import java.lang.reflect.InvocationTargetException; +import jdk.internal.vm.annotation.Stable; public class TestStableChar { static final boolean isStableEnabled = StableConfiguration.isStableEnabled; @@ -127,7 +100,7 @@ public class TestStableChar { public static final DefaultValue c = new DefaultValue(); public static char get() { return c.v; } public static void test() throws Exception { - char val1 = get(); + char val1 = get(); c.v = 'a'; char val2 = get(); assertEquals(val1, 0); assertEquals(val2, 'a'); @@ -157,7 +130,7 @@ public class TestStableChar { public static final DefaultStaticValue c = new DefaultStaticValue(); public static char get() { return c.v; } public static void test() throws Exception { - char val1 = get(); + char val1 = get(); c.v = 'a'; char val2 = get(); assertEquals(val1, 0); assertEquals(val2, 'a'); @@ -207,24 +180,24 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1]; c.v[0] = 'a'; char val1 = get(); - c.v[0] = 'b'; char val2 = get(); + c.v[0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, (isServerWithStable ? 'a' : 'b')); c.v = new char[1]; c.v[0] = 'c'; char val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'c')); + : 'c')); } { c.v = new char[20]; c.v[10] = 'a'; char val1 = get1(); - c.v[10] = 'b'; char val2 = get1(); + c.v[10] = 'b'; char val2 = get1(); assertEquals(val1, 'a'); assertEquals(val2, (isServerWithStable ? 'a' : 'b')); c.v = new char[20]; c.v[10] = 'c'; char val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'c')); + : 'c')); } { @@ -247,17 +220,17 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1][1]; c.v[0][0] = 'a'; char val1 = get(); - c.v[0][0] = 'b'; char val2 = get(); + c.v[0][0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, (isServerWithStable ? 'a' : 'b')); c.v = new char[1][1]; c.v[0][0] = 'c'; char val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'c')); + : 'c')); c.v[0] = new char[1]; c.v[0][0] = 'd'; char val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'd')); + : 'd')); } { @@ -287,21 +260,21 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1][1][1]; c.v[0][0][0] = 'a'; char val1 = get(); - c.v[0][0][0] = 'b'; char val2 = get(); + c.v[0][0][0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, (isServerWithStable ? 'a' : 'b')); c.v = new char[1][1][1]; c.v[0][0][0] = 'c'; char val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'c')); + : 'c')); c.v[0] = new char[1][1]; c.v[0][0][0] = 'd'; char val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'd')); + : 'd')); c.v[0][0] = new char[1]; c.v[0][0][0] = 'e'; char val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'e')); + : 'e')); } { @@ -338,25 +311,25 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'a'; char val1 = get(); - c.v[0][0][0][0] = 'b'; char val2 = get(); + c.v[0][0][0][0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, (isServerWithStable ? 'a' : 'b')); c.v = new char[1][1][1][1]; c.v[0][0][0][0] = 'c'; char val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'c')); + : 'c')); c.v[0] = new char[1][1][1]; c.v[0][0][0][0] = 'd'; char val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'd')); + : 'd')); c.v[0][0] = new char[1][1]; c.v[0][0][0][0] = 'e'; char val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'e')); + : 'e')); c.v[0][0][0] = new char[1]; c.v[0][0][0][0] = 'f'; char val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 'a' : 'b') - : 'f')); + : 'f')); } { @@ -397,7 +370,7 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1]; ((char[])c.v)[0] = 'a'; char val1 = get(); - ((char[])c.v)[0] = 'b'; char val2 = get(); + ((char[])c.v)[0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, 'b'); @@ -424,7 +397,7 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1][1]; ((char[][])c.v)[0][0] = 'a'; char val1 = get(); - ((char[][])c.v)[0][0] = 'b'; char val2 = get(); + ((char[][])c.v)[0][0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, 'b'); @@ -432,7 +405,7 @@ public class TestStableChar { { c.v = new char[1][1]; c.v[0] = new char[0]; char[] val1 = get1(); - c.v[0] = new char[0]; char[] val2 = get1(); + c.v[0] = new char[0]; char[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -460,7 +433,7 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new char[1][1][1]; ((char[][][])c.v)[0][0][0] = 'a'; char val1 = get(); - ((char[][][])c.v)[0][0][0] = 'b'; char val2 = get(); + ((char[][][])c.v)[0][0][0] = 'b'; char val2 = get(); assertEquals(val1, 'a'); assertEquals(val2, 'b'); @@ -468,14 +441,14 @@ public class TestStableChar { { c.v = new char[1][1][1]; c.v[0][0] = new char[0]; char[] val1 = get1(); - c.v[0][0] = new char[0]; char[] val2 = get1(); + c.v[0][0] = new char[0]; char[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new char[1][1][1]; c.v[0] = new char[0][0]; char[][] val1 = get2(); - c.v[0] = new char[0][0]; char[][] val2 = get2(); + c.v[0] = new char[0][0]; char[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -505,7 +478,7 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new A(); c.v.a = 'a'; A val1 = get(); - c.v.a = 'b'; A val2 = get(); + c.v.a = 'b'; A val2 = get(); assertEquals(val1.a, 'b'); assertEquals(val2.a, 'b'); @@ -513,7 +486,7 @@ public class TestStableChar { { c.v = new A(); c.v.a = 'a'; char val1 = get1(); - c.v.a = 'b'; char val2 = get1(); + c.v.a = 'b'; char val2 = get1(); c.v = new A(); c.v.a = 'c'; char val3 = get1(); assertEquals(val1, 'a'); @@ -539,8 +512,8 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 'a'; c.v.next.a = 'a'; A val1 = get(); - c.v.a = 'b'; c.v.next.a = 'b'; A val2 = get(); + c.v.a = 'a'; c.v.next.a = 'a'; A val1 = get(); + c.v.a = 'b'; c.v.next.a = 'b'; A val2 = get(); assertEquals(val1.a, 'b'); assertEquals(val2.a, 'b'); @@ -548,10 +521,10 @@ public class TestStableChar { { c.v = new A(); c.v.next = c.v; - c.v.a = 'a'; char val1 = get1(); - c.v.a = 'b'; char val2 = get1(); + c.v.a = 'a'; char val1 = get1(); + c.v.a = 'b'; char val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 'c'; char val3 = get1(); + c.v.a = 'c'; char val3 = get1(); assertEquals(val1, 'a'); assertEquals(val2, (isStableEnabled ? 'a' : 'b')); @@ -577,8 +550,8 @@ public class TestStableChar { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 'a'; char val1 = get(); char val2 = get1(); - c.v.a = 'b'; char val3 = get(); char val4 = get1(); + c.v.a = 'a'; char val1 = get(); char val2 = get1(); + c.v.a = 'b'; char val3 = get(); char val4 = get1(); assertEquals(val1, 'a'); assertEquals(val3, (isStableEnabled ? 'a' : 'b')); @@ -608,8 +581,8 @@ public class TestStableChar { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 'a'; char val1 = get(); char val2 = get1(); - elem.a = 'b'; char val3 = get(); char val4 = get1(); + elem.a = 'a'; char val1 = get(); char val2 = get1(); + elem.a = 'b'; char val3 = get(); char val4 = get1(); assertEquals(val1, 'a'); assertEquals(val3, (isServerWithStable ? 'a' : 'b')); diff --git a/hotspot/test/compiler/stable/TestStableDouble.java b/hotspot/test/compiler/stable/TestStableDouble.java index 5e55a0f8597..c5ef689f365 100644 --- a/hotspot/test/compiler/stable/TestStableDouble.java +++ b/hotspot/test/compiler/stable/TestStableDouble.java @@ -26,65 +26,38 @@ /* * @test TestStableDouble * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableDouble StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableDouble - * java/lang/invoke/TestStableDouble$DoubleStable - * java/lang/invoke/TestStableDouble$StaticDoubleStable - * java/lang/invoke/TestStableDouble$VolatileDoubleStable - * java/lang/invoke/TestStableDouble$DoubleArrayDim1 - * java/lang/invoke/TestStableDouble$DoubleArrayDim2 - * java/lang/invoke/TestStableDouble$DoubleArrayDim3 - * java/lang/invoke/TestStableDouble$DoubleArrayDim4 - * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableDouble$NestedStableField - * java/lang/invoke/TestStableDouble$NestedStableField$A - * java/lang/invoke/TestStableDouble$NestedStableField1 - * java/lang/invoke/TestStableDouble$NestedStableField1$A - * java/lang/invoke/TestStableDouble$NestedStableField2 - * java/lang/invoke/TestStableDouble$NestedStableField2$A - * java/lang/invoke/TestStableDouble$NestedStableField3 - * java/lang/invoke/TestStableDouble$NestedStableField3$A - * java/lang/invoke/TestStableDouble$DefaultValue - * java/lang/invoke/TestStableDouble$DefaultStaticValue - * java/lang/invoke/TestStableDouble$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableDouble * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableDouble - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableDouble - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableDouble - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableDouble + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableDouble + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableDouble * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableDouble + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableDouble */ -package java.lang.invoke; -import jdk.internal.vm.annotation.Stable; +package compiler.stable; import java.lang.reflect.InvocationTargetException; +import jdk.internal.vm.annotation.Stable; public class TestStableDouble { static final boolean isStableEnabled = StableConfiguration.isStableEnabled; @@ -127,7 +100,7 @@ public class TestStableDouble { public static final DefaultValue c = new DefaultValue(); public static double get() { return c.v; } public static void test() throws Exception { - double val1 = get(); + double val1 = get(); c.v = 1.0; double val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1.0); @@ -157,7 +130,7 @@ public class TestStableDouble { public static final DefaultStaticValue c = new DefaultStaticValue(); public static double get() { return c.v; } public static void test() throws Exception { - double val1 = get(); + double val1 = get(); c.v = 1.0; double val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1.0); @@ -207,24 +180,24 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1]; c.v[0] = 1.0; double val1 = get(); - c.v[0] = 2.0; double val2 = get(); + c.v[0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, (isServerWithStable ? 1.0 : 2.0)); c.v = new double[1]; c.v[0] = 3.0; double val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 3.0)); + : 3.0)); } { c.v = new double[20]; c.v[10] = 1.0; double val1 = get1(); - c.v[10] = 2.0; double val2 = get1(); + c.v[10] = 2.0; double val2 = get1(); assertEquals(val1, 1.0); assertEquals(val2, (isServerWithStable ? 1.0 : 2.0)); c.v = new double[20]; c.v[10] = 3.0; double val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 3.0)); + : 3.0)); } { @@ -247,17 +220,17 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1][1]; c.v[0][0] = 1.0; double val1 = get(); - c.v[0][0] = 2.0; double val2 = get(); + c.v[0][0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, (isServerWithStable ? 1.0 : 2.0)); c.v = new double[1][1]; c.v[0][0] = 3.0; double val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 3.0)); + : 3.0)); c.v[0] = new double[1]; c.v[0][0] = 4.0; double val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 4.0)); + : 4.0)); } { @@ -287,21 +260,21 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1][1][1]; c.v[0][0][0] = 1.0; double val1 = get(); - c.v[0][0][0] = 2.0; double val2 = get(); + c.v[0][0][0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, (isServerWithStable ? 1.0 : 2.0)); c.v = new double[1][1][1]; c.v[0][0][0] = 3.0; double val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 3.0)); + : 3.0)); c.v[0] = new double[1][1]; c.v[0][0][0] = 4.0; double val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 4.0)); + : 4.0)); c.v[0][0] = new double[1]; c.v[0][0][0] = 5.0; double val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 5.0)); + : 5.0)); } { @@ -338,25 +311,25 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 1.0; double val1 = get(); - c.v[0][0][0][0] = 2.0; double val2 = get(); + c.v[0][0][0][0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, (isServerWithStable ? 1.0 : 2.0)); c.v = new double[1][1][1][1]; c.v[0][0][0][0] = 3.0; double val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 3.0)); + : 3.0)); c.v[0] = new double[1][1][1]; c.v[0][0][0][0] = 4.0; double val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 4.0)); + : 4.0)); c.v[0][0] = new double[1][1]; c.v[0][0][0][0] = 5.0; double val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 5.0)); + : 5.0)); c.v[0][0][0] = new double[1]; c.v[0][0][0][0] = 6.0; double val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 1.0 : 2.0) - : 6.0)); + : 6.0)); } { @@ -397,7 +370,7 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1]; ((double[])c.v)[0] = 1.0; double val1 = get(); - ((double[])c.v)[0] = 2.0; double val2 = get(); + ((double[])c.v)[0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, 2.0); @@ -424,7 +397,7 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1][1]; ((double[][])c.v)[0][0] = 1.0; double val1 = get(); - ((double[][])c.v)[0][0] = 2.0; double val2 = get(); + ((double[][])c.v)[0][0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, 2.0); @@ -432,7 +405,7 @@ public class TestStableDouble { { c.v = new double[1][1]; c.v[0] = new double[0]; double[] val1 = get1(); - c.v[0] = new double[0]; double[] val2 = get1(); + c.v[0] = new double[0]; double[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -460,7 +433,7 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new double[1][1][1]; ((double[][][])c.v)[0][0][0] = 1.0; double val1 = get(); - ((double[][][])c.v)[0][0][0] = 2.0; double val2 = get(); + ((double[][][])c.v)[0][0][0] = 2.0; double val2 = get(); assertEquals(val1, 1.0); assertEquals(val2, 2.0); @@ -468,14 +441,14 @@ public class TestStableDouble { { c.v = new double[1][1][1]; c.v[0][0] = new double[0]; double[] val1 = get1(); - c.v[0][0] = new double[0]; double[] val2 = get1(); + c.v[0][0] = new double[0]; double[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new double[1][1][1]; c.v[0] = new double[0][0]; double[][] val1 = get2(); - c.v[0] = new double[0][0]; double[][] val2 = get2(); + c.v[0] = new double[0][0]; double[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -505,7 +478,7 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new A(); c.v.a = 1.0; A val1 = get(); - c.v.a = 2.0; A val2 = get(); + c.v.a = 2.0; A val2 = get(); assertEquals(val1.a, 2.0); assertEquals(val2.a, 2.0); @@ -513,7 +486,7 @@ public class TestStableDouble { { c.v = new A(); c.v.a = 1.0; double val1 = get1(); - c.v.a = 2.0; double val2 = get1(); + c.v.a = 2.0; double val2 = get1(); c.v = new A(); c.v.a = 3.0; double val3 = get1(); assertEquals(val1, 1.0); @@ -539,8 +512,8 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 1.0; c.v.next.a = 1.0; A val1 = get(); - c.v.a = 2.0; c.v.next.a = 2.0; A val2 = get(); + c.v.a = 1.0; c.v.next.a = 1.0; A val1 = get(); + c.v.a = 2.0; c.v.next.a = 2.0; A val2 = get(); assertEquals(val1.a, 2.0); assertEquals(val2.a, 2.0); @@ -548,10 +521,10 @@ public class TestStableDouble { { c.v = new A(); c.v.next = c.v; - c.v.a = 1.0; double val1 = get1(); - c.v.a = 2.0; double val2 = get1(); + c.v.a = 1.0; double val1 = get1(); + c.v.a = 2.0; double val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 3.0; double val3 = get1(); + c.v.a = 3.0; double val3 = get1(); assertEquals(val1, 1.0); assertEquals(val2, (isStableEnabled ? 1.0 : 2.0)); @@ -577,8 +550,8 @@ public class TestStableDouble { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 1.0; double val1 = get(); double val2 = get1(); - c.v.a = 2.0; double val3 = get(); double val4 = get1(); + c.v.a = 1.0; double val1 = get(); double val2 = get1(); + c.v.a = 2.0; double val3 = get(); double val4 = get1(); assertEquals(val1, 1.0); assertEquals(val3, (isStableEnabled ? 1.0 : 2.0)); @@ -608,8 +581,8 @@ public class TestStableDouble { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 1.0; double val1 = get(); double val2 = get1(); - elem.a = 2.0; double val3 = get(); double val4 = get1(); + elem.a = 1.0; double val1 = get(); double val2 = get1(); + elem.a = 2.0; double val3 = get(); double val4 = get1(); assertEquals(val1, 1.0); assertEquals(val3, (isServerWithStable ? 1.0 : 2.0)); diff --git a/hotspot/test/compiler/stable/TestStableFloat.java b/hotspot/test/compiler/stable/TestStableFloat.java index 04acead22ef..28f3427c47b 100644 --- a/hotspot/test/compiler/stable/TestStableFloat.java +++ b/hotspot/test/compiler/stable/TestStableFloat.java @@ -26,64 +26,37 @@ /* * @test TestStableFloat * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableFloat StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableFloat - * java/lang/invoke/TestStableFloat$FloatStable - * java/lang/invoke/TestStableFloat$StaticFloatStable - * java/lang/invoke/TestStableFloat$VolatileFloatStable - * java/lang/invoke/TestStableFloat$FloatArrayDim1 - * java/lang/invoke/TestStableFloat$FloatArrayDim2 - * java/lang/invoke/TestStableFloat$FloatArrayDim3 - * java/lang/invoke/TestStableFloat$FloatArrayDim4 - * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableFloat$NestedStableField - * java/lang/invoke/TestStableFloat$NestedStableField$A - * java/lang/invoke/TestStableFloat$NestedStableField1 - * java/lang/invoke/TestStableFloat$NestedStableField1$A - * java/lang/invoke/TestStableFloat$NestedStableField2 - * java/lang/invoke/TestStableFloat$NestedStableField2$A - * java/lang/invoke/TestStableFloat$NestedStableField3 - * java/lang/invoke/TestStableFloat$NestedStableField3$A - * java/lang/invoke/TestStableFloat$DefaultValue - * java/lang/invoke/TestStableFloat$DefaultStaticValue - * java/lang/invoke/TestStableFloat$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableFloat * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableFloat - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableFloat - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableFloat - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableFloat + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableFloat + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableFloat * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableFloat + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableFloat */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableFloat { @@ -127,7 +100,7 @@ public class TestStableFloat { public static final DefaultValue c = new DefaultValue(); public static float get() { return c.v; } public static void test() throws Exception { - float val1 = get(); + float val1 = get(); c.v = 1.0F; float val2 = get(); assertEquals(val1, 0F); assertEquals(val2, 1.0F); @@ -157,7 +130,7 @@ public class TestStableFloat { public static final DefaultStaticValue c = new DefaultStaticValue(); public static float get() { return c.v; } public static void test() throws Exception { - float val1 = get(); + float val1 = get(); c.v = 1.0F; float val2 = get(); assertEquals(val1, 0F); assertEquals(val2, 1.0F); @@ -207,24 +180,24 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1]; c.v[0] = 1.0F; float val1 = get(); - c.v[0] = 2.0F; float val2 = get(); + c.v[0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, (isServerWithStable ? 1.0F : 2.0F)); c.v = new float[1]; c.v[0] = 3.0F; float val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 3.0F)); + : 3.0F)); } { c.v = new float[20]; c.v[10] = 1.0F; float val1 = get1(); - c.v[10] = 2.0F; float val2 = get1(); + c.v[10] = 2.0F; float val2 = get1(); assertEquals(val1, 1.0F); assertEquals(val2, (isServerWithStable ? 1.0F : 2.0F)); c.v = new float[20]; c.v[10] = 3.0F; float val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 3.0F)); + : 3.0F)); } { @@ -247,17 +220,17 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1][1]; c.v[0][0] = 1.0F; float val1 = get(); - c.v[0][0] = 2.0F; float val2 = get(); + c.v[0][0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, (isServerWithStable ? 1.0F : 2.0F)); c.v = new float[1][1]; c.v[0][0] = 3.0F; float val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 3.0F)); + : 3.0F)); c.v[0] = new float[1]; c.v[0][0] = 4.0F; float val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 4.0F)); + : 4.0F)); } { @@ -287,21 +260,21 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1][1][1]; c.v[0][0][0] = 1.0F; float val1 = get(); - c.v[0][0][0] = 2.0F; float val2 = get(); + c.v[0][0][0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, (isServerWithStable ? 1.0F : 2.0F)); c.v = new float[1][1][1]; c.v[0][0][0] = 3.0F; float val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 3.0F)); + : 3.0F)); c.v[0] = new float[1][1]; c.v[0][0][0] = 4.0F; float val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 4.0F)); + : 4.0F)); c.v[0][0] = new float[1]; c.v[0][0][0] = 5.0F; float val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 5.0F)); + : 5.0F)); } { @@ -338,25 +311,25 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 1.0F; float val1 = get(); - c.v[0][0][0][0] = 2.0F; float val2 = get(); + c.v[0][0][0][0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, (isServerWithStable ? 1.0F : 2.0F)); c.v = new float[1][1][1][1]; c.v[0][0][0][0] = 3.0F; float val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 3.0F)); + : 3.0F)); c.v[0] = new float[1][1][1]; c.v[0][0][0][0] = 4.0F; float val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 4.0F)); + : 4.0F)); c.v[0][0] = new float[1][1]; c.v[0][0][0][0] = 5.0F; float val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 5.0F)); + : 5.0F)); c.v[0][0][0] = new float[1]; c.v[0][0][0][0] = 6.0F; float val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 1.0F : 2.0F) - : 6.0F)); + : 6.0F)); } { @@ -397,7 +370,7 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1]; ((float[])c.v)[0] = 1.0F; float val1 = get(); - ((float[])c.v)[0] = 2.0F; float val2 = get(); + ((float[])c.v)[0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, 2.0F); @@ -424,7 +397,7 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1][1]; ((float[][])c.v)[0][0] = 1.0F; float val1 = get(); - ((float[][])c.v)[0][0] = 2.0F; float val2 = get(); + ((float[][])c.v)[0][0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, 2.0F); @@ -432,7 +405,7 @@ public class TestStableFloat { { c.v = new float[1][1]; c.v[0] = new float[0]; float[] val1 = get1(); - c.v[0] = new float[0]; float[] val2 = get1(); + c.v[0] = new float[0]; float[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -460,7 +433,7 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new float[1][1][1]; ((float[][][])c.v)[0][0][0] = 1.0F; float val1 = get(); - ((float[][][])c.v)[0][0][0] = 2.0F; float val2 = get(); + ((float[][][])c.v)[0][0][0] = 2.0F; float val2 = get(); assertEquals(val1, 1.0F); assertEquals(val2, 2.0F); @@ -468,14 +441,14 @@ public class TestStableFloat { { c.v = new float[1][1][1]; c.v[0][0] = new float[0]; float[] val1 = get1(); - c.v[0][0] = new float[0]; float[] val2 = get1(); + c.v[0][0] = new float[0]; float[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new float[1][1][1]; c.v[0] = new float[0][0]; float[][] val1 = get2(); - c.v[0] = new float[0][0]; float[][] val2 = get2(); + c.v[0] = new float[0][0]; float[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -505,7 +478,7 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new A(); c.v.a = 1.0F; A val1 = get(); - c.v.a = 2.0F; A val2 = get(); + c.v.a = 2.0F; A val2 = get(); assertEquals(val1.a, 2.0F); assertEquals(val2.a, 2.0F); @@ -513,7 +486,7 @@ public class TestStableFloat { { c.v = new A(); c.v.a = 1.0F; float val1 = get1(); - c.v.a = 2.0F; float val2 = get1(); + c.v.a = 2.0F; float val2 = get1(); c.v = new A(); c.v.a = 3.0F; float val3 = get1(); assertEquals(val1, 1.0F); @@ -539,8 +512,8 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 1.0F; c.v.next.a = 1.0F; A val1 = get(); - c.v.a = 2.0F; c.v.next.a = 2.0F; A val2 = get(); + c.v.a = 1.0F; c.v.next.a = 1.0F; A val1 = get(); + c.v.a = 2.0F; c.v.next.a = 2.0F; A val2 = get(); assertEquals(val1.a, 2.0F); assertEquals(val2.a, 2.0F); @@ -548,10 +521,10 @@ public class TestStableFloat { { c.v = new A(); c.v.next = c.v; - c.v.a = 1.0F; float val1 = get1(); - c.v.a = 2.0F; float val2 = get1(); + c.v.a = 1.0F; float val1 = get1(); + c.v.a = 2.0F; float val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 3.0F; float val3 = get1(); + c.v.a = 3.0F; float val3 = get1(); assertEquals(val1, 1.0F); assertEquals(val2, (isStableEnabled ? 1.0F : 2.0F)); @@ -577,8 +550,8 @@ public class TestStableFloat { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 1.0F; float val1 = get(); float val2 = get1(); - c.v.a = 2.0F; float val3 = get(); float val4 = get1(); + c.v.a = 1.0F; float val1 = get(); float val2 = get1(); + c.v.a = 2.0F; float val3 = get(); float val4 = get1(); assertEquals(val1, 1.0F); assertEquals(val3, (isStableEnabled ? 1.0F : 2.0F)); @@ -608,8 +581,8 @@ public class TestStableFloat { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 1.0F; float val1 = get(); float val2 = get1(); - elem.a = 2.0F; float val3 = get(); float val4 = get1(); + elem.a = 1.0F; float val1 = get(); float val2 = get1(); + elem.a = 2.0F; float val3 = get(); float val4 = get1(); assertEquals(val1, 1.0F); assertEquals(val3, (isServerWithStable ? 1.0F : 2.0F)); diff --git a/hotspot/test/compiler/stable/TestStableInt.java b/hotspot/test/compiler/stable/TestStableInt.java index 2837bd3d1a5..831afd2bf9d 100644 --- a/hotspot/test/compiler/stable/TestStableInt.java +++ b/hotspot/test/compiler/stable/TestStableInt.java @@ -26,64 +26,37 @@ /* * @test TestStableInt * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableInt StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableInt - * java/lang/invoke/TestStableInt$IntStable - * java/lang/invoke/TestStableInt$StaticIntStable - * java/lang/invoke/TestStableInt$VolatileIntStable - * java/lang/invoke/TestStableInt$IntArrayDim1 - * java/lang/invoke/TestStableInt$IntArrayDim2 - * java/lang/invoke/TestStableInt$IntArrayDim3 - * java/lang/invoke/TestStableInt$IntArrayDim4 - * java/lang/invoke/TestStableInt$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableInt$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableInt$NestedStableField - * java/lang/invoke/TestStableInt$NestedStableField$A - * java/lang/invoke/TestStableInt$NestedStableField1 - * java/lang/invoke/TestStableInt$NestedStableField1$A - * java/lang/invoke/TestStableInt$NestedStableField2 - * java/lang/invoke/TestStableInt$NestedStableField2$A - * java/lang/invoke/TestStableInt$NestedStableField3 - * java/lang/invoke/TestStableInt$NestedStableField3$A - * java/lang/invoke/TestStableInt$DefaultValue - * java/lang/invoke/TestStableInt$DefaultStaticValue - * java/lang/invoke/TestStableInt$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableInt * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableInt - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableInt - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableInt - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableInt + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableInt + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableInt * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableInt + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableInt */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableInt { @@ -127,7 +100,7 @@ public class TestStableInt { public static final DefaultValue c = new DefaultValue(); public static int get() { return c.v; } public static void test() throws Exception { - int val1 = get(); + int val1 = get(); c.v = 1; int val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1); @@ -157,7 +130,7 @@ public class TestStableInt { public static final DefaultStaticValue c = new DefaultStaticValue(); public static int get() { return c.v; } public static void test() throws Exception { - int val1 = get(); + int val1 = get(); c.v = 1; int val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1); @@ -207,24 +180,24 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1]; c.v[0] = 1; int val1 = get(); - c.v[0] = 2; int val2 = get(); + c.v[0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new int[1]; c.v[0] = 3; int val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { c.v = new int[20]; c.v[10] = 1; int val1 = get1(); - c.v[10] = 2; int val2 = get1(); + c.v[10] = 2; int val2 = get1(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new int[20]; c.v[10] = 3; int val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { @@ -247,17 +220,17 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1][1]; c.v[0][0] = 1; int val1 = get(); - c.v[0][0] = 2; int val2 = get(); + c.v[0][0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new int[1][1]; c.v[0][0] = 3; int val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new int[1]; c.v[0][0] = 4; int val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); } { @@ -287,21 +260,21 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1][1][1]; c.v[0][0][0] = 1; int val1 = get(); - c.v[0][0][0] = 2; int val2 = get(); + c.v[0][0][0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new int[1][1][1]; c.v[0][0][0] = 3; int val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new int[1][1]; c.v[0][0][0] = 4; int val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new int[1]; c.v[0][0][0] = 5; int val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); } { @@ -338,25 +311,25 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 1; int val1 = get(); - c.v[0][0][0][0] = 2; int val2 = get(); + c.v[0][0][0][0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new int[1][1][1][1]; c.v[0][0][0][0] = 3; int val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new int[1][1][1]; c.v[0][0][0][0] = 4; int val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new int[1][1]; c.v[0][0][0][0] = 5; int val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); c.v[0][0][0] = new int[1]; c.v[0][0][0][0] = 6; int val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 6)); + : 6)); } { @@ -397,7 +370,7 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1]; ((int[])c.v)[0] = 1; int val1 = get(); - ((int[])c.v)[0] = 2; int val2 = get(); + ((int[])c.v)[0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -424,7 +397,7 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1][1]; ((int[][])c.v)[0][0] = 1; int val1 = get(); - ((int[][])c.v)[0][0] = 2; int val2 = get(); + ((int[][])c.v)[0][0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -432,7 +405,7 @@ public class TestStableInt { { c.v = new int[1][1]; c.v[0] = new int[0]; int[] val1 = get1(); - c.v[0] = new int[0]; int[] val2 = get1(); + c.v[0] = new int[0]; int[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -460,7 +433,7 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new int[1][1][1]; ((int[][][])c.v)[0][0][0] = 1; int val1 = get(); - ((int[][][])c.v)[0][0][0] = 2; int val2 = get(); + ((int[][][])c.v)[0][0][0] = 2; int val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -468,14 +441,14 @@ public class TestStableInt { { c.v = new int[1][1][1]; c.v[0][0] = new int[0]; int[] val1 = get1(); - c.v[0][0] = new int[0]; int[] val2 = get1(); + c.v[0][0] = new int[0]; int[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new int[1][1][1]; c.v[0] = new int[0][0]; int[][] val1 = get2(); - c.v[0] = new int[0][0]; int[][] val2 = get2(); + c.v[0] = new int[0][0]; int[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -505,7 +478,7 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new A(); c.v.a = 1; A val1 = get(); - c.v.a = 2; A val2 = get(); + c.v.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -513,7 +486,7 @@ public class TestStableInt { { c.v = new A(); c.v.a = 1; int val1 = get1(); - c.v.a = 2; int val2 = get1(); + c.v.a = 2; int val2 = get1(); c.v = new A(); c.v.a = 3; int val3 = get1(); assertEquals(val1, 1); @@ -539,8 +512,8 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 1; c.v.next.a = 1; A val1 = get(); - c.v.a = 2; c.v.next.a = 2; A val2 = get(); + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -548,10 +521,10 @@ public class TestStableInt { { c.v = new A(); c.v.next = c.v; - c.v.a = 1; int val1 = get1(); - c.v.a = 2; int val2 = get1(); + c.v.a = 1; int val1 = get1(); + c.v.a = 2; int val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 3; int val3 = get1(); + c.v.a = 3; int val3 = get1(); assertEquals(val1, 1); assertEquals(val2, (isStableEnabled ? 1 : 2)); @@ -577,8 +550,8 @@ public class TestStableInt { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 1; int val1 = get(); int val2 = get1(); - c.v.a = 2; int val3 = get(); int val4 = get1(); + c.v.a = 1; int val1 = get(); int val2 = get1(); + c.v.a = 2; int val3 = get(); int val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isStableEnabled ? 1 : 2)); @@ -608,8 +581,8 @@ public class TestStableInt { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 1; int val1 = get(); int val2 = get1(); - elem.a = 2; int val3 = get(); int val4 = get1(); + elem.a = 1; int val1 = get(); int val2 = get1(); + elem.a = 2; int val3 = get(); int val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isServerWithStable ? 1 : 2)); diff --git a/hotspot/test/compiler/stable/TestStableLong.java b/hotspot/test/compiler/stable/TestStableLong.java index b6c2fbb0be6..d162e53313e 100644 --- a/hotspot/test/compiler/stable/TestStableLong.java +++ b/hotspot/test/compiler/stable/TestStableLong.java @@ -26,64 +26,37 @@ /* * @test TestStableLong * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableLong StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableLong - * java/lang/invoke/TestStableLong$LongStable - * java/lang/invoke/TestStableLong$StaticLongStable - * java/lang/invoke/TestStableLong$VolatileLongStable - * java/lang/invoke/TestStableLong$LongArrayDim1 - * java/lang/invoke/TestStableLong$LongArrayDim2 - * java/lang/invoke/TestStableLong$LongArrayDim3 - * java/lang/invoke/TestStableLong$LongArrayDim4 - * java/lang/invoke/TestStableLong$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableLong$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableLong$NestedStableField - * java/lang/invoke/TestStableLong$NestedStableField$A - * java/lang/invoke/TestStableLong$NestedStableField1 - * java/lang/invoke/TestStableLong$NestedStableField1$A - * java/lang/invoke/TestStableLong$NestedStableField2 - * java/lang/invoke/TestStableLong$NestedStableField2$A - * java/lang/invoke/TestStableLong$NestedStableField3 - * java/lang/invoke/TestStableLong$NestedStableField3$A - * java/lang/invoke/TestStableLong$DefaultValue - * java/lang/invoke/TestStableLong$DefaultStaticValue - * java/lang/invoke/TestStableLong$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableLong * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableLong - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableLong - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableLong - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableLong + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableLong + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableLong * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableLong + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableLong */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableLong { @@ -127,7 +100,7 @@ public class TestStableLong { public static final DefaultValue c = new DefaultValue(); public static long get() { return c.v; } public static void test() throws Exception { - long val1 = get(); + long val1 = get(); c.v = 1L; long val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1L); @@ -157,7 +130,7 @@ public class TestStableLong { public static final DefaultStaticValue c = new DefaultStaticValue(); public static long get() { return c.v; } public static void test() throws Exception { - long val1 = get(); + long val1 = get(); c.v = 1L; long val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1L); @@ -207,24 +180,24 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1]; c.v[0] = 1; long val1 = get(); - c.v[0] = 2; long val2 = get(); + c.v[0] = 2; long val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new long[1]; c.v[0] = 3; long val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { c.v = new long[20]; c.v[10] = 1; long val1 = get1(); - c.v[10] = 2; long val2 = get1(); + c.v[10] = 2; long val2 = get1(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new long[20]; c.v[10] = 3; long val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { @@ -247,17 +220,17 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1][1]; c.v[0][0] = 1; long val1 = get(); - c.v[0][0] = 2; long val2 = get(); + c.v[0][0] = 2; long val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new long[1][1]; c.v[0][0] = 3; long val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new long[1]; c.v[0][0] = 4; long val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); } { @@ -287,21 +260,21 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1][1][1]; c.v[0][0][0] = 1; long val1 = get(); - c.v[0][0][0] = 2; long val2 = get(); + c.v[0][0][0] = 2; long val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new long[1][1][1]; c.v[0][0][0] = 3; long val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new long[1][1]; c.v[0][0][0] = 4; long val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new long[1]; c.v[0][0][0] = 5; long val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); } { @@ -338,25 +311,25 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 1; long val1 = get(); - c.v[0][0][0][0] = 2; long val2 = get(); + c.v[0][0][0][0] = 2; long val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new long[1][1][1][1]; c.v[0][0][0][0] = 3; long val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new long[1][1][1]; c.v[0][0][0][0] = 4; long val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new long[1][1]; c.v[0][0][0][0] = 5; long val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); c.v[0][0][0] = new long[1]; c.v[0][0][0][0] = 6; long val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 6)); + : 6)); } { @@ -397,7 +370,7 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1]; ((long[])c.v)[0] = 1; long val1 = get(); - ((long[])c.v)[0] = 2; long val2 = get(); + ((long[])c.v)[0] = 2; long val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -424,7 +397,7 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1][1]; ((long[][])c.v)[0][0] = 1; long val1 = get(); - ((long[][])c.v)[0][0] = 2; long val2 = get(); + ((long[][])c.v)[0][0] = 2; long val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -432,7 +405,7 @@ public class TestStableLong { { c.v = new long[1][1]; c.v[0] = new long[0]; long[] val1 = get1(); - c.v[0] = new long[0]; long[] val2 = get1(); + c.v[0] = new long[0]; long[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -460,7 +433,7 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new long[1][1][1]; ((long[][][])c.v)[0][0][0] = 1L; long val1 = get(); - ((long[][][])c.v)[0][0][0] = 2L; long val2 = get(); + ((long[][][])c.v)[0][0][0] = 2L; long val2 = get(); assertEquals(val1, 1L); assertEquals(val2, 2L); @@ -468,14 +441,14 @@ public class TestStableLong { { c.v = new long[1][1][1]; c.v[0][0] = new long[0]; long[] val1 = get1(); - c.v[0][0] = new long[0]; long[] val2 = get1(); + c.v[0][0] = new long[0]; long[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new long[1][1][1]; c.v[0] = new long[0][0]; long[][] val1 = get2(); - c.v[0] = new long[0][0]; long[][] val2 = get2(); + c.v[0] = new long[0][0]; long[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -505,7 +478,7 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new A(); c.v.a = 1; A val1 = get(); - c.v.a = 2; A val2 = get(); + c.v.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -513,7 +486,7 @@ public class TestStableLong { { c.v = new A(); c.v.a = 1; long val1 = get1(); - c.v.a = 2; long val2 = get1(); + c.v.a = 2; long val2 = get1(); c.v = new A(); c.v.a = 3; long val3 = get1(); assertEquals(val1, 1); @@ -539,8 +512,8 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 1; c.v.next.a = 1; A val1 = get(); - c.v.a = 2; c.v.next.a = 2; A val2 = get(); + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -548,10 +521,10 @@ public class TestStableLong { { c.v = new A(); c.v.next = c.v; - c.v.a = 1; long val1 = get1(); - c.v.a = 2; long val2 = get1(); + c.v.a = 1; long val1 = get1(); + c.v.a = 2; long val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 3; long val3 = get1(); + c.v.a = 3; long val3 = get1(); assertEquals(val1, 1); assertEquals(val2, (isStableEnabled ? 1 : 2)); @@ -577,8 +550,8 @@ public class TestStableLong { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 1; long val1 = get(); long val2 = get1(); - c.v.a = 2; long val3 = get(); long val4 = get1(); + c.v.a = 1; long val1 = get(); long val2 = get1(); + c.v.a = 2; long val3 = get(); long val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isStableEnabled ? 1 : 2)); @@ -608,8 +581,8 @@ public class TestStableLong { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 1; long val1 = get(); long val2 = get1(); - elem.a = 2; long val3 = get(); long val4 = get1(); + elem.a = 1; long val1 = get(); long val2 = get1(); + elem.a = 2; long val3 = get(); long val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isServerWithStable ? 1 : 2)); diff --git a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java index f49b2ad811a..6b413401a8a 100644 --- a/hotspot/test/compiler/stable/TestStableMemoryBarrier.java +++ b/hotspot/test/compiler/stable/TestStableMemoryBarrier.java @@ -28,66 +28,44 @@ * @bug 8139758 * @summary tests memory barrier correctly inserted for stable fields * @library /testlibrary /test/lib + * @modules java.base/jdk.internal.vm.annotation * * @run main/bootclasspath -Xcomp -XX:CompileOnly=::testCompile - * java.lang.invoke.TestStableMemoryBarrier + * compiler.stable.TestStableMemoryBarrier * * @author hui.shi@linaro.org */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; -import java.lang.reflect.InvocationTargetException; - public class TestStableMemoryBarrier { - public static void main(String[] args) throws Exception { - run(NotDominate.class); - + for (int i = 0; i < 1000000; i++) { + NotDominate.testCompile(i); + } } - /* ==================================================== * Stable field initialized in method, but its allocation * doesn't dominate MemBar Release at the end of method. */ - - static class NotDominate{ + private static class NotDominate { public @Stable int v; public static int[] array = new int[100]; + public static NotDominate testCompile(int n) { - if ((n % 2) == 0) return null; - // add a loop here, trigger PhaseIdealLoop::verify_dominance - for (int i = 0; i < 100; i++) { - array[i] = n; - } - NotDominate nm = new NotDominate(); - nm.v = n; - return nm; - } - - public static void test() throws Exception { - for (int i = 0; i < 1000000; i++) - testCompile(i); - } - } - - public static void run(Class test) { - Throwable ex = null; - System.out.print(test.getName()+": "); - try { - test.getMethod("test").invoke(null); - } catch (InvocationTargetException e) { - ex = e.getCause(); - } catch (Throwable e) { - ex = e; - } finally { - if (ex == null) { - System.out.println("PASSED"); - } else { - System.out.println("FAILED"); - ex.printStackTrace(System.out); + if ((n % 2) == 0) return null; + // add a loop here, trigger PhaseIdealLoop::verify_dominance + for (int i = 0; i < 100; i++) { + array[i] = n; } + NotDominate nm = new NotDominate(); + nm.v = n; + return nm; } + + } } + diff --git a/hotspot/test/compiler/stable/TestStableObject.java b/hotspot/test/compiler/stable/TestStableObject.java index b61736b6e32..d16a5441c16 100644 --- a/hotspot/test/compiler/stable/TestStableObject.java +++ b/hotspot/test/compiler/stable/TestStableObject.java @@ -26,65 +26,37 @@ /* * @test TestStableObject * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableObject StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableObject - * java/lang/invoke/TestStableObject$ObjectStable - * java/lang/invoke/TestStableObject$StaticObjectStable - * java/lang/invoke/TestStableObject$VolatileObjectStable - * java/lang/invoke/TestStableObject$ObjectArrayDim1 - * java/lang/invoke/TestStableObject$ObjectArrayDim2 - * java/lang/invoke/TestStableObject$ObjectArrayDim3 - * java/lang/invoke/TestStableObject$ObjectArrayDim4 - * java/lang/invoke/TestStableObject$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableObject$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableObject$NestedStableField - * java/lang/invoke/TestStableObject$NestedStableField$A - * java/lang/invoke/TestStableObject$NestedStableField1 - * java/lang/invoke/TestStableObject$NestedStableField1$A - * java/lang/invoke/TestStableObject$NestedStableField2 - * java/lang/invoke/TestStableObject$NestedStableField2$A - * java/lang/invoke/TestStableObject$NestedStableField3 - * java/lang/invoke/TestStableObject$NestedStableField3$A - * java/lang/invoke/TestStableObject$Values - * java/lang/invoke/TestStableObject$DefaultValue - * java/lang/invoke/TestStableObject$DefaultStaticValue - * java/lang/invoke/TestStableObject$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableObject * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableObject - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableObject - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableObject - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableObject + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableObject + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableObject * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableObject + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableObject */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableObject { @@ -130,7 +102,7 @@ public class TestStableObject { public static final DefaultValue c = new DefaultValue(); public static Object get() { return c.v; } public static void test() throws Exception { - Object val1 = get(); + Object val1 = get(); c.v = Values.A; Object val2 = get(); assertEquals(val1, null); assertEquals(val2, Values.A); @@ -160,7 +132,7 @@ public class TestStableObject { public static final DefaultStaticValue c = new DefaultStaticValue(); public static Object get() { return c.v; } public static void test() throws Exception { - Object val1 = get(); + Object val1 = get(); c.v = Values.A; Object val2 = get(); assertEquals(val1, null); assertEquals(val2, Values.A); @@ -210,24 +182,24 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1]; c.v[0] = Values.A; Object val1 = get(); - c.v[0] = Values.B; Object val2 = get(); + c.v[0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, (isServerWithStable ? Values.A : Values.B)); c.v = new Object[1]; c.v[0] = Values.C; Object val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.C)); + : Values.C)); } { c.v = new Object[20]; c.v[10] = Values.A; Object val1 = get1(); - c.v[10] = Values.B; Object val2 = get1(); + c.v[10] = Values.B; Object val2 = get1(); assertEquals(val1, Values.A); assertEquals(val2, (isServerWithStable ? Values.A : Values.B)); c.v = new Object[20]; c.v[10] = Values.C; Object val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.C)); + : Values.C)); } { @@ -250,17 +222,17 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1][1]; c.v[0][0] = Values.A; Object val1 = get(); - c.v[0][0] = Values.B; Object val2 = get(); + c.v[0][0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, (isServerWithStable ? Values.A : Values.B)); c.v = new Object[1][1]; c.v[0][0] = Values.C; Object val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.C)); + : Values.C)); c.v[0] = new Object[1]; c.v[0][0] = Values.D; Object val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.D)); + : Values.D)); } { @@ -290,21 +262,21 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1][1][1]; c.v[0][0][0] = Values.A; Object val1 = get(); - c.v[0][0][0] = Values.B; Object val2 = get(); + c.v[0][0][0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, (isServerWithStable ? Values.A : Values.B)); c.v = new Object[1][1][1]; c.v[0][0][0] = Values.C; Object val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.C)); + : Values.C)); c.v[0] = new Object[1][1]; c.v[0][0][0] = Values.D; Object val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.D)); + : Values.D)); c.v[0][0] = new Object[1]; c.v[0][0][0] = Values.E; Object val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.E)); + : Values.E)); } { @@ -341,25 +313,25 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.A; Object val1 = get(); - c.v[0][0][0][0] = Values.B; Object val2 = get(); + c.v[0][0][0][0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, (isServerWithStable ? Values.A : Values.B)); c.v = new Object[1][1][1][1]; c.v[0][0][0][0] = Values.C; Object val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.C)); + : Values.C)); c.v[0] = new Object[1][1][1]; c.v[0][0][0][0] = Values.D; Object val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.D)); + : Values.D)); c.v[0][0] = new Object[1][1]; c.v[0][0][0][0] = Values.E; Object val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.E)); + : Values.E)); c.v[0][0][0] = new Object[1]; c.v[0][0][0][0] = Values.F; Object val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? Values.A : Values.B) - : Values.F)); + : Values.F)); } { @@ -400,7 +372,7 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1]; ((Object[])c.v)[0] = Values.A; Object val1 = get(); - ((Object[])c.v)[0] = Values.B; Object val2 = get(); + ((Object[])c.v)[0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, Values.B); @@ -427,7 +399,7 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1][1]; ((Object[][])c.v)[0][0] = Values.A; Object val1 = get(); - ((Object[][])c.v)[0][0] = Values.B; Object val2 = get(); + ((Object[][])c.v)[0][0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, Values.B); @@ -435,7 +407,7 @@ public class TestStableObject { { c.v = new Object[1][1]; c.v[0] = new Object[0]; Object[] val1 = get1(); - c.v[0] = new Object[0]; Object[] val2 = get1(); + c.v[0] = new Object[0]; Object[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -463,7 +435,7 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new Object[1][1][1]; ((Object[][][])c.v)[0][0][0] = Values.A; Object val1 = get(); - ((Object[][][])c.v)[0][0][0] = Values.B; Object val2 = get(); + ((Object[][][])c.v)[0][0][0] = Values.B; Object val2 = get(); assertEquals(val1, Values.A); assertEquals(val2, Values.B); @@ -471,14 +443,14 @@ public class TestStableObject { { c.v = new Object[1][1][1]; c.v[0][0] = new Object[0]; Object[] val1 = get1(); - c.v[0][0] = new Object[0]; Object[] val2 = get1(); + c.v[0][0] = new Object[0]; Object[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new Object[1][1][1]; c.v[0] = new Object[0][0]; Object[][] val1 = get2(); - c.v[0] = new Object[0][0]; Object[][] val2 = get2(); + c.v[0] = new Object[0][0]; Object[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -508,7 +480,7 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new A(); c.v.a = Values.A; A val1 = get(); - c.v.a = Values.B; A val2 = get(); + c.v.a = Values.B; A val2 = get(); assertEquals(val1.a, Values.B); assertEquals(val2.a, Values.B); @@ -516,7 +488,7 @@ public class TestStableObject { { c.v = new A(); c.v.a = Values.A; Object val1 = get1(); - c.v.a = Values.B; Object val2 = get1(); + c.v.a = Values.B; Object val2 = get1(); c.v = new A(); c.v.a = Values.C; Object val3 = get1(); assertEquals(val1, Values.A); @@ -542,8 +514,8 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = Values.A; c.v.next.a = Values.A; A val1 = get(); - c.v.a = Values.B; c.v.next.a = Values.B; A val2 = get(); + c.v.a = Values.A; c.v.next.a = Values.A; A val1 = get(); + c.v.a = Values.B; c.v.next.a = Values.B; A val2 = get(); assertEquals(val1.a, Values.B); assertEquals(val2.a, Values.B); @@ -551,10 +523,10 @@ public class TestStableObject { { c.v = new A(); c.v.next = c.v; - c.v.a = Values.A; Object val1 = get1(); - c.v.a = Values.B; Object val2 = get1(); + c.v.a = Values.A; Object val1 = get1(); + c.v.a = Values.B; Object val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = Values.C; Object val3 = get1(); + c.v.a = Values.C; Object val3 = get1(); assertEquals(val1, Values.A); assertEquals(val2, (isStableEnabled ? Values.A : Values.B)); @@ -580,8 +552,8 @@ public class TestStableObject { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = Values.A; Object val1 = get(); Object val2 = get1(); - c.v.a = Values.B; Object val3 = get(); Object val4 = get1(); + c.v.a = Values.A; Object val1 = get(); Object val2 = get1(); + c.v.a = Values.B; Object val3 = get(); Object val4 = get1(); assertEquals(val1, Values.A); assertEquals(val3, (isStableEnabled ? Values.A : Values.B)); @@ -611,8 +583,8 @@ public class TestStableObject { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = Values.A; Object val1 = get(); Object val2 = get1(); - elem.a = Values.B; Object val3 = get(); Object val4 = get1(); + elem.a = Values.A; Object val1 = get(); Object val2 = get1(); + elem.a = Values.B; Object val3 = get(); Object val4 = get1(); assertEquals(val1, Values.A); assertEquals(val3, (isServerWithStable ? Values.A : Values.B)); diff --git a/hotspot/test/compiler/stable/TestStableShort.java b/hotspot/test/compiler/stable/TestStableShort.java index 1b0f127785c..617fb929b4e 100644 --- a/hotspot/test/compiler/stable/TestStableShort.java +++ b/hotspot/test/compiler/stable/TestStableShort.java @@ -26,64 +26,37 @@ /* * @test TestStableShort * @summary tests on stable fields and arrays - * @library /testlibrary /test/lib - * @build TestStableShort StableConfiguration sun.hotspot.WhiteBox - * @run main ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission - * @run main ClassFileInstaller - * java/lang/invoke/StableConfiguration - * java/lang/invoke/TestStableShort - * java/lang/invoke/TestStableShort$ShortStable - * java/lang/invoke/TestStableShort$StaticShortStable - * java/lang/invoke/TestStableShort$VolatileShortStable - * java/lang/invoke/TestStableShort$ShortArrayDim1 - * java/lang/invoke/TestStableShort$ShortArrayDim2 - * java/lang/invoke/TestStableShort$ShortArrayDim3 - * java/lang/invoke/TestStableShort$ShortArrayDim4 - * java/lang/invoke/TestStableShort$ObjectArrayLowerDim0 - * java/lang/invoke/TestStableShort$ObjectArrayLowerDim1 - * java/lang/invoke/TestStableShort$NestedStableField - * java/lang/invoke/TestStableShort$NestedStableField$A - * java/lang/invoke/TestStableShort$NestedStableField1 - * java/lang/invoke/TestStableShort$NestedStableField1$A - * java/lang/invoke/TestStableShort$NestedStableField2 - * java/lang/invoke/TestStableShort$NestedStableField2$A - * java/lang/invoke/TestStableShort$NestedStableField3 - * java/lang/invoke/TestStableShort$NestedStableField3$A - * java/lang/invoke/TestStableShort$DefaultValue - * java/lang/invoke/TestStableShort$DefaultStaticValue - * java/lang/invoke/TestStableShort$ObjectArrayLowerDim2 + * @library /testlibrary /test/lib / + * @modules java.base/jdk.internal.vm.annotation + * @build sun.hotspot.WhiteBox + * @build compiler.stable.TestStableShort * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableShort - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:-TieredCompilation - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableShort - * - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:+FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableShort - * @run main/othervm -Xbootclasspath/a:. - * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp - * -XX:+TieredCompilation -XX:TieredStopAtLevel=1 - * -XX:-FoldStableValues - * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 - * java.lang.invoke.TestStableShort + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableShort + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableShort * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableShort + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xcomp + * -XX:CompileOnly=::get,::get1,::get2,::get3,::get4 + * -XX:-TieredCompilation + * -XX:+FoldStableValues + * compiler.stable.TestStableShort */ -package java.lang.invoke; + +package compiler.stable; import jdk.internal.vm.annotation.Stable; - import java.lang.reflect.InvocationTargetException; public class TestStableShort { @@ -127,7 +100,7 @@ public class TestStableShort { public static final DefaultValue c = new DefaultValue(); public static short get() { return c.v; } public static void test() throws Exception { - short val1 = get(); + short val1 = get(); c.v = 1; short val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1); @@ -157,7 +130,7 @@ public class TestStableShort { public static final DefaultStaticValue c = new DefaultStaticValue(); public static short get() { return c.v; } public static void test() throws Exception { - short val1 = get(); + short val1 = get(); c.v = 1; short val2 = get(); assertEquals(val1, 0); assertEquals(val2, 1); @@ -207,24 +180,24 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1]; c.v[0] = 1; short val1 = get(); - c.v[0] = 2; short val2 = get(); + c.v[0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new short[1]; c.v[0] = 3; short val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { c.v = new short[20]; c.v[10] = 1; short val1 = get1(); - c.v[10] = 2; short val2 = get1(); + c.v[10] = 2; short val2 = get1(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new short[20]; c.v[10] = 3; short val3 = get1(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); } { @@ -247,17 +220,17 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1][1]; c.v[0][0] = 1; short val1 = get(); - c.v[0][0] = 2; short val2 = get(); + c.v[0][0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new short[1][1]; c.v[0][0] = 3; short val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new short[1]; c.v[0][0] = 4; short val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); } { @@ -287,21 +260,21 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1][1][1]; c.v[0][0][0] = 1; short val1 = get(); - c.v[0][0][0] = 2; short val2 = get(); + c.v[0][0][0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new short[1][1][1]; c.v[0][0][0] = 3; short val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new short[1][1]; c.v[0][0][0] = 4; short val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new short[1]; c.v[0][0][0] = 5; short val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); } { @@ -338,25 +311,25 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 1; short val1 = get(); - c.v[0][0][0][0] = 2; short val2 = get(); + c.v[0][0][0][0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, (isServerWithStable ? 1 : 2)); c.v = new short[1][1][1][1]; c.v[0][0][0][0] = 3; short val3 = get(); assertEquals(val3, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 3)); + : 3)); c.v[0] = new short[1][1][1]; c.v[0][0][0][0] = 4; short val4 = get(); assertEquals(val4, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 4)); + : 4)); c.v[0][0] = new short[1][1]; c.v[0][0][0][0] = 5; short val5 = get(); assertEquals(val5, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 5)); + : 5)); c.v[0][0][0] = new short[1]; c.v[0][0][0][0] = 6; short val6 = get(); assertEquals(val6, (isStableEnabled ? (isServerWithStable ? 1 : 2) - : 6)); + : 6)); } { @@ -397,7 +370,7 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1]; ((short[])c.v)[0] = 1; short val1 = get(); - ((short[])c.v)[0] = 2; short val2 = get(); + ((short[])c.v)[0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -424,7 +397,7 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1][1]; ((short[][])c.v)[0][0] = 1; short val1 = get(); - ((short[][])c.v)[0][0] = 2; short val2 = get(); + ((short[][])c.v)[0][0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -432,7 +405,7 @@ public class TestStableShort { { c.v = new short[1][1]; c.v[0] = new short[0]; short[] val1 = get1(); - c.v[0] = new short[0]; short[] val2 = get1(); + c.v[0] = new short[0]; short[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -460,7 +433,7 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new short[1][1][1]; ((short[][][])c.v)[0][0][0] = 1; short val1 = get(); - ((short[][][])c.v)[0][0][0] = 2; short val2 = get(); + ((short[][][])c.v)[0][0][0] = 2; short val2 = get(); assertEquals(val1, 1); assertEquals(val2, 2); @@ -468,14 +441,14 @@ public class TestStableShort { { c.v = new short[1][1][1]; c.v[0][0] = new short[0]; short[] val1 = get1(); - c.v[0][0] = new short[0]; short[] val2 = get1(); + c.v[0][0] = new short[0]; short[] val2 = get1(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } { c.v = new short[1][1][1]; c.v[0] = new short[0][0]; short[][] val1 = get2(); - c.v[0] = new short[0][0]; short[][] val2 = get2(); + c.v[0] = new short[0][0]; short[][] val2 = get2(); assertTrue((isServerWithStable ? (val1 == val2) : (val1 != val2))); } @@ -505,7 +478,7 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new A(); c.v.a = 1; A val1 = get(); - c.v.a = 2; A val2 = get(); + c.v.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -513,7 +486,7 @@ public class TestStableShort { { c.v = new A(); c.v.a = 1; short val1 = get1(); - c.v.a = 2; short val2 = get1(); + c.v.a = 2; short val2 = get1(); c.v = new A(); c.v.a = 3; short val3 = get1(); assertEquals(val1, 1); @@ -539,8 +512,8 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new A(); c.v.next = new A(); c.v.next.next = c.v; - c.v.a = 1; c.v.next.a = 1; A val1 = get(); - c.v.a = 2; c.v.next.a = 2; A val2 = get(); + c.v.a = 1; c.v.next.a = 1; A val1 = get(); + c.v.a = 2; c.v.next.a = 2; A val2 = get(); assertEquals(val1.a, 2); assertEquals(val2.a, 2); @@ -548,10 +521,10 @@ public class TestStableShort { { c.v = new A(); c.v.next = c.v; - c.v.a = 1; short val1 = get1(); - c.v.a = 2; short val2 = get1(); + c.v.a = 1; short val1 = get1(); + c.v.a = 2; short val2 = get1(); c.v = new A(); c.v.next = c.v; - c.v.a = 3; short val3 = get1(); + c.v.a = 3; short val3 = get1(); assertEquals(val1, 1); assertEquals(val2, (isStableEnabled ? 1 : 2)); @@ -577,8 +550,8 @@ public class TestStableShort { public static void test() throws Exception { { c.v = new A(); c.v.left = c.v.right = c.v; - c.v.a = 1; short val1 = get(); short val2 = get1(); - c.v.a = 2; short val3 = get(); short val4 = get1(); + c.v.a = 1; short val1 = get(); short val2 = get1(); + c.v.a = 2; short val3 = get(); short val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isStableEnabled ? 1 : 2)); @@ -608,8 +581,8 @@ public class TestStableShort { { A elem = new A(); c.v = new A[] { elem, elem }; c.v[0].left = c.v[0].right = c.v; - elem.a = 1; short val1 = get(); short val2 = get1(); - elem.a = 2; short val3 = get(); short val4 = get1(); + elem.a = 1; short val1 = get(); short val2 = get1(); + elem.a = 2; short val3 = get(); short val4 = get1(); assertEquals(val1, 1); assertEquals(val3, (isServerWithStable ? 1 : 2)); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java index 1f19d4c14da..f8b82d21549 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java @@ -128,6 +128,20 @@ public class JdkInternalMiscUnsafeAccessTestBoolean { } + // Lazy + { + UNSAFE.putBooleanRelease(base, offset, true); + boolean x = UNSAFE.getBooleanAcquire(base, offset); + assertEquals(x, true, "putRelease boolean value"); + } + + // Opaque + { + UNSAFE.putBooleanOpaque(base, offset, false); + boolean x = UNSAFE.getBooleanOpaque(base, offset); + assertEquals(x, false, "putOpaque boolean value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java index a3ffa6fb8ab..edc6f9ad859 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestByte { } + // Lazy + { + UNSAFE.putByteRelease(base, offset, (byte)1); + byte x = UNSAFE.getByteAcquire(base, offset); + assertEquals(x, (byte)1, "putRelease byte value"); + } + + // Opaque + { + UNSAFE.putByteOpaque(base, offset, (byte)2); + byte x = UNSAFE.getByteOpaque(base, offset); + assertEquals(x, (byte)2, "putOpaque byte value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java index b148aee5c8a..b63b1716ffa 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestChar { } + // Lazy + { + UNSAFE.putCharRelease(base, offset, 'a'); + char x = UNSAFE.getCharAcquire(base, offset); + assertEquals(x, 'a', "putRelease char value"); + } + + // Opaque + { + UNSAFE.putCharOpaque(base, offset, 'b'); + char x = UNSAFE.getCharOpaque(base, offset); + assertEquals(x, 'b', "putOpaque char value"); + } + // Unaligned { UNSAFE.putCharUnaligned(base, offset, 'b'); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java index 3ea637178ac..2309269f473 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestDouble { } + // Lazy + { + UNSAFE.putDoubleRelease(base, offset, 1.0d); + double x = UNSAFE.getDoubleAcquire(base, offset); + assertEquals(x, 1.0d, "putRelease double value"); + } + + // Opaque + { + UNSAFE.putDoubleOpaque(base, offset, 2.0d); + double x = UNSAFE.getDoubleOpaque(base, offset); + assertEquals(x, 2.0d, "putOpaque double value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java index a2e313620fb..07f537f4c5e 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestFloat { } + // Lazy + { + UNSAFE.putFloatRelease(base, offset, 1.0f); + float x = UNSAFE.getFloatAcquire(base, offset); + assertEquals(x, 1.0f, "putRelease float value"); + } + + // Opaque + { + UNSAFE.putFloatOpaque(base, offset, 2.0f); + float x = UNSAFE.getFloatOpaque(base, offset); + assertEquals(x, 2.0f, "putOpaque float value"); + } + } diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java index 1ea024f1320..0d8bc7e4291 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java @@ -163,6 +163,20 @@ public class JdkInternalMiscUnsafeAccessTestInt { assertEquals(x, 1, "putRelease int value"); } + // Lazy + { + UNSAFE.putIntRelease(base, offset, 1); + int x = UNSAFE.getIntAcquire(base, offset); + assertEquals(x, 1, "putRelease int value"); + } + + // Opaque + { + UNSAFE.putIntOpaque(base, offset, 2); + int x = UNSAFE.getIntOpaque(base, offset); + assertEquals(x, 2, "putOpaque int value"); + } + // Unaligned { UNSAFE.putIntUnaligned(base, offset, 2); @@ -199,6 +213,70 @@ public class JdkInternalMiscUnsafeAccessTestInt { assertEquals(x, 2, "failing compareAndSwap int value"); } + // Advanced compare + { + int r = UNSAFE.compareAndExchangeIntVolatile(base, offset, 2, 1); + assertEquals(r, 2, "success compareAndExchangeVolatile int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "success compareAndExchangeVolatile int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntVolatile(base, offset, 2, 3); + assertEquals(r, 1, "failing compareAndExchangeVolatile int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "failing compareAndExchangeVolatile int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntAcquire(base, offset, 1, 2); + assertEquals(r, 1, "success compareAndExchangeAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "success compareAndExchangeAcquire int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntAcquire(base, offset, 1, 3); + assertEquals(r, 2, "failing compareAndExchangeAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "failing compareAndExchangeAcquire int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntRelease(base, offset, 2, 1); + assertEquals(r, 2, "success compareAndExchangeRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "success compareAndExchangeRelease int value"); + } + + { + int r = UNSAFE.compareAndExchangeIntRelease(base, offset, 2, 3); + assertEquals(r, 1, "failing compareAndExchangeRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "failing compareAndExchangeRelease int value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapInt(base, offset, 1, 2); + assertEquals(r, true, "weakCompareAndSwap int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "weakCompareAndSwap int value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapIntAcquire(base, offset, 2, 1); + assertEquals(r, true, "weakCompareAndSwapAcquire int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 1, "weakCompareAndSwapAcquire int"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapIntRelease(base, offset, 1, 2); + assertEquals(r, true, "weakCompareAndSwapRelease int"); + int x = UNSAFE.getInt(base, offset); + assertEquals(x, 2, "weakCompareAndSwapRelease int"); + } + // Compare set and get { int o = UNSAFE.getAndSetInt(base, offset, 1); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java index 0c5262019b1..4460b4452e4 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java @@ -163,6 +163,20 @@ public class JdkInternalMiscUnsafeAccessTestLong { assertEquals(x, 1L, "putRelease long value"); } + // Lazy + { + UNSAFE.putLongRelease(base, offset, 1L); + long x = UNSAFE.getLongAcquire(base, offset); + assertEquals(x, 1L, "putRelease long value"); + } + + // Opaque + { + UNSAFE.putLongOpaque(base, offset, 2L); + long x = UNSAFE.getLongOpaque(base, offset); + assertEquals(x, 2L, "putOpaque long value"); + } + // Unaligned { UNSAFE.putLongUnaligned(base, offset, 2L); @@ -199,6 +213,70 @@ public class JdkInternalMiscUnsafeAccessTestLong { assertEquals(x, 2L, "failing compareAndSwap long value"); } + // Advanced compare + { + long r = UNSAFE.compareAndExchangeLongVolatile(base, offset, 2L, 1L); + assertEquals(r, 2L, "success compareAndExchangeVolatile long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "success compareAndExchangeVolatile long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongVolatile(base, offset, 2L, 3L); + assertEquals(r, 1L, "failing compareAndExchangeVolatile long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "failing compareAndExchangeVolatile long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongAcquire(base, offset, 1L, 2L); + assertEquals(r, 1L, "success compareAndExchangeAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "success compareAndExchangeAcquire long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongAcquire(base, offset, 1L, 3L); + assertEquals(r, 2L, "failing compareAndExchangeAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "failing compareAndExchangeAcquire long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongRelease(base, offset, 2L, 1L); + assertEquals(r, 2L, "success compareAndExchangeRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "success compareAndExchangeRelease long value"); + } + + { + long r = UNSAFE.compareAndExchangeLongRelease(base, offset, 2L, 3L); + assertEquals(r, 1L, "failing compareAndExchangeRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "failing compareAndExchangeRelease long value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLong(base, offset, 1L, 2L); + assertEquals(r, true, "weakCompareAndSwap long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "weakCompareAndSwap long value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLongAcquire(base, offset, 2L, 1L); + assertEquals(r, true, "weakCompareAndSwapAcquire long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 1L, "weakCompareAndSwapAcquire long"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapLongRelease(base, offset, 1L, 2L); + assertEquals(r, true, "weakCompareAndSwapRelease long"); + long x = UNSAFE.getLong(base, offset); + assertEquals(x, 2L, "weakCompareAndSwapRelease long"); + } + // Compare set and get { long o = UNSAFE.getAndSetLong(base, offset, 1L); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java index c23cffd02ad..98afe49f6fa 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java @@ -134,6 +134,20 @@ public class JdkInternalMiscUnsafeAccessTestObject { assertEquals(x, "foo", "putRelease Object value"); } + // Lazy + { + UNSAFE.putObjectRelease(base, offset, "foo"); + Object x = UNSAFE.getObjectAcquire(base, offset); + assertEquals(x, "foo", "putRelease Object value"); + } + + // Opaque + { + UNSAFE.putObjectOpaque(base, offset, "bar"); + Object x = UNSAFE.getObjectOpaque(base, offset); + assertEquals(x, "bar", "putOpaque Object value"); + } + UNSAFE.putObject(base, offset, "foo"); @@ -152,6 +166,70 @@ public class JdkInternalMiscUnsafeAccessTestObject { assertEquals(x, "bar", "failing compareAndSwap Object value"); } + // Advanced compare + { + Object r = UNSAFE.compareAndExchangeObjectVolatile(base, offset, "bar", "foo"); + assertEquals(r, "bar", "success compareAndExchangeVolatile Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "success compareAndExchangeVolatile Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectVolatile(base, offset, "bar", "baz"); + assertEquals(r, "foo", "failing compareAndExchangeVolatile Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "failing compareAndExchangeVolatile Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectAcquire(base, offset, "foo", "bar"); + assertEquals(r, "foo", "success compareAndExchangeAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "success compareAndExchangeAcquire Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectAcquire(base, offset, "foo", "baz"); + assertEquals(r, "bar", "failing compareAndExchangeAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "failing compareAndExchangeAcquire Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectRelease(base, offset, "bar", "foo"); + assertEquals(r, "bar", "success compareAndExchangeRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "success compareAndExchangeRelease Object value"); + } + + { + Object r = UNSAFE.compareAndExchangeObjectRelease(base, offset, "bar", "baz"); + assertEquals(r, "foo", "failing compareAndExchangeRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "failing compareAndExchangeRelease Object value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObject(base, offset, "foo", "bar"); + assertEquals(r, true, "weakCompareAndSwap Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "weakCompareAndSwap Object value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObjectAcquire(base, offset, "bar", "foo"); + assertEquals(r, true, "weakCompareAndSwapAcquire Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "foo", "weakCompareAndSwapAcquire Object"); + } + + { + boolean r = UNSAFE.weakCompareAndSwapObjectRelease(base, offset, "foo", "bar"); + assertEquals(r, true, "weakCompareAndSwapRelease Object"); + Object x = UNSAFE.getObject(base, offset); + assertEquals(x, "bar", "weakCompareAndSwapRelease Object"); + } + // Compare set and get { Object o = UNSAFE.getAndSetObject(base, offset, "foo"); diff --git a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java index 40a20789769..600425dc913 100644 --- a/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java +++ b/hotspot/test/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java @@ -157,6 +157,20 @@ public class JdkInternalMiscUnsafeAccessTestShort { } + // Lazy + { + UNSAFE.putShortRelease(base, offset, (short)1); + short x = UNSAFE.getShortAcquire(base, offset); + assertEquals(x, (short)1, "putRelease short value"); + } + + // Opaque + { + UNSAFE.putShortOpaque(base, offset, (short)2); + short x = UNSAFE.getShortOpaque(base, offset); + assertEquals(x, (short)2, "putOpaque short value"); + } + // Unaligned { UNSAFE.putShortUnaligned(base, offset, (short)2); diff --git a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java index 8c144143d62..45f08e63d9f 100644 --- a/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java +++ b/hotspot/test/compiler/unsafe/UnsafeGetConstantField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,35 +26,50 @@ /* * @test * @summary tests on constant folding of unsafe get operations - * @library /testlibrary /test/lib + * @library /testlibrary + * + * @requires vm.flavor != "client" + * + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.vm.annotation + * java.base/jdk.internal.misc * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions - * -Xbatch -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:+UseUnalignedAccesses - * java.lang.invoke.UnsafeGetConstantField + * -Xbatch -XX:-TieredCompilation + * -XX:+FoldStableValues + * -XX:CompileCommand=dontinline,UnsafeGetConstantField.checkGetAddress() + * -XX:CompileCommand=dontinline,*.test* + * -XX:+UseUnalignedAccesses + * compiler.unsafe.UnsafeGetConstantField + * * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions - * -Xbatch -XX:-TieredCompilation - * -XX:+FoldStableValues - * -XX:-UseUnalignedAccesses - * java.lang.invoke.UnsafeGetConstantField + * -Xbatch -XX:-TieredCompilation + * -XX:+FoldStableValues + * -XX:CompileCommand=dontinline,UnsafeGetConstantField.checkGetAddress() + * -XX:CompileCommand=dontinline,*.test* + * -XX:-UseUnalignedAccesses + * compiler.unsafe.UnsafeGetConstantField */ -package java.lang.invoke; +package compiler.unsafe; -import jdk.internal.vm.annotation.DontInline; -import jdk.internal.vm.annotation.Stable; -import jdk.internal.misc.Unsafe; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.FieldVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Type; +import jdk.internal.vm.annotation.Stable; import jdk.test.lib.Asserts; +import jdk.internal.misc.Unsafe; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import static jdk.internal.org.objectweb.asm.Opcodes.*; public class UnsafeGetConstantField { static final Class THIS_CLASS = UnsafeGetConstantField.class; - static final Unsafe U = Unsafe.getUnsafe(); public static void main(String[] args) { @@ -72,7 +87,7 @@ public class UnsafeGetConstantField { Asserts.assertEquals(checkGetAddress(), cookie); } } - @DontInline + static long checkGetAddress() { return U.getAddress(nativeAddr); } @@ -114,36 +129,65 @@ public class UnsafeGetConstantField { static void runTest(JavaType t, int flags, boolean stable, boolean hasDefaultValue, String postfix) { Generator g = new Generator(t, flags, stable, hasDefaultValue, postfix); Test test = g.generate(); - System.out.printf("type=%s flags=%d stable=%b default=%b post=%s\n", + System.err.printf("type=%s flags=%d stable=%b default=%b post=%s\n", t.typeName, flags, stable, hasDefaultValue, postfix); - // Trigger compilation - for (int i = 0; i < 20_000; i++) { - Asserts.assertEQ(test.testDirect(), test.testUnsafe()); + try { + Object expected = hasDefaultValue ? t.defaultValue : t.value; + // Trigger compilation + for (int i = 0; i < 20_000; i++) { + Asserts.assertEQ(expected, test.testDirect(), "i = "+ i +" direct read returns wrong value"); + Asserts.assertEQ(expected, test.testUnsafe(), "i = "+ i +" unsafe read returns wrong value"); + } + + test.changeToDefault(); + if (!hasDefaultValue && (stable || g.isFinal())) { + Asserts.assertEQ(t.value, test.testDirect(), + "direct read doesn't return prev value"); + // fails for getCharUnaligned due to JDK-8148518 + if (!(t == JavaType.C && "Unaligned".equals(postfix))) { + Asserts.assertEQ(test.testDirect(), test.testUnsafe()); + } + } else { + Asserts.assertEQ(t.defaultValue, test.testDirect(), + "direct read doesn't return default value"); + Asserts.assertEQ(test.testDirect(), test.testUnsafe(), + "direct and unsafe reads return different values"); + } + } catch (Throwable e) { + try { + g.dump(); + } catch (IOException io) { + io.printStackTrace(); + } + throw e; } } - interface Test { + public interface Test { Object testDirect(); Object testUnsafe(); + void changeToDefault(); } enum JavaType { - Z("Boolean", true), - B("Byte", new Byte((byte)-1)), - S("Short", new Short((short)-1)), - C("Char", Character.MAX_VALUE), - I("Int", -1), - J("Long", -1L), - F("Float", -1F), - D("Double", -1D), - L("Object", new Object()); + Z("Boolean", true, false), + B("Byte", new Byte((byte) -1), new Byte((byte) 0)), + S("Short", new Short((short) -1), new Short((short) 0)), + C("Char", Character.MAX_VALUE, '\0'), + I("Int", -1, 0), + J("Long", -1L, 0L), + F("Float", -1F, 0F), + D("Double", -1D, 0D), + L("Object", "", null); String typeName; Object value; + Object defaultValue; String wrapper; - JavaType(String name, Object value) { + JavaType(String name, Object value, Object defaultValue) { this.typeName = name; this.value = value; + this.defaultValue = defaultValue; this.wrapper = internalName(value.getClass()); } @@ -151,7 +195,7 @@ public class UnsafeGetConstantField { if (this == JavaType.L) { return "Ljava/lang/Object;"; } else { - return toString(); + return name(); } } } @@ -174,6 +218,7 @@ public class UnsafeGetConstantField { * } * public Object testDirect() { return t.f; } * public Object testUnsafe() { return U.getInt(t, FIELD_OFFSET); } + * public void changeToDefault() { U.putInt(t, 0, FIELD_OFFSET); } * } */ static class Generator { @@ -187,9 +232,11 @@ public class UnsafeGetConstantField { final boolean hasDefaultValue; final String nameSuffix; + final String name; final String className; final String classDesc; final String fieldDesc; + final byte[] classFile; Generator(JavaType t, int flags, boolean stable, boolean hasDefaultValue, String suffix) { this.type = t; @@ -199,9 +246,11 @@ public class UnsafeGetConstantField { this.nameSuffix = suffix; fieldDesc = type.desc(); - className = String.format("%s$Test%s%s__f=%d__s=%b__d=%b", internalName(THIS_CLASS), type.typeName, - suffix, flags, stable, hasDefaultValue); + name = String.format("Test%s%s__f=%d__s=%b__d=%b", + type.typeName, suffix, flags, stable, hasDefaultValue); + className = "java/lang/invoke/" + name; classDesc = String.format("L%s;", className); + classFile = generateClassFile(); } byte[] generateClassFile() { @@ -225,7 +274,7 @@ public class UnsafeGetConstantField { // Methods { // - MethodVisitor mv = cw.visitMethod(0, "", "()V", null, null); + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); @@ -263,6 +312,30 @@ public class UnsafeGetConstantField { mv.visitEnd(); } + { // public void changeToDefault() { U.putInt(t, FIELD_OFFSET, 0); } + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "changeToDefault", "()V", null, null); + mv.visitCode(); + getUnsafe(mv); + if (isStatic()) { + mv.visitFieldInsn(GETSTATIC, className, "STATIC_BASE", "Ljava/lang/Object;"); + } else { + mv.visitFieldInsn(GETSTATIC, className, "t", classDesc); + } + mv.visitFieldInsn(GETSTATIC, className, "FIELD_OFFSET", "J"); + + if (type.defaultValue != null) { + mv.visitLdcInsn(type.defaultValue); + } else { + mv.visitInsn(ACONST_NULL); + } + String name = "put" + type.typeName + nameSuffix; + mv.visitMethodInsn(INVOKEVIRTUAL, UNSAFE_NAME, name, "(Ljava/lang/Object;J" + type.desc()+ ")V", false); + mv.visitInsn(RETURN); + + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + { // MethodVisitor mv = cw.visitMethod(ACC_STATIC, "", "()V", null, null); mv.visitCode(); @@ -302,7 +375,6 @@ public class UnsafeGetConstantField { } Test generate() { - byte[] classFile = generateClassFile(); Class c = U.defineClass(className, classFile, 0, classFile.length, THIS_CLASS.getClassLoader(), null); try { return (Test) c.newInstance(); @@ -357,20 +429,14 @@ public class UnsafeGetConstantField { if (!isStatic()) { mv.visitVarInsn(ALOAD, 0); } - switch (type) { - case L: { - mv.visitTypeInsn(NEW, "java/lang/Object"); - mv.visitInsn(DUP); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - - break; - } - default: { - mv.visitLdcInsn(type.value); - break; - } - } + mv.visitLdcInsn(type.value); mv.visitFieldInsn((isStatic() ? PUTSTATIC : PUTFIELD), className, FIELD_NAME, fieldDesc); } + + public void dump() throws IOException { + Path path = Paths.get(".", name + ".class").toAbsolutePath(); + System.err.println("dumping test class to " + path); + Files.write(path, classFile); + } } } diff --git a/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java new file mode 100644 index 00000000000..1ec5dc5ba17 --- /dev/null +++ b/hotspot/test/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary tests on constant folding of unsafe get operations from stable arrays + * @library /testlibrary /test/lib + * @ignore 8151137 + * + * @requires vm.flavor != "client" + * + * @run main/bootclasspath -XX:+UnlockDiagnosticVMOptions + * -Xbatch -XX:-TieredCompilation + * -XX:+FoldStableValues + * -XX:CompileCommand=dontinline,*Test::test* + * UnsafeGetStableArrayElement + */ +import jdk.internal.misc.Unsafe; +import jdk.internal.vm.annotation.Stable; +import java.util.concurrent.Callable; + +import static jdk.internal.misc.Unsafe.*; +import static jdk.test.lib.Asserts.*; + +public class UnsafeGetStableArrayElement { + @Stable static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; + @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[16]; + @Stable static final short[] STABLE_SHORT_ARRAY = new short[8]; + @Stable static final char[] STABLE_CHAR_ARRAY = new char[8]; + @Stable static final int[] STABLE_INT_ARRAY = new int[4]; + @Stable static final long[] STABLE_LONG_ARRAY = new long[2]; + @Stable static final float[] STABLE_FLOAT_ARRAY = new float[4]; + @Stable static final double[] STABLE_DOUBLE_ARRAY = new double[2]; + @Stable static final Object[] STABLE_OBJECT_ARRAY = new Object[4]; + + static { + Setter.reset(); + } + static final Unsafe U = Unsafe.getUnsafe(); + + static class Setter { + private static void setZ(boolean defaultVal) { STABLE_BOOLEAN_ARRAY[0] = defaultVal ? false : true; } + private static void setB(boolean defaultVal) { STABLE_BYTE_ARRAY[0] = defaultVal ? 0 : Byte.MAX_VALUE; } + private static void setS(boolean defaultVal) { STABLE_SHORT_ARRAY[0] = defaultVal ? 0 : Short.MAX_VALUE; } + private static void setC(boolean defaultVal) { STABLE_CHAR_ARRAY[0] = defaultVal ? 0 : Character.MAX_VALUE; } + private static void setI(boolean defaultVal) { STABLE_INT_ARRAY[0] = defaultVal ? 0 : Integer.MAX_VALUE; } + private static void setJ(boolean defaultVal) { STABLE_LONG_ARRAY[0] = defaultVal ? 0 : Long.MAX_VALUE; } + private static void setF(boolean defaultVal) { STABLE_FLOAT_ARRAY[0] = defaultVal ? 0 : Float.MAX_VALUE; } + private static void setD(boolean defaultVal) { STABLE_DOUBLE_ARRAY[0] = defaultVal ? 0 : Double.MAX_VALUE; } + private static void setL(boolean defaultVal) { STABLE_OBJECT_ARRAY[0] = defaultVal ? null : new Object(); } + + static void reset() { + setZ(false); + setB(false); + setS(false); + setC(false); + setI(false); + setJ(false); + setF(false); + setD(false); + setL(false); + } + } + + static class Test { + static void changeZ() { Setter.setZ(true); } + static void changeB() { Setter.setB(true); } + static void changeS() { Setter.setS(true); } + static void changeC() { Setter.setC(true); } + static void changeI() { Setter.setI(true); } + static void changeJ() { Setter.setJ(true); } + static void changeF() { Setter.setF(true); } + static void changeD() { Setter.setD(true); } + static void changeL() { Setter.setL(true); } + + static boolean testZ_Z() { return U.getBoolean(STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static byte testZ_B() { return U.getByte( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static short testZ_S() { return U.getShort( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static char testZ_C() { return U.getChar( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static int testZ_I() { return U.getInt( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static long testZ_J() { return U.getLong( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static float testZ_F() { return U.getFloat( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + static double testZ_D() { return U.getDouble( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } + + static boolean testB_Z() { return U.getBoolean(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static byte testB_B() { return U.getByte( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static short testB_S() { return U.getShort( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static char testB_C() { return U.getChar( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static int testB_I() { return U.getInt( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static long testB_J() { return U.getLong( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static float testB_F() { return U.getFloat( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + static double testB_D() { return U.getDouble( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } + + static boolean testS_Z() { return U.getBoolean(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static byte testS_B() { return U.getByte( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static short testS_S() { return U.getShort( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static char testS_C() { return U.getChar( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static int testS_I() { return U.getInt( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static long testS_J() { return U.getLong( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static float testS_F() { return U.getFloat( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + static double testS_D() { return U.getDouble( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } + + static boolean testC_Z() { return U.getBoolean(STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static byte testC_B() { return U.getByte( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static short testC_S() { return U.getShort( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static char testC_C() { return U.getChar( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static int testC_I() { return U.getInt( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static long testC_J() { return U.getLong( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static float testC_F() { return U.getFloat( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + static double testC_D() { return U.getDouble( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } + + static boolean testI_Z() { return U.getBoolean(STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static byte testI_B() { return U.getByte( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static short testI_S() { return U.getShort( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static char testI_C() { return U.getChar( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static int testI_I() { return U.getInt( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static long testI_J() { return U.getLong( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static float testI_F() { return U.getFloat( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + static double testI_D() { return U.getDouble( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } + + static boolean testJ_Z() { return U.getBoolean(STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static byte testJ_B() { return U.getByte( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static short testJ_S() { return U.getShort( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static char testJ_C() { return U.getChar( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static int testJ_I() { return U.getInt( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static long testJ_J() { return U.getLong( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static float testJ_F() { return U.getFloat( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + static double testJ_D() { return U.getDouble( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } + + static boolean testF_Z() { return U.getBoolean(STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static byte testF_B() { return U.getByte( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static short testF_S() { return U.getShort( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static char testF_C() { return U.getChar( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static int testF_I() { return U.getInt( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static long testF_J() { return U.getLong( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static float testF_F() { return U.getFloat( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + static double testF_D() { return U.getDouble( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } + + static boolean testD_Z() { return U.getBoolean(STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static byte testD_B() { return U.getByte( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static short testD_S() { return U.getShort( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static char testD_C() { return U.getChar( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static int testD_I() { return U.getInt( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static long testD_J() { return U.getLong( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static float testD_F() { return U.getFloat( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + static double testD_D() { return U.getDouble( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } + + static Object testL_L() { return U.getObject( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static boolean testL_Z() { return U.getBoolean(STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static byte testL_B() { return U.getByte( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static short testL_S() { return U.getShort( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static char testL_C() { return U.getChar( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static int testL_I() { return U.getInt( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static long testL_J() { return U.getLong( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static float testL_F() { return U.getFloat( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + static double testL_D() { return U.getDouble( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } + + static short testS_U() { return U.getShortUnaligned(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET + 1); } + static char testC_U() { return U.getCharUnaligned( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET + 1); } + static int testI_U() { return U.getIntUnaligned( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET + 1); } + static long testJ_U() { return U.getLongUnaligned( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET + 1); } + } + + static void run(Callable c) throws Exception { + run(c, null, null); + } + + static void run(Callable c, Runnable sameResultAction, Runnable changeResultAction) throws Exception { + Object first = c.call(); + + // Trigger compilation. + for (int i = 0; i < 20_000; i++) { + // Don't compare results here, since most of Test::testL_* results vary across iterations (due to GC). + c.call(); + } + + if (sameResultAction != null) { + sameResultAction.run(); + assertEQ(first, c.call()); + } + + if (changeResultAction != null) { + changeResultAction.run(); + assertNE(first, c.call()); + assertEQ(c.call(), c.call()); + } + } + + static void testMatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, setDefaultAction, null); + Setter.reset(); + } + + static void testMismatched(Callable c, Runnable setDefaultAction) throws Exception { + run(c, null, setDefaultAction); + Setter.reset(); + } + + public static void main(String[] args) throws Exception { + // boolean[], aligned accesses + testMatched( Test::testZ_Z, Test::changeZ); + testMismatched(Test::testZ_B, Test::changeZ); + testMismatched(Test::testZ_S, Test::changeZ); + testMismatched(Test::testZ_C, Test::changeZ); + testMismatched(Test::testZ_I, Test::changeZ); + testMismatched(Test::testZ_J, Test::changeZ); + testMismatched(Test::testZ_F, Test::changeZ); + testMismatched(Test::testZ_D, Test::changeZ); + + // byte[], aligned accesses + testMismatched(Test::testB_Z, Test::changeB); + testMatched( Test::testB_B, Test::changeB); + testMismatched(Test::testB_S, Test::changeB); + testMismatched(Test::testB_C, Test::changeB); + testMismatched(Test::testB_I, Test::changeB); + testMismatched(Test::testB_J, Test::changeB); + testMismatched(Test::testB_F, Test::changeB); + testMismatched(Test::testB_D, Test::changeB); + + // short[], aligned accesses + testMismatched(Test::testS_Z, Test::changeS); + testMismatched(Test::testS_B, Test::changeS); + testMatched( Test::testS_S, Test::changeS); + testMismatched(Test::testS_C, Test::changeS); + testMismatched(Test::testS_I, Test::changeS); + testMismatched(Test::testS_J, Test::changeS); + testMismatched(Test::testS_F, Test::changeS); + testMismatched(Test::testS_D, Test::changeS); + + // char[], aligned accesses + testMismatched(Test::testC_Z, Test::changeC); + testMismatched(Test::testC_B, Test::changeC); + testMismatched(Test::testC_S, Test::changeC); + testMatched( Test::testC_C, Test::changeC); + testMismatched(Test::testC_I, Test::changeC); + testMismatched(Test::testC_J, Test::changeC); + testMismatched(Test::testC_F, Test::changeC); + testMismatched(Test::testC_D, Test::changeC); + + // int[], aligned accesses + testMismatched(Test::testI_Z, Test::changeI); + testMismatched(Test::testI_B, Test::changeI); + testMismatched(Test::testI_S, Test::changeI); + testMismatched(Test::testI_C, Test::changeI); + testMatched( Test::testI_I, Test::changeI); + testMismatched(Test::testI_J, Test::changeI); + testMismatched(Test::testI_F, Test::changeI); + testMismatched(Test::testI_D, Test::changeI); + + // long[], aligned accesses + testMismatched(Test::testJ_Z, Test::changeJ); + testMismatched(Test::testJ_B, Test::changeJ); + testMismatched(Test::testJ_S, Test::changeJ); + testMismatched(Test::testJ_C, Test::changeJ); + testMismatched(Test::testJ_I, Test::changeJ); + testMatched( Test::testJ_J, Test::changeJ); + testMismatched(Test::testJ_F, Test::changeJ); + testMismatched(Test::testJ_D, Test::changeJ); + + // float[], aligned accesses + testMismatched(Test::testF_Z, Test::changeF); + testMismatched(Test::testF_B, Test::changeF); + testMismatched(Test::testF_S, Test::changeF); + testMismatched(Test::testF_C, Test::changeF); + testMismatched(Test::testF_I, Test::changeF); + testMismatched(Test::testF_J, Test::changeF); + testMatched( Test::testF_F, Test::changeF); + testMismatched(Test::testF_D, Test::changeF); + + // double[], aligned accesses + testMismatched(Test::testD_Z, Test::changeD); + testMismatched(Test::testD_B, Test::changeD); + testMismatched(Test::testD_S, Test::changeD); + testMismatched(Test::testD_C, Test::changeD); + testMismatched(Test::testD_I, Test::changeD); + testMismatched(Test::testD_J, Test::changeD); + testMismatched(Test::testD_F, Test::changeD); + testMatched( Test::testD_D, Test::changeD); + + // Object[], aligned accesses + testMismatched(Test::testL_J, Test::changeL); // long & double are always as large as an OOP + testMismatched(Test::testL_D, Test::changeL); + testMatched( Test::testL_L, Test::changeL); + + // Unaligned accesses + testMismatched(Test::testS_U, Test::changeS); + testMismatched(Test::testC_U, Test::changeC); + testMismatched(Test::testI_U, Test::changeI); + testMismatched(Test::testJ_U, Test::changeJ); + + // No way to reliably check the expected behavior: + // (1) OOPs change during GC; + // (2) there's no way to reliably change some part of an OOP (e.g., when reading a byte from it). + // + // Just trigger the compilation hoping to catch any problems with asserts. + run(Test::testL_B); + run(Test::testL_Z); + run(Test::testL_S); + run(Test::testL_C); + run(Test::testL_I); + run(Test::testL_F); + } +} diff --git a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template index fcc74e325b0..4553635a158 100644 --- a/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template +++ b/hotspot/test/compiler/unsafe/X-UnsafeAccessTest.java.template @@ -169,6 +169,22 @@ public class $Qualifier$UnsafeAccessTest$Type$ { } #end[Ordered] +#if[JdkInternalMisc] + // Lazy + { + UNSAFE.put$Type$Release(base, offset, $value1$); + $type$ x = UNSAFE.get$Type$Acquire(base, offset); + assertEquals(x, $value1$, "putRelease $type$ value"); + } + + // Opaque + { + UNSAFE.put$Type$Opaque(base, offset, $value2$); + $type$ x = UNSAFE.get$Type$Opaque(base, offset); + assertEquals(x, $value2$, "putOpaque $type$ value"); + } +#end[JdkInternalMisc] + #if[JdkInternalMisc] #if[Unaligned] // Unaligned @@ -210,6 +226,72 @@ public class $Qualifier$UnsafeAccessTest$Type$ { assertEquals(x, $value2$, "failing compareAndSwap $type$ value"); } +#if[JdkInternalMisc] + // Advanced compare + { + $type$ r = UNSAFE.compareAndExchange$Type$Volatile(base, offset, $value2$, $value1$); + assertEquals(r, $value2$, "success compareAndExchangeVolatile $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "success compareAndExchangeVolatile $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Volatile(base, offset, $value2$, $value3$); + assertEquals(r, $value1$, "failing compareAndExchangeVolatile $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "failing compareAndExchangeVolatile $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Acquire(base, offset, $value1$, $value2$); + assertEquals(r, $value1$, "success compareAndExchangeAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "success compareAndExchangeAcquire $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Acquire(base, offset, $value1$, $value3$); + assertEquals(r, $value2$, "failing compareAndExchangeAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "failing compareAndExchangeAcquire $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Release(base, offset, $value2$, $value1$); + assertEquals(r, $value2$, "success compareAndExchangeRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "success compareAndExchangeRelease $type$ value"); + } + + { + $type$ r = UNSAFE.compareAndExchange$Type$Release(base, offset, $value2$, $value3$); + assertEquals(r, $value1$, "failing compareAndExchangeRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "failing compareAndExchangeRelease $type$ value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$(base, offset, $value1$, $value2$); + assertEquals(r, true, "weakCompareAndSwap $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "weakCompareAndSwap $type$ value"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$Acquire(base, offset, $value2$, $value1$); + assertEquals(r, true, "weakCompareAndSwapAcquire $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value1$, "weakCompareAndSwapAcquire $type$"); + } + + { + boolean r = UNSAFE.weakCompareAndSwap$Type$Release(base, offset, $value1$, $value2$); + assertEquals(r, true, "weakCompareAndSwapRelease $type$"); + $type$ x = UNSAFE.get$Type$(base, offset); + assertEquals(x, $value2$, "weakCompareAndSwapRelease $type$"); + } +#end[JdkInternalMisc] + // Compare set and get { $type$ o = UNSAFE.getAndSet$Type$(base, offset, $value1$); @@ -244,4 +326,5 @@ public class $Qualifier$UnsafeAccessTest$Type$ { } #end[!boolean] #end[!Object] -} \ No newline at end of file +} + diff --git a/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh b/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh new file mode 100644 index 00000000000..a20c45afa86 --- /dev/null +++ b/hotspot/test/compiler/unsafe/generate-unsafe-tests.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +javac -d . ../../../../jdk/make/src/classes/build/tools/spp/Spp.java + +SPP=build.tools.spp.Spp + +# Generates unsafe access tests for objects and all primitive types +# $1 = package name to Unsafe, sun.misc | jdk.internal.misc +# $2 = test class qualifier name, SunMisc | JdkInternalMisc +function generate { + package=$1 + Qualifier=$2 + + for type in boolean byte short char int long float double Object + do + Type="$(tr '[:lower:]' '[:upper:]' <<< ${type:0:1})${type:1}" + args="-K$type -Dtype=$type -DType=$Type" + + case $type in + Object|int|long) + args="$args -KCAS -KOrdered" + ;; + esac + + case $type in + int|long) + args="$args -KAtomicAdd" + ;; + esac + + case $type in + short|char|int|long) + args="$args -KUnaligned" + ;; + esac + + case $type in + boolean) + value1=true + value2=false + value3=false + ;; + byte) + value1=(byte)1 + value2=(byte)2 + value3=(byte)3 + ;; + short) + value1=(short)1 + value2=(short)2 + value3=(short)3 + ;; + char) + value1=\'a\' + value2=\'b\' + value3=\'c\' + ;; + int) + value1=1 + value2=2 + value3=3 + ;; + long) + value1=1L + value2=2L + value3=3L + ;; + float) + value1=1.0f + value2=2.0f + value3=3.0f + ;; + double) + value1=1.0d + value2=2.0d + value3=3.0d + ;; + Object) + value1=\"foo\" + value2=\"bar\" + value3=\"baz\" + ;; + esac + + args="$args -Dvalue1=$value1 -Dvalue2=$value2 -Dvalue3=$value3" + + echo $args + + java $SPP -nel -K$Qualifier -Dpackage=$package -DQualifier=$Qualifier \ + $args < X-UnsafeAccessTest.java.template > ${Qualifier}UnsafeAccessTest${Type}.java + done +} + +generate sun.misc SunMisc +generate jdk.internal.misc JdkInternalMisc + +rm -fr build \ No newline at end of file diff --git a/hotspot/test/gc/TestSmallHeap.java b/hotspot/test/gc/TestSmallHeap.java index 1289046edba..ffafa078a71 100644 --- a/hotspot/test/gc/TestSmallHeap.java +++ b/hotspot/test/gc/TestSmallHeap.java @@ -31,6 +31,7 @@ * @summary Verify that starting the VM with a small heap works * @library /testlibrary /test/lib * @modules java.management/sun.management + * @ignore 8076621 * @build TestSmallHeap * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx2m -XX:+UseParallelGC TestSmallHeap diff --git a/hotspot/test/gc/g1/TestGCLogMessages.java b/hotspot/test/gc/g1/TestGCLogMessages.java index 8ab921b0186..81526644c59 100644 --- a/hotspot/test/gc/g1/TestGCLogMessages.java +++ b/hotspot/test/gc/g1/TestGCLogMessages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test TestGCLogMessages - * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 + * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 8150630 * @summary Ensure the output for a minor GC with G1 * includes the expected necessary messages. * @key gc @@ -38,10 +38,24 @@ import jdk.test.lib.OutputAnalyzer; public class TestGCLogMessages { private enum Level { - OFF, DEBUG, TRACE; - public boolean lessOrEqualTo(Level other) { + OFF(""), + INFO("info"), + DEBUG("debug"), + TRACE("trace"); + + private String logName; + + Level(String logName) { + this.logName = logName; + } + + public boolean lessThan(Level other) { return this.compareTo(other) < 0; } + + public String toString() { + return logName; + } } private class LogMessageWithLevel { @@ -56,44 +70,48 @@ public class TestGCLogMessages { private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] { // Update RS - new LogMessageWithLevel("Scan HCC", Level.DEBUG), + new LogMessageWithLevel("Scan HCC", Level.TRACE), // Ext Root Scan - new LogMessageWithLevel("Thread Roots:", Level.DEBUG), - new LogMessageWithLevel("StringTable Roots:", Level.DEBUG), - new LogMessageWithLevel("Universe Roots:", Level.DEBUG), - new LogMessageWithLevel("JNI Handles Roots:", Level.DEBUG), - new LogMessageWithLevel("ObjectSynchronizer Roots:", Level.DEBUG), - new LogMessageWithLevel("FlatProfiler Roots", Level.DEBUG), - new LogMessageWithLevel("Management Roots", Level.DEBUG), - new LogMessageWithLevel("SystemDictionary Roots", Level.DEBUG), - new LogMessageWithLevel("CLDG Roots", Level.DEBUG), - new LogMessageWithLevel("JVMTI Roots", Level.DEBUG), - new LogMessageWithLevel("SATB Filtering", Level.DEBUG), - new LogMessageWithLevel("CM RefProcessor Roots", Level.DEBUG), - new LogMessageWithLevel("Wait For Strong CLD", Level.DEBUG), - new LogMessageWithLevel("Weak CLD Roots", Level.DEBUG), + new LogMessageWithLevel("Thread Roots", Level.TRACE), + new LogMessageWithLevel("StringTable Roots", Level.TRACE), + new LogMessageWithLevel("Universe Roots", Level.TRACE), + new LogMessageWithLevel("JNI Handles Roots", Level.TRACE), + new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE), + new LogMessageWithLevel("FlatProfiler Roots", Level.TRACE), + new LogMessageWithLevel("Management Roots", Level.TRACE), + new LogMessageWithLevel("SystemDictionary Roots", Level.TRACE), + new LogMessageWithLevel("CLDG Roots", Level.TRACE), + new LogMessageWithLevel("JVMTI Roots", Level.TRACE), + new LogMessageWithLevel("SATB Filtering", Level.TRACE), + new LogMessageWithLevel("CM RefProcessor Roots", Level.TRACE), + new LogMessageWithLevel("Wait For Strong CLD", Level.TRACE), + new LogMessageWithLevel("Weak CLD Roots", Level.TRACE), // Redirty Cards new LogMessageWithLevel("Redirty Cards", Level.DEBUG), - new LogMessageWithLevel("Parallel Redirty", Level.DEBUG), - new LogMessageWithLevel("Redirtied Cards", Level.DEBUG), + new LogMessageWithLevel("Parallel Redirty", Level.TRACE), + new LogMessageWithLevel("Redirtied Cards", Level.TRACE), // Misc Top-level - new LogMessageWithLevel("Code Root Purge", Level.DEBUG), - new LogMessageWithLevel("String Dedup Fixup", Level.DEBUG), - new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG), + new LogMessageWithLevel("Code Roots Purge", Level.DEBUG), + new LogMessageWithLevel("String Dedup Fixup", Level.INFO), + new LogMessageWithLevel("Expand Heap After Collection", Level.INFO), // Free CSet - new LogMessageWithLevel("Young Free CSet", Level.TRACE), - new LogMessageWithLevel("Non-Young Free CSet", Level.TRACE), + new LogMessageWithLevel("Young Free Collection Set", Level.DEBUG), + new LogMessageWithLevel("Non-Young Free Collection Set", Level.DEBUG), // Humongous Eager Reclaim new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG), new LogMessageWithLevel("Humongous Register", Level.DEBUG), + // Preserve CM Referents + new LogMessageWithLevel("Preserve CM Refs", Level.DEBUG), + // Merge PSS + new LogMessageWithLevel("Merge Per-Thread State", Level.INFO), }; void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception { for (LogMessageWithLevel l : messages) { - if (level.lessOrEqualTo(l.level)) { + if (level.lessThan(l.level)) { output.shouldNotContain(l.message); } else { - output.shouldContain(l.message); + output.shouldMatch("\\[" + l.level + ".*" + l.message); } } } diff --git a/hotspot/test/gc/g1/TestPLABOutput.java b/hotspot/test/gc/g1/TestPLABOutput.java index a8265ac00c1..4b85b1cbcd6 100644 --- a/hotspot/test/gc/g1/TestPLABOutput.java +++ b/hotspot/test/gc/g1/TestPLABOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ public class TestPLABOutput { System.out.println(output.getStdout()); - String pattern = ".*GC\\(0\\) .*allocated = (\\d+).*"; + String pattern = ".*GC\\(0\\) .*allocated: (\\d+).*"; Pattern r = Pattern.compile(pattern); Matcher m = r.matcher(output.getStdout()); diff --git a/hotspot/test/gc/g1/plab/TestPLABPromotion.java b/hotspot/test/gc/g1/plab/TestPLABPromotion.java index 54a56bb5092..7b892f29fa3 100644 --- a/hotspot/test/gc/g1/plab/TestPLABPromotion.java +++ b/hotspot/test/gc/g1/plab/TestPLABPromotion.java @@ -23,7 +23,7 @@ /* * @test TestPLABPromotion - * @bug 8141278 + * @bug 8141278 8141141 * @summary Test PLAB promotion * @requires vm.gc=="G1" | vm.gc=="null" * @requires vm.opt.FlightRecorder != true @@ -130,16 +130,15 @@ public class TestPLABPromotion { long plabAllocatedOld; long directAllocatedOld; long memAllocated = testCase.getMemToFill(); - long wordSize = Platform.is32bit() ? 4l : 8l; LogParser logParser = new LogParser(output); Map survivorStats = getPlabStats(logParser, LogParser.ReportType.SURVIVOR_STATS, GC_ID_SURVIVOR_STATS); Map oldStats = getPlabStats(logParser, LogParser.ReportType.OLD_STATS, GC_ID_OLD_STATS); - plabAllocatedSurvivor = wordSize * survivorStats.get("used"); - directAllocatedSurvivor = wordSize * survivorStats.get("direct_allocated"); - plabAllocatedOld = wordSize * oldStats.get("used"); - directAllocatedOld = wordSize * oldStats.get("direct_allocated"); + plabAllocatedSurvivor = survivorStats.get("used"); + directAllocatedSurvivor = survivorStats.get("direct allocated"); + plabAllocatedOld = oldStats.get("used"); + directAllocatedOld = oldStats.get("direct allocated"); System.out.printf("Survivor PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedSurvivor, directAllocatedSurvivor, memAllocated); System.out.printf("Old PLAB allocated:%17d Direct allocated: %17d Mem consumed:%17d%n", plabAllocatedOld, directAllocatedOld, memAllocated); diff --git a/hotspot/test/gc/g1/plab/TestPLABResize.java b/hotspot/test/gc/g1/plab/TestPLABResize.java index b07b769baa3..e9aef79c07f 100644 --- a/hotspot/test/gc/g1/plab/TestPLABResize.java +++ b/hotspot/test/gc/g1/plab/TestPLABResize.java @@ -23,7 +23,7 @@ /* * @test TestPLABResize - * @bug 8141278 + * @bug 8141278 8141141 * @summary Test for PLAB resizing * @requires vm.gc=="G1" | vm.gc=="null" * @requires vm.opt.FlightRecorder != true @@ -117,7 +117,7 @@ public class TestPLABResize { .map(item -> { return item.getValue() .get(LogParser.ReportType.SURVIVOR_STATS) - .get("desired_plab_sz"); + .get("actual"); }) .collect(Collectors.toCollection(ArrayList::new)); diff --git a/hotspot/test/gc/g1/plab/lib/LogParser.java b/hotspot/test/gc/g1/plab/lib/LogParser.java index ce2f94ef6e6..2bf933edabd 100644 --- a/hotspot/test/gc/g1/plab/lib/LogParser.java +++ b/hotspot/test/gc/g1/plab/lib/LogParser.java @@ -35,14 +35,12 @@ import java.util.regex.Pattern; * * Typical GC log with PLAB statistics (options - -Xlog:gc=debug,gc+plab=debug) looks like: * - * [2,244s][info ][gc ] GC(30) Concurrent Mark abort - * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,245s][debug ][gc,plab] GC(33) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,245s][info ][gc ] GC(33) Pause Young (G1 Evacuation Pause) 127M->127M(128M) (2,244s, 2,245s) 0,899ms - * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,246s][debug ][gc,plab] GC(34) (allocated = 1 wasted = 0 unused = 0 used = 1 undo_waste = 0 region_end_waste = 0 regions filled = 0 direct_allocated = 0 failure_used = 0 failure_waste = 0) (plab_sz = 0 desired_plab_sz = 258) - * [2,246s][info ][gc ] GC(34) Pause Initial Mark (G1 Evacuation Pause) 127M->127M(128M) (2,245s, 2,246s) 0,907ms - + * [0.330s][debug][gc,plab ] GC(0) Young PLAB allocation: allocated: 1825632B, wasted: 29424B, unused: 2320B, used: 1793888B, undo waste: 0B, + * [0.330s][debug][gc,plab ] GC(0) Young other allocation: region end waste: 0B, regions filled: 2, direct allocated: 271520B, failure used: 0B, failure wasted: 0B + * [0.330s][debug][gc,plab ] GC(0) Young sizing: calculated: 358776B, actual: 358776B + * [0.330s][debug][gc,plab ] GC(0) Old PLAB allocation: allocated: 427248B, wasted: 592B, unused: 368584B, used: 58072B, undo waste: 0B, + * [0.330s][debug][gc,plab ] GC(0) Old other allocation: region end waste: 0B, regions filled: 1, direct allocated: 41704B, failure used: 0B, failure wasted: 0B + * [0.330s][debug][gc,plab ] GC(0) Old sizing: calculated: 11608B, actual: 11608B */ final public class LogParser { @@ -53,7 +51,6 @@ final public class LogParser { * Type of parsed log element. */ public static enum ReportType { - SURVIVOR_STATS, OLD_STATS } @@ -64,8 +61,8 @@ final public class LogParser { // GC ID private static final Pattern GC_ID_PATTERN = Pattern.compile("\\[gc,plab\\s*\\] GC\\((\\d+)\\)"); - // Pattern for extraction pair = - private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w+\\s+=\\s+\\d+"); + // Pattern for extraction pair : + private static final Pattern PAIRS_PATTERN = Pattern.compile("\\w* \\w+:\\s+\\d+"); /** * Construct LogParser Object @@ -108,24 +105,29 @@ final public class LogParser { if (matcher.find()) { Map> oneReportItem; ReportType reportType; - // Second line in log is statistics for Old PLAB allocation - if ( !allocationStatistics.containsKey(gc_id.get()) ) { - oneReportItem = new EnumMap<>(ReportType.class); + + if (!allocationStatistics.containsKey(gc_id.get())) { + allocationStatistics.put(gc_id.get(), new EnumMap<>(ReportType.class)); + } + + if ( line.contains("Young") ) { reportType = ReportType.SURVIVOR_STATS; - allocationStatistics.put(gc_id.get(), oneReportItem); } else { - oneReportItem = allocationStatistics.get(gc_id.get()); reportType = ReportType.OLD_STATS; } + oneReportItem = allocationStatistics.get(gc_id.get()); + if (!oneReportItem.containsKey(reportType)) { + oneReportItem.put(reportType,new HashMap()); + } + // Extract all pairs from log. - HashMap plabStats = new HashMap<>(); + Map plabStats = oneReportItem.get(reportType); do { String pair = matcher.group(); - String[] nameValue = pair.replaceAll(" ", "").split("="); - plabStats.put(nameValue[0], Long.parseLong(nameValue[1])); + String[] nameValue = pair.replaceAll(": ", ":").split(":"); + plabStats.put(nameValue[0].trim(), Long.parseLong(nameValue[1])); } while (matcher.find()); - oneReportItem.put(reportType,plabStats); } } } diff --git a/hotspot/test/testlibrary/jdk/test/lib/PerfCounter.java b/hotspot/test/gc/metaspace/PerfCounter.java similarity index 98% rename from hotspot/test/testlibrary/jdk/test/lib/PerfCounter.java rename to hotspot/test/gc/metaspace/PerfCounter.java index fe0bd1da5ab..d39277c910e 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/PerfCounter.java +++ b/hotspot/test/gc/metaspace/PerfCounter.java @@ -21,8 +21,6 @@ * questions. */ -package jdk.test.lib; - import sun.jvmstat.monitor.Monitor; /** diff --git a/hotspot/test/testlibrary/jdk/test/lib/PerfCounters.java b/hotspot/test/gc/metaspace/PerfCounters.java similarity index 98% rename from hotspot/test/testlibrary/jdk/test/lib/PerfCounters.java rename to hotspot/test/gc/metaspace/PerfCounters.java index 5db6a0496bf..d6848f2b7b7 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/PerfCounters.java +++ b/hotspot/test/gc/metaspace/PerfCounters.java @@ -21,13 +21,12 @@ * questions. */ -package jdk.test.lib; - import sun.jvmstat.monitor.Monitor; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; import sun.jvmstat.monitor.VmIdentifier; +import jdk.test.lib.ProcessTools; /** * PerfCounters can be used to get a performance counter from the currently diff --git a/hotspot/test/native_sanity/JniVersion.java b/hotspot/test/native_sanity/JniVersion.java index a85a184c241..e1451d2e9a5 100644 --- a/hotspot/test/native_sanity/JniVersion.java +++ b/hotspot/test/native_sanity/JniVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,12 +27,12 @@ */ public class JniVersion { - public static final int JNI_VERSION_1_8 = 0x00010008; + public static final int JNI_VERSION_9 = 0x00090000; public static void main(String... args) throws Exception { System.loadLibrary("JniVersion"); int res = getJniVersion(); - if (res < JNI_VERSION_1_8) { + if (res != JNI_VERSION_9) { throw new Exception("Unexpected value returned from getJniVersion(): 0x" + Integer.toHexString(res)); } } diff --git a/hotspot/test/runtime/BadObjectClass/BootstrapRedefine.java b/hotspot/test/runtime/BadObjectClass/BootstrapRedefine.java index fde6feb76fd..bed5f7c510f 100644 --- a/hotspot/test/runtime/BadObjectClass/BootstrapRedefine.java +++ b/hotspot/test/runtime/BadObjectClass/BootstrapRedefine.java @@ -28,7 +28,6 @@ * @library /testlibrary * @modules java.base/sun.misc * java.management - * @compile Object.java * @run main BootstrapRedefine */ @@ -37,8 +36,19 @@ import jdk.test.lib.*; public class BootstrapRedefine { public static void main(String[] args) throws Exception { - String testClasses = System.getProperty("test.classes", "."); - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/p:" + testClasses, "-version"); + String source = "package java.lang;" + + "public class Object {" + + " void dummy1() { return; }" + + " void dummy2() { return; }" + + " void dummy3() { return; }" + + "}"; + + ClassFileInstaller.writeClassToDisk("java/lang/Object", + InMemoryJavaCompiler.compile("java.lang.Object", source, + "-Xmodule:java.base"), + "mods/java.base"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xpatch:mods", "-version"); new OutputAnalyzer(pb.start()) .shouldContain("Incompatible definition of java.lang.Object") .shouldHaveExitValue(1); diff --git a/hotspot/test/runtime/BootClassAppendProp/BootClassPathAppend.java b/hotspot/test/runtime/BootClassAppendProp/BootClassPathAppend.java new file mode 100644 index 00000000000..5dba459c4b7 --- /dev/null +++ b/hotspot/test/runtime/BootClassAppendProp/BootClassPathAppend.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8087154 + * @summary Uninitialized system property jdk.boot.class.path.append causes SIGSEGV + * @library /testlibrary + * @modules java.base/sun.misc + */ + +import jdk.test.lib.*; + +// Test that system property jdk.boot.class.path.append is initialized. Otherwise, +// -XX:+PrintCompilation does causes a SIGSEGV. +public class BootClassPathAppend { + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+PrintCompilation", "-Xcomp", "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("java.lang.Object"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/BootClassAppendProp/BootClassPathAppendProp.java b/hotspot/test/runtime/BootClassAppendProp/BootClassPathAppendProp.java new file mode 100644 index 00000000000..1d18c3ababd --- /dev/null +++ b/hotspot/test/runtime/BootClassAppendProp/BootClassPathAppendProp.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.File; + +/* + * @test + * @build BootClassPathAppendProp + * @run main/othervm -Xbootclasspath/a:/usr/lib -showversion -Xbootclasspath/a:/i/dont/exist BootClassPathAppendProp + * @run main/othervm -Xpatch:/not/here -Xbootclasspath/a:/i/may/exist BootClassPathAppendProp + * @run main/othervm -Djdk.boot.class.path.append=newdir BootClassPathAppendProp + * @run main/othervm BootClassPathAppendProp + */ + +// Test that property jdk.boot.class.path.append contains only the bootclasspath +// info following the "modules" jimage file. +public class BootClassPathAppendProp { + public static void main(String[] args) throws Exception { + // jdk.boot.class.path.append is a non-writeable, internal property. + // The call to System.getProperty should return null. + if (System.getProperty("jdk.boot.class.path.append") != null) { + throw new RuntimeException("Test failed, jdk.boot.class.path.append has value: " + + System.getProperty("jdk.boot.class.path.append")); + } else { + System.out.println("Test BootClassPathAppendProp passed"); + } + } +} diff --git a/hotspot/test/runtime/BootClassAppendProp/SunBootClassPath.java b/hotspot/test/runtime/BootClassAppendProp/SunBootClassPath.java new file mode 100644 index 00000000000..e18b2853d9f --- /dev/null +++ b/hotspot/test/runtime/BootClassAppendProp/SunBootClassPath.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Make sure property sun.boot.class.path is null starting with JDK-9. + */ + +// Test that the value of property sun.boot.class.path is null. +public class SunBootClassPath { + public static void main(String[] args) throws Exception { + if (System.getProperty("sun.boot.class.path") != null) { + throw new RuntimeException("Test failed, sun.boot.class.path has value: " + + System.getProperty("sun.boot.class.path")); + } else { + System.out.println("Test SunBootClassPath passed"); + } + } +} diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java index 27ccc5d546b..dcbc3535027 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java @@ -27,8 +27,9 @@ * @library /testlibrary /runtime/CommandLine/OptionsValidation/common * @modules java.base/sun.misc * java.management - * jdk.attach - * jdk.management/sun.tools.attach + * jdk.attach/sun.tools.attach + * jdk.jvmstat/sun.jvmstat.monitor + * @build jdk.test.lib.* TestOptionsWithRanges * @run main/othervm/timeout=900 TestOptionsWithRanges */ diff --git a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java index 517f3a16266..66c84a20bb4 100644 --- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java +++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRangesDynamic.java @@ -26,9 +26,8 @@ * @summary Test writeable VM Options with ranges. * @library /testlibrary /runtime/CommandLine/OptionsValidation/common * @modules java.base/sun.misc + * jdk.attach/sun.tools.attach * java.management - * jdk.attach - * jdk.management/sun.tools.attach * @run main/othervm -XX:MinHeapFreeRatio=0 -XX:MaxHeapFreeRatio=100 TestOptionsWithRangesDynamic */ diff --git a/hotspot/test/runtime/SharedArchiveFile/BasicJarBuilder.java b/hotspot/test/runtime/SharedArchiveFile/BasicJarBuilder.java index 8a0b6f783f1..ab8955cb0f7 100644 --- a/hotspot/test/runtime/SharedArchiveFile/BasicJarBuilder.java +++ b/hotspot/test/runtime/SharedArchiveFile/BasicJarBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,8 +40,18 @@ import sun.tools.jar.Main; public class BasicJarBuilder { private static final String classDir = System.getProperty("test.classes"); + public static void build(boolean classesInWorkDir, String jarName, + String ...classNames) throws Exception { + + if (classesInWorkDir) { + createSimpleJar(".", classDir + File.separator + jarName + ".jar", classNames); + } else { + build(jarName, classNames); + } + } + public static void build(String jarName, String ...classNames) throws Exception { - createSimpleJar(".", classDir + File.separator + jarName + ".jar", + createSimpleJar(classDir, classDir + File.separator + jarName + ".jar", classNames); } diff --git a/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java new file mode 100644 index 00000000000..3b69f956465 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/BootAppendTests.java @@ -0,0 +1,252 @@ +/* + * 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 + * @summary Testing -Xbootclasspath/a support for CDS + * @library /testlibrary + * @modules java.base/jdk.internal.misc + * java.management + * jdk.jartool/sun.tools.jar + * jdk.jvmstat/sun.jvmstat.monitor + * @ignore 8150683 + * @compile javax/sound/sampled/MyClass.jasm + * @compile org/omg/CORBA/Context.jasm + * @compile nonjdk/myPackage/MyClass.java + * @build jdk.test.lib.* LoadClass + * @run main ClassFileInstaller LoadClass + * @run main/othervm BootAppendTests + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.ProcessTools; +import jdk.test.lib.OutputAnalyzer; + +public class BootAppendTests { + private static final String APP_CLASS = "LoadClass"; + private static final String BOOT_APPEND_MODULE_CLASS = "javax/sound/sampled/MyClass"; + private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS = "org/omg/CORBA/Context"; + private static final String BOOT_APPEND_CLASS = "nonjdk/myPackage/MyClass"; + private static final String BOOT_APPEND_MODULE_CLASS_NAME = + BOOT_APPEND_MODULE_CLASS.replace('/', '.'); + private static final String BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME = + BOOT_APPEND_DUPLICATE_MODULE_CLASS.replace('/', '.'); + private static final String BOOT_APPEND_CLASS_NAME = + BOOT_APPEND_CLASS.replace('/', '.'); + private static final String[] ARCHIVE_CLASSES = + {BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS}; + + private static final String modes[] = {"on", "off"}; + + private static String appJar; + private static String bootAppendJar; + + public static void main(String... args) throws Exception { + dumpArchive(); + testBootAppendModuleClass(); + testBootAppendDuplicateModuleClass(); + testBootAppendExcludedModuleClass(); + testBootAppendDuplicateExcludedModuleClass(); + testBootAppendClass(); + } + + static void dumpArchive() throws Exception { + // create the classlist + File classlist = new File(new File(System.getProperty("test.classes", ".")), + "BootAppendTest.classlist"); + FileOutputStream fos = new FileOutputStream(classlist); + PrintStream ps = new PrintStream(fos); + for (String s : ARCHIVE_CLASSES) { + ps.println(s); + } + ps.close(); + fos.close(); + + // build jar files + BasicJarBuilder.build(true, "app", APP_CLASS); + appJar = BasicJarBuilder.getTestJar("app.jar"); + BasicJarBuilder.build("bootAppend", + BOOT_APPEND_MODULE_CLASS, BOOT_APPEND_DUPLICATE_MODULE_CLASS, BOOT_APPEND_CLASS); + bootAppendJar = BasicJarBuilder.getTestJar("bootAppend.jar"); + + // dump + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./BootAppendTests.jsa", + "-XX:SharedClassListFile=" + classlist.getPath(), + "-XX:+PrintSharedSpaces", + "-Xbootclasspath/a:" + bootAppendJar, + "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Loading classes to share") + .shouldHaveExitValue(0); + + // Make sure all the classes were successfully archived. + for (String archiveClass : ARCHIVE_CLASSES) { + output.shouldNotContain("Preload Warning: Cannot find " + archiveClass); + } + } + + // Test #1: If a class on -Xbootclasspath/a is from a package defined in + // bootmodules, the class is not loaded at runtime. + // Verify the behavior is the same when the class is archived + // with CDS enabled at runtime. + // + // The javax.sound.sampled package is defined in the java.desktop module. + // The archived javax.sound.sampled.MyClass from the -Xbootclasspath/a + // should not be loaded at runtime. + public static void testBootAppendModuleClass() throws Exception { + for (String mode : modes) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./BootAppendTests.jsa", + "-cp", appJar, + "-Xbootclasspath/a:" + bootAppendJar, + "-Xshare:" + mode, + APP_CLASS, + BOOT_APPEND_MODULE_CLASS_NAME); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("java.lang.ClassNotFoundException: javax.sound.sampled.MyClass"); + } + } + + // Test #2: If a class on -Xbootclasspath/a has the same fully qualified + // name as a class defined in boot modules, the class is not loaded + // from -Xbootclasspath/a. Verify the behavior is the same at runtime + // when CDS is enabled. + // + // The org.omg.CORBA.Context is a boot module class. The class on + // the -Xbootclasspath/a path that has the same fully-qualified name + // should not be loaded at runtime when CDS is enabled. + // The one from the boot modules should be loaded instead. + public static void testBootAppendDuplicateModuleClass() throws Exception { + for (String mode : modes) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./BootAppendTests.jsa", + "-XX:+TraceClassLoading", + "-cp", appJar, + "-Xbootclasspath/a:" + bootAppendJar, + "-Xshare:" + mode, + APP_CLASS, + BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[classload] org.omg.CORBA.Context source: jrt:/java.corba"); + } + } + + // Test #3: If a class on -Xbootclasspath/a is from a package defined in boot modules, + // the class can be loaded from -Xbootclasspath/a when the module is excluded + // using -limitmods. Verify the behavior is the same at runtime when CDS is + // enabled. + // + // The java.desktop module is excluded using -limitmods at runtime, + // javax.sound.sampled.MyClass is archived from -Xbootclasspath/a. It can be + // loaded from the archive at runtime. + public static void testBootAppendExcludedModuleClass() throws Exception { + for (String mode : modes) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./BootAppendTests.jsa", + "-XX:+TraceClassLoading", + "-cp", appJar, + "-Xbootclasspath/a:" + bootAppendJar, + "-limitmods", "java.base", + "-Xshare:" + mode, + APP_CLASS, + BOOT_APPEND_MODULE_CLASS_NAME); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[classload] javax.sound.sampled.MyClass"); + + // When CDS is enabled, the shared class should be loaded from the archive. + if (mode.equals("on")) { + output.shouldContain("[classload] javax.sound.sampled.MyClass source: shared objects file"); + } + } + } + + // Test #4: If a class on -Xbootclasspath/a has the same fully qualified + // name as a class defined in boot modules, the class is loaded + // from -Xbootclasspath/a when the boot module is excluded using + // -limitmods. Verify the behavior is the same at runtime when CDS is + // enabled. + // + // The org.omg.CORBA.Context is a boot module class. The class + // on -Xbootclasspath/a that has the same fully-qualified name + // as org.omg.CORBA.Context can be loaded at runtime when + // java.corba is excluded. + public static void testBootAppendDuplicateExcludedModuleClass() throws Exception { + for (String mode : modes) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./BootAppendTests.jsa", + "-XX:+TraceClassLoading", + "-cp", appJar, + "-Xbootclasspath/a:" + bootAppendJar, + "-limitmods", "java.base", + "-Xshare:" + mode, + APP_CLASS, + BOOT_APPEND_DUPLICATE_MODULE_CLASS_NAME); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[classload] org.omg.CORBA.Context"); + output.shouldMatch(".*\\[classload\\] org.omg.CORBA.Context source:.*bootAppend.jar"); + } + } + + // Test #5: If a class on -Xbootclasspath/a is not from named modules, + // the class can be loaded at runtime. Verify the behavior is + // the same at runtime when CDS is enabled. + // + // The nonjdk.myPackage is not defined in named modules. The + // archived nonjdk.myPackage.MyClass from -Xbootclasspath/a + // can be loaded at runtime when CDS is enabled. + public static void testBootAppendClass() throws Exception { + for (String mode : modes) { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./BootAppendTests.jsa", + "-XX:+TraceClassLoading", + "-cp", appJar, + "-Xbootclasspath/a:" + bootAppendJar, + "-Xshare:" + mode, + APP_CLASS, + BOOT_APPEND_CLASS_NAME); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("[classload] nonjdk.myPackage.MyClass"); + + // If CDS is enabled, the nonjdk.myPackage.MyClass should be loaded + // from the shared archive. + if (mode.equals("on")) { + output.shouldContain( + "[classload] nonjdk.myPackage.MyClass source: shared objects file"); + } + } + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/LoadClass.java b/hotspot/test/runtime/SharedArchiveFile/LoadClass.java new file mode 100644 index 00000000000..417f92451ae --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/LoadClass.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +/* + * @summary Load the class specifiecd by the argument + * Input: className + */ +public class LoadClass { + public static void main(String args[]) { + Class c = null; + try { + c = Class.forName(args[0]); + } catch (ClassNotFoundException e) { + System.out.println(e); + } + if (c != null) { + System.out.println(c + " loaded."); + } + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java b/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java index 55e35246b96..45f74515339 100644 --- a/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java +++ b/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java @@ -60,24 +60,6 @@ public class PrintSharedArchiveAndExit { output.shouldNotContain("Usage:"); // Should not print JVM help message output.shouldHaveExitValue(0); // Should report success in error code. - // (2) With an invalid archive (boot class path has been prepended) - pb = ProcessTools.createJavaProcessBuilder( - "-Xbootclasspath/p:foo.jar", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, - "-XX:+PrintSharedArchiveAndExit", "-version"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("archive is invalid"); - output.shouldNotContain("java version"); // Should not print JVM version - output.shouldHaveExitValue(1); // Should report failure in error code. - - pb = ProcessTools.createJavaProcessBuilder( - "-Xbootclasspath/p:foo.jar", - "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=" + filename, - "-XX:+PrintSharedArchiveAndExit"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("archive is invalid"); - output.shouldNotContain("Usage:"); // Should not print JVM help message - output.shouldHaveExitValue(1); // Should report failure in error code. } catch (RuntimeException e) { e.printStackTrace(); output.shouldContain("Unable to use shared archive"); diff --git a/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java b/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java index 50906ea5d33..67059bf5715 100644 --- a/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java +++ b/hotspot/test/runtime/SharedArchiveFile/SharedStrings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,6 +32,7 @@ * @library /testlibrary /test/lib * @modules java.base/sun.misc * java.management + * jdk.jartool/sun.tools.jar * @build SharedStringsWb SharedStrings BasicJarBuilder sun.hotspot.WhiteBox * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main SharedStrings @@ -40,7 +41,7 @@ import jdk.test.lib.*; public class SharedStrings { public static void main(String[] args) throws Exception { - BasicJarBuilder.build("whitebox", "sun/hotspot/WhiteBox"); + BasicJarBuilder.build(true, "whitebox", "sun/hotspot/WhiteBox"); ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-XX:+UnlockDiagnosticVMOptions", diff --git a/hotspot/test/runtime/SharedArchiveFile/javax/sound/sampled/MyClass.jasm b/hotspot/test/runtime/SharedArchiveFile/javax/sound/sampled/MyClass.jasm new file mode 100644 index 00000000000..5e6078cbee2 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/javax/sound/sampled/MyClass.jasm @@ -0,0 +1,46 @@ +/* + * 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 javax/sound/sampled; + +public class MyClass + version 51:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + +public Method toString:"()Ljava/lang/String;" + stack 1 locals 1 +{ + ldc String "hi"; + areturn; +} + +} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg1/Class1Pkg1.java b/hotspot/test/runtime/SharedArchiveFile/nonjdk/myPackage/MyClass.java similarity index 85% rename from langtools/test/com/sun/javadoc/testProfiles/pkg1/Class1Pkg1.java rename to hotspot/test/runtime/SharedArchiveFile/nonjdk/myPackage/MyClass.java index dc5c50d76fc..265457ca70c 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg1/Class1Pkg1.java +++ b/hotspot/test/runtime/SharedArchiveFile/nonjdk/myPackage/MyClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,10 @@ * questions. */ -package pkg1; +package nonjdk.myPackage; -/** - * A test class. - * - * @author Bhavesh Patel - */ -public class Class1Pkg1 { +public class MyClass { + public String toString() { + return "hi"; + } } diff --git a/hotspot/test/runtime/SharedArchiveFile/org/omg/CORBA/Context.jasm b/hotspot/test/runtime/SharedArchiveFile/org/omg/CORBA/Context.jasm new file mode 100644 index 00000000000..c3424b9f799 --- /dev/null +++ b/hotspot/test/runtime/SharedArchiveFile/org/omg/CORBA/Context.jasm @@ -0,0 +1,46 @@ +/* + * 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 org/omg/CORBA; + +public class Context + version 51:0 +{ + +public Method "":"()V" + stack 1 locals 1 +{ + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; +} + + +public Method toString:"()Ljava/lang/String;" + stack 1 locals 1 +{ + ldc String "hi"; + areturn; +} + +} diff --git a/hotspot/test/runtime/getSysPackage/GetSysPkgTest.java b/hotspot/test/runtime/getSysPackage/GetSysPkgTest.java new file mode 100644 index 00000000000..7e3930137e7 --- /dev/null +++ b/hotspot/test/runtime/getSysPackage/GetSysPkgTest.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +/* + * @test + * @modules java.base/jdk.internal.loader + * java.desktop + * @library /testlibrary + * @run main/othervm GetSysPkgTest + */ + +import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import jdk.test.lib.*; + +// Test that JVM get_system_package() returns the module location for defined packages. +public class GetSysPkgTest { + + private static Object invoke(Method m, Object obj, Object... args) throws Throwable { + try { + return m.invoke(obj, args); + } catch (InvocationTargetException e) { + throw e.getCause(); + } + } + + private static Method findMethod(String name) { + for (Method m : jdk.internal.loader.BootLoader.class.getDeclaredMethods()) { + if (m.getName().equals(name)) { + m.setAccessible(true); + return m; + } + } + throw new RuntimeException("Failed to find method " + name + " in java.lang.reflect.Module"); + } + + // Throw RuntimeException if getSystemPackageLocation() does not return + // the expected location. + static void getPkg(String name, String expected_loc) throws Throwable { + String loc = (String)invoke(findMethod("getSystemPackageLocation"), null, name); + if (loc == null) { + if (expected_loc == null) return; + System.out.println("Expected location: " + expected_loc + + ", for package: " + name + ", got: null"); + } else if (expected_loc == null) { + System.out.println("Expected location: null, for package: " + + name + ", got: " + loc); + } else if (!loc.equals(expected_loc)) { + System.out.println("Expected location: " + + expected_loc + ", for package: " + name + ", got: " + loc); + } else { + return; + } + throw new RuntimeException(); + } + + public static void main(String args[]) throws Throwable { + if (args.length == 0 || !args[0].equals("do_tests")) { + + // Create a package found via -Xbootclasspath/a + String source = "package BootLdr_package; " + + "public class BootLdrPkg { " + + " public int mth() { return 4; } " + + "}"; + byte[] klassbuf = + InMemoryJavaCompiler.compile("BootLdr_package.BootLdrPkg", source); + ClassFileInstaller.writeClassToDisk("BootLdr_package/BootLdrPkg", klassbuf, "bl_dir"); + + // Create a package found via -cp. + source = "package GetSysPkg_package; " + + "public class GetSysClass { " + + " public int mth() { return 4; } " + + "}"; + klassbuf = + InMemoryJavaCompiler.compile("GetSysPkg_package.GetSysClass", source); + ClassFileInstaller.writeClassToDisk("GetSysPkg_package/GetSysClass", klassbuf); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/a:bl_dir", + "-XaddExports:java.base/jdk.internal.loader=ALL-UNNAMED", "-cp", "." + File.pathSeparator + + System.getProperty("test.classes"), "GetSysPkgTest", "do_tests"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + return; + } + + getPkg("java/lang", "jrt:/java.base"); + getPkg("javax/script", null); // Package not defined + + // Test a package that does not yet have any referenced classes. + // Note: if another class in com/sun/crypto/provider/ happens to get + // loaded or if class PrivateKeyInfo disappears from this package + // then this test will fail. + getPkg("com/sun/crypto/provider", null); + // Now make sure a class in the package is referenced. + Class newClass = Class.forName("com.sun.crypto.provider.PrivateKeyInfo"); + getPkg("com/sun/crypto/provider", "jrt:/java.base"); + + getPkg("java/nio/charset", "jrt:/java.base"); + + // Test a package in a module not owned by boot loader. + Class clss = Class.forName("javax.activation.DataHandler"); + if (clss == null) + throw new RuntimeException("Could not find class javax.activation.DataHandler"); + getPkg("javax/activation", null); // Not owned by boot loader + + // Test a package not in jimage file. + clss = Class.forName("GetSysPkg_package.GetSysClass"); + if (clss == null) + throw new RuntimeException("Could not find class GetSysPkg_package.GetSysClass"); + getPkg("GetSysPkg_package", null); + + // Access a class with a package in a boot loader module other than java.base + clss = Class.forName("java.awt.Button"); + if (clss == null) + throw new RuntimeException("Could not find class java.awt.Button"); + getPkg("java/awt", "jrt:/java.desktop"); + + // Test getting the package location from a class found via -Xbootclasspath/a + clss = Class.forName("BootLdr_package.BootLdrPkg"); + if (clss == null) + throw new RuntimeException("Could not find class BootLdr_package.BootLdrPkg"); + String bootldrPkg = (String)invoke(findMethod("getSystemPackageLocation"), null, "BootLdr_package"); + if (bootldrPkg == null) { + throw new RuntimeException("Expected BootLdr_package to return non-null value"); + } + if (!bootldrPkg.equals("bl_dir")) { + throw new RuntimeException("Expected BootLdr_package to return bl_dir, got: " + bootldrPkg); + } + + // Test when package's class reference is an array. + // Note: if another class in javax/crypto happens to get loaded + // or if class AEADBadTagException disappears from this package + // then this test will fail. + getPkg("javax/crypto", null); + javax.crypto.AEADBadTagException[] blah = new javax.crypto.AEADBadTagException[3]; + getPkg("javax/crypto", "jrt:/java.base"); + + } +} diff --git a/hotspot/test/runtime/logging/ItablesTest.java b/hotspot/test/runtime/logging/ItablesTest.java index c1cfd33d865..0fe9d84213c 100644 --- a/hotspot/test/runtime/logging/ItablesTest.java +++ b/hotspot/test/runtime/logging/ItablesTest.java @@ -49,7 +49,6 @@ public class ItablesTest { output.shouldContain("invokespecial resolved method: caller-class:ClassB"); output.shouldContain("invokespecial selected method: resolved-class:ClassB"); output.shouldContain("invokeinterface selected method: receiver-class"); - output.shouldContain("Resolving: klass: "); output.shouldHaveExitValue(0); pb = ProcessTools.createJavaProcessBuilder("-Xlog:itables=trace", "ItablesVtableTest"); diff --git a/hotspot/test/runtime/logging/ModulesTest.java b/hotspot/test/runtime/logging/ModulesTest.java new file mode 100644 index 00000000000..3547a06062a --- /dev/null +++ b/hotspot/test/runtime/logging/ModulesTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary modules=debug should have logging from statements in the code + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run main ModulesTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class ModulesTest { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xlog:modules=trace", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("define_javabase_module(): Definition of module:"); + output.shouldContain("define_javabase_module(): creation of package"); + output.shouldContain("define_module(): creation of module"); + output.shouldContain("define_module(): creation of package"); + output.shouldContain("set_bootloader_unnamed_module(): recording unnamed"); + output.shouldContain("add_module_exports(): package"); + output.shouldContain("add_reads_module(): Adding read from module"); + output.shouldContain("Setting package: class:"); + output.shouldHaveExitValue(0); + } +} + diff --git a/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java b/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java new file mode 100644 index 00000000000..57790ad1248 --- /dev/null +++ b/hotspot/test/runtime/logging/ProtectionDomainVerificationTest.java @@ -0,0 +1,62 @@ +/* + * 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 ProtectionDomainVerificationTest + * @bug 8149064 + * @library /testlibrary + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.Platform jdk.test.lib.ProcessTools + * @run driver ProtectionDomainVerificationTest + */ + +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.Platform; +import jdk.test.lib.ProcessTools; + +public class ProtectionDomainVerificationTest { + + public static void main(String... args) throws Exception { + + // -Xlog:protectiondomain=trace + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:protectiondomain=trace", + "-Xmx64m", + Hello.class.getName()); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldContain("[protectiondomain] Checking package access"); + out.shouldContain("[protectiondomain] pd set count = #"); + + // -Xlog:protectiondomain=debug + pb = ProcessTools.createJavaProcessBuilder("-Xlog:protectiondomain=debug", + "-Xmx64m", + Hello.class.getName()); + out = new OutputAnalyzer(pb.start()); + out.shouldContain("[protectiondomain] Checking package access"); + out.shouldNotContain("pd set count = #"); + } + + public static class Hello { + public static void main(String[] args) { + System.out.print("Hello!"); + } + } +} diff --git a/hotspot/test/runtime/logging/ThreadLoggingTest.java b/hotspot/test/runtime/logging/ThreadLoggingTest.java new file mode 100644 index 00000000000..a5cde9c845c --- /dev/null +++ b/hotspot/test/runtime/logging/ThreadLoggingTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, SAP SE and/or its affiliates. All rights reserved. + * 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 8149036 8150619 + * @summary os+thread output should contain logging calls for thread start stop attaches detaches + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @build jdk.test.lib.OutputAnalyzer jdk.test.lib.ProcessTools + * @run driver ThreadLoggingTest + * @author Thomas Stuefe (SAP) + */ + +import java.io.File; +import java.util.Map; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; + +public class ThreadLoggingTest { + + static void analyzeOutputForInfoLevel(OutputAnalyzer output) throws Exception { + output.shouldContain("Thread started"); + output.shouldContain("Thread is alive"); + output.shouldContain("Thread finished"); + output.shouldHaveExitValue(0); + } + + static void analyzeOutputForDebugLevel(OutputAnalyzer output) throws Exception { + analyzeOutputForInfoLevel(output); + output.shouldContain("stack dimensions"); + output.shouldContain("stack guard pages"); + } + + public static void main(String[] args) throws Exception { + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread", "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + analyzeOutputForInfoLevel(output); + + pb = ProcessTools.createJavaProcessBuilder("-Xlog:os+thread=debug", "-version"); + output = new OutputAnalyzer(pb.start()); + analyzeOutputForDebugLevel(output); + + } + +} diff --git a/hotspot/test/runtime/modules/AccModuleTest.java b/hotspot/test/runtime/modules/AccModuleTest.java new file mode 100644 index 00000000000..f1f8ab0bc60 --- /dev/null +++ b/hotspot/test/runtime/modules/AccModuleTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary + * @modules java.base/sun.misc + * @compile acc_module.jcod + * @build AccModuleTest + * @run main AccModuleTest + */ + +import java.io.File; +import jdk.test.lib.*; + +public class AccModuleTest { + + public static void main(String args[]) throws Throwable { + System.out.println("Test that ACC_MODULE in class access flags does not cause ClassFormatError"); + Class clss = Class.forName("acc_module"); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/CheckRead.java b/hotspot/test/runtime/modules/AccessCheck/CheckRead.java new file mode 100644 index 00000000000..ec88eef6525 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/CheckRead.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can not read module m2, then class p1.c1 + * in module m1 can not access p2.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build CheckRead + * @run main/othervm -Xbootclasspath/a:. CheckRead + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can not read m2 +// package p2 in m2 is exported to m1 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2. +// Access denied since m1 can not read m2. +// +public class CheckRead { + + // 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: m1 + // Can read: java.base, m3 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m3") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Define module: m3 + // Can read: java.base, m2 + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .requires("m2") + .conceals("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + map.put("m3", MySameClassLoader.loader1); + + // Create Layer that contains m1, m2 and m3 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m3") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m1 but m2 is not readable from m1)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("cannot access")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + CheckRead test = new CheckRead(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_CheckRead.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_CheckRead.java new file mode 100644 index 00000000000..7ccf918d232 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_CheckRead.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can not read module m2, then class p1.c1 + * in module m1 can not access p2.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build DiffCL_CheckRead + * @run main/othervm -Xbootclasspath/a:. DiffCL_CheckRead + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can not read m2 +// package p2 in m2 is exported to m1 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2. +// Access denied since m1 can not read m2. +// +public class DiffCL_CheckRead { + + // 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: m1 + // Can read: java.base, m3 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m3") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Define module: m3 + // Can read: java.base, m2 + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .requires("m2") + .conceals("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + map.put("m3", MyDiffClassLoader.loader2); + + // Create Layer that contains m1, m2 and m3 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("m3") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m1 but m2 is not readable from m1)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("cannot access")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_CheckRead test = new DiffCL_CheckRead(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualOther.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualOther.java new file mode 100644 index 00000000000..c815a85fac7 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualOther.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, but package p2 in m2 + * is exported specifically to module m3, then class p1.c1 in m1 can not + * access p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build DiffCL_ExpQualOther + * @run main/othervm -Xbootclasspath/a:. DiffCL_ExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can read m2 +// package p2 in m2 is exported to m3 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access denied since although m1 can read m2, p2 is exported only to m3. +// +public class DiffCL_ExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2, m3 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .requires("m3") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base, m3 + // Packages: p2 + // Packages exported: p2 is exported to m3 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m3") + .build(); + + // Define module: m3 + // Can read: java.base, m2 + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .requires("m2") + .conceals("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + map.put("m3", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("m3") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m3 not to m1)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_ExpQualOther test = new DiffCL_ExpQualOther(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualToM1.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualToM1.java new file mode 100644 index 00000000000..c1c38fd61dc --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpQualToM1.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in m1 tries to access p2.c2 defined in m2. + * Access allowed since m1 can read m2 and package p2 is exported to m1. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build DiffCL_ExpQualToM1 + * @run main/othervm -Xbootclasspath/a:. DiffCL_ExpQualToM1 + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported to m1 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access allowed since m1 can read m2 and package p2 is exported to m1. +// +public class DiffCL_ExpQualToM1 { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported to unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: package p2 is exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1"); + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_ExpQualToM1 test = new DiffCL_ExpQualToM1(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpUnqual.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpUnqual.java new file mode 100644 index 00000000000..a8668333d73 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_ExpUnqual.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, and package p2 in m2 is + * exported unqualifiedly, then class p1.c1 in m1 can read p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build DiffCL_ExpUnqual + * @run main/othervm -Xbootclasspath/a:. DiffCL_ExpUnqual + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported to m1 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access allowed since m1 can read m2 and package p2 is exported +// unqualifiedly. +// +public class DiffCL_ExpUnqual { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: package p2 is exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1"); + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_ExpUnqual test = new DiffCL_ExpUnqual(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_PkgNotExp.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_PkgNotExp.java new file mode 100644 index 00000000000..d4f3d62d4ec --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_PkgNotExp.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, but package p2 in m2 is not + * exported, then class p1.c1 in m1 can not read p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build DiffCL_PkgNotExp + * @run main/othervm -Xbootclasspath/a:. DiffCL_PkgNotExp + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// ClassLoader2 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is not exported +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access denied since p2 is not exported. +// +public class DiffCL_PkgNotExp { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .conceals("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is not exported)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_PkgNotExp test = new DiffCL_PkgNotExp(); + test.createLayerOnBoot(); + } +} + diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_Umod.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_Umod.java new file mode 100644 index 00000000000..6df74bfa689 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_Umod.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in m1 tries to access p2.c2 defined in unnamed module. + * @library /testlibrary /test/lib + * @modules java.base/jdk.internal.module + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @compile p1/c1ReadEdgeDiffLoader.java + * @compile p1/c1Loose.java + * @build DiffCL_Umod + * @run main/othervm -Xbootclasspath/a:. DiffCL_Umod + */ + +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; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// package p1 in m1 is exported unqualifiedly +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in +// in unnamed module. +// +// Three access attempts occur in this test: +// 1. The first access is not allowed because a strict module +// cannot read an unnamed module. +// 2. In this scenario a strict module establishes readability +// to the particular unnamed module it is trying to access. +// Access is allowed. +// 3. Module m1 in the test_looseModuleLayer() method +// is transitioned to a loose module, access +// to all unnamed modules is allowed. +// +public class DiffCL_Umod { + + // Create Layers over the boot layer to test different + // accessing scenarios of a named module to an unnamed module. + + // Module m1 is a strict module and has not established + // readability to an unnamed module that p2.c2 is defined in. + public void test_strictModuleLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MyDiffClassLoader.loader1 = new MyDiffClassLoader(); + MyDiffClassLoader.loader2 = new MyDiffClassLoader(); + + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader2 + // to achieve differing class loaders. + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + + // Attempt access + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, strict module m1 should not be able " + + "to access public type p2.c2 defined in unnamed module"); + } catch (IllegalAccessError e) { + } +} + + // Module m1 is a strict module and has established + // readability to an unnamed module that p2.c2 is defined in. + public void test_strictModuleUnnamedReadableLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MyDiffClassLoader.loader1 = new MyDiffClassLoader(); + MyDiffClassLoader.loader2 = new MyDiffClassLoader(); + + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader2 + // to achieve differing class loaders. + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1ReadEdgeDiffLoader + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1ReadEdgeDiffLoader"); + + try { + // Read edge between m1 and the unnamed module that loads p2.c2 is established in + // c1ReadEdgeDiffLoader's ctor before attempting access. + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, module m1 has established readability to p2/c2 loader's " + + "unnamed module, access should be allowed: " + e.getMessage()); + } + } + + // Module m1 is a loose module and thus can read all unnamed modules. + public void test_looseModuleLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MyDiffClassLoader.loader1 = new MyDiffClassLoader(); + MyDiffClassLoader.loader2 = new MyDiffClassLoader(); + + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader2 + // to achieve differing class loaders. + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1Loose + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1Loose"); + + // change m1 to be a loose module + Module m1 = layer.findModule("m1").get(); + jdk.internal.module.Modules.addReads(m1, null); + + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, loose module m1 should be able to access " + + "public type p2.c2 defined in unnamed module: " + e.getMessage()); + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_Umod test = new DiffCL_Umod(); + test.test_strictModuleLayer(); // access denied + test.test_strictModuleUnnamedReadableLayer(); // access allowed + test.test_looseModuleLayer(); // access allowed + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/DiffCL_UmodUpkg.java b/hotspot/test/runtime/modules/AccessCheck/DiffCL_UmodUpkg.java new file mode 100644 index 00000000000..5cd133db695 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/DiffCL_UmodUpkg.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p3.c3 defined in module m1 tries to access c4 defined in an unnamed package + * and an unnamed module. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile c4.java + * @compile p3/c3.jcod + * @compile p3/c3ReadEdgeDiffLoader.jcod + * @build DiffCL_UmodUpkg + * @run main/othervm -Xbootclasspath/a:. DiffCL_UmodUpkg + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p3 +// package p3 in m1 is exported unqualifiedly +// +// class p3.c3 defined in m1 tries to access c4 defined in +// in unnamed module. +// +// Two access attempts occur in this test: +// 1. The first access is not allowed because a strict module +// cannot read an unnamed module. +// 2. In this scenario a strict module establishes readability +// to the particular unnamed module it is trying to access. +// Access is allowed. +// +public class DiffCL_UmodUpkg { + + // Create Layers over the boot layer to test different + // accessing scenarios of a named module to an unnamed module. + + // Module m1 is a strict module and has not established + // readability to an unnamed module that c4 is defined in. + public void test_strictModuleLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p3 + // Packages exported: p3 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MyDiffClassLoader.loader1 = new MyDiffClassLoader(); + MyDiffClassLoader.loader2 = new MyDiffClassLoader(); + + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader2 + // to achieve differing class loaders. + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p3.c3 + Class p3_c3_class = MyDiffClassLoader.loader1.loadClass("p3.c3"); + + // Attempt access + try { + p3_c3_class.newInstance(); + throw new RuntimeException("Test Failed, strict module m1 should not be able to access " + + "public type c4 defined in unnamed module"); + } catch (IllegalAccessError e) { + } +} + + // Module m1 is a strict module and has established + // readability to an unnamed module that c4 is defined in. + public void test_strictModuleUnnamedReadableLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p3 + // Packages exported: p3 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MyDiffClassLoader.loader1 = new MyDiffClassLoader(); + MyDiffClassLoader.loader2 = new MyDiffClassLoader(); + + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader2 + // to achieve differing class loaders. + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p3.c3ReadEdgeDiffLoader + Class p3_c3_class = MyDiffClassLoader.loader1.loadClass("p3.c3ReadEdgeDiffLoader"); + + try { + // Read edge between m1 and the unnamed module that loads c4 is established in + // C3ReadEdgeDiffLoader's ctor before attempting access. + p3_c3_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, module m1 has established readability to " + + "c4 loader's unnamed module, access should be allowed: " + e.getMessage()); + } + } + + public static void main(String args[]) throws Throwable { + DiffCL_UmodUpkg test = new DiffCL_UmodUpkg(); + test.test_strictModuleLayer(); // access denied + test.test_strictModuleUnnamedReadableLayer(); // access allowed + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/ExpQualOther.java b/hotspot/test/runtime/modules/AccessCheck/ExpQualOther.java new file mode 100644 index 00000000000..4645d096746 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/ExpQualOther.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, but package p2 in m2 + * is exported specifically to module m3, then class p1.c1 in m1 can not + * access p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build ExpQualOther + * @run main/othervm -Xbootclasspath/a:. ExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can read m2 +// package p2 in m2 is exported to m3 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access denied since although m1 can read m2, p2 is exported only to m3. +// +public class ExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2, m3 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .requires("m3") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to m3 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m3") + .build(); + + // Define module: m3 + // Can read: java.base, m2 + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .requires("m2") + .conceals("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + map.put("m3", MySameClassLoader.loader1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m3") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m3 not to m1)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + ExpQualOther test = new ExpQualOther(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/ExpQualToM1.java b/hotspot/test/runtime/modules/AccessCheck/ExpQualToM1.java new file mode 100644 index 00000000000..fa0b0944ff1 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/ExpQualToM1.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, AND package p2 in m2 is + * exported qualifiedly to m1, then class p1.c1 in m1 can read p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build ExpQualToM1 + * @run main/othervm -Xbootclasspath/a:. ExpQualToM1 + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +public class ExpQualToM1 { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported qualifiedly to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to the same class loader for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported qualifiedly to m1"); + } + } + + public static void main(String args[]) throws Throwable { + ExpQualToM1 test = new ExpQualToM1(); + test.createLayerOnBoot(); + } + +} diff --git a/hotspot/test/runtime/modules/AccessCheck/ExpUnqual.java b/hotspot/test/runtime/modules/AccessCheck/ExpUnqual.java new file mode 100644 index 00000000000..a7c74ba5084 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/ExpUnqual.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, AND package p2 in module2 is + * exported unqualifiedly, then class p1.c1 in m1 can read p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build ExpUnqual + * @run main/othervm -Xbootclasspath/a:. ExpUnqual + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +public class ExpUnqual { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported unqualifiedly + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to the same class loader for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an IAE should not be thrown since p2 is exported unqualifiedly."); + } + } + + public static void main(String args[]) throws Throwable { + ExpUnqual test = new ExpUnqual(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/ExportAllUnnamed.java b/hotspot/test/runtime/modules/AccessCheck/ExportAllUnnamed.java new file mode 100644 index 00000000000..cb09a5315d6 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/ExportAllUnnamed.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test if package p2 in module m2 is exported to all unnamed, + * then class p1.c1 in an unnamed module can read p2.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @compile -XaddExports:java.base/jdk.internal.module=ALL-UNNAMED ExportAllUnnamed.java + * @run main/othervm -XaddExports:java.base/jdk.internal.module=ALL-UNNAMED -Xbootclasspath/a:. ExportAllUnnamed + */ + +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; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported unqualifiedly +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2 +// Access allowed, an unnamed module can read all modules and p2 in module +// m2 is exported to all unnamed modules. + +public class ExportAllUnnamed { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported unqualifiedly + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + Class p2_c2_class = MySameClassLoader.loader1.loadClass("p2.c2"); + Module m2 = p2_c2_class.getModule(); + + // Export m2/p2 to all unnamed modules. + jdk.internal.module.Modules.addExportsToAllUnnamed(m2, "p2"); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, unnamed module failed to access public type p2.c2 " + + "that was exported to all unnamed"); + } + } + + public static void main(String args[]) throws Throwable { + ExportAllUnnamed test = new ExportAllUnnamed(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java b/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java new file mode 100644 index 00000000000..54872b9ec04 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/ModuleLibrary.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +/** + * A container of modules that acts as a ModuleFinder for testing + * purposes. + */ + +class ModuleLibrary implements ModuleFinder { + private final Map namesToReference = new HashMap<>(); + + private ModuleLibrary() { } + + void add(ModuleDescriptor... descriptors) { + for (ModuleDescriptor descriptor: descriptors) { + String name = descriptor.name(); + if (!namesToReference.containsKey(name)) { + //modules.add(descriptor); + + URI uri = URI.create("module:/" + descriptor.name()); + + Supplier supplier = () -> { + throw new UnsupportedOperationException(); + }; + + ModuleReference mref = new ModuleReference(descriptor, uri, supplier); + + namesToReference.put(name, mref); + } + } + } + + static ModuleLibrary of(ModuleDescriptor... descriptors) { + ModuleLibrary ml = new ModuleLibrary(); + ml.add(descriptors); + return ml; + } + + @Override + public Optional find(String name) { + return Optional.ofNullable(namesToReference.get(name)); + } + + @Override + public Set findAll() { + return new HashSet<>(namesToReference.values()); + } +} + diff --git a/hotspot/test/runtime/modules/AccessCheck/PkgNotExp.java b/hotspot/test/runtime/modules/AccessCheck/PkgNotExp.java new file mode 100644 index 00000000000..b8a56173988 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/PkgNotExp.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if module m1 can read module m2, but package p2 in m2 is not + * exported, then class p1.c1 in m1 can not read p2.c2 in m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build PkgNotExp + * @run main/othervm -Xbootclasspath/a:. PkgNotExp + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is not exported +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access denied since p2 is not exported. +// +public class PkgNotExp { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .exports("p1") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .conceals("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to the same class loader for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 and m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is not exported)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + PkgNotExp test = new PkgNotExp(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/Umod.java b/hotspot/test/runtime/modules/AccessCheck/Umod.java new file mode 100644 index 00000000000..639891b4339 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/Umod.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in m1 tries to access p2.c2 defined in unnamed module. + * @library /testlibrary /test/lib + * @modules java.base/jdk.internal.module + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @compile p1/c1ReadEdge.java + * @compile p1/c1Loose.java + * @build Umod + * @run main/othervm -Xbootclasspath/a:. Umod + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p1 +// package p1 in m1 is exported unqualifiedly +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in +// in unnamed module. +// +// Three access attempts occur in this test: +// 1. The first access is not allowed because a strict module +// cannot read an unnamed module. +// 2. In this scenario a strict module establishes readability +// to the particular unnamed module it is trying to access. +// Access is allowed. +// 3. Module m1 in the test_looseModuleLayer() method +// is transitioned to a loose module, access +// to all unnamed modules is allowed. +// +public class Umod { + + // Create Layers over the boot layer to test different + // accessing scenarios of a named module to an unnamed module. + + // Module m1 is a strict module and has not established + // readability to an unnamed module that p2.c2 is defined in. + public void test_strictModuleLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader. + MySameClassLoader loader = new MySameClassLoader(); + Map map = new HashMap<>(); + map.put("m1", loader); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = loader.loadClass("p1.c1"); + + // Attempt access + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Test Failed, strict module m1, type p1.c1, should not be able " + + "to access public type p2.c2 defined in unnamed module"); + } catch (IllegalAccessError e) { + } + } + + // Module m1 is a strict module and has established + // readability to an unnamed module that p2.c2 is defined in. + public void test_strictModuleUnnamedReadableLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MySameClassLoader loader = new MySameClassLoader(); + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader. + Map map = new HashMap<>(); + map.put("m1", loader); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1ReadEdge + Class p1_c1_class = loader.loadClass("p1.c1ReadEdge"); + + try { + // Read edge between m1 and the unnamed module that loads p2.c2 is established in + // c1ReadEdge's ctor before attempting access. + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, strict module m1, type p1.c1ReadEdge, should be able to acccess public type " + + "p2.c2 defined in unnamed module: " + e.getMessage()); + } +} + + // Module m1 is a loose module and thus can read all unnamed modules. + public void test_looseModuleLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p1 + // Packages exported: p1 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MySameClassLoader loader = new MySameClassLoader(); + // map module m1 to class loader. + // class c2 will be loaded in an unnamed module/loader. + Map map = new HashMap<>(); + map.put("m1", loader); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1Loose + Class p1_c1_class = loader.loadClass("p1.c1Loose"); + + // change m1 to be a loose module + Module m1 = layer.findModule("m1").get(); + jdk.internal.module.Modules.addReads(m1, null); + + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, strict module m1, type p1.c1Loose, should be able to acccess public type " + + "p2.c2 defined in unnamed module: " + e.getMessage()); + } + } + + public static void main(String args[]) throws Throwable { + Umod test = new Umod(); + test.test_strictModuleLayer(); // access denied + test.test_strictModuleUnnamedReadableLayer(); // access allowed + test.test_looseModuleLayer(); // access allowed + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpQualOther.java b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpQualOther.java new file mode 100644 index 00000000000..34ea50f6c1e --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpQualOther.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2. + * Access is denied, since an unnamed module can read all modules but p2 in module + * m2 is exported specifically to module m1, not to all modules. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build UmodDiffCL_ExpQualOther + * @run main/othervm -Xbootclasspath/a:. UmodDiffCL_ExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// ClassLoader2 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is not exported +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2 +// Access denied, an unnamed module can read all modules but p2 in module +// m2 is exported specifically to module m1 not to all modules. +// +public class UmodDiffCL_ExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + // NOTE: module m1 does not define a package named p1. + // p1 will be loaded in an unnamed module. + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m1, not unqualifiedly"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + UmodDiffCL_ExpQualOther test = new UmodDiffCL_ExpQualOther(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpUnqual.java b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpUnqual.java new file mode 100644 index 00000000000..52d253b352c --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_ExpUnqual.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2. + * Access allowed, an unnamed module can read all modules and p2 in module m2 + * which is exported unqualifiedly. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build UmodDiffCL_ExpUnqual + * @run main/othervm -Xbootclasspath/a:. UmodDiffCL_ExpUnqual + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// ClassLoader2 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported unqualifiedly. +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2 +// Access allowed, an unnamed module can read all modules and p2 in module +// m2 which is exported unqualifiedly. +// +public class UmodDiffCL_ExpUnqual { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // NOTE: module m1 does not define a package named p1. + // p1 will be loaded in an unnamed module. + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, p1.c1 defined in unnamed module can access p2.c2 in module m2"); + } + } + + public static void main(String args[]) throws Throwable { + UmodDiffCL_ExpUnqual test = new UmodDiffCL_ExpUnqual(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_PkgNotExp.java b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_PkgNotExp.java new file mode 100644 index 00000000000..ebe3e5d004e --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_PkgNotExp.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in unnamed module tries to access p2.c2 defined in m2. + * Access is denied since even though unnamed module can read all modules, p2 + * in module m2 is not exported at all. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p1/c1.java + * @build UmodDiffCL_PkgNotExp + * @run main/othervm -Xbootclasspath/a:. UmodDiffCL_PkgNotExp + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// ClassLoader2 --> defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is not exported +// +// class p1.c1 defined in unnamed module tries to access p2.c2 defined in m2 +// Access denied since even though unnamed module can read all modules, p2 +// in module m2 is not exported at all. +// +public class UmodDiffCL_PkgNotExp { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .conceals("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + // NOTE: module m1 does not define a package named p1. + // p1 will be loaded in an unnamed module. + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is not exported to an unnamed module)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + UmodDiffCL_PkgNotExp test = new UmodDiffCL_PkgNotExp(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_Umod.java b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_Umod.java new file mode 100644 index 00000000000..6fd267961b1 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_Umod.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p1.c1 defined in an unnamed module tries to access p2.c2 + * defined in an unnamed module. Access allowed since unnamed module + * can read unnamed module even when class p1.c1 is loaded by + * a different loader than p2.c2. + * @compile myloaders/MyDiffClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build UmodDiffCL_Umod + * @run main/othervm -Xbootclasspath/a:. UmodDiffCL_Umod + */ + +import myloaders.MyDiffClassLoader; + +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in +// in an unnamed module. +// Access allowed since unnamed module can read unnamed module even when +// class p1.c1 is loaded by a different loader than p2.c2 +// and all packages in an unnamed module are exported unqualifiedly. +public class UmodDiffCL_Umod { + + public static void main(String args[]) throws Throwable { + Class p1_c1_class = MyDiffClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, unnamed module can access unnamed module"); + } + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_UmodUpkg.java b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_UmodUpkg.java new file mode 100644 index 00000000000..909ab0ffb29 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodDiffCL_UmodUpkg.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p3.c3 defined in a named package in an unnamed module tries to access c4 + * defined in an unnamed package in an unnamed module. Access allowed since + * any class in an unnamed module can read an unnamed module. + * @compile myloaders/MyDiffClassLoader.java + * @compile c4.java + * @compile p3/c3.jcod + * @build UmodDiffCL_UmodUpkg + * @run main/othervm -Xbootclasspath/a:. UmodDiffCL_UmodUpkg + */ + +import myloaders.MyDiffClassLoader; + +public class UmodDiffCL_UmodUpkg { + + public void testAccess() throws Throwable { + + Class p3_c3_class = MyDiffClassLoader.loader1.loadClass("p3.c3"); + try { + p3_c3_class.newInstance(); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + throw new RuntimeException("Test Failed, public type c3 defined in an unnamed module " + + "should be able to access public type c4 defined in an unnamed module"); + } + } + + public static void main(String args[]) throws Throwable { + UmodDiffCL_UmodUpkg test = new UmodDiffCL_UmodUpkg(); + test.testAccess(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUPkg.java b/hotspot/test/runtime/modules/AccessCheck/UmodUPkg.java new file mode 100644 index 00000000000..97f781c8c7a --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUPkg.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p3.c3 defined in module m1 tries to access c4 defined in unnamed module. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile c4.java + * @compile p3/c3.jcod + * @compile p3/c3ReadEdge.jcod + * @build UmodUPkg + * @run main/othervm -Xbootclasspath/a:. UmodUPkg + */ + +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; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> packages p3 +// package p3 in m1 is exported unqualifiedly +// +// class p3.c3 defined in m1 tries to access c4 defined in +// in unnamed module. +// +// Two access attempts occur in this test: +// 1. The first access is not allowed because a strict module +// cannot read an unnamed module. +// 2. In this scenario a strict module establishes readability +// to the particular unnamed module it is trying to access. +// Access is allowed. +// +public class UmodUPkg { + + // Create Layers over the boot layer to test different + // accessing scenarios of a named module to an unnamed module. + + // Module m1 is a strict module and has not established + // readability to an unnamed module that c4 is defined in. + public void test_strictModuleLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p3 + // Packages exported: p3 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map module m1 to class loader. + // class c4 will be loaded in an unnamed module/loader. + MySameClassLoader loader = new MySameClassLoader(); + Map map = new HashMap<>(); + map.put("m1", loader); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p3.c3 + Class p3_c3_class = loader.loadClass("p3.c3"); + + // Attempt access + try { + p3_c3_class.newInstance(); + throw new RuntimeException("Test Failed, strict module m1, type p3.c3, should not be able to access " + + "public type c4 defined in unnamed module"); + } catch (IllegalAccessError e) { + } + } + + // Module m1 is a strict module and has established + // readability to an unnamed module that c4 is defined in. + public void test_strictModuleUnnamedReadableLayer() throws Throwable { + + // Define module: m1 + // Can read: java.base + // Packages: p3 + // Packages exported: p3 is exported unqualifiedly + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("p3") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + MySameClassLoader loader = new MySameClassLoader(); + // map module m1 to class loader. + // class c4 will be loaded in an unnamed module/loader. + Map map = new HashMap<>(); + map.put("m1", loader); + + // Create Layer that contains m1 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p3.c3ReadEdge + Class p3_c3_class = loader.loadClass("p3.c3ReadEdge"); + + try { + // Read edge between m1 and the unnamed module that loads c4 is established in + // c3ReadEdge's ctor before attempting access. + p3_c3_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, module m1, type p3.c3ReadEdge, has established readability to " + + "c4 loader's unnamed module, access should be allowed: " + e.getMessage()); + } + } + + public static void main(String args[]) throws Throwable { + UmodUPkg test = new UmodUPkg(); + test.test_strictModuleLayer(); // access denied + test.test_strictModuleUnnamedReadableLayer(); // access allowed + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_ExpQualOther.java b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_ExpQualOther.java new file mode 100644 index 00000000000..299a41f4003 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_ExpQualOther.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class c5 defined in an unnamed module tries to access p6.c6 defined in m2. + * Access is denied, since an unnamed module can read all modules but p6 in module + * m2 is exported specifically to module m1, not to all modules. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p6/c6.java + * @compile c5.java + * @build UmodUpkgDiffCL_ExpQualOther + * @run main/othervm -Xbootclasspath/a:. UmodUpkgDiffCL_ExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// ClassLoader2 --> defines m2 --> packages p6 +// +// m1 can read m2 +// package p6 in m2 is not exported +// +// class c5 defined in an unnamed module tries to access p6.c6 defined in m2 +// Access denied, an unnamed module can read all modules but p6 in module +// m2 is exported specifically to module m1 not to all modules. +// +public class UmodUpkgDiffCL_ExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p6 + // Packages exported: p6 exported to m1 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p6", "m1") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class c5 + Class c5_class = MyDiffClassLoader.loader1.loadClass("c5"); + try { + c5_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p6 in m2 is exported to m1, not unqualifiedly"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + UmodUpkgDiffCL_ExpQualOther test = new UmodUpkgDiffCL_ExpQualOther(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_NotExp.java b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_NotExp.java new file mode 100644 index 00000000000..9210c295ac7 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_NotExp.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class c5 in an unnamed module can read module m2, but package p6 in module m2 is not exported. + * Access denied since even though unnamed module can read all modules, p6 in module m2 is not exported at all. + * @library /testlibrary /test/lib + * @compile myloaders/MyDiffClassLoader.java + * @compile p6/c6.java + * @compile c5.java + * @build UmodUpkgDiffCL_NotExp + * @run main/othervm -Xbootclasspath/a:. UmodUpkgDiffCL_NotExp + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MyDiffClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// ClassLoader2 --> defines m2 --> packages p6 +// +// m1 can read m2 +// package p6 in m2 is not exported +// +// class c5 defined in unnamed module tries to access p6.c6 defined in m2 +// Access denied since even though unnamed module can read all modules, p6 +// in module m2 is not exported at all. +// +public class UmodUpkgDiffCL_NotExp { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p6 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .conceals("p6") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MyDiffClassLoader.loader1); + map.put("m2", MyDiffClassLoader.loader2); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MyDiffClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MyDiffClassLoader.loader2); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class c5 + // NOTE: module m1 does not define any packages. + // c5 will be loaded in an unnamed module. + Class c5_class = MyDiffClassLoader.loader1.loadClass("c5"); + try { + c5_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p6 in m2 is not exported to " + + "an unnamed module that c5 is defined within)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + UmodUpkgDiffCL_NotExp test = new UmodUpkgDiffCL_NotExp(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_Umod.java b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_Umod.java new file mode 100644 index 00000000000..597389546d8 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkgDiffCL_Umod.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test public type c5 defined in an unnamed package and unnamed module can + * access public type p6.c6 defined in an unnamed module. + * @compile myloaders/MyDiffClassLoader.java + * @compile p6/c6.java + * @compile c5.java + * @build UmodUpkgDiffCL_Umod + * @run main/othervm -Xbootclasspath/a:. UmodUpkgDiffCL_Umod + */ + +import myloaders.MyDiffClassLoader; + +public class UmodUpkgDiffCL_Umod { + + public void testAccess() throws Throwable { + + Class c5_class = MyDiffClassLoader.loader1.loadClass("c5"); + try { + c5_class.newInstance(); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + throw new RuntimeException("Test Failed, public type c5 defined in an unnamed package and unnamed " + + "module should be able to access public type p6.c6 defined in an unnamed module"); + } + } + + public static void main(String args[]) throws Throwable { + UmodUpkgDiffCL_Umod test = new UmodUpkgDiffCL_Umod(); + test.testAccess(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_ExpQualOther.java b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_ExpQualOther.java new file mode 100644 index 00000000000..1084294a1e5 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_ExpQualOther.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if class c5 in an unnamed module can read package p6 in module m2, but package p6 in module m2 is + * exported qualifiedly to module m3, then class c5 in an unnamed module can not read p6.c6 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p6/c6.java + * @compile c5.java + * @build UmodUpkg_ExpQualOther + * @run main/othervm -Xbootclasspath/a:. UmodUpkg_ExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p6 +// defines m3 --> packages p3 +// +// m1 can read m2 +// package p6 in m2 is exported to m3 +// +// class c5 defined in m1 tries to access p6.c6 defined in m2 +// Access denied since although m1 can read m2, p6 is exported only to m3. +// +public class UmodUpkg_ExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 (need to define m1 to establish the Layer successfully) + // Can read: java.base, m2, m3 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .requires("m3") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p6 + // Packages exported: p6 is exported to m3 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p6", "m3") + .build(); + + // Define module: m3 + // Can read: java.base + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + map.put("m3", MySameClassLoader.loader1); + + // Create Layer that contains m1, m2 and m3 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m3") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class c5 + Class c5_class = MySameClassLoader.loader1.loadClass("c5"); + try { + c5_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p6 in m2 is exported to m3, not unqualifiedly to everyone)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + UmodUpkg_ExpQualOther test = new UmodUpkg_ExpQualOther(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_NotExp.java b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_NotExp.java new file mode 100644 index 00000000000..8ee6e92921c --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_NotExp.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test if package p6 in module m2 is not exported, then class c5 + * in an unnamed module can not access p6.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p6/c6.java + * @compile c5.java + * @build UmodUpkg_NotExp + * @run main/othervm -Xbootclasspath/a:. UmodUpkg_NotExp + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p6 +// +// m1 can read m2 +// package p6 in m2 is not exported +// +// class c5 defined in an unnamed module tries to access p6.c2 defined in m2 +// Access denied since p6 is not exported. +// +public class UmodUpkg_NotExp { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p6 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .conceals("p6") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to the same class loader for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 and m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class c5 + Class c5_class = MySameClassLoader.loader1.loadClass("c5"); + try { + c5_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p6 in m2 is not exported)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + UmodUpkg_NotExp test = new UmodUpkg_NotExp(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_Umod.java b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_Umod.java new file mode 100644 index 00000000000..7a96e5c2afb --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/UmodUpkg_Umod.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test public type c5 defined in an unnamed package and unnamed module can + * access public type p6.c6 defined in an unnamed module. + * @compile myloaders/MySameClassLoader.java + * @compile p6/c6.java + * @compile c5.java + * @build UmodUpkg_Umod + * @run main/othervm -Xbootclasspath/a:. UmodUpkg_Umod + */ + +import myloaders.MySameClassLoader; + +public class UmodUpkg_Umod { + + public void testAccess() throws Throwable { + + Class c5_class = MySameClassLoader.loader1.loadClass("c5"); + try { + c5_class.newInstance(); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + throw new RuntimeException("Test Failed, public type c5 defined in an unnamed package and unnamed " + + "module should be able to access public type c6 defined in an unnamed module"); + } + } + + public static void main(String args[]) throws Throwable { + UmodUpkg_Umod test = new UmodUpkg_Umod(); + test.testAccess(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/Umod_ExpQualOther.java b/hotspot/test/runtime/modules/AccessCheck/Umod_ExpQualOther.java new file mode 100644 index 00000000000..fe2fb7bb076 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/Umod_ExpQualOther.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test that if package p2 in module m2 is exported to module m3, + * then class p1.c1 in an unnamed module can not read p2.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build Umod_ExpQualOther + * @run main/othervm -Xbootclasspath/a:. Umod_ExpQualOther + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p2 +// defines m3 --> packages p3 +// +// m1 can read m2 +// package p2 in m2 is exported to m3 +// +// class p1.c1 defined in m1 tries to access p2.c2 defined in m2 +// Access denied since although m1 can read m2, p2 is exported only to m3. +// +public class Umod_ExpQualOther { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 (need to define m1 to establish the Layer successfully) + // Can read: java.base, m2, m3 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .requires("m3") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported to m3 + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2", "m3") + .build(); + + // Define module: m3 + // Can read: java.base + // Packages: p3 + // Packages exported: none + ModuleDescriptor descriptor_m3 = + new ModuleDescriptor.Builder("m3") + .requires("java.base") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2, descriptor_m3); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + map.put("m3", MySameClassLoader.loader1); + + // Create Layer that contains m1, m2 and m3 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m3") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is exported to m3, not unqualifiedly to everyone)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + Umod_ExpQualOther test = new Umod_ExpQualOther(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/Umod_ExpUnqual.java b/hotspot/test/runtime/modules/AccessCheck/Umod_ExpUnqual.java new file mode 100644 index 00000000000..445713c8352 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/Umod_ExpUnqual.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test if package p2 in module m2 is exported unqualifiedly, + * then class p1.c1 in an unnamed module can read p2.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build Umod_ExpUnqual + * @run main/othervm -Xbootclasspath/a:. Umod_ExpUnqual + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is exported unqualifiedly +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2 +// Access allowed, an unnamed module can read all modules and p2 in module +// m2 which is exported unqualifiedly. + +public class Umod_ExpUnqual { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: p2 is exported unqualifiedly + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .exports("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to differing class loaders for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 & m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed, an unnamed module can access public type " + + "p2.c2 since it is exported unqualifiedly"); + } + } + + public static void main(String args[]) throws Throwable { + Umod_ExpUnqual test = new Umod_ExpUnqual(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/Umod_PkgNotExp.java b/hotspot/test/runtime/modules/AccessCheck/Umod_PkgNotExp.java new file mode 100644 index 00000000000..7a346cfda1b --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/Umod_PkgNotExp.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test if package p2 in module m2 is not exported, then class p1.c1 + * in an unnamed module can not access p2.c2 in module m2. + * @library /testlibrary /test/lib + * @compile myloaders/MySameClassLoader.java + * @compile p2/c2.java + * @compile p1/c1.java + * @build Umod_PkgNotExp + * @run main/othervm -Xbootclasspath/a:. Umod_PkgNotExp + */ + +import static jdk.test.lib.Asserts.*; + +import java.lang.reflect.Layer; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import myloaders.MySameClassLoader; + +// ClassLoader1 --> defines m1 --> no packages +// defines m2 --> packages p2 +// +// m1 can read m2 +// package p2 in m2 is not exported +// +// class p1.c1 defined in an unnamed module tries to access p2.c2 defined in m2 +// Access denied since p2 is not exported. +// +public class Umod_PkgNotExp { + + // Create a Layer over the boot layer. + // Define modules within this layer to test access between + // publically defined classes within packages of those modules. + public void createLayerOnBoot() throws Throwable { + + // Define module: m1 + // Can read: java.base, m2 + // Packages: none + // Packages exported: none + ModuleDescriptor descriptor_m1 = + new ModuleDescriptor.Builder("m1") + .requires("java.base") + .requires("m2") + .build(); + + // Define module: m2 + // Can read: java.base + // Packages: p2 + // Packages exported: none + ModuleDescriptor descriptor_m2 = + new ModuleDescriptor.Builder("m2") + .requires("java.base") + .conceals("p2") + .build(); + + // Set up a ModuleFinder containing all modules for this layer. + ModuleFinder finder = ModuleLibrary.of(descriptor_m1, descriptor_m2); + + // Resolves "m1" + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, ModuleFinder.empty(), Set.of("m1")); + + // map each module to the same class loader for this test + Map map = new HashMap<>(); + map.put("m1", MySameClassLoader.loader1); + map.put("m2", MySameClassLoader.loader1); + + // Create Layer that contains m1 and m2 + Layer layer = Layer.boot().defineModules(cf, map::get); + + assertTrue(layer.findLoader("m1") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("m2") == MySameClassLoader.loader1); + assertTrue(layer.findLoader("java.base") == null); + + // now use the same loader to load class p1.c1 + Class p1_c1_class = MySameClassLoader.loader1.loadClass("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is not exported)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } + + public static void main(String args[]) throws Throwable { + Umod_PkgNotExp test = new Umod_PkgNotExp(); + test.createLayerOnBoot(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/Umod_UmodUpkg.java b/hotspot/test/runtime/modules/AccessCheck/Umod_UmodUpkg.java new file mode 100644 index 00000000000..23abc1e5a35 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/Umod_UmodUpkg.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary class p3.c3 defined in an unnamed module tries to access c4 defined in an unnamed package + * and an unnamed module. + * Access allowed since any class in an unnamed module can read an unnamed module. + * @compile myloaders/MySameClassLoader.java + * @compile c4.java + * @compile p3/c3.jcod + * @build Umod_UmodUpkg + * @run main/othervm -Xbootclasspath/a:. Umod_UmodUpkg + */ + +import myloaders.MySameClassLoader; + +public class Umod_UmodUpkg { + + public void testAccess() throws Throwable { + + Class p3_c3_class = MySameClassLoader.loader1.loadClass("p3.c3"); + try { + p3_c3_class.newInstance(); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + throw new RuntimeException("Test Failed, public type c3 defined in an unnamed module should be able " + + "to access public type c4 defined in an unnamed module"); + } + } + + public static void main(String args[]) throws Throwable { + Umod_UmodUpkg test = new Umod_UmodUpkg(); + test.testAccess(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/c4.java b/hotspot/test/runtime/modules/AccessCheck/c4.java new file mode 100644 index 00000000000..f2840b6e529 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/c4.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck* tests. + +public class c4 { + public void method4() { } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/c5.java b/hotspot/test/runtime/modules/AccessCheck/c5.java new file mode 100644 index 00000000000..1a3c25a1249 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/c5.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests. +import p6.c6; + +public class c5 { + + public c5 () { + p6.c6 c6_obj = new p6.c6(); + c6_obj.method6(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/myloaders/MyDiffClassLoader.java b/hotspot/test/runtime/modules/AccessCheck/myloaders/MyDiffClassLoader.java new file mode 100644 index 00000000000..63627590ebc --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/myloaders/MyDiffClassLoader.java @@ -0,0 +1,72 @@ +/* + * 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 myloaders; + +import java.io.*; +import java.lang.module.ModuleReference; + +// Declare a MyDiffClassLoader class to be used to map modules to. +// This class loader will also be used to load classes within modules. +public class MyDiffClassLoader extends ClassLoader +{ + public static MyDiffClassLoader loader1 = new MyDiffClassLoader(); + public static MyDiffClassLoader loader2 = new MyDiffClassLoader(); + + public Class loadClass(String name) throws ClassNotFoundException { + if (!name.equals("p1.c1") && + !name.equals("p1.c1ReadEdgeDiffLoader") && + !name.equals("p1.c1Loose") && + !name.equals("p2.c2") && + !name.equals("p3.c3") && + !name.equals("p3.c3ReadEdgeDiffLoader") && + !name.equals("c4") && + !name.equals("c5") && + !name.equals("p6.c6")) { + return super.loadClass(name); + } + if ((name.equals("p2.c2") || name.equals("c4") || name.equals("p6.c6")) && + (this == MyDiffClassLoader.loader1)) { + return MyDiffClassLoader.loader2.loadClass(name); + } + + byte[] data = getClassData(name); + return defineClass(name, data, 0, data.length); + } + byte[] getClassData(String name) { + try { + String TempName = name.replaceAll("\\.", "/"); + String currentDir = System.getProperty("test.classes"); + String filename = currentDir + File.separator + TempName + ".class"; + FileInputStream fis = new FileInputStream(filename); + byte[] b = new byte[5000]; + int cnt = fis.read(b, 0, 5000); + byte[] c = new byte[cnt]; + for (int i=0; i System ClassLoader's unnamed module + Module m1 = c1ReadEdgeDiffLoader.class.getModule(); + ClassLoader system_loader = ClassLoader.getSystemClassLoader(); + Module unnamed_module1 = system_loader.getUnnamedModule(); + m1.addReads(unnamed_module1); + + // Step #2: read edge m1 -> MyDiffClassLoader.loader2's unnamed module + ClassLoader loader2 = MyDiffClassLoader.loader2; + Module unnamed_module2 = loader2.getUnnamedModule(); + m1.addReads(unnamed_module2); + + // Attempt access - access should succeed since m1 can read + // MyDiffClassLoader.loader2's unnamed module + p2.c2 c2_obj = new p2.c2(); + c2_obj.method2(); + } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/p2/c2.java b/hotspot/test/runtime/modules/AccessCheck/p2/c2.java new file mode 100644 index 00000000000..3d21e327553 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p2/c2.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests. + +package p2; + +public class c2 { + public void method2() { } +} diff --git a/hotspot/test/runtime/modules/AccessCheck/p3/c3.jcod b/hotspot/test/runtime/modules/AccessCheck/p3/c3.jcod new file mode 100644 index 00000000000..10c97a71445 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p3/c3.jcod @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/* Small class used by multiple hotspot/runtime/modules/AccessCheck* tests. + * package p3; + * + * public class c3 { + * + * public c3 () { + * c4 c4_obj = new c4(); + * c4_obj.method4(); + * } + * } + */ + +class p3/c3 { + 0xCAFEBABE; + 0; // minor version + 52; // version + [19] { // Constant Pool + ; // first element is empty + Method #6 #13; // #1 at 0x0A + class #14; // #2 at 0x0F + Method #2 #13; // #3 at 0x12 + Method #2 #15; // #4 at 0x17 + class #16; // #5 at 0x1C + class #17; // #6 at 0x1F + Utf8 ""; // #7 at 0x22 + Utf8 "()V"; // #8 at 0x2B + Utf8 "Code"; // #9 at 0x31 + Utf8 "LineNumberTable"; // #10 at 0x38 + Utf8 "SourceFile"; // #11 at 0x4A + Utf8 "c3.java"; // #12 at 0x57 + NameAndType #7 #8; // #13 at 0x61 + Utf8 "c4"; // #14 at 0x66 + NameAndType #18 #8; // #15 at 0x6E + Utf8 "p3/c3"; // #16 at 0x73 + Utf8 "java/lang/Object"; // #17 at 0x7B + Utf8 "method4"; // #18 at 0x8E + } // Constant Pool + + 0x0021; // access + #5;// this_cpx + #6;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [1] { // methods + { // Member at 0xA4 + 0x0001; // access + #7; // name_cpx + #8; // sig_cpx + [1] { // Attributes + Attr(#9, 53) { // Code at 0xAC + 2; // max_stack + 2; // max_locals + Bytes[17]{ + 0x2AB70001BB000259; + 0xB700034C2BB60004; + 0xB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 18) { // LineNumberTable at 0xCF + [4] { // LineNumberTable + 0 4; // at 0xDB + 4 5; // at 0xDF + 12 6; // at 0xE3 + 16 7; // at 0xE7 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#11, 2) { // SourceFile at 0xE9 + #12; + } // end SourceFile + } // Attributes +} // end class p3/c3 diff --git a/hotspot/test/runtime/modules/AccessCheck/p3/c3ReadEdge.jcod b/hotspot/test/runtime/modules/AccessCheck/p3/c3ReadEdge.jcod new file mode 100644 index 00000000000..50df6180233 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p3/c3ReadEdge.jcod @@ -0,0 +1,142 @@ +/* + * 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 p3; + * import java.lang.reflect.*; + * public class c3ReadEdge { + * public c3ReadEdge() { + * // Establish read edge from module m1, where c3ReadEdge is defined, + * // to the unnamed module, where c4 will be defined. + * Module m1 = c3ReadEdge.class.getModule(); + * ClassLoader loader = c3ReadEdge.class.getClassLoader(); + * Module unnamed_module = loader.getUnnamedModule(); + * m1.addReads(unnamed_module); + * // Attempt access - access should succeed + * c4 c4_obj = new c4(); + * c4_obj.method4(); + * } + * } + */ + +class p3/c3ReadEdge { + 0xCAFEBABE; + 0; // minor version + 52; // version + [40] { // Constant Pool + ; // first element is empty + Method #10 #17; // #1 at 0x0A + class #18; // #2 at 0x0F + Method #19 #20; // #3 at 0x12 + Method #19 #21; // #4 at 0x17 + Method #22 #23; // #5 at 0x1C + Method #24 #25; // #6 at 0x21 + class #26; // #7 at 0x26 + Method #7 #17; // #8 at 0x29 + Method #7 #27; // #9 at 0x2E + class #28; // #10 at 0x33 + Utf8 ""; // #11 at 0x36 + Utf8 "()V"; // #12 at 0x3F + Utf8 "Code"; // #13 at 0x45 + Utf8 "LineNumberTable"; // #14 at 0x4C + Utf8 "SourceFile"; // #15 at 0x5E + Utf8 "c3ReadEdge.java"; // #16 at 0x6B + NameAndType #11 #12; // #17 at 0x7D + Utf8 "p3/c3ReadEdge"; // #18 at 0x82 + class #29; // #19 at 0x92 + NameAndType #30 #31; // #20 at 0x95 + NameAndType #32 #33; // #21 at 0x9A + class #34; // #22 at 0x9F + NameAndType #35 #31; // #23 at 0xA2 + class #36; // #24 at 0xA7 + NameAndType #37 #38; // #25 at 0xAA + Utf8 "c4"; // #26 at 0xAF + NameAndType #39 #12; // #27 at 0xB7 + Utf8 "java/lang/Object"; // #28 at 0xBC + Utf8 "java/lang/Class"; // #29 at 0xCF + Utf8 "getModule"; // #30 at 0xE1 + Utf8 "()Ljava/lang/reflect/Module;"; // #31 at 0xED + Utf8 "getClassLoader"; // #32 at 0x010C + Utf8 "()Ljava/lang/ClassLoader;"; // #33 at 0x011D + Utf8 "java/lang/ClassLoader"; // #34 at 0x0139 + Utf8 "getUnnamedModule"; // #35 at 0x0151 + Utf8 "java/lang/reflect/Module"; // #36 at 0x0164 + Utf8 "addReads"; // #37 at 0x017F + Utf8 "(Ljava/lang/reflect/Module;)Ljava/lang/reflect/Module;"; // #38 at 0x018A + Utf8 "method4"; // #39 at 0x01C3 + } // Constant Pool + + 0x0021; // access + #2;// this_cpx + #10;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [1] { // methods + { // Member at 0x01D9 + 0x0001; // access + #11; // name_cpx + #12; // sig_cpx + [1] { // Attributes + Attr(#13, 94) { // Code at 0x01E1 + 2; // max_stack + 5; // max_locals + Bytes[42]{ + 0x2AB700011202B600; + 0x034C1202B600044D; + 0x2CB600054E2B2DB6; + 0x000657BB000759B7; + 0x00083A041904B600; + 0x09B1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#14, 34) { // LineNumberTable at 0x021D + [8] { // LineNumberTable + 0 32; // at 0x0229 + 4 38; // at 0x022D + 10 39; // at 0x0231 + 16 40; // at 0x0235 + 21 41; // at 0x0239 + 27 44; // at 0x023D + 36 45; // at 0x0241 + 41 46; // at 0x0245 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#15, 2) { // SourceFile at 0x0247 + #16; + } // end SourceFile + } // Attributes +} // end class p3/c3ReadEdge diff --git a/hotspot/test/runtime/modules/AccessCheck/p3/c3ReadEdgeDiffLoader.jcod b/hotspot/test/runtime/modules/AccessCheck/p3/c3ReadEdgeDiffLoader.jcod new file mode 100644 index 00000000000..103f7eea2c7 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p3/c3ReadEdgeDiffLoader.jcod @@ -0,0 +1,175 @@ +/* + * 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 p3; + * import java.lang.reflect.*; + * import myloaders.MyDiffClassLoader; + * + * public class c3ReadEdgeDiffLoader { + * public c3ReadEdgeDiffLoader() { + * // The goal is to establish a read edge between module m1 + * // which is the module where p3.c3ReadEdgeDiffLoader is defined, + * // and the unnamed module that defines c4. This must be + * // done in 2 steps: + * // + * // Step #1: Establish a read edge between m1, where c3ReadEdgeDiffLoader + * // is defined, and the System ClassLoader's unnamed module, + * // where MyDiffClassLoader is defined. This read edge + * // is needed before we can obtain MyDiffClassLoader.loader2's unnamed module. + * // + * // Step #2: Establish a read edge between m1, where c3ReadEdgeDiffLoader + * // is defined, and the MyDiffClassLoader.loader2's unnamed module, + * // where c4 will be defined. + * + * // Step #1: read edge m1 -> System ClassLoader's unnamed module + * Module m1 = c3ReadEdgeDiffLoader.class.getModule(); + * ClassLoader system_loader = ClassLoader.getSystemClassLoader(); + * Module unnamed_module1 = system_loader.getUnnamedModule(); + * m1.addReads(unnamed_module1); + * + * // Step #2: read edge m1 -> MyDiffClassLoader.loader2's unnamed module + * ClassLoader loader2 = MyDiffClassLoader.loader2; + * Module unnamed_module2 = loader2.getUnnamedModule(); + * m1.addReads(unnamed_module2); + * + * // Attempt access - should succeed since m1 can read + * // MyDiffClassLoader.loader2's unnamed module + * c4 c4_obj = new c4(); + * c4_obj.method4(); + * } + * } + */ + +class p3/c3ReadEdgeDiffLoader { + 0xCAFEBABE; + 0; // minor version + 52; // version + [46] { // Constant Pool + ; // first element is empty + Method #11 #18; // #1 at 0x0A + class #19; // #2 at 0x0F + Method #20 #21; // #3 at 0x12 + Method #22 #23; // #4 at 0x17 + Method #22 #24; // #5 at 0x1C + Method #25 #26; // #6 at 0x21 + Field #27 #28; // #7 at 0x26 + class #29; // #8 at 0x2B + Method #8 #18; // #9 at 0x2E + Method #8 #30; // #10 at 0x33 + class #31; // #11 at 0x38 + Utf8 ""; // #12 at 0x3B + Utf8 "()V"; // #13 at 0x44 + Utf8 "Code"; // #14 at 0x4A + Utf8 "LineNumberTable"; // #15 at 0x51 + Utf8 "SourceFile"; // #16 at 0x63 + Utf8 "c3ReadEdgeDiffLoader.java"; // #17 at 0x70 + NameAndType #12 #13; // #18 at 0x8C + Utf8 "p3/c3ReadEdgeDiffLoader"; // #19 at 0x91 + class #32; // #20 at 0xAB + NameAndType #33 #34; // #21 at 0xAE + class #35; // #22 at 0xB3 + NameAndType #36 #37; // #23 at 0xB6 + NameAndType #38 #34; // #24 at 0xBB + class #39; // #25 at 0xC0 + NameAndType #40 #41; // #26 at 0xC3 + class #42; // #27 at 0xC8 + NameAndType #43 #44; // #28 at 0xCB + Utf8 "c4"; // #29 at 0xD0 + NameAndType #45 #13; // #30 at 0xD8 + Utf8 "java/lang/Object"; // #31 at 0xDD + Utf8 "java/lang/Class"; // #32 at 0xF0 + Utf8 "getModule"; // #33 at 0x0102 + Utf8 "()Ljava/lang/reflect/Module;"; // #34 at 0x010E + Utf8 "java/lang/ClassLoader"; // #35 at 0x012D + Utf8 "getSystemClassLoader"; // #36 at 0x0145 + Utf8 "()Ljava/lang/ClassLoader;"; // #37 at 0x015C + Utf8 "getUnnamedModule"; // #38 at 0x0178 + Utf8 "java/lang/reflect/Module"; // #39 at 0x018B + Utf8 "addReads"; // #40 at 0x01A6 + Utf8 "(Ljava/lang/reflect/Module;)Ljava/lang/reflect/Module;"; // #41 at 0x01B1 + Utf8 "myloaders/MyDiffClassLoader"; // #42 at 0x01EA + Utf8 "loader2"; // #43 at 0x0208 + Utf8 "Lmyloaders/MyDiffClassLoader;"; // #44 at 0x0212 + Utf8 "method4"; // #45 at 0x0232 + } // Constant Pool + + 0x0021; // access + #2;// this_cpx + #11;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [1] { // methods + { // Member at 0x0248 + 0x0001; // access + #12; // name_cpx + #13; // sig_cpx + [1] { // Attributes + Attr(#14, 123) { // Code at 0x0250 + 2; // max_stack + 7; // max_locals + Bytes[59]{ + 0x2AB700011202B600; + 0x034CB800044D2CB6; + 0x00054E2B2DB60006; + 0x57B200073A041904; + 0xB600053A052B1905; + 0xB6000657BB000859; + 0xB700093A061906B6; + 0x000AB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#15, 46) { // LineNumberTable at 0x029D + [11] { // LineNumberTable + 0 33; // at 0x02A9 + 4 34; // at 0x02AD + 10 36; // at 0x02B1 + 14 37; // at 0x02B5 + 19 39; // at 0x02B9 + 25 41; // at 0x02BD + 30 42; // at 0x02C1 + 37 46; // at 0x02C5 + 44 49; // at 0x02C9 + 53 50; // at 0x02CD + 58 51; // at 0x02D1 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#16, 2) { // SourceFile at 0x02D3 + #17; + } // end SourceFile + } // Attributes +} // end class p3/c3ReadEdgeDiffLoader diff --git a/hotspot/test/runtime/modules/AccessCheck/p6/c6.java b/hotspot/test/runtime/modules/AccessCheck/p6/c6.java new file mode 100644 index 00000000000..37c11615750 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheck/p6/c6.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck/* tests. + +package p6; + +public class c6 { + public void method6() { } +} diff --git a/hotspot/test/runtime/modules/AccessCheckAllUnnamed.java b/hotspot/test/runtime/modules/AccessCheckAllUnnamed.java new file mode 100644 index 00000000000..a97f7ccf8d1 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckAllUnnamed.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +/* + * @test + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckAllUnnamed + */ + +public class AccessCheckAllUnnamed { + + // Test a series of error conditions for API JVM_AddModuleExportsToAllUnnamed + // and then test that a class in the unnamed module can access a package in a + // named module that has been exported to all unnamed modules. + public static void main(String args[]) throws Throwable { + Object m1, m2; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for AccessCheckWorks and assume it's also used to + // load class p2.c2. + ClassLoader this_cldr = AccessCheckAllUnnamed.class.getClassLoader(); + + // Define a module for p3. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p3" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/there", new String[] { "p3" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + try { + ModuleHelper.AddModuleExportsToAllUnnamed((Module)null, "p2"); + throw new RuntimeException("Failed to get the expected NPE for null module"); + } catch(NullPointerException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAllUnnamed(m2, null); + throw new RuntimeException("Failed to get the expected NPE for null package"); + } catch(NullPointerException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAllUnnamed(this_cldr, "p2"); + throw new RuntimeException("Failed to get the expected IAE for bad module"); + } catch(IllegalArgumentException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAllUnnamed(m2, "p3"); + throw new RuntimeException("Failed to get the expected IAE for package in other module"); + } catch(IllegalArgumentException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAllUnnamed(m2, "p4"); + throw new RuntimeException("Failed to get the expected IAE for package not in module"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export package p2 in m2 to allUnnamed. + ModuleHelper.AddModuleExportsToAllUnnamed(m2, "p2"); + + // p1.c1's ctor tries to call a method in p2.c2. This should succeed because + // p1 is in an unnamed module and p2.c2 is exported to all unnamed modules. + Class p1_c1_class = Class.forName("p1.c1"); + try { + Object c1_obj = p1_c1_class.newInstance(); + } catch (IllegalAccessError f) { + throw new RuntimeException( + "Class in unnamed module could not access package p2 exported to all unnamed modules"); + } + } +} + diff --git a/hotspot/test/runtime/modules/AccessCheckExp.java b/hotspot/test/runtime/modules/AccessCheckExp.java new file mode 100644 index 00000000000..304af7f9ee8 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckExp.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckExp + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class AccessCheckExp { + + // Test that if module1 can read module2, but package p2 in module2 is not + // exported then class p1.c1 in module1 can not read p2.c2 in module2. + public static void main(String args[]) throws Throwable { + Object m1, m2; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for AccessCheckExp and assume it's also used to + // load classes p1.c1 and p2.c2. + ClassLoader this_cldr = AccessCheckExp.class.getClassLoader(); + + // Define a module for p1. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p1" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/here", new String[] { "p1" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + // Make package p1 in m1 visible to everyone. + ModuleHelper.AddModuleExportsToAll(m1, "p1"); + + // p1.c1's ctor tries to call a method in p2.c2, but p2.c2 is not + // exported. So should get IllegalAccessError. + ModuleHelper.AddReadsModule(m1, m2); + + Class p1_c1_class = Class.forName("p1.c1"); + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is not exported"); + } catch (IllegalAccessError f) { + System.out.println(f.getMessage()); + if (!f.getMessage().contains("does not export")) { + throw new RuntimeException("Wrong message: " + f.getMessage()); + } + } + } +} + diff --git a/hotspot/test/runtime/modules/AccessCheckJavaBase.java b/hotspot/test/runtime/modules/AccessCheckJavaBase.java new file mode 100644 index 00000000000..764f9fb2be4 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckJavaBase.java @@ -0,0 +1,58 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckJavaBase + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class AccessCheckJavaBase { + + // Test that a class defined to module2 always can read java.base. + public static void main(String args[]) throws Throwable { + // Get the class loader for AccessCheckJavaBase and assume it's also used to + // load class p2.c2. + ClassLoader this_cldr = AccessCheckJavaBase.class.getClassLoader(); + + // Define a module for p2. + Object m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + + // p2.c2 can read its superclass java.lang.Object defined within java.base + try { + Class p2_c2_class = Class.forName("p2.c2"); + } catch (IllegalAccessError e) { + throw new RuntimeException("Test Failed" + e.getMessage()); + } + } +} diff --git a/hotspot/test/runtime/modules/AccessCheckRead.java b/hotspot/test/runtime/modules/AccessCheckRead.java new file mode 100644 index 00000000000..8158582e866 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckRead.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckRead + */ + +import jdk.test.lib.*; +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class AccessCheckRead { + + // Test that a class in a package in module1 cannot access a class in + // a package n module2 if module1 cannot read module2. + public static void main(String args[]) throws Throwable { + Object m1, m2; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for AccessCheckRead and assume it's also used to + // load classes p1.c1 and p2.c2. + ClassLoader this_cldr = AccessCheckRead.class.getClassLoader(); + + // Define a module for p1. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p1" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/here", new String[] { "p1" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + // Make package p1 in m1 visible to everyone. + ModuleHelper.AddModuleExportsToAll(m1, "p1"); + + Class p1_c1_class = Class.forName("p1.c1"); + + // p1.c1's ctor tries to call a method in p2.c2, but p1's module + // cannot read p2's module. So should get IllegalAccessError. + try { + p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (m1 can't read m2)"); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not read") || + e.getMessage().contains("strict")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } +} diff --git a/hotspot/test/runtime/modules/AccessCheckSuper.java b/hotspot/test/runtime/modules/AccessCheckSuper.java new file mode 100644 index 00000000000..bd2065b5ff0 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckSuper.java @@ -0,0 +1,71 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p3/c3.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckSuper + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class AccessCheckSuper { + + // Test that when a class cannot access its super class the message + // contains both "superclass" text and module text. + public static void main(String args[]) throws Throwable { + + // Get the class loader for AccessCheckSuper and assume it's also used to + // load class p2.c2 and class p3.c3. + ClassLoader this_cldr = AccessCheckSuper.class.getClassLoader(); + + // Define a module for p2. + Object m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + + // Define a module for p3. + Object m3 = ModuleHelper.ModuleObject("module3", this_cldr, new String[] { "p3" }); + assertNotNull(m3, "Module should not be null"); + ModuleHelper.DefineModule(m3, "9.0", "m3/there", new String[] { "p3" }); + + // Since a readability edge has not been established between module2 + // and module3, p3.c3 cannot read its superclass p2.c2. + try { + Class p3_c3_class = Class.forName("p3.c3"); + throw new RuntimeException("Failed to get IAE (can't read superclass)"); + } catch (IllegalAccessError e) { + if (!e.getMessage().contains("superclass access check failed") || + !e.getMessage().contains("does not read")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } +} diff --git a/hotspot/test/runtime/modules/AccessCheckUnnamed.java b/hotspot/test/runtime/modules/AccessCheckUnnamed.java new file mode 100644 index 00000000000..0451489be56 --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckUnnamed.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +/* + * @test + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckUnnamed + */ + +public class AccessCheckUnnamed { + + // Test that a class in the unnamed module can not access a package in a + // named module that has not been unqualifiedly exported. + public static void main(String args[]) throws Throwable { + Object m1, m2; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for AccessCheckWorks and assume it's also used to + // load class p2.c2. + ClassLoader this_cldr = AccessCheckUnnamed.class.getClassLoader(); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + // p1.c1's ctor tries to call a method in p2.c2. This should fail because + // p1 is in the unnamed module and p2.c2 is not unqualifiedly exported. + Class p1_c1_class = Class.forName("p1.c1"); + try { + Object c1_obj = p1_c1_class.newInstance(); + throw new RuntimeException("Failed to get IAE (p2 in m2 is not exported to unnamed module)"); + } catch (IllegalAccessError f) { + System.out.println(f.getMessage()); + if (!f.getMessage().contains("does not export p2 to unnamed module")) { + throw new RuntimeException("Wrong message: " + f.getMessage()); + } + } + } +} + diff --git a/hotspot/test/runtime/modules/AccessCheckWorks.java b/hotspot/test/runtime/modules/AccessCheckWorks.java new file mode 100644 index 00000000000..3a13b04a59b --- /dev/null +++ b/hotspot/test/runtime/modules/AccessCheckWorks.java @@ -0,0 +1,79 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AccessCheckWorks + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class AccessCheckWorks { + + // Check that a class in a package in module1 can successfully access a + // class in module2 when module1 can read module2 and the class's package + // has been exported. + public static void main(String args[]) throws Throwable { + Object m1, m2; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for AccessCheckWorks and assume it's also used to + // load classes p1.c1 and p2.c2. + ClassLoader this_cldr = AccessCheckWorks.class.getClassLoader(); + + // Define a module for p1. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p1" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/here", new String[] { "p1" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + // Make package p1 in m1 visible to everyone. + ModuleHelper.AddModuleExportsToAll(m1, "p1"); + + // p1.c1's ctor tries to call a method in p2.c2. This should work because + // p1's module can read p2's module and p2 is exported to p1's module. + ModuleHelper.AddReadsModule(m1, m2); + ModuleHelper.AddModuleExports(m2, "p2", m1); + Class p1_c1_class = Class.forName("p1.c1"); + p1_c1_class.newInstance(); + } +} + diff --git a/hotspot/test/runtime/modules/CCE_module_msg.java b/hotspot/test/runtime/modules/CCE_module_msg.java new file mode 100644 index 00000000000..54ece088b29 --- /dev/null +++ b/hotspot/test/runtime/modules/CCE_module_msg.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @run main/othervm CCE_module_msg + */ + +// Test that the message in a runtime ClassCastException contains module info. +public class CCE_module_msg { + + public static void main(String[] args) { + invalidCastTest(); + } + + public static void invalidCastTest() { + java.lang.Object instance = new java.lang.Object(); + int left = 23; + int right = 42; + try { + for (int i = 0; i < 1; i += 1) { + left = ((Derived) instance).method(left, right); + } + throw new RuntimeException("ClassCastException wasn't thrown, test failed."); + } catch (ClassCastException cce) { + System.out.println(cce.getMessage()); + if (!cce.getMessage().contains("java.lang.Object (in module: java.base) cannot be cast")) { + throw new RuntimeException("Wrong message: " + cce.getMessage()); + } + } + } +} + +class Derived extends java.lang.Object { + public int method(int left, int right) { + return right; + } +} diff --git a/hotspot/test/runtime/modules/ExportTwice.java b/hotspot/test/runtime/modules/ExportTwice.java new file mode 100644 index 00000000000..b33b55ef787 --- /dev/null +++ b/hotspot/test/runtime/modules/ExportTwice.java @@ -0,0 +1,92 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI ExportTwice + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class ExportTwice { + + // Check that a package can not be exported unqualifiedly, and then exported + // to a specific package. + // Also, check that a package can be exported to a specific package and then + // exported unqualifiedly. + public static void main(String args[]) throws Throwable { + Object m1, m2, m3; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for ExportTwice and assume it's also used to + // load classes p1.c1 and p2.c2. + ClassLoader this_cldr = ExportTwice.class.getClassLoader(); + + // Define a module for p1. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p1" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/here", new String[] { "p1" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + // Define a module for p3. + m3 = ModuleHelper.ModuleObject("module3", this_cldr, new String[] { "p3" }); + assertNotNull(m3, "Module should not be null"); + ModuleHelper.DefineModule(m3, "9.0", "m3/there", new String[] { "p3" }); + ModuleHelper.AddReadsModule(m3, jlObject_jlrM); + + // Make package p1 in m1 visible to everyone. + ModuleHelper.AddModuleExportsToAll(m1, "p1"); + + // Try to export p1 only to m2 after it was exported unqualifiedly. It + // should silently succeed. + ModuleHelper.AddModuleExports(m1, "p1", m2); + + // Export p2 to m3 then export it again unqualifiedly. + ModuleHelper.AddModuleExports(m2, "p2", m3); + ModuleHelper.AddModuleExportsToAll(m2, "p2"); + + // p1.c1's ctor tries to call a method in p2.c2. This should work because + // p1's module can read p2's module and p2 is now exported unqualifiedly. + ModuleHelper.AddReadsModule(m1, m2); + Class p1_c1_class = Class.forName("p1.c1"); + p1_c1_class.newInstance(); + } +} diff --git a/hotspot/test/runtime/modules/JVMAddModuleExportToAllUnnamed.java b/hotspot/test/runtime/modules/JVMAddModuleExportToAllUnnamed.java new file mode 100644 index 00000000000..b7b34b7411f --- /dev/null +++ b/hotspot/test/runtime/modules/JVMAddModuleExportToAllUnnamed.java @@ -0,0 +1,76 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMAddModuleExportToAllUnnamed + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class JVMAddModuleExportToAllUnnamed { + + // Check that a class in a package in module1 cannot access a class + // that is in the unnamed module if the accessing package is strict. + public static void main(String args[]) throws Throwable { + Object m1; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for JVMAddModuleExportToAllUnnamed and assume it's also used to + // load class p1.c1. + ClassLoader this_cldr = JVMAddModuleExportToAllUnnamed.class.getClassLoader(); + + // Define a module for p1. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p1" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/here", new String[] { "p1" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Make package p1 in m1 visible to everyone. + ModuleHelper.AddModuleExportsToAll(m1, "p1"); + + // p1.c1's ctor tries to call a method in p2.c2. This should not work + // because p2 is in the unnamed module and p1.c1 is strict. + try { + Class p1_c1_class = Class.forName("p1.c1"); + p1_c1_class.newInstance(); + } catch (IllegalAccessError e) { + System.out.println(e.getMessage()); + if (!e.getMessage().contains("does not read unnamed module")) { + throw new RuntimeException("Wrong message: " + e.getMessage()); + } + } + } +} diff --git a/hotspot/test/runtime/modules/JVMAddModuleExports.java b/hotspot/test/runtime/modules/JVMAddModuleExports.java new file mode 100644 index 00000000000..330dd923411 --- /dev/null +++ b/hotspot/test/runtime/modules/JVMAddModuleExports.java @@ -0,0 +1,145 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMAddModuleExports + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +public class JVMAddModuleExports { + + public static void main(String args[]) throws Throwable { + MyClassLoader from_cl = new MyClassLoader(); + MyClassLoader to_cl = new MyClassLoader(); + Module from_module, to_module; + + from_module = ModuleHelper.ModuleObject("from_module", from_cl, new String[] { "mypackage", "this/package" }); + assertNotNull(from_module, "Module should not be null"); + ModuleHelper.DefineModule(from_module, "9.0", "from_module/here", new String[] { "mypackage", "this/package" }); + to_module = ModuleHelper.ModuleObject("to_module", to_cl, new String[] { "yourpackage", "that/package" }); + assertNotNull(to_module, "Module should not be null"); + ModuleHelper.DefineModule(to_module, "9.0", "to_module/here", new String[] { "yourpackage", "that/package" }); + + // Null from_module argument, expect an NPE + try { + ModuleHelper.AddModuleExports((Module)null, "mypackage", to_module); + throw new RuntimeException("Failed to get the expected NPE for null from_module"); + } catch(NullPointerException e) { + // Expected + } + + // Null to_module argument, expect an NPE + try { + ModuleHelper.AddModuleExports(from_module, "mypackage", (Module)null); + throw new RuntimeException("Failed to get the expected NPE for null to_module"); + } catch(NullPointerException e) { + // Expected + } + + // Bad from_module argument, expect an IAE + try { + ModuleHelper.AddModuleExports(to_cl, "mypackage", to_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Null package argument, expect an NPE + try { + ModuleHelper.AddModuleExports(from_module, null, to_module); + throw new RuntimeException("Failed to get the expected NPE"); + } catch(NullPointerException e) { + // Expected + } + + // Bad to_module argument, expect an IAE + try { + ModuleHelper.AddModuleExports(from_module, "mypackage", from_cl); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Exporting a package to the same module + ModuleHelper.AddModuleExports(from_module, "mypackage", from_module); + + // Export a package that does not exist to to_module + try { + ModuleHelper.AddModuleExports(from_module, "notmypackage", to_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export a package, that is not in from_module, to to_module + try { + ModuleHelper.AddModuleExports(from_module, "yourpackage", to_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export a package, that does not exist, to from_module + try { + ModuleHelper.AddModuleExports(from_module, "notmypackage", from_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export a package, that is not in from_module, to from_module + try { + ModuleHelper.AddModuleExports(from_module, "that/package", from_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export the same package twice to the same module + ModuleHelper.AddModuleExports(from_module, "this/package", to_module); + ModuleHelper.AddModuleExports(from_module, "this/package", to_module); + + // Export a package, using '.' instead of '/' + try { + ModuleHelper.AddModuleExports(from_module, "this.package", to_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export a package to the unnamed module and then to a specific module. + // The qualified export should be ignored. + ModuleHelper.AddModuleExportsToAll(to_module, "that/package"); + ModuleHelper.AddModuleExports(to_module, "that/package", from_module); + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/JVMAddModuleExportsToAll.java b/hotspot/test/runtime/modules/JVMAddModuleExportsToAll.java new file mode 100644 index 00000000000..f41d401c10d --- /dev/null +++ b/hotspot/test/runtime/modules/JVMAddModuleExportsToAll.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.reflect.Module; +import static jdk.test.lib.Asserts.*; + +/* + * @test + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @compile p1/c1.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMAddModuleExportsToAll + */ + +public class JVMAddModuleExportsToAll { + + // Test a series of error conditions for API JVM_AddModuleExportsToAll() + // and then test that a class in the unnamed module can access a package in + // a named module that has been exported unqualifiedly. + public static void main(String args[]) throws Throwable { + Object m1, m2, m3; + + // Get the java.lang.reflect.Module object for module java.base. + Class jlObject = Class.forName("java.lang.Object"); + Object jlObject_jlrM = jlObject.getModule(); + assertNotNull(jlObject_jlrM, "jlrModule object of java.lang.Object should not be null"); + + // Get the class loader for JVMAddModuleExportsToAll and assume it's also used to + // load class p2.c2. + ClassLoader this_cldr = JVMAddModuleExportsToAll.class.getClassLoader(); + + // Define a module for p3. + m1 = ModuleHelper.ModuleObject("module1", this_cldr, new String[] { "p3" }); + assertNotNull(m1, "Module should not be null"); + ModuleHelper.DefineModule(m1, "9.0", "m1/there", new String[] { "p3" }); + ModuleHelper.AddReadsModule(m1, jlObject_jlrM); + + // Define a module for p2. + m2 = ModuleHelper.ModuleObject("module2", this_cldr, new String[] { "p2" }); + assertNotNull(m2, "Module should not be null"); + ModuleHelper.DefineModule(m2, "9.0", "m2/there", new String[] { "p2" }); + ModuleHelper.AddReadsModule(m2, jlObject_jlrM); + + try { + ModuleHelper.AddModuleExportsToAll((Module)null, "p2"); + throw new RuntimeException("Failed to get the expected NPE for null module"); + } catch(NullPointerException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAll(m2, null); + throw new RuntimeException("Failed to get the expected NPE for null package"); + } catch(NullPointerException e) { + // Expected + } + + try { // Expect IAE when passing a ClassLoader object instead of a java.lang.reflect.Module object. + ModuleHelper.AddModuleExportsToAll(this_cldr, "p2"); + throw new RuntimeException("Failed to get the expected IAE for bad module"); + } catch(IllegalArgumentException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAll(m2, "p3"); + throw new RuntimeException("Failed to get the expected IAE for package that is in another module"); + } catch(IllegalArgumentException e) { + // Expected + } + + try { + ModuleHelper.AddModuleExportsToAll(m2, "p4"); + throw new RuntimeException("Failed to get the expected IAE for package not in any module"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Export package p2 in m2 unqualifiedly. Then, do a qualified export + // of p2 in m2 to m3. This should not affect the unqualified export. + m3 = ModuleHelper.ModuleObject("module3", this_cldr, new String[] { "p4" }); + assertNotNull(m3, "Module m3 should not be null"); + ModuleHelper.DefineModule(m3, "9.0", "m3/there", new String[] { "p4" }); + ModuleHelper.AddModuleExportsToAll(m2, "p2"); + ModuleHelper.AddModuleExports(m2, "p2", m3); + + // p1.c1's ctor tries to call a method in p2.c2. This should succeed because + // p1 is in an unnamed module and p2.c2 is exported unqualifiedly. + Class p1_c1_class = Class.forName("p1.c1"); + try { + Object c1_obj = p1_c1_class.newInstance(); + } catch (IllegalAccessError f) { + throw new RuntimeException( + "Class in unnamed module could not access package p2 exported unqualifieldly"); + } + } +} + diff --git a/hotspot/test/runtime/modules/JVMAddModulePackage.java b/hotspot/test/runtime/modules/JVMAddModulePackage.java new file mode 100644 index 00000000000..430c67ca6fd --- /dev/null +++ b/hotspot/test/runtime/modules/JVMAddModulePackage.java @@ -0,0 +1,129 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMAddModulePackage + */ + +import static jdk.test.lib.Asserts.*; + +public class JVMAddModulePackage { + + public static void main(String args[]) throws Throwable { + MyClassLoader cl1 = new MyClassLoader(); + MyClassLoader cl3 = new MyClassLoader(); + Object module1, module2, module3; + boolean result; + + module1 = ModuleHelper.ModuleObject("module1", cl1, new String[] { "mypackage" }); + assertNotNull(module1, "Module should not be null"); + ModuleHelper.DefineModule(module1, "9.0", "module1/here", new String[] { "mypackage" }); + module2 = ModuleHelper.ModuleObject("module2", cl1, new String[] { "yourpackage" }); + assertNotNull(module2, "Module should not be null"); + ModuleHelper.DefineModule(module2, "9.0", "module2/here", new String[] { "yourpackage" }); + module3 = ModuleHelper.ModuleObject("module3", cl3, new String[] { "package/num3" }); + assertNotNull(module3, "Module should not be null"); + ModuleHelper.DefineModule(module3, "9.0", "module3/here", new String[] { "package/num3" }); + + // Simple call + ModuleHelper.AddModulePackage(module1, "new_package"); + + // Add a package and export it + ModuleHelper.AddModulePackage(module1, "package/num3"); + ModuleHelper.AddModuleExportsToAll(module1, "package/num3"); + + // Null module argument, expect an NPE + try { + ModuleHelper.AddModulePackage(null, "new_package"); + throw new RuntimeException("Failed to get the expected NPE"); + } catch(NullPointerException e) { + // Expected + } + + // Bad module argument, expect an IAE + try { + ModuleHelper.AddModulePackage(cl1, "new_package"); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Null package argument, expect an NPE + try { + ModuleHelper.AddModulePackage(module1, null); + throw new RuntimeException("Failed to get the expected NPE"); + } catch(NullPointerException e) { + // Expected + } + + // Existing package, expect an IAE + try { + ModuleHelper.AddModulePackage(module1, "yourpackage"); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Invalid package name, expect an IAE + try { + ModuleHelper.AddModulePackage(module1, "your.package"); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Invalid package name, expect an IAE + try { + ModuleHelper.AddModulePackage(module1, ";your/package"); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Invalid package name, expect an IAE + try { + ModuleHelper.AddModulePackage(module1, "7[743"); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Empty package name, expect an IAE + try { + ModuleHelper.AddModulePackage(module1, ""); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + } + + static class MyClassLoader extends ClassLoader { } +} + diff --git a/hotspot/test/runtime/modules/JVMAddReadsModule.java b/hotspot/test/runtime/modules/JVMAddReadsModule.java new file mode 100644 index 00000000000..78f1d3bf62e --- /dev/null +++ b/hotspot/test/runtime/modules/JVMAddReadsModule.java @@ -0,0 +1,83 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMAddReadsModule + */ + +import static jdk.test.lib.Asserts.*; + +public class JVMAddReadsModule { + + public static void main(String args[]) throws Throwable { + MyClassLoader from_cl = new MyClassLoader(); + MyClassLoader to_cl = new MyClassLoader(); + Object from_module, to_module; + + from_module = ModuleHelper.ModuleObject("from_module", from_cl, new String[] { "mypackage" }); + assertNotNull(from_module, "Module should not be null"); + ModuleHelper.DefineModule(from_module, "9.0", "from_module/here", new String[] { "mypackage" }); + + to_module = ModuleHelper.ModuleObject("to_module", to_cl, new String[] { "yourpackage" }); + assertNotNull(to_module, "Module should not be null"); + ModuleHelper.DefineModule(to_module, "9.0", "to_module/here", new String[] { "yourpackage" }); + + // Null from_module argument, expect an NPE + try { + ModuleHelper.AddReadsModule(null, to_module); + throw new RuntimeException("Failed to get the expected NPE"); + } catch(NullPointerException e) { + // Expected + } + + // Null to_module argument, do not expect an NPE + try { + ModuleHelper.AddReadsModule(from_module, null); + } catch(NullPointerException e) { + throw new RuntimeException("Unexpected NPE was thrown"); + } + + // Null from_module and to_module arguments, expect an NPE + try { + ModuleHelper.AddReadsModule(null, null); + throw new RuntimeException("Failed to get the expected NPE"); + } catch(NullPointerException e) { + // Expected + } + + // Both modules are the same, should not throw an exception + ModuleHelper.AddReadsModule(from_module, from_module); + + // Duplicate calls, should not throw an exception + ModuleHelper.AddReadsModule(from_module, to_module); + ModuleHelper.AddReadsModule(from_module, to_module); + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/JVMCanReadModule.java b/hotspot/test/runtime/modules/JVMCanReadModule.java new file mode 100644 index 00000000000..ca131df42ec --- /dev/null +++ b/hotspot/test/runtime/modules/JVMCanReadModule.java @@ -0,0 +1,96 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMCanReadModule + */ + +import static jdk.test.lib.Asserts.*; + +public class JVMCanReadModule { + + public static void main(String args[]) throws Throwable { + MyClassLoader asking_cl = new MyClassLoader(); + MyClassLoader target_cl = new MyClassLoader(); + Object asking_module, target_module; + boolean result; + + asking_module = ModuleHelper.ModuleObject("asking_module", asking_cl, new String[] { "mypackage" }); + assertNotNull(asking_module, "Module should not be null"); + ModuleHelper.DefineModule(asking_module, "9.0", "asking_module/here", new String[] { "mypackage" }); + target_module = ModuleHelper.ModuleObject("target_module", target_cl, new String[] { "yourpackage" }); + assertNotNull(target_module, "Module should not be null"); + ModuleHelper.DefineModule(target_module, "9.0", "target_module/here", new String[] { "yourpackage" }); + + // Set up relationship + ModuleHelper.AddReadsModule(asking_module, target_module); + + // Null asking_module argument, expect an NPE + try { + result = ModuleHelper.CanReadModule(null, target_module); + throw new RuntimeException("Failed to get the expected NPE"); + } catch(NullPointerException e) { + // Expected + } + + // Bad asking_module argument, expect an IAE + try { + result = ModuleHelper.CanReadModule(asking_cl, target_module); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Bad target_module argument, expect an IAE + try { + result = ModuleHelper.CanReadModule(asking_module, asking_cl); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Verify strict modules can not read the unnamed module + result = ModuleHelper.CanReadModule(target_module, null); + assertFalse(result, "target_module can not read unnamed module"); + + // Verify asking_module can read itself + result = ModuleHelper.CanReadModule(asking_module, asking_module); + assertTrue(result, "asking_module can read itself"); + + // Verify asking_module can read target_module + result = ModuleHelper.CanReadModule(asking_module, target_module); + assertTrue(result, "asking_module can read target_module"); + + // Verify target_module cannot read asking_module + result = ModuleHelper.CanReadModule(target_module, asking_module); + assertTrue(!result, "target_module cannot read asking_module"); + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/JVMDefineModule.java b/hotspot/test/runtime/modules/JVMDefineModule.java new file mode 100644 index 00000000000..77d3c0f3940 --- /dev/null +++ b/hotspot/test/runtime/modules/JVMDefineModule.java @@ -0,0 +1,262 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMDefineModule + */ + +import static jdk.test.lib.Asserts.*; + +public class JVMDefineModule { + + public static void main(String args[]) throws Throwable { + MyClassLoader cl = new MyClassLoader(); + Object m; + + // NULL classloader argument, expect success + m = ModuleHelper.ModuleObject("mymodule", null, new String[] { "mypackage" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "9.0", "mymodule/here", new String[] { "mypackage" }); + +/* Invalid test, won't compile. + // Invalid classloader argument, expect an IAE + try { + m = ModuleHelper.ModuleObject("mymodule1", new Object(), new String[] { "mypackage1" }); + ModuleHelper.DefineModule(m, "9.0", "mymodule/here", new String[] { "mypackage1" }); + throw new RuntimeException("Failed to get expected IAE for bad loader"); + } catch(IllegalArgumentException e) { + // Expected + } +*/ + + // NULL package argument, should not throw an exception + m = ModuleHelper.ModuleObject("mymodule2", cl, new String[] { "nullpkg" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "9.0", "mymodule2/here", null); + + // Null module argument, expect an NPE + try { + ModuleHelper.DefineModule(null, "9.0", "mymodule/here", new String[] { "mypackage1" }); + throw new RuntimeException("Failed to get expected NPE for null module"); + } catch(NullPointerException e) { + if (!e.getMessage().contains("Null module object")) { + throw new RuntimeException("Failed to get expected IAE message for null module: " + e.getMessage()); + } + // Expected + } + + // Invalid module argument, expect an IAE + try { + ModuleHelper.DefineModule(new Object(), "9.0", "mymodule/here", new String[] { "mypackage1" }); + throw new RuntimeException("Failed to get expected IAE or NPE for bad module"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("module is not a subclass")) { + throw new RuntimeException("Failed to get expected IAE message for bad module: " + e.getMessage()); + } + } + + // NULL module name, expect an IAE or NPE + try { + m = ModuleHelper.ModuleObject(null, cl, new String[] { "mypackage2" }); + ModuleHelper.DefineModule(m, "9.0", "mymodule/here", new String[] { "mypackage2" }); + throw new RuntimeException("Failed to get expected NPE for NULL module"); + } catch(IllegalArgumentException e) { + // Expected + } catch(NullPointerException e) { + // Expected + } + + // module name is java.base, expect an IAE + m = ModuleHelper.ModuleObject("java.base", cl, new String[] { "mypackage3" }); + try { + ModuleHelper.DefineModule(m, "9.0", "mymodule/here", new String[] { "mypackage3" }); + throw new RuntimeException("Failed to get expected IAE for java.base, not defined with boot class loader"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("Class loader must be the boot class loader")) { + throw new RuntimeException("Failed to get expected IAE message for java.base: " + e.getMessage()); + } + } + + // Duplicates in package list, expect an IAE + m = ModuleHelper.ModuleObject("module.x", cl, new String[] { "mypackage4", "mypackage5" }); + try { + ModuleHelper.DefineModule(m, "9.0", "mymodule/here", new String[] { "mypackage4", "mypackage5", "mypackage4" }); + throw new RuntimeException("Failed to get IAE for duplicate packages"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("Duplicate package name")) { + throw new RuntimeException("Failed to get expected IAE message for duplicate package: " + e.getMessage()); + } + } + + // Empty entry in package list, expect an IAE + m = ModuleHelper.ModuleObject("module.y", cl, new String[] { "mypackageX", "mypackageY" }); + try { + ModuleHelper.DefineModule(m, "9.0", "mymodule/here", new String[] { "mypackageX", "", "mypackageY" }); + throw new RuntimeException("Failed to get IAE for empty package"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("Invalid package name")) { + throw new RuntimeException("Failed to get expected IAE message empty package entry: " + e.getMessage()); + } + } + + // Duplicate module name, expect an IAE + m = ModuleHelper.ModuleObject("module.name", 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()); + } + } + + // Package is already defined for class loader, expect an IAE + 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()); + } + } + + // Empty module name, expect an IAE + try { + m = ModuleHelper.ModuleObject("", cl, new String[] { "mypackage8" }); + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage8" }); + throw new RuntimeException("Failed to get expected IAE for empty module name"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Bad module name, expect an IAE + try { + m = ModuleHelper.ModuleObject("bad;name", cl, new String[] { "mypackage9" }); + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9" }); + throw new RuntimeException("Failed to get expected IAE for bad;name"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Bad module name, expect an IAE + try { + m = ModuleHelper.ModuleObject(".leadingdot", cl, new String[] { "mypackage9a" }); + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9a" }); + throw new RuntimeException("Failed to get expected IAE for .leadingdot"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Bad module name, expect an IAE + try { + m = ModuleHelper.ModuleObject("trailingdot.", cl, new String[] { "mypackage9b" }); + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9b" }); + throw new RuntimeException("Failed to get expected IAE for trailingdot."); + } catch(IllegalArgumentException e) { + // Expected + } + + // Bad module name, expect an IAE + m = ModuleHelper.ModuleObject("consecutive..dots", cl, new String[] { "mypackage9c" }); + try { + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9c" }); + throw new RuntimeException("Failed to get expected IAE for consecutive..dots"); + } catch(IllegalArgumentException e) { + // Expected + } + + // module name with multiple dots, should be okay + m = ModuleHelper.ModuleObject("more.than.one.dat", cl, new String[] { "mypackage9d" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "mypackage9d" }); + + // Zero length package list, should be okay + m = ModuleHelper.ModuleObject("zero.packages", cl, new String[] { }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { }); + + // Invalid package name, expect an IAE + m = ModuleHelper.ModuleObject("module5", cl, new String[] { "your.package" }); + try { + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "your.package" }); + throw new RuntimeException("Failed to get expected IAE for your.package"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("Invalid package name")) { + throw new RuntimeException("Failed to get expected IAE message for bad package name: " + e.getMessage()); + } + } + + // Invalid package name, expect an IAE + m = ModuleHelper.ModuleObject("module6", cl, new String[] { "foo" }); // Name irrelevant + try { + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { ";your/package" }); + throw new RuntimeException("Failed to get expected IAE for ;your.package"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("Invalid package name")) { + throw new RuntimeException("Failed to get expected IAE message for bad package name: " + e.getMessage()); + } + } + + // Invalid package name, expect an IAE + m = ModuleHelper.ModuleObject("module7", cl, new String[] { "foo" }); // Name irrelevant + try { + ModuleHelper.DefineModule(m, "9.0", "module.name/here", new String[] { "7[743" }); + throw new RuntimeException("Failed to get expected IAE for package 7[743"); + } catch(IllegalArgumentException e) { + if (!e.getMessage().contains("Invalid package name")) { + throw new RuntimeException("Failed to get expected IAE message for bad package name: " + e.getMessage()); + } + } + + // module version that is null, should be okay + m = ModuleHelper.ModuleObject("module8", cl, new String[] { "a_package_8" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, null, "module8/here", new String[] { "a_package_8" }); + + // module version that is "", should be okay + m = ModuleHelper.ModuleObject("module9", cl, new String[] { "a_package_9" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "", "module9/here", new String[] { "a_package_9" }); + + // module location that is null, should be okay + m = ModuleHelper.ModuleObject("module10", cl, new String[] { "a_package_10" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "9.0", null, new String[] { "a_package_10" }); + + // module location that is "", should be okay + m = ModuleHelper.ModuleObject("module11", cl, new String[] { "a_package_11" }); + assertNotNull(m, "Module should not be null"); + ModuleHelper.DefineModule(m, "9.0", "", new String[] { "a_package_11" }); + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/JVMGetModuleByPkgName.java b/hotspot/test/runtime/modules/JVMGetModuleByPkgName.java new file mode 100644 index 00000000000..25065e2812c --- /dev/null +++ b/hotspot/test/runtime/modules/JVMGetModuleByPkgName.java @@ -0,0 +1,90 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @compile p2/c2.java + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMGetModuleByPkgName + */ + +import static jdk.test.lib.Asserts.*; +import java.lang.ClassLoader; +import java.lang.reflect.Module; + +public class JVMGetModuleByPkgName { + + public static void main(String args[]) throws Throwable { + + Module javaBase = ModuleHelper.GetModuleByPackageName(null, "java/lang"); + if (!javaBase.getName().equals("java.base")) { + throw new RuntimeException( + "Failed to get module java.base for package java/lang"); + } + + if (ModuleHelper.GetModuleByPackageName(null, "bad.package.name") != null) { + throw new RuntimeException("Failed to get null for bad.package.name"); + } + + ClassLoader systemLoader = ClassLoader.getSystemClassLoader(); + if (ModuleHelper.GetModuleByPackageName(systemLoader, "java/lang") != null) { + throw new RuntimeException( + "Failed to get null for systemClassLoader and java/lang"); + } + + try { + ModuleHelper.GetModuleByPackageName(systemLoader, null); + throw new RuntimeException( + "Failed to throw NullPointerException for null package name"); + } catch(NullPointerException e) { + // Expected + } + + Module unnamedModule = ModuleHelper.GetModuleByPackageName(systemLoader, ""); + if (unnamedModule.isNamed()) { + throw new RuntimeException( + "Unexpected named module returned for unnamed package"); + } + + p2.c2 obj = new p2.c2(); + unnamedModule = ModuleHelper.GetModuleByPackageName(systemLoader, "p2"); + if (unnamedModule.isNamed()) { + throw new RuntimeException( + "Unexpected named module returned for package p2 in unnamed module"); + } + + MyClassLoader cl1 = new MyClassLoader(); + Module module1 = (Module)ModuleHelper.ModuleObject("module1", cl1, new String[] { "mypackage" }); + assertNotNull(module1, "Module should not be null"); + ModuleHelper.DefineModule(module1, "9.0", "module1/here", new String[] { "mypackage" }); + if (ModuleHelper.GetModuleByPackageName(cl1, "mypackage") != module1) { + throw new RuntimeException("Wrong module returned for cl1 mypackage"); + } + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/JVMIsExportedToModule.java b/hotspot/test/runtime/modules/JVMIsExportedToModule.java new file mode 100644 index 00000000000..0e35b7d8d1c --- /dev/null +++ b/hotspot/test/runtime/modules/JVMIsExportedToModule.java @@ -0,0 +1,123 @@ +/* + * 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 + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI JVMIsExportedToModule + */ + +import static jdk.test.lib.Asserts.*; + +public class JVMIsExportedToModule { + + public static void main(String args[]) throws Throwable { + MyClassLoader from_cl = new MyClassLoader(); + MyClassLoader to_cl = new MyClassLoader(); + Object from_module, to_module; + boolean result; + + from_module = ModuleHelper.ModuleObject("from_module", from_cl, new String[] { "mypackage", "this/package" }); + assertNotNull(from_module, "Module from_module should not be null"); + ModuleHelper.DefineModule(from_module, "9.0", "from_module/here", new String[] { "mypackage", "this/package" }); + to_module = ModuleHelper.ModuleObject("to_module", to_cl, new String[] { "yourpackage", "that/package" }); + assertNotNull(to_module, "Module to_module should not be null"); + ModuleHelper.DefineModule(to_module, "9.0", "to_module/here", new String[] { "yourpackage", "that/package" }); + + Object unnamed_module = JVMIsExportedToModule.class.getModule(); + assertNotNull(unnamed_module, "Module unnamed_module should not be null"); + + // Null from_module argument, expect an NPE + try { + result = ModuleHelper.IsExportedToModule(null, "mypackage", to_module); + throw new RuntimeException("Failed to get the expected NPE for null from_module"); + } catch(NullPointerException e) { + // Expected + } + + // Null to_module argument, expect an NPE + try { + result = ModuleHelper.IsExportedToModule(from_module, "mypackage", null); + throw new RuntimeException("Failed to get expected NPE for null to_module"); + } catch(NullPointerException e) { + // Expected + } + + // Null package argument, expect an NPE + try { + result = ModuleHelper.IsExportedToModule(from_module, null, to_module); + throw new RuntimeException("Failed to get the expected NPE for null package"); + } catch(NullPointerException e) { + // Expected + } + + // Bad from_module argument, expect an IAE + try { + result = ModuleHelper.IsExportedToModule(to_cl, "mypackage", to_module); + throw new RuntimeException("Failed to get the expected IAE for bad from_module"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Bad to_module argument, expect an IAE + try { + result = ModuleHelper.IsExportedToModule(from_module, "mypackage", from_cl); + throw new RuntimeException("Failed to get the expected IAE"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Check that package is exported to its own module + result = ModuleHelper.IsExportedToModule(from_module, "mypackage", from_module); + assertTrue(result, "Package is always exported to itself"); + + // Package is not in to_module, expect an IAE + try { + result = ModuleHelper.IsExportedToModule(from_module, "yourpackage", from_cl); + throw new RuntimeException("Failed to get the expected IAE for package not in to_module"); + } catch(IllegalArgumentException e) { + // Expected + } + + // Package is accessible when exported to unnamed module + ModuleHelper.AddModuleExportsToAll(from_module, "mypackage"); + result = ModuleHelper.IsExportedToModule(from_module, "mypackage", to_module); + assertTrue(result, "Package exported to unnamed module is visible to named module"); + + result = ModuleHelper.IsExportedToModule(from_module, "mypackage", unnamed_module); + assertTrue(result, "Package exported to unnamed module is visible to unnamed module"); + + // Package is accessible only to named module when exported to named module + ModuleHelper.AddModuleExports(from_module, "this/package", to_module); + result = ModuleHelper.IsExportedToModule(from_module, "this/package", to_module); + assertTrue(result, "Package exported to named module is visible to named module"); + result = ModuleHelper.IsExportedToModule(from_module, "this/package", unnamed_module); + assertTrue(!result, "Package exported to named module is not visible to unnamed module"); + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/LoadUnloadModuleStress.java b/hotspot/test/runtime/modules/LoadUnloadModuleStress.java new file mode 100644 index 00000000000..53d45c9a892 --- /dev/null +++ b/hotspot/test/runtime/modules/LoadUnloadModuleStress.java @@ -0,0 +1,70 @@ +/* + * 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 + * @summary Ensure module information is cleaned when owning class loader unloads + * @library /testlibrary /test/lib /compiler/whitebox .. + * @build sun.hotspot.WhiteBox + * @compile/module=java.base java/lang/reflect/ModuleHelper.java + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xmx64m -Xmx64m LoadUnloadModuleStress 15000 + */ + +import java.lang.ref.WeakReference; + +import static jdk.test.lib.Asserts.*; + +public class LoadUnloadModuleStress { + private static long timeout; + private static long timeStamp; + + public static byte[] garbage; + public static volatile WeakReference clweak; + + public static Object createModule() throws Throwable { + MyClassLoader cl = new MyClassLoader(); + Object module = ModuleHelper.ModuleObject("mymodule", cl, new String [] {"PackageA"}); + assertNotNull(module); + ModuleHelper.DefineModule(module, "9.0", "mymodule", new String[] { "PackageA" }); + clweak = new WeakReference<>(cl); + return module; + } + + public static void main(String args[]) throws Throwable { + timeout = Long.valueOf(args[0]); + timeStamp = System.currentTimeMillis(); + + while(System.currentTimeMillis() - timeStamp < timeout) { + WeakReference modweak = new WeakReference<>(createModule()); + + while(clweak.get() != null) { + garbage = new byte[8192]; + System.gc(); + } + assertNull(modweak.get()); + } + } + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/ModuleHelper.java b/hotspot/test/runtime/modules/ModuleHelper.java new file mode 100644 index 00000000000..2761b48ff4a --- /dev/null +++ b/hotspot/test/runtime/modules/ModuleHelper.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +import java.net.URI; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Module; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import sun.hotspot.WhiteBox; + +public class ModuleHelper { + + public static void DefineModule(Object module, String version, String location, + String[] pkgs) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.DefineModule(module, version, location, pkgs); + } + + public static void AddModuleExports(Object from, String pkg, Object to) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.AddModuleExports(from, pkg, to); + java.lang.reflect.ModuleHelper.addExportsNoSync((Module)from, pkg, (Module)to); + } + + public static void AddReadsModule(Object from, Object to) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.AddReadsModule(from, to); + java.lang.reflect.ModuleHelper.addReadsNoSync((Module)from, (Module)to); + } + + public static void AddModulePackage(Object m, String pkg) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.AddModulePackage(m, pkg); + java.lang.reflect.ModuleHelper.addPackageNoSync((Module)m, pkg); + } + + public static Module GetModuleByPackageName(Object ldr, String pkg) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + return (Module)wb.GetModuleByPackageName(ldr, pkg); + } + + public static void AddModuleExportsToAllUnnamed(Object m, String pkg) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.AddModuleExportsToAllUnnamed(m, pkg); + //java.lang.reflect.ModuleHelper.addExportsToAllUnnamedNoSync((Module)m, pkg); + } + + public static void AddModuleExportsToAll(Object m, String pkg) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.AddModuleExportsToAll(m, pkg); + java.lang.reflect.ModuleHelper.addExportsNoSync((Module)m, pkg, (Module)null); + } + + public static boolean CanReadModule(Object from, Object to) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + return wb.CanReadModule(from, to); + } + + public static boolean IsExportedToModule(Object from, String pkg, + Object to) throws Throwable { + WhiteBox wb = WhiteBox.getWhiteBox(); + return wb.IsExportedToModule(from, pkg, to); + } + + public static Module ModuleObject(String name, ClassLoader loader, String[] pkgs) throws Throwable { + Set pkg_set = new HashSet<>(); + if (pkgs != null) { + for (String pkg: pkgs) { + pkg_set.add(pkg.replace('/', '.')); + } + } else { + pkg_set = Collections.emptySet(); + } + + ModuleDescriptor descriptor = + new ModuleDescriptor.Builder(name).conceals(pkg_set).build(); + URI uri = URI.create("module:/" + name); + + return java.lang.reflect.ModuleHelper.newModule(loader, descriptor); + } + +} diff --git a/hotspot/test/runtime/modules/Visibility/XbootcpNoVisibility.java b/hotspot/test/runtime/modules/Visibility/XbootcpNoVisibility.java new file mode 100644 index 00000000000..3dd36caaa03 --- /dev/null +++ b/hotspot/test/runtime/modules/Visibility/XbootcpNoVisibility.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Ensure that a class defined within a java.base package can not + * be located via -Xbootclasspath/a + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @run main/othervm XbootcpNoVisibility + */ + +import jdk.test.lib.*; + +public class XbootcpNoVisibility { + public static void main(String args[]) throws Exception { + + String Vis3_B_src = + "package sun.util;" + + "public class Vis3_B { public void m() { System.out.println(\"In B's m()\"); } }"; + + ClassFileInstaller.writeClassToDisk("sun/util/Vis3_B", + InMemoryJavaCompiler.compile("sun.util.Vis3_B", Vis3_B_src), System.getProperty("test.classes")); + + String Vis3_A_src = + "import sun.util.*;" + + "public class Vis3_A {" + + " public static void main(String args[]) throws Exception {" + + // Try loading a class within a named package in a module which has been defined + // to the boot loader. In this situation, the class should only be attempted + // to be loaded from the boot loader's module path which consists of: + // [-Xpatch]; exploded build | "modules" jimage + // + // Since the class is located on the boot loader's append path via + // -Xbootclasspath/a specification, it should not be found. + " try {" + + " sun.util.Vis3_B b = new sun.util.Vis3_B();" + + " } catch (NoClassDefFoundError e) {" + + " System.out.println(\"XbootcpNoVisibility PASSED - " + + "test should throw exception\\n\");" + + " return;" + + " }" + + " throw new RuntimeException(\"XbootcpNoVisibility FAILED - " + + "test should have thrown exception\");" + + " }" + + "}"; + + ClassFileInstaller.writeClassToDisk("Vis3_A", + InMemoryJavaCompiler.compile("Vis3_A", Vis3_A_src), System.getProperty("test.classes")); + + new OutputAnalyzer(ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:.", + "Vis3_A") + .start()).shouldContain("XbootcpNoVisibility PASSED"); + } +} diff --git a/hotspot/test/runtime/modules/Visibility/XbootcpVisibility.java b/hotspot/test/runtime/modules/Visibility/XbootcpVisibility.java new file mode 100644 index 00000000000..5eb8882e870 --- /dev/null +++ b/hotspot/test/runtime/modules/Visibility/XbootcpVisibility.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Ensure that a package whose module has not been defined to the boot loader + * is correctly located with -Xbootclasspath/a + * @requires !(os.family == "windows") + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @run main/othervm XbootcpVisibility + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +import jdk.test.lib.*; + +public class XbootcpVisibility { + + public static void main(String[] args) throws Throwable { + + String Vis1_B_src = + "package p2;" + + "public class Vis1_B { public void m() { System.out.println(\"In B's m()\"); } }"; + + ClassFileInstaller.writeClassToDisk("p2/Vis1_B", + InMemoryJavaCompiler.compile("p2.Vis1_B", Vis1_B_src), System.getProperty("test.classes")); + ClassFileInstaller.writeClassToDisk("p2/Vis1_B", "mods1"); + + String Vis1_C_src = + "package p2;" + + "public class Vis1_C { public void m() { System.out.println(\"In C's m()\"); } }"; + + ClassFileInstaller.writeClassToDisk("p2/Vis1_C", + InMemoryJavaCompiler.compile("p2.Vis1_C", Vis1_C_src), System.getProperty("test.classes")); + ClassFileInstaller.writeClassToDisk("p2/Vis1_C", "mods1"); + + String Vis1_A_src = + "public class Vis1_A {" + + " public static void main(String args[]) throws Exception {" + + // Try loading a class within a named package + // in the unnamed module. + // Ensure the class can still be loaded successfully by the + // boot loader since it is located on -Xbootclasspath/a. + " try {" + + " p2.Vis1_B b = new p2.Vis1_B();" + + " if (b.getClass().getClassLoader() != null) {" + + " throw new RuntimeException(\"XbootcpVisibility FAILED - class B " + + "should be loaded by boot class loader\\n\");" + + " }" + + " b.m();" + + // Now that the package p2 has been recorded in the + // unnamed module within the boot loader's PackageEntryTable, + // ensure that a different class within the same package + // can be located on -Xbootclasspath/a as well. + " p2.Vis1_C c = new p2.Vis1_C();" + + " if (c.getClass().getClassLoader() != null) {" + + " throw new RuntimeException(\"XbootcpVisibility FAILED - class C " + + "should be loaded by boot class loader\\n\");" + + " }" + + " c.m();" + + " } catch (Exception e) {" + + " System.out.println(e);" + + " throw new RuntimeException(\"XbootcpVisibility FAILED - " + + "test should not throw exception\\n\");" + + " }" + + " System.out.println(\"XbootcpVisibility PASSED\\n\");" + + " }" + + "}"; + + ClassFileInstaller.writeClassToDisk("Vis1_A", + InMemoryJavaCompiler.compile("Vis1_A", Vis1_A_src), System.getProperty("test.classes")); + + // Make sure the classes are actually being loaded from mods1 + Files.delete(Paths.get(System.getProperty("test.classes") + File.separator + + "p2" + File.separator + "Vis1_B.class")); + Files.delete(Paths.get(System.getProperty("test.classes") + File.separator + + "p2" + File.separator + "Vis1_C.class")); + + new OutputAnalyzer(ProcessTools.createJavaProcessBuilder( + "-Xbootclasspath/a:nonexistent.jar", + "-Xbootclasspath/a:mods1", + "Vis1_A") + .start()).shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/modules/Visibility/XpatchVisibility.java b/hotspot/test/runtime/modules/Visibility/XpatchVisibility.java new file mode 100644 index 00000000000..1fe53d19b74 --- /dev/null +++ b/hotspot/test/runtime/modules/Visibility/XpatchVisibility.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Ensure that a newly introduced java.base package placed within the -Xpatch directory + * is considered part of the boot loader's visibility boundary + * @requires !(os.family == "windows") + * @library /testlibrary + * @modules java.base/sun.misc + * java.management + * @run main/othervm XpatchVisibility + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; + +import jdk.test.lib.*; + +public class XpatchVisibility { + + public static void main(String[] args) throws Throwable { + + String Vis2_B_src = + "package p2;" + + "public class Vis2_B {" + + " public void m() {" + + " System.out.println(\"In B's m()\");" + + " }" + + "}"; + + String Vis2_A_src = + "import p2.*;" + + "public class Vis2_A {" + + " public static void main(String args[]) throws Exception {" + + // Try loading a class within a newly introduced java.base + // package. Make sure the class can be found via -Xpatch. + " try {" + + " p2.Vis2_B b = new p2.Vis2_B();" + + " if (b.getClass().getClassLoader() != null) {" + + " throw new RuntimeException(\"XpatchVisibility FAILED - class B " + + "should be loaded by boot class loader\\n\");" + + " }" + + " b.m();" + + " } catch (Throwable e) {" + + " throw new RuntimeException(\"XpatchVisibility FAILED - test " + + "should not throw an error or exception\\n\");" + + " }" + + " System.out.println(\"XpatchVisibility PASSED\\n\");" + + " }" + + "}"; + + ClassFileInstaller.writeClassToDisk("p2/Vis2_B", + InMemoryJavaCompiler.compile("p2.Vis2_B", Vis2_B_src), System.getProperty("test.classes")); + ClassFileInstaller.writeClassToDisk("p2/Vis2_B", "mods2/java.base"); + + ClassFileInstaller.writeClassToDisk("Vis2_A", + InMemoryJavaCompiler.compile("Vis2_A", Vis2_A_src), System.getProperty("test.classes")); + + // Make sure the classes are actually being loaded from mods2 + Files.delete(Paths.get(System.getProperty("test.classes") + File.separator + + "p2" + File.separator + "Vis2_B.class")); + + new OutputAnalyzer(ProcessTools.createJavaProcessBuilder( + "-Xpatch:mods2", + "-XaddExports:java.base/p2=ALL-UNNAMED", + "Vis2_A") + .start()).shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/modules/Xpatch/Xpatch2Dirs.java b/hotspot/test/runtime/modules/Xpatch/Xpatch2Dirs.java new file mode 100644 index 00000000000..014476cbd6e --- /dev/null +++ b/hotspot/test/runtime/modules/Xpatch/Xpatch2Dirs.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Make sure -Xpatch works with multiple directories. + * @library /testlibrary + * @compile Xpatch2DirsMain.java + * @run main Xpatch2Dirs + */ + +import jdk.test.lib.*; +import java.io.File; + +public class Xpatch2Dirs { + + public static void main(String[] args) throws Exception { + String source1 = "package javax.naming.spi; " + + "public class NamingManager { " + + " static { " + + " System.out.println(\"I pass one!\"); " + + " } " + + "}"; + String source2 = "package java.beans; " + + "public class Encoder { " + + " static { " + + " System.out.println(\"I pass two!\"); " + + " } " + + "}"; + + ClassFileInstaller.writeClassToDisk("javax/naming/spi/NamingManager", + InMemoryJavaCompiler.compile("javax.naming.spi.NamingManager", source1, "-Xmodule:java.naming"), + "mods/java.naming"); + + ClassFileInstaller.writeClassToDisk("java/beans/Encoder", + InMemoryJavaCompiler.compile("java.beans.Encoder", source2, "-Xmodule:java.desktop"), + "mods2/java.desktop"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xpatch:mods" + File.pathSeparator + "mods2", + "Xpatch2DirsMain", "javax.naming.spi.NamingManager", "java.beans.Encoder"); + + OutputAnalyzer oa = new OutputAnalyzer(pb.start()); + oa.shouldContain("I pass one!"); + oa.shouldContain("I pass two!"); + oa.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/modules/Xpatch/Xpatch2DirsMain.java b/hotspot/test/runtime/modules/Xpatch/Xpatch2DirsMain.java new file mode 100644 index 00000000000..9691156030b --- /dev/null +++ b/hotspot/test/runtime/modules/Xpatch/Xpatch2DirsMain.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +// This loads the class affected by the -Xpatch option. For the test to pass +// it must load both classes from the -Xpatch directory, not the jimage file. +public class Xpatch2DirsMain { + public static void main(String[] args) throws Exception { + Class.forName(args[0]); + Class.forName(args[1]); + } +} diff --git a/hotspot/test/runtime/modules/Xpatch/XpatchMain.java b/hotspot/test/runtime/modules/Xpatch/XpatchMain.java new file mode 100644 index 00000000000..5509cbc7621 --- /dev/null +++ b/hotspot/test/runtime/modules/Xpatch/XpatchMain.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +// This loads the class affected by the -Xpatch option. For the test to pass +// it must load the class from the -Xpatch directory, not the jimage file. +public class XpatchMain { + public static void main(String[] args) throws Exception { + Class.forName(args[0]); + } +} diff --git a/hotspot/test/runtime/modules/Xpatch/XpatchTest.java b/hotspot/test/runtime/modules/Xpatch/XpatchTest.java new file mode 100644 index 00000000000..ddc873feca5 --- /dev/null +++ b/hotspot/test/runtime/modules/Xpatch/XpatchTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8130399 + * @summary Make sure -Xpatch works for modules besides java.base. + * @library /testlibrary + * @compile XpatchMain.java + * @run main XpatchTest + */ + +import jdk.test.lib.*; + +public class XpatchTest { + + public static void main(String[] args) throws Exception { + String source = "package javax.naming.spi; " + + "public class NamingManager { " + + " static { " + + " System.out.println(\"I pass!\"); " + + " } " + + "}"; + + ClassFileInstaller.writeClassToDisk("javax/naming/spi/NamingManager", + InMemoryJavaCompiler.compile("javax.naming.spi.NamingManager", source, "-Xmodule:java.naming"), + "mods/java.naming"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xpatch:mods", + "XpatchMain", "javax.naming.spi.NamingManager"); + + new OutputAnalyzer(pb.start()) + .shouldContain("I pass!") + .shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/modules/Xpatch/XpatchTraceCL.java b/hotspot/test/runtime/modules/Xpatch/XpatchTraceCL.java new file mode 100644 index 00000000000..02edebf60c0 --- /dev/null +++ b/hotspot/test/runtime/modules/Xpatch/XpatchTraceCL.java @@ -0,0 +1,83 @@ +/* + * 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 8069469 + * @summary Make sure -XX:+TraceClassLoading works properly with "modules" jimage, + -Xpatch, and with -Xbootclasspath/a + * @library /testlibrary + * @compile XpatchMain.java + * @run main XpatchTraceCL + */ + +import java.io.File; +import jdk.test.lib.*; + +public class XpatchTraceCL { + + public static void main(String[] args) throws Exception { + String source = "package javax.naming.spi; " + + "public class NamingManager { " + + " static { " + + " System.out.println(\"I pass!\"); " + + " } " + + "}"; + + // Test -XX:+TraceClassLoading output for -Xpatch + ClassFileInstaller.writeClassToDisk("javax/naming/spi/NamingManager", + InMemoryJavaCompiler.compile("javax.naming.spi.NamingManager", source, "-Xmodule:java.naming"), + "mods/java.naming"); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xpatch:mods", + "-XX:+TraceClassLoading", "XpatchMain", "javax.naming.spi.NamingManager"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + // "modules" jimage case. + output.shouldContain("[classload] java.lang.Thread source: jrt:/java.base"); + // -Xpatch case. + output.shouldContain("[classload] javax.naming.spi.NamingManager source: mods" + + File.separator + "java.naming"); + // -cp case. + output.shouldContain("[classload] XpatchMain source: file"); + + // Test -XX:+TraceClassLoading output for -Xbootclasspath/a + source = "package XpatchTraceCL_pkg; " + + "public class ItIsI { " + + " static { " + + " System.out.println(\"I also pass!\"); " + + " } " + + "}"; + + ClassFileInstaller.writeClassToDisk("XpatchTraceCL_pkg/ItIsI", + InMemoryJavaCompiler.compile("XpatchTraceCL_pkg.ItIsI", source), + "xbcp"); + + pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/a:xbcp", + "-XX:+TraceClassLoading", "XpatchMain", "XpatchTraceCL_pkg.ItIsI"); + output = new OutputAnalyzer(pb.start()); + // -Xbootclasspath/a case. + output.shouldContain("[classload] XpatchTraceCL_pkg.ItIsI source: xbcp"); + output.shouldHaveExitValue(0); + } +} diff --git a/hotspot/test/runtime/modules/XpatchCDS.java b/hotspot/test/runtime/modules/XpatchCDS.java new file mode 100644 index 00000000000..4c80beca9fb --- /dev/null +++ b/hotspot/test/runtime/modules/XpatchCDS.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /testlibrary + * @modules java.base/sun.misc + * @run main XpatchCDS + */ + +import java.io.File; +import jdk.test.lib.*; + +public class XpatchCDS { + + public static void main(String args[]) throws Throwable { + System.out.println("Test that -Xpatch and -Xshare:dump are incompatibable"); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xpatch:.", "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Cannot use the following option when dumping the shared archive: -Xpatch"); + + System.out.println("Test that -Xpatch and -Xshare:on are incompatibable"); + String filename = "Xpatch.jsa"; + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + filename, + "-Xshare:dump"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("ro space:"); // Make sure archive got created. + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=" + filename, + "-Xshare:on", + "-Xpatch:.", + "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("The shared archive file cannot be used with -Xpatch"); + + output.shouldHaveExitValue(1); + } +} diff --git a/hotspot/test/runtime/modules/acc_module.jcod b/hotspot/test/runtime/modules/acc_module.jcod new file mode 100644 index 00000000000..573c7dde2a6 --- /dev/null +++ b/hotspot/test/runtime/modules/acc_module.jcod @@ -0,0 +1,137 @@ +/* + * 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. + */ + +/* + * This class consists of the following java code, but has an illegal class + * access_flags value of 0x8000, that should be ignored by the JVM. + * + * public class acc_module { + * public static void main(String[] args) { + * System.out.println("hello"); + * } + * } + */ +class acc_module { + 0xCAFEBABE; + 0; // minor version + 52; // version + [29] { // Constant Pool + ; // first element is empty + Method #6 #15; // #1 at 0x0A + Field #16 #17; // #2 at 0x0F + String #18; // #3 at 0x14 + Method #19 #20; // #4 at 0x17 + class #21; // #5 at 0x1C + class #22; // #6 at 0x1F + Utf8 ""; // #7 at 0x22 + Utf8 "()V"; // #8 at 0x2B + Utf8 "Code"; // #9 at 0x31 + Utf8 "LineNumberTable"; // #10 at 0x38 + Utf8 "main"; // #11 at 0x4A + Utf8 "([Ljava/lang/String;)V"; // #12 at 0x51 + Utf8 "SourceFile"; // #13 at 0x6A + Utf8 "acc_module.java"; // #14 at 0x77 + NameAndType #7 #8; // #15 at 0x89 + class #23; // #16 at 0x8E + NameAndType #24 #25; // #17 at 0x91 + Utf8 "hello"; // #18 at 0x96 + class #26; // #19 at 0x9E + NameAndType #27 #28; // #20 at 0xA1 + Utf8 "acc_module"; // #21 at 0xA6 + Utf8 "java/lang/Object"; // #22 at 0xB3 + Utf8 "java/lang/System"; // #23 at 0xC6 + Utf8 "out"; // #24 at 0xD9 + Utf8 "Ljava/io/PrintStream;"; // #25 at 0xDF + Utf8 "java/io/PrintStream"; // #26 at 0xF7 + Utf8 "println"; // #27 at 0x010D + Utf8 "(Ljava/lang/String;)V"; // #28 at 0x0117 + } // Constant Pool + + 0x8000; // access + #5;// this_cpx + #6;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [2] { // methods + { // Member at 0x013B + 0x0001; // access + #7; // name_cpx + #8; // sig_cpx + [1] { // Attributes + Attr(#9, 29) { // Code at 0x0143 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x015A + [1] { // LineNumberTable + 0 1; // at 0x0166 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0166 + 0x0009; // access + #11; // name_cpx + #12; // sig_cpx + [1] { // Attributes + Attr(#9, 37) { // Code at 0x016E + 2; // max_stack + 1; // max_locals + Bytes[9]{ + 0xB200021203B60004; + 0xB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 10) { // LineNumberTable at 0x0189 + [2] { // LineNumberTable + 0 3; // at 0x0195 + 8 4; // at 0x0199 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#13, 2) { // SourceFile at 0x019B + #14; + } // end SourceFile + } // Attributes +} // end class acc_module diff --git a/hotspot/test/runtime/modules/getModuleJNI/GetModule.java b/hotspot/test/runtime/modules/getModuleJNI/GetModule.java new file mode 100644 index 00000000000..bc9883c6a64 --- /dev/null +++ b/hotspot/test/runtime/modules/getModuleJNI/GetModule.java @@ -0,0 +1,167 @@ +/* + * 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 + * @summary test JNI_GetModule() API + * @run main/native GetModule + */ + +import java.lang.reflect.Module; +import java.lang.management.LockInfo; +public class GetModule { + + static { + System.loadLibrary("GetModule"); + } + + static native Object callGetModule(java.lang.Class clazz); + static native void callAddModuleReads(java.lang.reflect.Module from_module, + java.lang.reflect.Module source_module); + static native boolean callCanReadModule(java.lang.reflect.Module asking_module, + java.lang.reflect.Module source_module); + + public static void main(String[] args) { + Module module; + + // Module for array of primitives, should be "java.base" + int[] int_array = {1, 2, 3}; + Module javaBaseModule; + try { + javaBaseModule = (Module)callGetModule(int_array.getClass()); + if (!javaBaseModule.getName().equals("java.base")) { + throw new RuntimeException("Unexpected module name for array of primitives: " + + javaBaseModule.getName()); + } + } catch(Throwable e) { + throw new RuntimeException("Unexpected exception for [I: " + e.toString()); + } + + // Module for java.lang.String + java.lang.String str = "abc"; + try { + module = (Module)callGetModule(str.getClass()); + if (!module.getName().equals("java.base")) { + throw new RuntimeException("Unexpected module name for class String: " + + module.getName()); + } + } catch(Throwable e) { + throw new RuntimeException("Unexpected exception for String: " + e.toString()); + } + + // Module for java.lang.management.LockInfo + try { + LockInfo li = new LockInfo("java.lang.Class", 57); + module = (Module)callGetModule(li.getClass()); + if (!module.getName().equals("java.management")) { + throw new RuntimeException("Unexpected module name for class LockInfo: " + + module.getName()); + } + } catch(Throwable e) { + throw new RuntimeException("Unexpected exception for LockInfo: " + e.toString()); + } + + // Unnamed module. + try { + module = (Module)callGetModule(MyClassLoader.class); + if (module == null || module.getName() != null) { + throw new RuntimeException("Bad module for unnamed module"); + } + } catch(Throwable e) { + throw new RuntimeException("Unexpected exception for unnamed module: " + e.toString()); + } + + try { + module = (Module)callGetModule(null); + throw new RuntimeException("Failed to get expected NullPointerException"); + } catch(NullPointerException e) { + // Expected + } + + + // Tests for JNI_AddModuleReads() // + + Module javaScriptingModule = javax.script.Bindings.class.getModule(); + if (javaScriptingModule == null) { + throw new RuntimeException("Failed to get java.scripting module"); + } + Module javaLoggingModule = java.util.logging.Level.class.getModule(); + if (javaLoggingModule == null) { + throw new RuntimeException("Failed to get java.logging module"); + } + + if (callCanReadModule(javaLoggingModule, javaScriptingModule)) { + throw new RuntimeException( + "Expected FALSE because javaLoggingModule cannot read javaScriptingModule"); + } + + callAddModuleReads(javaLoggingModule, javaScriptingModule); + callAddModuleReads(javaScriptingModule, GetModule.class.getModule()); // unnamed module + + try { + callAddModuleReads(null, javaLoggingModule); + throw new RuntimeException( + "Expected NullPointerException for bad from_module not thrown"); + } catch(NullPointerException e) { + // expected + } + + try { + callAddModuleReads(javaLoggingModule, null); + throw new RuntimeException( + "Expected NullPointerException for bad source_module not thrown"); + } catch(NullPointerException e) { + // expected + } + + + // Tests for JNI_CanReadModule() // + + if (!callCanReadModule(javaLoggingModule, javaScriptingModule)) { + throw new RuntimeException( + "Expected TRUE because javaLoggingModule can read javaScriptingModule"); + } + + if (callCanReadModule(javaBaseModule, javaScriptingModule)) { + throw new RuntimeException( + "Expected FALSE because javaBaseModule cannnot read javaScriptingModule"); + } + + try { + callCanReadModule(javaLoggingModule, null); + throw new RuntimeException( + "Expected NullPointerException for bad sourceModule not thrown"); + } catch(NullPointerException e) { + // expected + } + + try { + callCanReadModule(null, javaScriptingModule); + throw new RuntimeException( + "Expected NullPointerException for bad asking_module not thrown"); + } catch(NullPointerException e) { + // expected + } + } + + static class MyClassLoader extends ClassLoader { } +} diff --git a/hotspot/test/runtime/modules/getModuleJNI/libGetModule.c b/hotspot/test/runtime/modules/getModuleJNI/libGetModule.c new file mode 100644 index 00000000000..a7b1b6d2dc0 --- /dev/null +++ b/hotspot/test/runtime/modules/getModuleJNI/libGetModule.c @@ -0,0 +1,42 @@ +/* + * 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. + */ + +#include + +JNIEXPORT jobject JNICALL +Java_GetModule_callGetModule(JNIEnv *env, jclass unused, jclass clazz) { + jobject res = (jobject)((*env)->GetModule(env, clazz)); + return res; +} + +JNIEXPORT void JNICALL +Java_GetModule_callAddModuleReads(JNIEnv *env, jclass unused, jobject from_module, jobject source_module) { + (*env)->AddModuleReads(env, from_module, source_module); +} + +JNIEXPORT jboolean JNICALL +Java_GetModule_callCanReadModule(JNIEnv *env, jclass unused, jobject asking_module, jobject source_module) { + jboolean res = (*env)->CanReadModule(env, asking_module, source_module); + return res; +} + diff --git a/hotspot/test/runtime/modules/java.base/java/lang/reflect/ModuleHelper.java b/hotspot/test/runtime/modules/java.base/java/lang/reflect/ModuleHelper.java new file mode 100644 index 00000000000..ca7977aee8d --- /dev/null +++ b/hotspot/test/runtime/modules/java.base/java/lang/reflect/ModuleHelper.java @@ -0,0 +1,69 @@ +/* + * 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 java.lang.reflect; + +import java.lang.module.ModuleDescriptor; + +/** + * A helper class intended to be injected into java.lang.reflect using the + * java -Xpatch option. The helper class provides access to package private + * methods in java.lang.reflect.Module. + */ + +public final class ModuleHelper { + + private ModuleHelper() { } + + /** + * Creates a named module but without defining the module to the VM. + */ + public static Module newModule(ClassLoader loader, ModuleDescriptor descriptor) { + return new Module(loader, descriptor); + } + + /** + * Updates module {@code from} to that it reads module {@code to} without + * notifying the VM. + */ + public static void addReadsNoSync(Module from, Module to) { + from.implAddReadsNoSync(to); + } + + /** + * Updates module {@code from} so that it exports package {@code pkg} + * to module {@code to} but without notifying the VM. If {@code to} is + * {@code null} then the package is exported unconditionally. + */ + public static void addExportsNoSync(Module from, String pkg, Module to) { + from.implAddExportsNoSync(pkg, to); + } + + /** + * Adds a package to a module without notifying the VM. + */ + public static void addPackageNoSync(Module m, String pkg) { + m.implAddPackageNoSync(pkg); + } + +} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkgDeprecated/Class1PkgDeprecated.java b/hotspot/test/runtime/modules/p1/c1.java similarity index 78% rename from langtools/test/com/sun/javadoc/testProfiles/pkgDeprecated/Class1PkgDeprecated.java rename to hotspot/test/runtime/modules/p1/c1.java index 51475499286..7fbe4f9dc1d 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkgDeprecated/Class1PkgDeprecated.java +++ b/hotspot/test/runtime/modules/p1/c1.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,16 +21,15 @@ * questions. */ -package pkgDeprecated; +// Small class used by multiple hotspot/runtime/modules/AccessCheck* tests. +package p1; -/** - * Simple deprecated class of deprecated package. - * - * @author Evgeniya Stepanova - */ -public class Class1PkgDeprecated { +import p2.c2; - public void method(int t) { - return null; +public class c1 { + + public c1 () { + p2.c2 c2_obj = new p2.c2(); + c2_obj.method2(); } } diff --git a/hotspot/test/runtime/modules/p2/c2.java b/hotspot/test/runtime/modules/p2/c2.java new file mode 100644 index 00000000000..74adc645a74 --- /dev/null +++ b/hotspot/test/runtime/modules/p2/c2.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck* tests. +package p2; + +public class c2 { + public void method2() { } +} diff --git a/hotspot/test/runtime/modules/p3/c3.java b/hotspot/test/runtime/modules/p3/c3.java new file mode 100644 index 00000000000..1e8130c49ad --- /dev/null +++ b/hotspot/test/runtime/modules/p3/c3.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +// Small class used by multiple hotspot/runtime/modules/AccessCheck* tests. +package p3; + +public class c3 extends p2.c2 { + public void method3() { } +} diff --git a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java index fac5034f984..321be8257f5 100644 --- a/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java +++ b/hotspot/test/serviceability/dcmd/compiler/CompilerQueueTest.java @@ -24,25 +24,33 @@ /* * @test CompilerQueueTest * @bug 8054889 - * @library /testlibrary + * @library /testlibrary /test/lib / * @modules java.base/sun.misc * java.compiler * java.management * jdk.jvmstat/sun.jvmstat.monitor - * @ignore 8069160 * @build jdk.test.lib.* - * @build jdk.test.lib.dcmd.* - * @run testng CompilerQueueTest - * @run testng/othervm -XX:-TieredCompilation CompilerQueueTest - * @run testng/othervm -Xint CompilerQueueTest + * jdk.test.lib.dcmd.* + * sun.hotspot.WhiteBox + * compiler.testlibrary.CompilerUtils + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xmixed -XX:+WhiteBoxAPI CompilerQueueTest + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xmixed -XX:-TieredCompilation -XX:+WhiteBoxAPI CompilerQueueTest + * @run testng/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -Xint -XX:+WhiteBoxAPI CompilerQueueTest * @summary Test of diagnostic command Compiler.queue */ +import compiler.testlibrary.CompilerUtils; import jdk.test.lib.OutputAnalyzer; import jdk.test.lib.dcmd.CommandExecutor; import jdk.test.lib.dcmd.JMXExecutor; import org.testng.annotations.Test; +import org.testng.Assert; +import sun.hotspot.WhiteBox; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; import java.util.Iterator; public class CompilerQueueTest { @@ -54,70 +62,123 @@ public class CompilerQueueTest { * * Output example: * - * Contents of C1 compile queue - * ---------------------------- - * 73 3 java.lang.AbstractStringBuilder::append (50 bytes) - * 74 1 java.util.TreeMap::size (5 bytes) - * 75 3 java.lang.StringBuilder::append (8 bytes) - * 83 3 java.util.TreeMap$ValueIterator::next (8 bytes) - * 84 1 javax.management.MBeanFeatureInfo::getName (5 bytes) - * ---------------------------- - * Contents of C2 compile queue - * ---------------------------- + * Current compiles: + * C1 CompilerThread14 267 3 java.net.URLStreamHandler::parseURL (1166 bytes) + * C1 CompilerThread13 760 3 javax.management.StandardMBean::getDescription (11 bytes) + * C1 CompilerThread12 757 s 3 com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory::getMapping (27 bytes) + * C1 CompilerThread11 756 s! 3 com.sun.jmx.mbeanserver.DefaultMXBeanMappingFactory::mappingForType (110 bytes) + * C1 CompilerThread10 761 3 java.lang.StringLatin1::indexOf (121 bytes) + * C2 CompilerThread7 769 4 CompilerQueueTest::testcaseMethod4 (1 bytes) + * + * C1 compile queue: + * 762 3 java.lang.invoke.MethodType::basicType (8 bytes) + * 763 3 java.util.ArrayList::rangeCheck (22 bytes) + * 764 3 java.util.ArrayList::elementData (7 bytes) + * 765 3 jdk.internal.org.objectweb.asm.MethodVisitor:: (35 bytes) + * 766 1 CompilerQueueTest::testcaseMethod1 (1 bytes) + * 767 2 CompilerQueueTest::testcaseMethod2 (1 bytes) + * 768 3 CompilerQueueTest::testcaseMethod3 (1 bytes) + * 770 3 java.util.Properties::getProperty (46 bytes) + * + * C2 compile queue: * Empty - * ---------------------------- * **/ + protected static final WhiteBox WB = WhiteBox.getWhiteBox(); + public void run(CommandExecutor executor) { + TestCase[] testcases = { + new TestCase(1, "testcaseMethod1"), + new TestCase(2, "testcaseMethod2"), + new TestCase(3, "testcaseMethod3"), + new TestCase(4, "testcaseMethod4"), + }; + + // Lock compilation makes all compiles stay in queue or compile thread before completion + WB.lockCompilation(); + + // Enqueue one test method for each available level + int[] complevels = CompilerUtils.getAvailableCompilationLevels(); + for (int level : complevels) { + TestCase testcase = testcases[level - 1]; + + boolean added = WB.enqueueMethodForCompilation(testcase.method, testcase.level); + // Set results to false for those methods we must to find + // We will also assert if we find any test method we don't expect + Assert.assertTrue(WB.isMethodQueuedForCompilation(testcase.method)); + testcase.check = false; + } + // Get output from dcmd (diagnostic command) OutputAnalyzer output = executor.execute("Compiler.queue"); Iterator lines = output.asLines().iterator(); + // Loop over output set result for all found methods while (lines.hasNext()) { String str = lines.next(); - if (str.startsWith("Contents of C")) { - match(lines.next(), "----------------------------"); - str = lines.next(); - if (!str.equals("Empty")) { - while (str.charAt(0) != '-') { - validateMethodLine(str); - str = lines.next(); + // Fast check for common part of method name + if (str.contains("testcaseMethod")) { + for (TestCase testcase : testcases) { + if (str.contains(testcase.methodName)) { + Assert.assertFalse(testcase.check, "Must not be found or already found."); + testcase.check = true; } - } else { - str = lines.next(); } - match(str,"----------------------------"); - } else { - Assert.fail("Failed parsing dcmd queue, line: " + str); } } - } - private static void validateMethodLine(String str) { - // Skip until package/class name begins. Trim to remove whitespace that - // may differ. - String name = str.substring(14).trim(); - int sep = name.indexOf("::"); - if (sep == -1) { - Assert.fail("Failed dcmd queue, didn't find separator :: in: " + name); + for (TestCase testcase : testcases) { + if (!testcase.check) { + // If this method wasn't found it must have been removed by policy, + // verify that it is now removed from the queue + Assert.assertFalse(WB.isMethodQueuedForCompilation(testcase.method), "Must be found or not in queue"); + } + // Otherwise all good. } - try { - Class.forName(name.substring(0, sep)); - } catch (ClassNotFoundException e) { - Assert.fail("Failed dcmd queue, Class for name: " + str); - } - } - public static void match(String line, String str) { - if (!line.equals(str)) { - Assert.fail("String equals: " + line + ", " + str); - } + // Enable compilations again + WB.unlockCompilation(); } @Test public void jmx() { run(new JMXExecutor()); } + + public void testcaseMethod1() { + } + + public void testcaseMethod2() { + } + + public void testcaseMethod3() { + } + + public void testcaseMethod4() { + } + + public static Method getMethod(Class klass, String name, Class... parameterTypes) { + try { + return klass.getDeclaredMethod(name, parameterTypes); + } catch (NoSuchMethodException | SecurityException e) { + throw new RuntimeException("exception on getting method Helper." + name, e); + } + } + + class TestCase { + Method method; + int level; + String methodName; + Boolean check; + + public TestCase(int level, String methodName) { + this.method = getMethod(CompilerQueueTest.class, methodName); + this.level = level; + this.methodName = methodName; + this.check = true; + } + } + } diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java index f0db464e46b..da7224583e0 100644 --- a/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java +++ b/hotspot/test/serviceability/dcmd/jvmti/LoadAgentDcmdTest.java @@ -22,6 +22,10 @@ */ import java.io.*; import java.nio.file.*; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; import jdk.test.lib.*; import jdk.test.lib.dcmd.*; import org.testng.annotations.Test; @@ -55,12 +59,7 @@ public class LoadAgentDcmdTest { "'-Dtest.jdk=/path/to/jdk'."); } - Path libpath; - if (Platform.isWindows()) { - libpath = Paths.get(jdkPath, "bin", "instrument.dll"); - } else { - libpath = Paths.get(jdkPath, "lib", Platform.getOsArch(), "libinstrument.so"); - } + Path libpath = Paths.get(jdkPath, Platform.jdkLibPath(), Platform.sharedObjectName("instrument")); if (!libpath.toFile().exists()) { throw new FileNotFoundException( @@ -70,31 +69,62 @@ public class LoadAgentDcmdTest { return libpath.toAbsolutePath().toString(); } + + public void createJarFileForAgent() + throws IOException { + + final String jarName = "agent.jar"; + final String agentClass = "SimpleJvmtiAgent"; + + Manifest manifest = new Manifest(); + + manifest.getMainAttributes().put( + Attributes.Name.MANIFEST_VERSION, "1.0"); + + manifest.getMainAttributes().put( + new Attributes.Name("Agent-Class"), agentClass); + + JarOutputStream target = null; + + try { + target = new + JarOutputStream(new FileOutputStream(jarName), manifest); + JarEntry entry = new JarEntry(agentClass + ".class"); + target.putNextEntry(entry); + target.closeEntry(); + } finally { + target.close(); + } + } + public void run(CommandExecutor executor) { try{ - PrintWriter pw = new PrintWriter("MANIFEST.MF"); - pw.println("Agent-Class: SimpleJvmtiAgent"); - pw.close(); - ProcessBuilder pb = new ProcessBuilder(); - pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), - "cmf", - "MANIFEST.MF", - "agent.jar", - "SimpleJvmtiAgent.class"}); - pb.start().waitFor(); + createJarFileForAgent(); String libpath = getLibInstrumentPath(); + OutputAnalyzer output = null; - // Test 1: No argument - OutputAnalyzer output = executor.execute("JVMTI.agent_load " + - libpath + " agent.jar"); - output.stderrShouldBeEmpty(); - - // Test 2: With argument + // Test 1: Native agent, no arguments output = executor.execute("JVMTI.agent_load " + - libpath + " \"agent.jar=foo=bar\""); + libpath + " agent.jar"); output.stderrShouldBeEmpty(); + + // Test 2: Native agent, with arguments + output = executor.execute("JVMTI.agent_load " + + libpath + " \"agent.jar=foo=bar\""); + output.stderrShouldBeEmpty(); + + // Test 3: Java agent, no arguments + output = executor.execute("JVMTI.agent_load " + + "agent.jar"); + output.stderrShouldBeEmpty(); + + // Test 4: Java agent, with arguments + output = executor.execute("JVMTI.agent_load " + + "\"agent.jar=foo=bar\""); + output.stderrShouldBeEmpty(); + } catch (Exception e) { throw new RuntimeException(e); } diff --git a/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java b/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java deleted file mode 100644 index 6c0c17760aa..00000000000 --- a/hotspot/test/serviceability/dcmd/jvmti/LoadJavaAgentDcmdTest.java +++ /dev/null @@ -1,81 +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. - */ -import java.io.*; -import jdk.test.lib.*; -import jdk.test.lib.dcmd.*; -import org.testng.annotations.Test; - -/* - * Test to attach JVMTI java agent. - * - * @test - * @bug 8147388 - * @library /testlibrary - * @modules java.base/sun.misc - * java.compiler - * java.instrument - * java.management - * jdk.jvmstat/sun.jvmstat.monitor - * @build ClassFileInstaller jdk.test.lib.* SimpleJvmtiAgent - * @run main ClassFileInstaller SimpleJvmtiAgent - * @run testng LoadJavaAgentDcmdTest - */ -public class LoadJavaAgentDcmdTest { - public void run(CommandExecutor executor) { - try{ - PrintWriter pw = new PrintWriter("MANIFEST.MF"); - pw.println("Agent-Class: SimpleJvmtiAgent"); - pw.close(); - - ProcessBuilder pb = new ProcessBuilder(); - pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), - "cmf", - "MANIFEST.MF", - "agent.jar", - "SimpleJvmtiAgent.class"}); - pb.start().waitFor(); - - // Test 1: No argument - OutputAnalyzer output = executor.execute("JVMTI.agent_load " + - "agent.jar"); - output.stderrShouldBeEmpty(); - - // Test 2: With argument - output = executor.execute("JVMTI.agent_load " + - "\"agent.jar=foo=bar\""); - output.stderrShouldBeEmpty(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - @Test - public void jmx() throws Throwable { - run(new JMXExecutor()); - } - - @Test - public void cli() throws Throwable { - run(new PidJcmdExecutor()); - } -} diff --git a/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java b/hotspot/test/serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java index 3ef260a5dfd..4e2abad9078 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, 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 @@ -54,7 +54,6 @@ import jdk.test.lib.ProcessTools; public class JMapHProfLargeHeapTest { private static final String HEAP_DUMP_FILE_NAME = "heap.hprof"; - private static final String HPROF_HEADER_1_0_1 = "JAVA PROFILE 1.0.1"; private static final String HPROF_HEADER_1_0_2 = "JAVA PROFILE 1.0.2"; private static final long M = 1024L; private static final long G = 1024L * M; @@ -79,8 +78,8 @@ public class JMapHProfLargeHeapTest { } } - // Small heap 22 megabytes, should create 1.0.1 file format - testHProfFileFormat("-Xmx1g", 22 * M, HPROF_HEADER_1_0_1); + // All heap dumps should create 1.0.2 file format + testHProfFileFormat("-Xmx1g", 22 * M, HPROF_HEADER_1_0_2); /** * This test was deliberately commented out since the test system lacks @@ -96,7 +95,7 @@ public class JMapHProfLargeHeapTest { String expectedFormat) throws Exception, IOException, InterruptedException, FileNotFoundException { ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder( - vmArgs, "JMapHProfLargeHeapProc", String.valueOf(heapSize)); + "-XaddExports:java.management/sun.management=ALL-UNNAMED", vmArgs, "JMapHProfLargeHeapProc", String.valueOf(heapSize)); procBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); Process largeHeapProc = procBuilder.start(); diff --git a/hotspot/test/testlibrary/ClassFileInstaller.java b/hotspot/test/testlibrary/ClassFileInstaller.java index 4e042dacde4..2c1541d0457 100644 --- a/hotspot/test/testlibrary/ClassFileInstaller.java +++ b/hotspot/test/testlibrary/ClassFileInstaller.java @@ -23,6 +23,7 @@ import java.io.FileNotFoundException; import java.io.InputStream; +import java.io.ByteArrayInputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -38,22 +39,47 @@ public class ClassFileInstaller { */ public static void main(String... args) throws Exception { for (String arg : args) { - ClassLoader cl = ClassFileInstaller.class.getClassLoader(); - - // Convert dotted class name to a path to a class file - String pathName = arg.replace('.', '/').concat(".class"); - InputStream is = cl.getResourceAsStream(pathName); - if (is == null) { - throw new FileNotFoundException(pathName); - } - - // Create the class file's package directory - Path p = Paths.get(pathName); - if (pathName.contains("/")) { - Files.createDirectories(p.getParent()); - } - // Create the class file - Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + writeClassToDisk(arg); } } + + public static void writeClassToDisk(String className) throws Exception { + writeClassToDisk(className, ""); + } + + public static void writeClassToDisk(String className, String prependPath) throws Exception { + ClassLoader cl = ClassFileInstaller.class.getClassLoader(); + + // Convert dotted class name to a path to a class file + String pathName = className.replace('.', '/').concat(".class"); + InputStream is = cl.getResourceAsStream(pathName); + if (prependPath.length() > 0) { + pathName = prependPath + "/" + pathName; + } + writeToDisk(pathName, is); + } + + public static void writeClassToDisk(String className, byte[] bytecode) throws Exception { + writeClassToDisk(className, bytecode, ""); + } + + public static void writeClassToDisk(String className, byte[] bytecode, String prependPath) throws Exception { + // Convert dotted class name to a path to a class file + String pathName = className.replace('.', '/').concat(".class"); + if (prependPath.length() > 0) { + pathName = prependPath + "/" + pathName; + } + writeToDisk(pathName, new ByteArrayInputStream(bytecode)); + } + + + private static void writeToDisk(String pathName, InputStream is) throws Exception { + // Create the class file's package directory + Path p = Paths.get(pathName); + if (pathName.contains("/")) { + Files.createDirectories(p.getParent()); + } + // Create the class file + Files.copy(is, p, StandardCopyOption.REPLACE_EXISTING); + } } diff --git a/hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java b/hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java index 80439f898b6..8384b28ca5d 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java +++ b/hotspot/test/testlibrary/jdk/test/lib/InMemoryJavaCompiler.java @@ -128,12 +128,13 @@ public class InMemoryJavaCompiler { * * @param className The name of the class * @param sourceCode The source code for the class with name {@code className} + * @param options additional command line options * @throws RuntimeException if the compilation did not succeed * @return The resulting byte code from the compilation */ - public static byte[] compile(String className, CharSequence sourceCode) { + public static byte[] compile(String className, CharSequence sourceCode, String... options) { MemoryJavaFileObject file = new MemoryJavaFileObject(className, sourceCode); - CompilationTask task = getCompilationTask(file); + CompilationTask task = getCompilationTask(file, options); if(!task.call()) { throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode); @@ -146,7 +147,7 @@ public class InMemoryJavaCompiler { return ToolProvider.getSystemJavaCompiler(); } - private static CompilationTask getCompilationTask(MemoryJavaFileObject file) { - return getCompiler().getTask(null, new FileManagerWrapper(file), null, null, null, Arrays.asList(file)); + private static CompilationTask getCompilationTask(MemoryJavaFileObject file, String... options) { + return getCompiler().getTask(null, new FileManagerWrapper(file), null, Arrays.asList(options), null, Arrays.asList(file)); } } diff --git a/hotspot/test/testlibrary/jdk/test/lib/Platform.java b/hotspot/test/testlibrary/jdk/test/lib/Platform.java index ecd6a0f64d5..64773223556 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/Platform.java +++ b/hotspot/test/testlibrary/jdk/test/lib/Platform.java @@ -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 @@ -203,4 +203,31 @@ public class Platform { public static boolean canAttachOSX() throws Exception { return userName.equals("root"); } + + /** + * return path to library inside jdk tree + */ + public static String jdkLibPath() { + if (isWindows()) { + return "bin"; + } + if (isOSX()) { + return "lib"; + } + + return "lib/" + getOsArch(); + } + + /** + * Build name of shared object according to platform rules + */ + public static String sharedObjectName(String name) { + if (isWindows()) { + return name + ".dll"; + } + if (isOSX()) { + return "lib" + name + ".dylib"; + } + return "lib" + name + ".so"; + } } diff --git a/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java b/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java index e1bb112ceb3..5fd3326c173 100644 --- a/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java +++ b/hotspot/test/testlibrary/jdk/test/lib/cli/CommandLineOptionTest.java @@ -101,6 +101,7 @@ public abstract class CommandLineOptionTest { throws Throwable { List finalOptions = new ArrayList<>(); if (addTestVMOptions) { + Collections.addAll(finalOptions, ProcessTools.getVmInputArgs()); Collections.addAll(finalOptions, Utils.getTestJavaOpts()); } Collections.addAll(finalOptions, options); diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java new file mode 100644 index 00000000000..367e46965c0 --- /dev/null +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2012, 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. + * + */ + +package sun.hotspot; + +import java.lang.reflect.Executable; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Stream; +import java.security.BasicPermission; + +import sun.hotspot.parser.DiagnosticCommand; + +public class WhiteBox { + + @SuppressWarnings("serial") + public static class WhiteBoxPermission extends BasicPermission { + public WhiteBoxPermission(String s) { + super(s); + } + } + + private WhiteBox() {} + private static final WhiteBox instance = new WhiteBox(); + private static native void registerNatives(); + + /** + * Returns the singleton WhiteBox instance. + * + * The returned WhiteBox object should be carefully guarded + * by the caller, since it can be used to read and write data + * at arbitrary memory addresses. It must never be passed to + * untrusted code. + */ + public synchronized static WhiteBox getWhiteBox() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new WhiteBoxPermission("getInstance")); + } + return instance; + } + + static { + registerNatives(); + } + + // Get the maximum heap size supporting COOPs + public native long getCompressedOopsMaxHeapSize(); + // Arguments + public native void printHeapSizes(); + + // Memory + public native long getObjectAddress(Object o); + public native int getHeapOopSize(); + public native int getVMPageSize(); + public native boolean isObjectInOldGen(Object o); + public native long getObjectSize(Object o); + + // Runtime + // Make sure class name is in the correct format + public boolean isClassAlive(String name) { + return isClassAlive0(name.replace('.', '/')); + } + private native boolean isClassAlive0(String name); + + // JVMTI + public native void addToBootstrapClassLoaderSearch(String segment); + public native void addToSystemClassLoaderSearch(String segment); + + // G1 + public native boolean g1InConcurrentMark(); + public native boolean g1IsHumongous(Object o); + public native long g1NumFreeRegions(); + public native int g1RegionSize(); + public native Object[] parseCommandLine(String commandline, char delim, DiagnosticCommand[] args); + + // NMT + public native long NMTMalloc(long size); + public native void NMTFree(long mem); + public native long NMTReserveMemory(long size); + public native void NMTCommitMemory(long addr, long size); + public native void NMTUncommitMemory(long addr, long size); + public native void NMTReleaseMemory(long addr, long size); + public native long NMTMallocWithPseudoStack(long size, int index); + public native boolean NMTIsDetailSupported(); + public native boolean NMTChangeTrackingLevel(); + public native int NMTGetHashSize(); + + // Compiler + public native void deoptimizeAll(); + public boolean isMethodCompiled(Executable method) { + return isMethodCompiled(method, false /*not osr*/); + } + public native boolean isMethodCompiled(Executable method, boolean isOsr); + public boolean isMethodCompilable(Executable method) { + return isMethodCompilable(method, -1 /*any*/); + } + public boolean isMethodCompilable(Executable method, int compLevel) { + return isMethodCompilable(method, compLevel, false /*not osr*/); + } + public native boolean isMethodCompilable(Executable method, int compLevel, boolean isOsr); + public native boolean isMethodQueuedForCompilation(Executable method); + public int deoptimizeMethod(Executable method) { + return deoptimizeMethod(method, false /*not osr*/); + } + public native int deoptimizeMethod(Executable method, boolean isOsr); + public void makeMethodNotCompilable(Executable method) { + makeMethodNotCompilable(method, -1 /*any*/); + } + public void makeMethodNotCompilable(Executable method, int compLevel) { + makeMethodNotCompilable(method, compLevel, false /*not osr*/); + } + public native void makeMethodNotCompilable(Executable method, int compLevel, boolean isOsr); + public int getMethodCompilationLevel(Executable method) { + return getMethodCompilationLevel(method, false /*not ost*/); + } + public native int getMethodCompilationLevel(Executable method, boolean isOsr); + public native boolean testSetDontInlineMethod(Executable method, boolean value); + public int getCompileQueuesSize() { + return getCompileQueueSize(-1 /*any*/); + } + public native int getCompileQueueSize(int compLevel); + public native boolean testSetForceInlineMethod(Executable method, boolean value); + public boolean enqueueMethodForCompilation(Executable method, int compLevel) { + return enqueueMethodForCompilation(method, compLevel, -1 /*InvocationEntryBci*/); + } + public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); + public native void clearMethodState(Executable method); + public native void lockCompilation(); + public native void unlockCompilation(); + public native int getMethodEntryBci(Executable method); + public native Object[] getNMethod(Executable method, boolean isOsr); + public native long allocateCodeBlob(int size, int type); + public long allocateCodeBlob(long size, int type) { + int intSize = (int) size; + if ((long) intSize != size || size < 0) { + throw new IllegalArgumentException( + "size argument has illegal value " + size); + } + return allocateCodeBlob( intSize, type); + } + public native void freeCodeBlob(long addr); + public void forceNMethodSweep() { + try { + forceNMethodSweep0().join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + public native Thread forceNMethodSweep0(); + public native Object[] getCodeHeapEntries(int type); + public native int getCompilationActivityMode(); + public native Object[] getCodeBlob(long addr); + + // Intered strings + public native boolean isInStringTable(String str); + + // Memory + public native void readReservedMemory(); + public native long allocateMetaspace(ClassLoader classLoader, long size); + public native void freeMetaspace(ClassLoader classLoader, long addr, long size); + public native long incMetaspaceCapacityUntilGC(long increment); + public native long metaspaceCapacityUntilGC(); + + // Force Young GC + public native void youngGC(); + + // Force Full GC + public native void fullGC(); + + // Method tries to start concurrent mark cycle. + // It returns false if CM Thread is always in concurrent cycle. + public native boolean g1StartConcMarkCycle(); + + // Tests on ReservedSpace/VirtualSpace classes + public native int stressVirtualSpaceResize(long reservedSpaceSize, long magnitude, long iterations); + public native void runMemoryUnitTests(); + public native void readFromNoaccessArea(); + public native long getThreadStackSize(); + public native long getThreadRemainingStackSize(); + + // CPU features + public native String getCPUFeatures(); + + // Native extensions + public native long getHeapUsageForContext(int context); + public native long getHeapRegionCountForContext(int context); + public native int getContextForObject(Object obj); + public native void printRegionInfo(int context); + + // VM flags + public native boolean isConstantVMFlag(String name); + public native boolean isLockedVMFlag(String name); + public native void setBooleanVMFlag(String name, boolean value); + public native void setIntxVMFlag(String name, long value); + public native void setUintxVMFlag(String name, long value); + public native void setUint64VMFlag(String name, long value); + public native void setSizeTVMFlag(String name, long value); + public native void setStringVMFlag(String name, String value); + public native void setDoubleVMFlag(String name, double value); + public native Boolean getBooleanVMFlag(String name); + public native Long getIntxVMFlag(String name); + public native Long getUintxVMFlag(String name); + public native Long getUint64VMFlag(String name); + public native Long getSizeTVMFlag(String name); + public native String getStringVMFlag(String name); + public native Double getDoubleVMFlag(String name); + private final List> flagsGetters = Arrays.asList( + this::getBooleanVMFlag, this::getIntxVMFlag, this::getUintxVMFlag, + this::getUint64VMFlag, this::getSizeTVMFlag, this::getStringVMFlag, + this::getDoubleVMFlag); + + public Object getVMFlag(String name) { + return flagsGetters.stream() + .map(f -> f.apply(name)) + .filter(x -> x != null) + .findAny() + .orElse(null); + } + + // Jigsaw + public native Object DefineModule(String name, Object loader, Object[] packages); + public native void AddModuleExports(Object from_module, String pkg, Object to_module); + public native void AddReadsModule(Object from_module, Object to_module); + public native boolean CanReadModule(Object asking_module, Object target_module); + public native boolean IsExportedToModule(Object from_module, String pkg, Object to_module); + public native Object GetModule(Class clazz); + public native void AddModulePackage(Object module, String pkg); + + // Image File + public native boolean readImageFile(String imagefile); + + public native int getOffsetForName0(String name); + public int getOffsetForName(String name) throws Exception { + int offset = getOffsetForName0(name); + if (offset == -1) { + throw new RuntimeException(name + " not found"); + } + return offset; + } + +} diff --git a/jaxp/.hgtags b/jaxp/.hgtags index b070406ac71..734c6534aa5 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -351,3 +351,5 @@ bdbf2342b21bd8ecad1b4e6499a0dfb314952bd7 jdk-9+103 65d615f71e81bae46dcb4d053e590582e5705879 jdk-9+106 781b83dadcae89b8ae7545bb4044ddc62c6fa006 jdk-9+107 3b9fa8b1491479f7ae18131a34036b58b647493e jdk-9+108 +24e247ee1fffaa625d480b2a4eef2d3a8a59f5cb jdk-9+109 +1c1bb661d35b846dc04931bd5f687a0348f80345 jdk-9+110 diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java index 1e6be9a9d85..47534bc4a8e 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/DOM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: DOM.java,v 1.2.4.1 2005/08/31 10:18:49 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc; @@ -102,4 +99,5 @@ public interface DOM { public int getDocument(); public String getUnparsedEntityURI(String name); public Map getElementsWithIDs(); + public void release(); } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java index 6d6a47c157a..fbbb5c8e986 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/ApplyTemplates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: ApplyTemplates.java,v 1.2.4.1 2005/09/12 09:59:21 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; @@ -122,12 +119,10 @@ final class ApplyTemplates extends Instruction { final int current = methodGen.getLocalIndex("current"); // check if sorting nodes is required - final Vector sortObjects = new Vector(); - final Iterator children = elements(); - while (children.hasNext()) { - final SyntaxTreeNode child = children.next(); + final Vector sortObjects = new Vector<>(); + for (final SyntaxTreeNode child : getContents()) { if (child instanceof Sort) { - sortObjects.addElement(child); + sortObjects.addElement((Sort)child); } } @@ -193,6 +188,13 @@ final class ApplyTemplates extends Instruction { applyTemplatesSig); il.append(new INVOKEVIRTUAL(applyTemplates)); + // unmap parameters to release temporary result trees + for (final SyntaxTreeNode child : getContents()) { + if (child instanceof WithParam) { + ((WithParam)child).releaseResultTree(classGen, methodGen); + } + } + // Pop parameter frame if (stylesheet.hasLocalParams() || hasContents()) { il.append(classGen.loadTranslet()); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java index caace085213..2e2ca146e84 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/CallTemplate.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -17,18 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: CallTemplate.java,v 1.2.4.1 2005/09/12 10:02:41 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; -import com.sun.org.apache.bcel.internal.generic.ALOAD; -import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionList; -import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; @@ -56,7 +49,7 @@ final class CallTemplate extends Instruction { * this array can be either a WithParam or a Param if no WithParam * exists for a particular parameter. */ - private Object[] _parameters = null; + private SyntaxTreeNode[] _parameters = null; /** * The corresponding template which this CallTemplate calls. @@ -147,11 +140,10 @@ final class CallTemplate extends Instruction { // If calling a simply named template, push actual arguments if (_calleeTemplate != null) { - Vector calleeParams = _calleeTemplate.getParameters(); int numParams = _parameters.length; for (int i = 0; i < numParams; i++) { - SyntaxTreeNode node = (SyntaxTreeNode)_parameters[i]; + SyntaxTreeNode node = _parameters[i]; methodSig.append(OBJECT_SIG); // append Object to signature // Push 'null' if Param to indicate no actual parameter specified @@ -170,6 +162,15 @@ final class CallTemplate extends Instruction { methodName, methodSig.toString()))); + // release temporary result trees + if (_parameters != null) { + for (int i = 0; i < _parameters.length; i++) { + if (_parameters[i] instanceof WithParam) { + ((WithParam)_parameters[i]).releaseResultTree(classGen, methodGen); + } + } + } + // Do not need to call Translet.popParamFrame() if we are // calling a simple named template. if (_calleeTemplate == null && (stylesheet.hasLocalParams() || hasContents())) { @@ -203,9 +204,9 @@ final class CallTemplate extends Instruction { private void buildParameterList() { // Put the parameters from the called template into the array first. // This is to ensure the order of the parameters. - Vector defaultParams = _calleeTemplate.getParameters(); + Vector defaultParams = _calleeTemplate.getParameters(); int numParams = defaultParams.size(); - _parameters = new Object[numParams]; + _parameters = new SyntaxTreeNode[numParams]; for (int i = 0; i < numParams; i++) { _parameters[i] = defaultParams.elementAt(i); } @@ -222,15 +223,15 @@ final class CallTemplate extends Instruction { // Search for a Param with the same name for (int k = 0; k < numParams; k++) { - Object object = _parameters[k]; - if (object instanceof Param - && ((Param)object).getName().equals(name)) { + SyntaxTreeNode parm = _parameters[k]; + if (parm instanceof Param + && ((Param)parm).getName().equals(name)) { withParam.setDoParameterOptimization(true); _parameters[k] = withParam; break; } - else if (object instanceof WithParam - && ((WithParam)object).getName().equals(name)) { + else if (parm instanceof WithParam + && ((WithParam)parm).getName().equals(name)) { withParam.setDoParameterOptimization(true); _parameters[k] = withParam; break; diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java index 6dd5c14a010..b5d9464afdd 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Constants.java @@ -505,4 +505,15 @@ public interface Constants extends InstructionConstants { = "com.sun.org.apache.xalan.internal.xsltc.compiler.Fallback"; public static final int RTF_INITIAL_SIZE = 32; + + // the API packages used by generated translet classes + public static String[] PKGS_USED_BY_TRANSLET_CLASSES = { + "com.sun.org.apache.xalan.internal.lib", + "com.sun.org.apache.xalan.internal.xsltc", + "com.sun.org.apache.xalan.internal.xsltc.runtime", + "com.sun.org.apache.xalan.internal.xsltc.dom", + "com.sun.org.apache.xml.internal.serializer", + "com.sun.org.apache.xml.internal.dtm", + "com.sun.org.apache.xml.internal.dtm.ref", + }; } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java index d8264a23f93..f7309e50125 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Sort.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2005 The Apache Software Foundation. @@ -17,32 +16,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: Sort.java,v 1.2.4.1 2005/09/12 11:08:12 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; -import java.text.Collator; import java.util.ArrayList; -import java.util.NoSuchElementException; -import java.util.StringTokenizer; import java.util.Vector; import com.sun.org.apache.bcel.internal.classfile.Field; -import com.sun.org.apache.bcel.internal.classfile.Method; import com.sun.org.apache.bcel.internal.generic.ALOAD; import com.sun.org.apache.bcel.internal.generic.ANEWARRAY; import com.sun.org.apache.bcel.internal.generic.ASTORE; import com.sun.org.apache.bcel.internal.generic.CHECKCAST; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.GETFIELD; -import com.sun.org.apache.bcel.internal.generic.ICONST; import com.sun.org.apache.bcel.internal.generic.ILOAD; import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; -import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC; -import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionHandle; import com.sun.org.apache.bcel.internal.generic.InstructionList; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; @@ -76,13 +65,10 @@ final class Sort extends Instruction implements Closure { private AttributeValue _order; private AttributeValue _caseOrder; private AttributeValue _dataType; - private String _lang; // bug! see 26869 - - private String _data = null; - + private String _lang; // bug! see 26869 private String _className = null; - private ArrayList _closureVars = null; + private ArrayList _closureVars = null; private boolean _needsSortRecordFactory = false; // -- Begin Closure interface -------------------- @@ -115,7 +101,7 @@ final class Sort extends Instruction implements Closure { */ public void addVariable(VariableRefBase variableRef) { if (_closureVars == null) { - _closureVars = new ArrayList(); + _closureVars = new ArrayList<>(); } // Only one reference per variable @@ -246,7 +232,7 @@ final class Sort extends Instruction implements Closure { public static void translateSortIterator(ClassGenerator classGen, MethodGenerator methodGen, Expression nodeSet, - Vector sortObjects) + Vector sortObjects) { final ConstantPoolGen cpg = classGen.getConstantPool(); final InstructionList il = methodGen.getInstructionList(); @@ -312,7 +298,7 @@ final class Sort extends Instruction implements Closure { * Compiles code that instantiates a NodeSortRecordFactory object which * will produce NodeSortRecord objects of a specific type. */ - public static void compileSortRecordFactory(Vector sortObjects, + public static void compileSortRecordFactory(Vector sortObjects, ClassGenerator classGen, MethodGenerator methodGen) { String sortRecordClass = @@ -321,7 +307,7 @@ final class Sort extends Instruction implements Closure { boolean needsSortRecordFactory = false; final int nsorts = sortObjects.size(); for (int i = 0; i < nsorts; i++) { - final Sort sort = (Sort) sortObjects.elementAt(i); + final Sort sort = sortObjects.elementAt(i); needsSortRecordFactory |= sort._needsSortRecordFactory; } @@ -429,7 +415,7 @@ final class Sort extends Instruction implements Closure { + "[" + STRING_SIG + ")V"))); // Initialize closure variables in sortRecordFactory - final ArrayList dups = new ArrayList(); + final ArrayList dups = new ArrayList<>(); for (int j = 0; j < nsorts; j++) { final Sort sort = (Sort) sortObjects.get(j); @@ -437,7 +423,7 @@ final class Sort extends Instruction implements Closure { sort._closureVars.size(); for (int i = 0; i < length; i++) { - VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i); + VariableRefBase varRef = sort._closureVars.get(i); // Discard duplicate variable references if (dups.contains(varRef)) continue; @@ -455,11 +441,11 @@ final class Sort extends Instruction implements Closure { } } - public static String compileSortRecordFactory(Vector sortObjects, + public static String compileSortRecordFactory(Vector sortObjects, ClassGenerator classGen, MethodGenerator methodGen, String sortRecordClass) { - final XSLTC xsltc = ((Sort)sortObjects.firstElement()).getXSLTC(); + final XSLTC xsltc = (sortObjects.firstElement()).getXSLTC(); final String className = xsltc.getHelperClassName(); final NodeSortRecordFactGenerator sortRecordFactory = @@ -474,15 +460,15 @@ final class Sort extends Instruction implements Closure { // Add a new instance variable for each var in closure final int nsorts = sortObjects.size(); - final ArrayList dups = new ArrayList(); + final ArrayList dups = new ArrayList<>(); for (int j = 0; j < nsorts; j++) { - final Sort sort = (Sort) sortObjects.get(j); + final Sort sort = sortObjects.get(j); final int length = (sort._closureVars == null) ? 0 : sort._closureVars.size(); for (int i = 0; i < length; i++) { - final VariableRefBase varRef = (VariableRefBase) sort._closureVars.get(i); + final VariableRefBase varRef = sort._closureVars.get(i); // Discard duplicate variable references if (dups.contains(varRef)) continue; @@ -600,10 +586,10 @@ final class Sort extends Instruction implements Closure { /** * Create a new auxillary class extending NodeSortRecord. */ - private static String compileSortRecord(Vector sortObjects, + private static String compileSortRecord(Vector sortObjects, ClassGenerator classGen, MethodGenerator methodGen) { - final XSLTC xsltc = ((Sort)sortObjects.firstElement()).getXSLTC(); + final XSLTC xsltc = sortObjects.firstElement().getXSLTC(); final String className = xsltc.getHelperClassName(); // This generates a new class for handling this specific sort @@ -619,10 +605,10 @@ final class Sort extends Instruction implements Closure { // Add a new instance variable for each var in closure final int nsorts = sortObjects.size(); - final ArrayList dups = new ArrayList(); + final ArrayList dups = new ArrayList<>(); for (int j = 0; j < nsorts; j++) { - final Sort sort = (Sort) sortObjects.get(j); + final Sort sort = sortObjects.get(j); // Set the name of the inner class in this sort object sort.setInnerClassName(className); @@ -644,8 +630,7 @@ final class Sort extends Instruction implements Closure { } } - MethodGenerator init = compileInit(sortObjects, sortRecord, - cpg, className); + MethodGenerator init = compileInit(sortRecord, cpg, className); MethodGenerator extract = compileExtract(sortObjects, sortRecord, cpg, className); sortRecord.addMethod(init); @@ -660,8 +645,7 @@ final class Sort extends Instruction implements Closure { * collator in the super calls only when the stylesheet specifies a new * language in xsl:sort. */ - private static MethodGenerator compileInit(Vector sortObjects, - NodeSortRecordGenerator sortRecord, + private static MethodGenerator compileInit(NodeSortRecordGenerator sortRecord, ConstantPoolGen cpg, String className) { @@ -688,7 +672,7 @@ final class Sort extends Instruction implements Closure { /** * Compiles a method that overloads NodeSortRecord.extractValueFromDOM() */ - private static MethodGenerator compileExtract(Vector sortObjects, + private static MethodGenerator compileExtract(Vector sortObjects, NodeSortRecordGenerator sortRecord, ConstantPoolGen cpg, String className) { @@ -730,7 +714,7 @@ final class Sort extends Instruction implements Closure { // Append all the cases for the switch statment for (int level = 0; level < levels; level++) { match[level] = level; - final Sort sort = (Sort)sortObjects.elementAt(level); + final Sort sort = sortObjects.elementAt(level); target[level] = il.append(NOP); sort.translateSelect(sortRecord, extractMethod); il.append(ARETURN); diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java index bfa00213915..3b921a1b815 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/SyntaxTreeNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SyntaxTreeNode.java,v 1.6 2006/06/06 22:34:33 spericas Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; @@ -519,9 +516,9 @@ public abstract class SyntaxTreeNode implements Constants { // references falling out-of-scope inside the for-each element. // (the cause of which being 'lazy' register allocation for references) for (int i = 0; i < n; i++) { - if( _contents.get(i) instanceof VariableBase) { + if ( _contents.get(i) instanceof VariableBase) { final VariableBase var = (VariableBase)_contents.get(i); - var.unmapRegister(methodGen); + var.unmapRegister(classGen, methodGen); } } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java index 9450702c90c..9284f2a03a3 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/Template.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: Template.java,v 1.2.4.1 2005/09/12 11:30:11 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; @@ -63,7 +60,7 @@ public final class Template extends TopLevelElement { // The list of parameters in this template. This is only used // for simple named templates. - private Vector _parameters = new Vector(); + private Vector _parameters = new Vector<>(); public boolean hasParams() { return _parameters.size() > 0; @@ -85,7 +82,7 @@ public final class Template extends TopLevelElement { _parameters.addElement(param); } - public Vector getParameters() { + public Vector getParameters() { return _parameters; } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java index 7ef4c1cabd6..02e1a5f3ef4 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/VariableBase.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -17,18 +16,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: VariableBase.java,v 1.5 2005/09/28 13:48:18 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; import java.util.Vector; +import com.sun.org.apache.bcel.internal.generic.CHECKCAST; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; import com.sun.org.apache.bcel.internal.generic.Instruction; import com.sun.org.apache.bcel.internal.generic.InstructionList; +import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKESPECIAL; +import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.NEW; import com.sun.org.apache.bcel.internal.generic.PUSH; @@ -36,6 +35,7 @@ import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.NodeSetType; +import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ResultTreeType; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Type; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util; import com.sun.org.apache.xml.internal.utils.XML11Char; @@ -49,21 +49,18 @@ import com.sun.org.apache.xml.internal.utils.XML11Char; */ class VariableBase extends TopLevelElement { - protected QName _name; // The name of the variable. - protected String _escapedName; // The escaped qname of the variable. - protected Type _type; // The type of this variable. - protected boolean _isLocal; // True if the variable is local. - protected LocalVariableGen _local; // Reference to JVM variable - protected Instruction _loadInstruction; // Instruction to load JVM variable + protected QName _name; // The name of the variable. + protected String _escapedName; // The escaped qname of the variable. + protected Type _type; // The type of this variable. + protected boolean _isLocal; // True if the variable is local. + protected LocalVariableGen _local; // Reference to JVM variable + protected Instruction _loadInstruction; // Instruction to load JVM variable protected Instruction _storeInstruction; // Instruction to load JVM variable - protected Expression _select; // Reference to variable expression - protected String select; // Textual repr. of variable expr. + protected Expression _select; // Reference to variable expression + protected String select; // Textual repr. of variable expr. // References to this variable (when local) - protected Vector _refs = new Vector(2); - - // Dependencies to other variables/parameters (for globals only) - protected Vector _dependencies = null; + protected Vector _refs = new Vector<>(2); // Used to make sure parameter field is not added twice protected boolean _ignore = false; @@ -92,7 +89,7 @@ class VariableBase extends TopLevelElement { public void copyReferences(VariableBase var) { final int size = _refs.size(); for (int i = 0; i < size; i++) { - var.addReference((VariableRefBase) _refs.get(i)); + var.addReference(_refs.get(i)); } } @@ -112,8 +109,24 @@ class VariableBase extends TopLevelElement { * Remove the mapping of this variable to a register. * Called when we leave the AST scope of the variable's declaration */ - public void unmapRegister(MethodGenerator methodGen) { + public void unmapRegister(ClassGenerator classGen, MethodGenerator methodGen) { if (_local != null) { + if (_type instanceof ResultTreeType) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + if (classGen.getStylesheet().callsNodeset() && classGen.getDOMClass().equals(MULTI_DOM_CLASS)) { + final int removeDA = cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter", "(" + DOM_ADAPTER_SIG + ")V"); + il.append(methodGen.loadDOM()); + il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS))); + il.append(loadInstruction()); + il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS))); + il.append(new INVOKEVIRTUAL(removeDA)); + } + final int release = cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V"); + il.append(loadInstruction()); + il.append(new INVOKEINTERFACE(release, 1)); + } + _local.setEnd(methodGen.getInstructionList().getEnd()); methodGen.removeLocalVariable(_local); _refs = null; @@ -126,7 +139,6 @@ class VariableBase extends TopLevelElement { * the JVM stack. */ public Instruction loadInstruction() { - final Instruction instr = _loadInstruction; if (_loadInstruction == null) { _loadInstruction = _type.LOAD(_local.getIndex()); } @@ -138,7 +150,6 @@ class VariableBase extends TopLevelElement { * into this variable. */ public Instruction storeInstruction() { - final Instruction instr = _storeInstruction; if (_storeInstruction == null) { _storeInstruction = _type.STORE(_local.getIndex()); } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java index 3a87d59313c..fc2b202ceea 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/WithParam.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 2001-2004 The Apache Software Foundation. @@ -17,15 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: WithParam.java,v 1.2.4.1 2005/09/12 11:38:01 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.compiler; +import com.sun.org.apache.bcel.internal.generic.ALOAD; +import com.sun.org.apache.bcel.internal.generic.ASTORE; +import com.sun.org.apache.bcel.internal.generic.CHECKCAST; import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; +import com.sun.org.apache.bcel.internal.generic.INVOKEINTERFACE; import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL; import com.sun.org.apache.bcel.internal.generic.InstructionList; +import com.sun.org.apache.bcel.internal.generic.LocalVariableGen; import com.sun.org.apache.bcel.internal.generic.PUSH; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; @@ -59,6 +60,11 @@ final class WithParam extends Instruction { */ private Expression _select; + /** + * Reference to JVM variable holding temporary result tree. + */ + private LocalVariableGen _domAdapter; + /** * %OPT% This is set to true when the WithParam is used in a CallTemplate * for a simple named template. If this is true, the parameters are @@ -164,8 +170,13 @@ final class WithParam extends Instruction { _select.startIterator(classGen, methodGen); } // If not, compile result tree from parameter body if present. + // Store result tree into local variable for releasing it later else if (hasContents()) { + final InstructionList il = methodGen.getInstructionList(); compileResultTree(classGen, methodGen); + _domAdapter = methodGen.addLocalVariable2("@" + _escapedName, Type.ResultTree.toJCType(), il.getEnd()); + il.append(DUP); + il.append(new ASTORE(_domAdapter.getIndex())); } // If neither are present then store empty string in parameter slot else { @@ -208,4 +219,26 @@ final class WithParam extends Instruction { ADD_PARAMETER_SIG))); il.append(POP); // cleanup stack } + + /** + * Release the compiled result tree. + */ + public void releaseResultTree(ClassGenerator classGen, MethodGenerator methodGen) { + if (_domAdapter != null) { + final ConstantPoolGen cpg = classGen.getConstantPool(); + final InstructionList il = methodGen.getInstructionList(); + if (classGen.getStylesheet().callsNodeset() && classGen.getDOMClass().equals(MULTI_DOM_CLASS)) { + final int removeDA = cpg.addMethodref(MULTI_DOM_CLASS, "removeDOMAdapter", "(" + DOM_ADAPTER_SIG + ")V"); + il.append(methodGen.loadDOM()); + il.append(new CHECKCAST(cpg.addClass(MULTI_DOM_CLASS))); + il.append(new ALOAD(_domAdapter.getIndex())); + il.append(new CHECKCAST(cpg.addClass(DOM_ADAPTER_CLASS))); + il.append(new INVOKEVIRTUAL(removeDA)); + } + final int release = cpg.addInterfaceMethodref(DOM_IMPL_CLASS, "release", "()V"); + il.append(new ALOAD(_domAdapter.getIndex())); + il.append(new INVOKEINTERFACE(release, 1)); + _domAdapter = null; + } + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java index efbbe789d67..9c771af6f07 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/XSLTC.java @@ -47,6 +47,7 @@ import java.util.Enumeration; import java.util.HashMap; import java.util.Map; import java.util.Properties; +import java.util.Objects; import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; @@ -115,7 +116,7 @@ public final class XSLTC { private boolean _debug = false; // -x private String _jarFileName = null; // -j private String _className = null; // -o - private String _packageName = null; // -p + private String _packageName = "die.verwandlung"; // override with -p private File _destDir = null; // -d private int _outputType = FILE_OUTPUT; // by default @@ -724,7 +725,7 @@ public final class XSLTC { * Set an optional package name for the translet and auxiliary classes */ public void setPackageName(String packageName) { - _packageName = packageName; + _packageName = Objects.requireNonNull(packageName); if (_className != null) setClassName(_className); } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java index fc1b1d9412c..cb50cf5d779 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/AdaptiveResultTreeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: AdaptiveResultTreeImpl.java,v 1.2.4.1 2005/09/06 05:52:18 pvedula Exp $ - */ + package com.sun.org.apache.xalan.internal.xsltc.dom; import com.sun.org.apache.xalan.internal.xsltc.DOM; @@ -1338,4 +1336,11 @@ public class AdaptiveResultTreeImpl extends SimpleResultTreeImpl } } + public void release() { + if (_dom != null) { + _dom.release(); + _dom = null; + } + super.release(); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java index a12d9e42c85..4f44ae1baa6 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/DOMAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: DOMAdapter.java,v 1.2.4.1 2005/09/06 06:07:28 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.dom; @@ -56,8 +53,6 @@ public final class DOMAdapter implements DOM { private short[] _NSmapping = null; private short[] _NSreverse = null; - private StripFilter _filter = null; - private int _multiDOMMask; public DOMAdapter(DOM dom, @@ -165,9 +160,7 @@ public final class DOMAdapter implements DOM { } } - public void setFilter(StripFilter filter) { - _filter = filter; - } + public void setFilter(StripFilter filter) {} public DTMAxisIterator getTypedChildren(final int type) { final int[] reverse = getReverse(); @@ -464,4 +457,8 @@ public final class DOMAdapter implements DOM { public Map getElementsWithIDs() { return _dom.getElementsWithIDs(); } + + public void release() { + _dom.release(); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java index fae254fabc8..cf22c31920f 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/MultiDOM.java @@ -1,7 +1,6 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ - /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -30,8 +29,8 @@ import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.dtm.DTMManager; import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIteratorBase; -import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIterNodeList; +import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; import com.sun.org.apache.xml.internal.utils.SuballocatedIntVector; import java.util.HashMap; @@ -671,4 +670,51 @@ public final class MultiDOM implements DOM { public Map getElementsWithIDs() { return _main.getElementsWithIDs(); } + + public void release() { + _main.release(); + } + + private boolean isMatchingAdapterEntry(DOM entry, DOMAdapter adapter) { + DOM dom = adapter.getDOMImpl(); + + return (entry == adapter) || ( + /* + * Method addDOMAdapter overwrites for AdaptiveResultTreeImpl + * objects the usual entry with an adapter to the nested + * DOM, so we must check this here. See last 'if' statement + * of addDOMAdapter. + */ + (dom instanceof AdaptiveResultTreeImpl) && + (entry instanceof DOMAdapter) && + (((AdaptiveResultTreeImpl)dom).getNestedDOM() == ((DOMAdapter)entry).getDOMImpl()) + ); + } + + public void removeDOMAdapter(DOMAdapter adapter) { + _documents.remove(adapter.getDocumentURI(0)); + DOM dom = adapter.getDOMImpl(); + + if (dom instanceof DTMDefaultBase) { + SuballocatedIntVector ids = ((DTMDefaultBase) dom).getDTMIDs(); + int idsSize = ids.size(); + for (int i = 0; i < idsSize; i++) { + _adapters[ids.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS] = null; + } + } else { + int id = dom.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS; + if ((id > 0) && (id < _adapters.length) && isMatchingAdapterEntry(_adapters[id], adapter)) { + _adapters[id] = null; + } else { + boolean found = false; + for (int i = 0; i < _adapters.length; i++) { + if (isMatchingAdapterEntry(_adapters[id], adapter)) { + _adapters[i] = null; + found = true; + break; + } + } + } + } + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java index c6b06931702..9a8bc34892a 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SAXImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -17,9 +17,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SAXImpl.java,v 1.5 2005/09/28 13:48:37 pvedula Exp $ - */ package com.sun.org.apache.xalan.internal.xsltc.dom; @@ -82,7 +79,7 @@ public final class SAXImpl extends SAX2DTM2 // Namespace prefix-to-uri mapping stuff private int _uriCount = 0; - private int _prefixCount = 0; + // private int _prefixCount = 0; // Stack used to keep track of what whitespace text nodes are protected // by xml:space="preserve" attributes and which nodes that are not. @@ -90,11 +87,11 @@ public final class SAXImpl extends SAX2DTM2 private int _idx = 1; private boolean _preserve = false; - private static final String XML_STRING = "xml:"; + // private static final String XML_STRING = "xml:"; private static final String XML_PREFIX = "xml"; private static final String XMLSPACE_STRING = "xml:space"; private static final String PRESERVE_STRING = "preserve"; - private static final String XMLNS_PREFIX = "xmlns"; + // private static final String XMLNS_PREFIX = "xmlns"; private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; private boolean _escaping = true; @@ -123,7 +120,7 @@ public final class SAXImpl extends SAX2DTM2 private BitArray _dontEscape = null; // The URI to this document - private String _documentURI = null; + // private String _documentURI = null; static private int _documentURIIndex = 0; // The owner Document when the input source is DOMSource. @@ -143,8 +140,7 @@ public final class SAXImpl extends SAX2DTM2 // Support for access/navigation through org.w3c.dom API private Node[] _nodes; private NodeList[] _nodeLists; - private final static String XML_LANG_ATTRIBUTE = - "http://www.w3.org/XML/1998/namespace:@lang"; + // private final static String XML_LANG_ATTRIBUTE = "http://www.w3.org/XML/1998/namespace:@lang"; /** * Define the origin of the document from which the tree was built @@ -491,6 +487,7 @@ public final class SAXImpl extends SAX2DTM2 /** * Sets up a translet-to-dom type mapping table */ + /* private int[] setupMapping(String[] names, String[] uris, int[] types, int nNames) { // Padding with number of names, because they // may need to be added, i.e for RTFs. See copy03 @@ -502,6 +499,7 @@ public final class SAXImpl extends SAX2DTM2 } return result; } + */ /** * Returns the internal type associated with an expanded QName @@ -1230,9 +1228,6 @@ public final class SAXImpl extends SAX2DTM2 */ public DTMAxisIterator getNamespaceAxisIterator(int axis, int ns) { - - DTMAxisIterator iterator = null; - if (ns == NO_TYPE) { return EMPTYITERATOR; } @@ -1546,7 +1541,6 @@ public final class SAXImpl extends SAX2DTM2 */ public DTMAxisIterator getNthDescendant(int type, int n, boolean includeself) { - DTMAxisIterator source = (DTMAxisIterator) new TypedDescendantIterator(type); return new NthDescendantIterator(n); } @@ -1882,4 +1876,7 @@ public final class SAXImpl extends SAX2DTM2 } } + public void release() { + _dtmManager.release(this, true); + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java index 6739458a94b..812258a8f76 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/dom/SimpleResultTreeImpl.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright 1999-2004 The Apache Software Foundation. @@ -17,15 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * $Id: SimpleResultTreeImpl.java,v 1.2.4.1 2005/09/06 10:09:25 pvedula Exp $ - */ + package com.sun.org.apache.xalan.internal.xsltc.dom; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.StripFilter; import com.sun.org.apache.xalan.internal.xsltc.TransletException; - import com.sun.org.apache.xml.internal.dtm.Axis; import com.sun.org.apache.xml.internal.dtm.DTM; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; @@ -1014,4 +1010,12 @@ public class SimpleResultTreeImpl extends EmptySerializer implements DOM, DTM public void migrateTo(DTMManager manager) { } + + public void release() + { + if (_documentID != 0) { + _dtmManager.release(this, true); + _documentID = 0; + } + } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java index e0ee6fbf8ad..bab16095c03 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TemplatesImpl.java @@ -28,6 +28,7 @@ import com.sun.org.apache.xalan.internal.utils.ObjectFactory; import com.sun.org.apache.xalan.internal.utils.SecuritySupport; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.Translet; +import com.sun.org.apache.xalan.internal.xsltc.compiler.Constants; import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import java.io.IOException; @@ -36,8 +37,11 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; import java.security.AccessController; import java.security.PrivilegedAction; +import java.lang.reflect.Module; import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -47,6 +51,8 @@ import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.URIResolver; +import jdk.internal.module.Modules; + /** * @author Morten Jorgensen * @author G. Todd Millerj @@ -410,6 +416,31 @@ public final class TemplatesImpl implements Templates, Serializable { _auxClasses = new HashMap<>(); } + // create a module for the translet + Module xmlModule = TemplatesImpl.class.getModule(); + String pn = _tfactory.getPackageName(); + assert pn != null && pn.length() > 0; + + Module m = Modules.defineModule(loader, "jdk.translet", + Collections.singleton(pn)); + + // jdk.translate reads java.base && java.xml + Modules.addReads(m, Object.class.getModule()); + Modules.addReads(m, xmlModule); + + // jdk.translet needs access to runtime classes + Arrays.asList(Constants.PKGS_USED_BY_TRANSLET_CLASSES).forEach(p -> { + xmlModule.addExports(p, m); + }); + + // jdk.translate also needs to be loose as the XSL may bind to + // java types in an unnamed module + Modules.addReads(m, null); + + // java.xml needs to instanitate the translate class + xmlModule.addReads(m); + Modules.addExports(m, pn, xmlModule); + for (int i = 0; i < classCount; i++) { _class[i] = loader.defineClass(_bytecodes[i]); final Class superClass = _class[i].getSuperclass(); @@ -434,7 +465,7 @@ public final class TemplatesImpl implements Templates, Serializable { } catch (LinkageError e) { ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name); - throw new TransformerConfigurationException(err.toString()); + throw new TransformerConfigurationException(err.toString(), e); } } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java index 24e07ae1859..261853c6367 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java @@ -137,7 +137,8 @@ public class TransformerFactoryImpl /** * The package name prefix for all generated translet classes */ - private String _packageName = null; + private static final String DEFAULT_TRANSLATE_PACKAGE = "die.verwandlung"; + private String _packageName = DEFAULT_TRANSLATE_PACKAGE; /** * The jar file name which the translet classes are packaged into @@ -307,6 +308,13 @@ public class TransformerFactoryImpl return _errorListener; } + /** + * Returns the package name. + */ + String getPackageName() { + return _packageName; + } + /** * javax.xml.transform.sax.TransformerFactory implementation. * Returns the value set for a TransformerFactory attribute @@ -884,7 +892,7 @@ public class TransformerFactoryImpl String transletClassName = getTransletBaseName(source); if (_packageName != null) - transletClassName = _packageName + "." + transletClassName; + transletClassName = _packageName + "." + transletClassName; if (_jarFileName != null) bytecodes = getBytecodesFromJar(source, transletClassName); @@ -1286,7 +1294,7 @@ public class TransformerFactoryImpl private void resetTransientAttributes() { _transletName = DEFAULT_TRANSLET_NAME; _destinationDirectory = null; - _packageName = null; + _packageName = DEFAULT_TRANSLATE_PACKAGE; _jarFileName = null; } diff --git a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java index f216fc91a8b..fe37af57234 100644 --- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java +++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/compiler/FunctionTable.java @@ -24,7 +24,6 @@ */ package com.sun.org.apache.xpath.internal.compiler; -import com.sun.org.apache.xpath.internal.Expression; import com.sun.org.apache.xpath.internal.functions.Function; import java.util.HashMap; import javax.xml.transform.TransformerException; @@ -341,11 +340,12 @@ public class FunctionTable throws javax.xml.transform.TransformerException { try{ - if (which < NUM_BUILT_IN_FUNCS) + if (which < NUM_BUILT_IN_FUNCS) { return (Function) m_functions[which].newInstance(); - else - return (Function) m_functions_customer[ - which-NUM_BUILT_IN_FUNCS].newInstance(); + } else { + Class c = m_functions_customer[which-NUM_BUILT_IN_FUNCS]; + return (Function) c.newInstance(); + } }catch (IllegalAccessException ex){ throw new TransformerException(ex.getMessage()); }catch (InstantiationException ex){ diff --git a/jaxp/src/java.xml/share/classes/module-info.java b/jaxp/src/java.xml/share/classes/module-info.java new file mode 100644 index 00000000000..3bd3fa340e7 --- /dev/null +++ b/jaxp/src/java.xml/share/classes/module-info.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.xml { + exports javax.xml; + exports javax.xml.catalog; + exports javax.xml.datatype; + exports javax.xml.namespace; + exports javax.xml.parsers; + exports javax.xml.stream; + exports javax.xml.stream.events; + exports javax.xml.stream.util; + exports javax.xml.transform; + exports javax.xml.transform.dom; + exports javax.xml.transform.sax; + exports javax.xml.transform.stax; + exports javax.xml.transform.stream; + exports javax.xml.validation; + exports javax.xml.xpath; + exports org.w3c.dom; + exports org.w3c.dom.bootstrap; + exports org.w3c.dom.events; + exports org.w3c.dom.ls; + exports org.w3c.dom.ranges; + exports org.w3c.dom.traversal; + exports org.w3c.dom.views; + exports org.xml.sax; + exports org.xml.sax.ext; + exports org.xml.sax.helpers; + exports com.sun.org.apache.xerces.internal.dom to + java.xml.ws; + exports com.sun.org.apache.xerces.internal.jaxp to + java.xml.ws; + exports com.sun.org.apache.xerces.internal.util to + java.xml.ws; + exports com.sun.org.apache.xml.internal.dtm to + java.xml.crypto; + exports com.sun.org.apache.xml.internal.resolver to + java.xml.ws, + jdk.xml.bind; + exports com.sun.org.apache.xml.internal.resolver.tools to + java.xml.ws, + jdk.xml.bind; + exports com.sun.org.apache.xml.internal.utils to + java.xml.crypto; + exports com.sun.org.apache.xpath.internal to + java.xml.crypto; + exports com.sun.org.apache.xpath.internal.compiler to + java.xml.crypto; + exports com.sun.org.apache.xpath.internal.functions to + java.xml.crypto; + exports com.sun.org.apache.xpath.internal.objects to + java.xml.crypto; + exports com.sun.org.apache.xpath.internal.res to + java.xml.crypto; + // reflection access from com.sun.xml.internal.ws.api.streaming.XMLStreamWriterFactory + exports com.sun.xml.internal.stream.writers to java.xml.ws; + uses javax.xml.datatype.DatatypeFactory; + uses javax.xml.parsers.DocumentBuilderFactory; + uses javax.xml.parsers.SAXParserFactory; + uses javax.xml.stream.XMLEventFactory; + uses javax.xml.stream.XMLInputFactory; + uses javax.xml.stream.XMLOutputFactory; + uses javax.xml.transform.TransformerFactory; + uses javax.xml.validation.SchemaFactory; + uses javax.xml.xpath.XPathFactory; +} + diff --git a/jaxp/src/jdk.xml.dom/share/classes/module-info.java b/jaxp/src/jdk.xml.dom/share/classes/module-info.java new file mode 100644 index 00000000000..a75c8f36b78 --- /dev/null +++ b/jaxp/src/jdk.xml.dom/share/classes/module-info.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module jdk.xml.dom { + requires public java.xml; + exports org.w3c.dom.css; + exports org.w3c.dom.html; + exports org.w3c.dom.stylesheets; + exports org.w3c.dom.xpath; +} + diff --git a/jaxp/test/TEST.ROOT b/jaxp/test/TEST.ROOT index b78892aa12d..4b6b17dc499 100644 --- a/jaxp/test/TEST.ROOT +++ b/jaxp/test/TEST.ROOT @@ -18,4 +18,4 @@ othervm.dirs=javax/xml/jaxp groups=TEST.groups # Minimum jtreg version -requiredVersion=4.1 b12 +requiredVersion=4.2 b01 diff --git a/jaxp/test/javax/xml/jaxp/unittest/TEST.properties b/jaxp/test/javax/xml/jaxp/unittest/TEST.properties index b39bb203ffc..93da2fdba82 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/TEST.properties +++ b/jaxp/test/javax/xml/jaxp/unittest/TEST.properties @@ -4,5 +4,5 @@ TestNG.dirs = . lib.dirs = /javax/xml/jaxp/libs # Declare module dependency -modules=java.xml - +modules=java.xml/com.sun.org.apache.xerces.internal.jaxp \ + java.xml/com.sun.org.apache.xml.internal.serialize diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out deleted file mode 100644 index e946a45a944..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341.out +++ /dev/null @@ -1,19 +0,0 @@ - - -10016 -Wed May 29 12:45:00 PDT 2002 - -ABC -XYZ -1234 Anywhere Street -Palo Alto -California -USA -94303 -NULL -NULL - - - - - \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java index f0dc71feb5a..8daef2e5cce 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ package transform; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.net.URL; import javax.xml.parsers.SAXParser; @@ -45,16 +46,27 @@ import org.xml.sax.helpers.DefaultHandler; * @summary Test transform with external dtd. */ public class Bug4693341Test { + // save dtd file to current working directory to avoid writing into source repository + public void copyDTDtoWorkDir() throws IOException { + try (FileInputStream dtdres = new FileInputStream(getClass().getResource("Bug4693341.dtd").getPath()); + FileOutputStream dtdwork = new FileOutputStream("Bug4693341.dtd");) { + int n; + byte[] buffer = new byte[1024]; + while((n = dtdres.read(buffer)) > -1) { + dtdwork.write(buffer, 0, n); + } + } + } @Test public void test() { - boolean status = false; - try { Transformer transformer = TransformerFactory.newInstance().newTransformer(); - String out = getClass().getResource("Bug4693341.out").getPath(); - StreamResult result = new StreamResult(new FileOutputStream(out)); + copyDTDtoWorkDir(); + + File outf = new File("Bug4693341.out"); + StreamResult result = new StreamResult(new FileOutputStream(outf)); String in = getClass().getResource("Bug4693341.xml").getPath(); File file = new File(in); @@ -63,7 +75,7 @@ public class Bug4693341Test { transformer.transform(source, result); //URL inputsource = new URL("file", "", golden); - URL output = new URL("file", "", out); + URL output = new URL("file", "", outf.getPath()); // error happens when trying to parse output String systemId = output.toExternalForm(); @@ -71,10 +83,8 @@ public class Bug4693341Test { InputSource is = new InputSource(systemId); SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); parser.parse(is, new DefaultHandler()); - } catch (Exception ex) { Assert.fail(ex.getMessage()); } } - } diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd deleted file mode 100644 index 9e4dd578483..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.dtd +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml deleted file mode 100644 index 5c0928e85ab..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug4693341_golden.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - -10016 -Wed May 29 12:45:00 PDT 2002 - -ABC -XYZ -1234 Anywhere Street -Palo Alto -California -USA -94303 -NULL -NULL - - - - - diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java deleted file mode 100644 index d3fa4fd30f4..00000000000 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug6505031.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package transform; - -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.testng.Assert; -import org.testng.annotations.Test; - -/* - * @bug 6505031 - * @summary Test transformer parses keys and their values coming from different xml documents. - */ -public class Bug6505031 { - - private String getResource(String s) { - return getClass().getResource(s).toString(); - - } - - @Test - public void test() { - Map params = new HashMap(); - - params.put("config", getResource("config.xml")); - params.put("mapsFile", getResource("maps.xml")); - generate(getResource("template.xml"), getResource("transform.xsl"), params); - } - - private void generate(String in, String xsl, Map params) { - try { - Transformer transformer = getTransformer(xsl); - - for (Iterator i = params.entrySet().iterator(); i.hasNext();) { - Map.Entry entry = (Map.Entry) i.next(); - - transformer.setParameter((String) entry.getKey(), entry.getValue()); - } - transform(in, transformer); - } catch (Exception e) { - Assert.fail(e.getMessage()); - } - } - - private Transformer getTransformer(String transform) throws Exception { - TransformerFactory tfactory = TransformerFactory.newInstance(); - - try { - // tfactory.setAttribute("generate-translet", Boolean.TRUE); - } catch (Exception e) { - // Ignore - } - - Transformer transformer = tfactory.newTransformer(new StreamSource(transform)); - return (transformer); - } - - private void transform(String in, Transformer transformer) throws Exception { - StringWriter sw = new StringWriter(); - transformer.transform(new StreamSource(in), new StreamResult(sw)); - String s = sw.toString(); - Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); - } - -} diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref new file mode 100644 index 00000000000..0af2588d894 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.ref @@ -0,0 +1 @@ +................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml new file mode 100644 index 00000000000..382a25f08fb --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xml @@ -0,0 +1,5 @@ + + + + . + diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl new file mode 100644 index 00000000000..f390323c2f9 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-1.xsl @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref new file mode 100644 index 00000000000..b012e31307c --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.ref @@ -0,0 +1,83 @@ +0fto-erech 200amos-batch 00000000X/ +1FB01 20150709 EWF 2016021207USD 0000,9302122026623 ////////91284422 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000007366,71//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////D8OOoOOooooOoooooO////15/07 P0480715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40090597 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150630 EWF 2016021206USD 0000,9302122026624 ////////1500006837 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000003844,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////b3oooooooooooooooo////15/07 R1683315 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40127254 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150709 EWF 2016021207CHF 0001,0000022026625 ////////94043801 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000438,50//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0CooOooooooooooOOo////15/07 P0472115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30092874 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150702 EWF 2016021207EUR 0001,0468822026626 ////////TL152062 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000661,30//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////3coooooooooooooooo////15/07 P0431815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40099751 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150617 EWF 2016021206EUR 0001,0468822026627 ////////TKL100216 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000699,92//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////55oooooOoOooooOoOo////15/07 L0032815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2014686 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150702 EWF 2016021207EUR 0001,0468822026628 ////////TL152063 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001983,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9boooooooooooooooo////15/07 P0431815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40099751 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207EUR 0001,0468822026629 ////////000359084 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000002230,76//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////51oOoOoOoOoooooOOO////15/07 R1735915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40128088 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207CHF 0001,0000022026630 ////////90864081 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001893,20//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////acoooooooooooooooo////15/07 P0470615 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090668 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207USD 0000,9302122026631 ////////123939 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000007896,34//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////09oooooooooooooooo////15/07 P0400015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40128846 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207USD 0000,9302122026633 ////////000358117 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000006810,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////f5oooooooooooooooo////15/07 P0462815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40128088 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207CHF 0001,0000022026635 ////////M90257500 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000016300,50//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////C3oOOOooOoOooOOOoo////15/07 R1488615 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207USD 0000,9302122026637 ////////M90257457 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000831,90//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////60ooooOooOOOoOoOoo////15/07 P0463815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000055,22//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0463815 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207USD 0000,9302122026638 ////////M90257509 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000002218,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////60OoooooOOooooOooo////15/07 P0491115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000055,22//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0491115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207CHF 0001,0000022026639 ////////M90257515 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000005833,20//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////A6OOooOoOoOooOoooo////15/07 R1575215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026642 ////////C/5 335835 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////16OooooOooOOoOoooo////15/07 R1612715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026643 ////////C/5 335833 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000835,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////58OOoOOooooOooOOoo////15/07 R1441715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207USD 0000,9302122026644 ////////C/5 336036 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6BooooOOoooOooOooo////15/07 R1659015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026645 ////////C/5 335836 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6DoOoooOooOOoOooOo////15/07 R1613415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207USD 0000,9302122026646 ////////C/5 336201 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////74ooOoOooooooooOoO////15/07 R1728915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207USD 0000,9302122026647 ////////C/5 336035 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000515,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////86OoooOOoooOoooOOo////15/07 R1612615 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207USD 0000,9302122026648 ////////C/5 336034 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000835,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////99OOooooooOooOoooo////15/07 R1445115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207USD 0000,9302122026649 ////////C/5 335834 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000835,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////D8OOoooOOOooooOOoo////15/07 R1445315 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126141 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207CHF 0001,0000022026650 ////////351732 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000192,80//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4BooOooooOOOoOOOOo////15/07 P0448015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207CHF 0001,0000022026651 ////////351730 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000057,25//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////69ooOoOooooooooooO////15/07 P0451715 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000007,02//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0451715 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400122 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150706 EWF 2016021207CHF 0001,0000022026652 ////////351731 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000100,05//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////A9oooooooOoOooOOOo////15/07 P0448015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30090682 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207EUR 0001,0468822026653 ////////05/91014407 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000225,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////22oooOooooOooOooOO////15/07 R1727915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207EUR 0001,0468822026654 ////////05/91015508 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000225,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////24OooooOOoOooOoOoO////15/07 R1728015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150701 EWF 2016021207EUR 0001,0468822026655 ////////05/91015531 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000768,45//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////76oOOOOooOoOooooOO////15/07 W0054415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207USD 0000,9302122026656 ////////SI156008034 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000261,79//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////96OooooOoOoooOOOoo////15/07 P0479215 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40126601 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150709 EWF 2016021207EUR 0001,0468822026657 ////////05/91015509 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000705,35//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////99ooOoOOoooooOoooo////15/07 R1625015 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40096899 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150713 EWF 2016021207EUR 0001,0468822026662 ////////55941607 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000725,60//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4BOoooOOOoOoooooOo////15/07 P0486115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40091085 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150708 EWF 2016021207CHF 0001,0000022026663 ////////100-120606 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000004229,50//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////0boooooooooooooooo////15/07 P0474115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30094003 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000430,56//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0474115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400158 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000054,38//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0474115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400122 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150707 EWF 2016021207CHF 0001,0000022026664 ////////13143106 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000318,65//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////6eoooooooooooooooo////15/07 P0468115 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30092269 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 40///////////////0000000000014,04//////////////////////////////////////////////// /////////////////////////////////////7000 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////P0468115 ////15/07 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////400122 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150709 EWF 2016021207EUR 0001,0468822026665 ////////TL152315 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001983,90//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////74oooooooooooooooo////15/07 P0431815 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40099751 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150710 EWF 2016021207EUR 0001,0468822026667 ////////11321 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000000840,00//////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////caoooooooooooooooo////15/07 P0471915 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////950//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////40129316 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20150401 EWF 2016021204EUR 0001,0553176278995 ////////76278995 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000007833,33//////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////15/04 S0026415 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////566//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VERB05001 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20110209 EWF 2016021202CHF 0001,0000090149059 ////////M90149059 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000001077,30//////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////11/03 S0080410 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////566//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124373 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +1FB01 20110209 EWF 2016021202USD 0000,9570290149062 ////////90149062 ///////////////////////////////////////////////////////////X/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +2BBSEG 31///////////////0000000002185,78//////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////11/03 S0125011 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////566//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////30124374 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml new file mode 100644 index 00000000000..19a8381e919 --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xml @@ -0,0 +1,2438 @@ + + + + 22026623 + + + CRX + CHF + + OPEN + I + V0409 + CAGE1 + 40090597 + + 91284422 + 2015-07-09 + + 2015-07-15 + 2015-07-15 + D8OOoOOooooOoooooOOOOooOoooOoOoo + + 7366.71 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0480715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026624 + + + CRX + CHF + + OPEN + I + V0307 + CAGE2 + 40127254 + + 1500006837 + 2015-06-30 + + 2015-07-16 + 2015-07-16 + b3oooooooooooooooooooooooooooooo + + 3844.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1683315 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-30 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026625 + + + CRX + CHF + + CLOSED + I + V0568 + 30092874 + + 94043801 + 2015-07-09 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 0CooOooooooooooOOoooOooOoOOoooOo + + 438.5 + 190.008 + 0.0 + 0.0 + + 4V + 32.48 + + + + P + P0472115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026626 + + + CRX + CHF + + OPEN + I + V0316 + CAGE3 + 40099751 + + TL152062 + 2015-07-02 + + 2015-07-16 + 2015-07-16 + 3coooooooooooooooooooooooooooooo + + 661.3 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0431815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-01 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026627 + + + CRX + CHF + + OPEN + I + V0440 + 2014686 + + TKL100216 + 2015-06-17 + + 2015-07-16 + 2015-07-16 + 55oooooOoOooooOoOoOOOoOOOoooOOoo + + 699.92 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + L + L0032815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-17 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026628 + + + CRX + CHF + + OPEN + I + V0316 + CAGE4 + 40099751 + + TL152063 + 2015-07-02 + + 2015-07-16 + 2015-07-16 + 9boooooooooooooooooooooooooooooo + + 1983.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0431815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-01 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026629 + + + CRX + CHF + + OPEN + I + V0506 + 40128088 + + 000359084 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + 51oOoOoOoOoooooOOOoOooooOOoooOoO + + 2230.76 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1735915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026630 + + + CRX + CHF + + OPEN + I + V0497 + 30090668 + + 90864081 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + acoooooooooooooooooooooooooooooo + + 1893.2 + 0.0 + 0.0 + 0.0 + + 4V + 0.0 + + + + P + P0470615 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026631 + + + CRX + CHF + + OPEN + I + V0512 + 40128846 + + 123939 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + 09oooooooooooooooooooooooooooooo + + 7896.34 + 0.0 + 0.0 + 0.0 + + TAX + 0.0 + + + + P + P0400015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026633 + + + CRX + CHF + + CLOSED + I + V0202 + 40128088 + + 000358117 + 2015-07-07 + 2015-07-16 + 2015-07-16 + 2015-07-16 + f5oooooooooooooooooooooooooooooo + + 6810.0 + 3187.08 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0462815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026635 + + + CRX + CHF + + OPEN + I + V0011 + 30124373 + + M90257500 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + C3oOOOooOoOooOOOoooOOOoOOoooOoOO + + 16300.5 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1488615 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026637 + + + CRX + CHF + + CLOSED + I + V0139 + 30124373 + + M90257457 + 2015-07-13 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 60ooooOooOOOoOoOoooooooOOOOoooOO + + 831.9 + 334.1052 + 118.0 + 0.0 + + V0 + 0.0 + + + + P + P0463815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + H + HANDLING CHARGE + N + N + + 400158 + + 7000 + 7000 + + + 55.224 + 55.224 + + V0 + V0 + 0.0 + + + D + + + + 22026638 + + + CRX + CHF + + CLOSED + I + V0139 + 30124373 + + M90257509 + 2015-07-13 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 60OoooooOOooooOoooooooooOOooOOOO + + 2218.0 + 982.8 + 118.0 + 0.0 + + V0 + 0.0 + + + + P + P0491115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + H + HANDLING CHARGE + N + N + + 400158 + + 7000 + 7000 + + + 55.224 + 55.224 + + V0 + V0 + 0.0 + + + D + + + + 22026639 + + + CRX + CHF + + OPEN + I + V0162 + 30124373 + + M90257515 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + A6OOooOoOoOooOoooooooooOooooOOoo + + 5833.2 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1575215 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026642 + + + CRX + CHF + + OPEN + I + V0400 + CAGE5 + 40126141 + + C/5 335835 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + 16OooooOooOOoOooooOoooooooooooOO + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1612715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026643 + + + CRX + CHF + + OPEN + I + V0400 + CAGE6 + 40126141 + + C/5 335833 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + 58OOoOOooooOooOOooOoooOooooOOoOo + + 835.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1441715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026644 + + + CRX + CHF + + OPEN + I + V0400 + CAGE7 + 40126141 + + C/5 336036 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 6BooooOOoooOooOooooOooooOoOOoooo + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1659015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026645 + + + CRX + CHF + + OPEN + I + V0400 + CAGE8 + 40126141 + + C/5 335836 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + 6DoOoooOooOOoOooOoOoOoOOOoOoOooo + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1613415 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026646 + + + CRX + CHF + + OPEN + I + V0400 + CAGE9 + 40126141 + + C/5 336201 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + 74ooOoOooooooooOoOOOoOoOooOoooOO + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1728915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026647 + + + CRX + CHF + + OPEN + I + V0400 + CAGEA + 40126141 + + C/5 336035 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 86OoooOOoooOoooOOoOooOoooOOoOoOo + + 515.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1612615 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026648 + + + CRX + CHF + + OPEN + I + V0400 + CAGEB + 40126141 + + C/5 336034 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 99OOooooooOooOooooOooOooOoOOoOoo + + 835.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1445115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026649 + + + CRX + CHF + + OPEN + I + V0400 + CAGEC + 40126141 + + C/5 335834 + 2015-07-01 + + 2015-07-16 + 2015-07-16 + D8OOoooOOOooooOOoooOOoOoooOoOOOO + + 835.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1445315 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026650 + + + CRX + CHF + + OPEN + I + V0429 + 30090682 + + 351732 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + 4BooOooooOOOoOOOOooo + + 192.8 + 0.0 + 0.0 + 0.0 + + 4V + 0.0 + + + + P + P0448015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026651 + + + CRX + CHF + + CLOSED + I + V0429 + 30090682 + + 351730 + 2015-07-06 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 69ooOoOooooooooooOoOooOOOOoooOoO + + 57.25 + 17.784 + 15.0 + 0.0 + + 4V + 4.24 + + + + P + P0451715 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + F + FREIGHT + N + N + + 400122 + + 7000 + 7000 + + + 7.02 + 7.02 + + 4V + 4V + 0.5616 + + + D + + + + 22026652 + + + CRX + CHF + + OPEN + I + V0429 + 30090682 + + 351731 + 2015-07-06 + + 2015-07-16 + 2015-07-16 + A9oooooooOoOooOOOoOO + + 100.05 + 0.0 + 0.0 + 0.0 + + 4V + 0.0 + + + + P + P0448015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-05 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + 22026653 + + + CRX + CHF + + OPEN + I + V0028 + CAGED + 40096899 + + 05/91014407 + 2015-07-07 + + 2015-07-16 + 2015-07-16 + 22oooOooooOooOooOOoOooOoooooOooO + + 225.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1727915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026654 + + + CRX + CHF + + OPEN + I + V0028 + CAGEE + 40096899 + + 05/91015508 + 2015-07-07 + + 2015-07-16 + 2015-07-16 + 24OooooOOoOooOoOoOoOoooOOoOOooOo + + 225.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1728015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026655 + + + CRX + CHF + + CLOSED + I + V0028 + CAGEF + 40096899 + + 05/91015531 + 2015-07-01 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 76oOOOOooOoOooooOOoOoOOooOooOoOO + + 768.45 + 359.6346 + 0.0 + 0.0 + + V0 + 0.0 + + + + W + W0054415 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-07-31 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026656 + + + CRX + CHF + + OPEN + I + V0651 + 40126601 + + SI156008034 + 2015-07-08 + + 2015-07-16 + 2015-07-16 + 96OooooOoOoooOOOoooOOoooOoOOOOoO + + 261.79 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0479215 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + USD + CHF + 0.93021 + + + + + 22026657 + + + CRX + CHF + + CLOSED + I + V0028 + CAGEG + 40096899 + + 05/91015509 + 2015-07-09 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 99ooOoOOoooooOooooOOOOoooOOoOOoO + + 705.35 + 330.1038 + 0.0 + 0.0 + + V0 + 0.0 + + + + R + R1625015 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026662 + + + CRX + CHF + + OPEN + I + V0495 + CAGEH + 40091085 + + 55941607 + 2015-07-13 + + 2015-07-16 + 2015-07-16 + 4BOoooOOOoOoooooOoOOooOooooOoOoo + + 725.6 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0486115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-12 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026663 + + + CRX + CHF + + CLOSED + I + V0604 + 30094003 + + 100-120606 + 2015-07-08 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 0boooooooooooooooooooooooooooooo + + 4229.5 + 1347.84 + 1036.2 + 0.0 + + TAX + 313.3 + + + + P + P0474115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-07 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + H + HANDLING CHARGE + N + N + + 400158 + + 7000 + 7000 + + + 430.56 + 430.56 + + 4V + 4V + 34.4448 + + + D + + + + F + FREIGHT + N + N + + 400122 + + 7000 + 7000 + + + 54.3816 + 54.3816 + + 4V + 4V + 4.3524 + + + D + + + + 22026664 + + + CRX + CHF + + CLOSED + I + V0634 + 30092269 + + 13143106 + 2015-07-07 + 2015-07-16 + 2015-07-16 + 2015-07-16 + 6eoooooooooooooooooooooooooooooo + + 318.65 + 124.0434 + 30.0 + 0.0 + + 4V + 23.599999999999998 + + + + P + P0468115 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-06 + 0 + Y + + + 07 + 2015 + + + CHF + CHF + 1.0 + + + + + F + FREIGHT + N + N + + 400122 + + 7000 + 7000 + + + 14.04 + 14.04 + + 4V + 4V + 1.1232 + + + D + + + + 22026665 + + + CRX + CHF + + OPEN + I + V0316 + CAGEI + 40099751 + + TL152315 + 2015-07-09 + + 2015-07-16 + 2015-07-16 + 74oooooooooooooooooooooooooooooo + + 1983.9 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0431815 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-08 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 22026667 + + + CRX + CHF + + OPEN + I + V0642 + 40129316 + + 11321 + 2015-07-10 + + 2015-07-16 + 2015-07-16 + caoooooooooooooooooooooooooooooo + + 840.0 + 0.0 + 0.0 + 0.0 + + V0 + 0.0 + + + + P + P0471915 + + + 2016-02-12 + + Y + + + + 30D + + + + + + 2015-08-09 + 0 + Y + + + 07 + 2015 + + + EUR + CHF + 1.04688 + + + + + 76278995 + + + CRX + CHF + + CLOSED + I + V0166 + CAGEJ + VERB05001 + + 76278995 + 2015-04-01 + 2015-04-17 + 2015-04-17 + 2015-04-17 + + 7833.33 + 3394.4414 + 0.0 + 0.0 + + V0 + 580.25 + + + + S + S0026415 + + + 2016-02-12 + + Y + + + + + + + + + + 2015-04-01 + 0 + Y + + + 04 + 2015 + + + EUR + CHF + 1.05531 + + + + + 90149059 + + + CRX + CHF + + CLOSED + I + V0016 + 30124373 + + M90149059 + 2011-02-09 + 2011-02-18 + 2011-02-18 + 2011-02-18 + + 1077.3 + 504.1764 + 0.0 + 0.0 + + TAX + 0.0 + + + + S + S0080410 + + + 2016-02-12 + + N + + + + 5 + + + + + + 2011-02-09 + 0 + N + + + 03 + 2011 + + + CHF + CHF + 1.0 + + + + + 90149062 + + + CRX + CHF + + CLOSED + I + V0016 + 30124374 + + 90149062 + 2011-02-09 + 2011-02-21 + 2011-02-21 + 2011-02-21 + + 2185.78 + 1022.945 + 0.0 + 0.0 + + TAX + 0.0 + + + + S + S0125011 + + + 2016-02-12 + + N + + + + 6 + + + + + + 2011-02-09 + 0 + N + + + 03 + 2011 + + + USD + CHF + 0.95702 + + + + + diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl new file mode 100644 index 00000000000..3fd6282b3de --- /dev/null +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/Bug8150704-2.xsl @@ -0,0 +1,1935 @@ + + + + + + + + + +0 +fto-erech +200 +amos-batch +00000000 +X + + +FB01 +TP +EWF + + +566 +950 + + +2w + +V0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1 + + + + + + + + + + + + + + + + + + + + +KA +EA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/ + + + +/ +/ +/ +/ +/ +X +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + +2 +BBSEG + +31 +21 + +/ +/ +/ + + + + +/ +/ +/ + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + + +/ +/ + + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + +2 +BBSEG + +40 +50 + +/ +/ +/ + + + + +/ +/ +/ + + + +/ +/ +/ +/ + + + + + + + + + + +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + +/ +/ + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + +2 +BBSEG + +40 +50 + +/ +/ +/ + + + +/ +/ +/ + + + +/ +/ +/ +/ + + + + + + + + + + +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + +2 +BBSEG + +40 +50 + +/ +/ +/ + + + + +/ +/ +/ + + + +/ +/ +/ +/ + + + + + + + + + + +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + +/ +/ +/ +/ + + +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ +/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +INVALID ALIGN + + + + \ No newline at end of file diff --git a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java index 18229dc28c9..2e01c5dbe59 100644 --- a/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java +++ b/jaxp/test/javax/xml/jaxp/unittest/transform/TransformerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,13 @@ package transform; +import com.sun.org.apache.xml.internal.serialize.OutputFormat; +import com.sun.org.apache.xml.internal.serialize.XMLSerializer; + +import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; @@ -55,56 +61,67 @@ import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; /* - * @summary Test Transformer. + * @summary Transformer Tests + * @bug 6272879 6305029 6505031 8150704 */ public class TransformerTest { - - private static final String LINE_SEPARATOR = System.getProperty("line.separator"); - - private static final String XML_DOCUMENT = "" + ""; - - //Test for JDK-6305029 - @Test - public final void testTransform() throws TransformerException { - - // test SAXSource - SAXSource saxSource = new SAXSource(new MyXMLReader(), new InputSource()); - - StringWriter builder = new StringWriter(); - TransformerFactory.newInstance().newTransformer().transform(saxSource, new StreamResult(builder)); - - AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, builder.toString()); - - // test StreamSource - StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT)); - - StringWriter streamResult = new StringWriter(); - - TransformerFactory.newInstance().newTransformer().transform(streamSource, new StreamResult(streamResult)); - - AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, streamResult.toString()); + private Transformer createTransformer() throws TransformerException { + return TransformerFactory.newInstance().newTransformer(); } - private static class MyXMLReader implements XMLReader { + private Transformer createTransformerFromInputstream(InputStream xslStream) throws TransformerException { + return TransformerFactory.newInstance().newTransformer(new StreamSource(xslStream)); + } + private Transformer createTransformerFromResource(String xslResource) throws TransformerException { + return TransformerFactory.newInstance().newTransformer(new StreamSource(getClass().getResource(xslResource).toString())); + } + + private Document transformInputStreamToDocument(Transformer transformer, InputStream sourceStream) throws TransformerException { + DOMResult response = new DOMResult(); + transformer.transform(new StreamSource(sourceStream), response); + return (Document)response.getNode(); + } + + private StringWriter transformResourceToStringWriter(Transformer transformer, String xmlResource) throws TransformerException { + StringWriter sw = new StringWriter(); + transformer.transform(new StreamSource(getClass().getResource(xmlResource).toString()), new StreamResult(sw)); + return sw; + } + + /** + * 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"); + } + return sb.toString(); + } + } + + private class XMLReaderFor6305029 implements XMLReader { private static final String NAMESPACES = "http://xml.org/sax/features/namespaces"; - private static final String NAMESPACE_PREFIXES = "http://xml.org/sax/features/namespace-prefixes"; - 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)) { @@ -115,7 +132,6 @@ public class TransformerTest { } public void setFeature(final String name, final boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { - if (name.equals(NAMESPACES)) { namespaces = value; } else if (name.equals(NAMESPACE_PREFIXES)) { @@ -165,12 +181,10 @@ public class TransformerTest { } public void parse(final InputSource input) throws IOException, SAXException { - parse(); } public void parse(final String systemId) throws IOException, SAXException { - parse(); } @@ -190,30 +204,50 @@ public class TransformerTest { } } + /* + * @bug 6272879 + * @summary Test for JDK-6272879 + */ @Test - public final void testCR6272879() { + public final void testBug6272879() throws IOException, TransformerException { + final String LINE_SEPARATOR = System.getProperty("line.separator"); - 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 + ""; + 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 + + ""; - final String sourceXml = "" - + LINE_SEPARATOR + 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 + ""; + "" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " Valeur 1" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + " Valeur 2" + LINE_SEPARATOR + + " " + LINE_SEPARATOR + + ""; Document document; Node node; @@ -230,9 +264,12 @@ public class TransformerTest { System.out.println("Source file after transformation:"); System.out.println("================================="); - document = getTransformation(xsl, sourceXml); - - System.out.println(document); + document = transformInputStreamToDocument(createTransformerFromInputstream(new ByteArrayInputStream(xsl.getBytes())), + new ByteArrayInputStream(sourceXml.getBytes())); + OutputFormat format = new OutputFormat(); + format.setIndenting(true); + new XMLSerializer(System.out, format).serialize(document); + System.out.println(); System.out.println("Node content for element valeur2:"); System.out.println("================================="); @@ -248,25 +285,60 @@ public class TransformerTest { } } - private static Document getTransformation(final String xsl, final String sourceXml) { + /* + * @bug 6305029 + * @summary Test for JDK-6305029 + */ + @Test + public final void testBug6305029() throws TransformerException { + final String XML_DOCUMENT = "" + ""; - Transformer transformer; - DOMResult reponse; - Document document = null; + // test SAXSource + SAXSource saxSource = new SAXSource(new XMLReaderFor6305029(), new InputSource()); + StringWriter resultWriter = new StringWriter(); + createTransformer().transform(saxSource, new StreamResult(resultWriter)); + AssertJUnit.assertEquals("Identity transform of SAXSource", XML_DOCUMENT, resultWriter.toString()); - try { - InputStream in = new ByteArrayInputStream(xsl.getBytes()); - transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(in)); + // test StreamSource + StreamSource streamSource = new StreamSource(new StringReader(XML_DOCUMENT)); + resultWriter = new StringWriter(); + createTransformer().transform(streamSource, new StreamResult(resultWriter)); + AssertJUnit.assertEquals("Identity transform of StreamSource", XML_DOCUMENT, resultWriter.toString()); + } - reponse = new DOMResult(); - transformer.transform(new StreamSource(new ByteArrayInputStream(sourceXml.getBytes())), reponse); - document = (Document) reponse.getNode(); - } catch (Exception e) { - String msg = "Exception in getTransformation: " + e; - System.err.println(msg); - Assert.fail(msg); - } + /* + * @bug 6505031 + * @summary Test transformer parses keys and their values coming from different xml documents. + */ + @Test + public final void testBug6505031() throws TransformerException { + Transformer transformer = createTransformerFromResource("transform.xsl"); + transformer.setParameter("config", getClass().getResource("config.xml").toString()); + transformer.setParameter("mapsFile", getClass().getResource("maps.xml").toString()); + String s = transformResourceToStringWriter(transformer, "template.xml").toString(); + Assert.assertTrue(s.contains("map1key1value") && s.contains("map2key1value")); + } - return (document); + /* + * @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..."); + Transformer transformer = createTransformerFromResource("Bug8150704-1.xsl"); + StringWriter result = transformResourceToStringWriter(transformer, "Bug8150704-1.xml"); + String resultstring = result.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."); + + System.out.println("Testing transformation of Bug8150704-2.xml..."); + transformer = createTransformerFromResource("Bug8150704-2.xsl"); + result = transformResourceToStringWriter(transformer, "Bug8150704-2.xml"); + resultstring = result.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."); } } diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 64b08144ae1..93f5e2e4c5c 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -354,3 +354,5 @@ eb5e005a17e50d7d8340daaf21a5c3c5ae358d68 jdk-9+103 c072c572d14948563ef5d86e1921699b3a2396ab jdk-9+106 fafd694e801f0f5a7c737fb08630ced3ca8f772c jdk-9+107 513eb2e432f64f85992442da9acdfcfbb36555d9 jdk-9+108 +4b0697e4ce8940b1599af274ff02296d7f59aded jdk-9+109 +0db939c930f332dfa275cedfc7cf223ff1221ea4 jdk-9+110 diff --git a/jaxws/src/java.activation/share/classes/javax/activation/DataContentHandler.java b/jaxws/src/java.activation/share/classes/javax/activation/DataContentHandler.java index 81480952611..8d429ef4c33 100644 --- a/jaxws/src/java.activation/share/classes/javax/activation/DataContentHandler.java +++ b/jaxws/src/java.activation/share/classes/javax/activation/DataContentHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -33,18 +33,23 @@ import java.io.OutputStream; import javax.activation.DataSource; /** - * The DataContentHandler interface is implemented by objects that can + *

The DataContentHandler interface is implemented by objects that can * be used to extend the capabilities of the DataHandler's implementation * of the Transferable interface. Through DataContentHandlers * the framework can be extended to convert streams in to objects, and - * to write objects to streams.

+ * to write objects to streams.

* - * Applications don't generally call the methods in DataContentHandlers + *

An implementation of DataContentHandler should be a public class + * with a public no-arg constructor. If the implementation class is in + * a named module then it should be in an API package that is exported + * to the module {@code java.activation}.

+ * + *

Applications don't generally call the methods in DataContentHandlers * directly. Instead, an application calls the equivalent methods in * DataHandler. The DataHandler will attempt to find an appropriate * DataContentHandler that corresponds to its MIME type using the * current DataContentHandlerFactory. The DataHandler then calls - * through to the methods in the DataContentHandler. + * through to the methods in the DataContentHandler.

* * @since 1.6 */ diff --git a/jaxws/src/java.activation/share/classes/javax/activation/MailcapCommandMap.java b/jaxws/src/java.activation/share/classes/javax/activation/MailcapCommandMap.java index dd7530c3121..29bc9ad0a44 100644 --- a/jaxws/src/java.activation/share/classes/javax/activation/MailcapCommandMap.java +++ b/jaxws/src/java.activation/share/classes/javax/activation/MailcapCommandMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -580,8 +580,7 @@ public class MailcapCommandMap extends CommandMap { // if anything goes wrong, do it the old way cl = Class.forName(name); } - if (cl != null) // XXX - always true? - return (DataContentHandler)cl.newInstance(); + return (DataContentHandler) cl.newInstance(); } catch (IllegalAccessException e) { if (LogSupport.isLoggable()) LogSupport.log("Can't load DCH " + name, e); diff --git a/jaxws/src/java.activation/share/classes/module-info.java b/jaxws/src/java.activation/share/classes/module-info.java new file mode 100644 index 00000000000..d6507874caa --- /dev/null +++ b/jaxws/src/java.activation/share/classes/module-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.activation { + requires public java.datatransfer; + // dependence on java.beans.Beans to be eliminated + requires java.desktop; + requires java.logging; + + exports javax.activation; +} + diff --git a/jaxws/src/java.annotations.common/share/classes/module-info.java b/jaxws/src/java.annotations.common/share/classes/module-info.java new file mode 100644 index 00000000000..0a3a8dd3c6e --- /dev/null +++ b/jaxws/src/java.annotations.common/share/classes/module-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.annotations.common { + exports javax.annotation; +} + diff --git a/jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/bind/v2/ClassFactory.java b/jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/bind/v2/ClassFactory.java index ce36be3541c..da4c5f373f4 100644 --- a/jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/bind/v2/ClassFactory.java +++ b/jaxws/src/java.xml.bind/share/classes/com/sun/xml/internal/bind/v2/ClassFactory.java @@ -113,7 +113,6 @@ public final class ClassFactory { m.put(clazz,new WeakReference(cons)); } - return cons.newInstance(emptyObject); } diff --git a/jaxws/src/java.xml.bind/share/classes/module-info.java b/jaxws/src/java.xml.bind/share/classes/module-info.java new file mode 100644 index 00000000000..7f7cde8190e --- /dev/null +++ b/jaxws/src/java.xml.bind/share/classes/module-info.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.xml.bind { + requires public java.activation; + requires public java.xml; + requires java.compiler; + requires java.desktop; + requires java.logging; + + uses javax.xml.bind.JAXBContextFactory; + + exports javax.xml.bind; + exports javax.xml.bind.annotation; + exports javax.xml.bind.annotation.adapters; + exports javax.xml.bind.attachment; + exports javax.xml.bind.helpers; + exports javax.xml.bind.util; + exports com.sun.istack.internal to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.istack.internal.localization to + java.xml.ws, + jdk.xml.ws; + exports com.sun.istack.internal.logging to + java.xml.ws, + jdk.xml.ws; + exports com.sun.xml.internal.bind to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.annotation to + jdk.xml.bind; + exports com.sun.xml.internal.bind.api to + java.xml.ws, + jdk.xml.bind; + exports com.sun.xml.internal.bind.api.impl to + java.xml.ws, + jdk.xml.bind; + exports com.sun.xml.internal.bind.marshaller to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.unmarshaller to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.util to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.v2 to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.v2.model.annotation to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.v2.model.core to + jdk.xml.bind; + exports com.sun.xml.internal.bind.v2.model.impl to + jdk.xml.bind; + exports com.sun.xml.internal.bind.v2.model.nav to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.bind.v2.model.runtime to + java.xml.ws; + exports com.sun.xml.internal.bind.v2.model.util to + jdk.xml.bind; + exports com.sun.xml.internal.bind.v2.runtime to + java.xml.ws, + jdk.xml.bind; + exports com.sun.xml.internal.bind.v2.runtime.unmarshaller to + java.xml.ws; + exports com.sun.xml.internal.bind.v2.schemagen to + java.xml.ws, + jdk.xml.bind; + exports com.sun.xml.internal.bind.v2.schemagen.episode to + jdk.xml.bind; + exports com.sun.xml.internal.bind.v2.schemagen.xmlschema to + java.xml.ws; + exports com.sun.xml.internal.bind.v2.util to + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.fastinfoset to + java.xml.ws; + exports com.sun.xml.internal.fastinfoset.stax to + java.xml.ws; + exports com.sun.xml.internal.fastinfoset.vocab to + java.xml.ws; + exports com.sun.xml.internal.org.jvnet.fastinfoset to + java.xml.ws; + exports com.sun.xml.internal.org.jvnet.mimepull to + java.xml.ws; + exports com.sun.xml.internal.org.jvnet.staxex to + java.xml.ws; + exports com.sun.xml.internal.org.jvnet.staxex.util to + java.xml.ws; + exports com.sun.xml.internal.txw2 to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.txw2.annotation to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; + exports com.sun.xml.internal.txw2.output to + java.xml.ws, + jdk.xml.bind, + jdk.xml.ws; +} diff --git a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/server/SDDocumentSource.java b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/server/SDDocumentSource.java index ccd1b3d41e0..0c774aa0308 100644 --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/server/SDDocumentSource.java +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/api/server/SDDocumentSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -26,6 +26,7 @@ package com.sun.xml.internal.ws.api.server; import com.sun.xml.internal.stream.buffer.XMLStreamBuffer; +import com.sun.xml.internal.ws.server.ServerRtException; import com.sun.xml.internal.ws.streaming.TidyXMLStreamReader; import com.sun.xml.internal.ws.api.streaming.XMLStreamReaderFactory; @@ -34,6 +35,7 @@ import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.io.IOException; import java.io.InputStream; +import java.net.MalformedURLException; import java.net.URL; /** @@ -111,6 +113,48 @@ public abstract class SDDocumentSource { }; } + /** + * Creates {@link SDDocumentSource} from resource path using resolvingClass to read the resource. + * Required for Jigsaw runtime. + * + * @param resolvingClass class used to read resource + * @param path resource path + */ + public static SDDocumentSource create(final Class resolvingClass, final String path) { + return new SDDocumentSource() { + + public XMLStreamReader read(XMLInputFactory xif) throws IOException, XMLStreamException { + InputStream is = inputStream(); + return new TidyXMLStreamReader(xif.createXMLStreamReader(path,is), is); + } + + public XMLStreamReader read() throws IOException, XMLStreamException { + InputStream is = inputStream(); + return new TidyXMLStreamReader(XMLStreamReaderFactory.create(path,is,false), is); + } + + public URL getSystemId() { + try { + return new URL("file://" + path); + } catch (MalformedURLException e) { + return null; + } + } + + private InputStream inputStream() throws IOException { + java.lang.reflect.Module module = resolvingClass.getModule(); + if (module != null) { + InputStream stream = module.getResourceAsStream(path); + if (stream != null) { + return stream; + } + } + throw new ServerRtException("cannot.load.wsdl", path); + } + + }; + } + /** * Creates a {@link SDDocumentSource} from {@link XMLStreamBuffer}. */ diff --git a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/EndpointImpl.java b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/EndpointImpl.java index 82db6e9e49d..9f23f51b43a 100644 --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/EndpointImpl.java +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/transport/http/server/EndpointImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -372,7 +372,7 @@ public class EndpointImpl extends Endpoint { if (url != null) { return SDDocumentSource.create(url); } - throw new ServerRtException("cannot.load.wsdl", wsdlLocation); + return SDDocumentSource.create(implClass, wsdlLocation); } return null; } diff --git a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/HandlerAnnotationProcessor.java b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/HandlerAnnotationProcessor.java index 37e7a20c5b3..42385239f3f 100644 --- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/HandlerAnnotationProcessor.java +++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/HandlerAnnotationProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -197,28 +197,62 @@ public class HandlerAnnotationProcessor { return null; } - static InputStream getFileAsStream(Class clazz, HandlerChain chain) { - URL url = clazz.getResource(chain.file()); - if (url == null) { - url = Thread.currentThread().getContextClassLoader(). - getResource(chain.file()); - } - if (url == null) { - String tmp = clazz.getPackage().getName(); - tmp = tmp.replace('.', '/'); - tmp += "/" + chain.file(); - url = - Thread.currentThread().getContextClassLoader().getResource(tmp); - } + static InputStream getFileAsStream(Class clazz, HandlerChain chain) { + Package pkg = clazz.getPackage(); + String filename = chain.file(); + String fullpath = addPackagePath(filename, pkg); + InputStream is; + + is = moduleResource(clazz, filename); + if (is != null) return is; + + is = moduleResource(clazz, fullpath); + if (is != null) return is; + + URL url = cpResource(clazz, filename); + if (url == null) url = cpResource(clazz, fullpath); + if (url == null) { throw new UtilException("util.failed.to.find.handlerchain.file", - clazz.getName(), chain.file()); + clazz.getName(), filename); } try { return url.openStream(); } catch (IOException e) { throw new UtilException("util.failed.to.parse.handlerchain.file", - clazz.getName(), chain.file()); + clazz.getName(), filename); } } + + private static URL cpResource(Class clazz, String name) { + URL url = clazz.getResource(name); + if (url == null) { + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + url = tccl.getResource(name); + } + return url; + } + + private static InputStream moduleResource(Class resolvingClass, String name) { + java.lang.reflect.Module module = resolvingClass.getModule(); + if (module != null) { + try { + InputStream stream = module.getResourceAsStream(name); + if (stream != null) { + return stream; + } + } catch(IOException e) { + throw new UtilException("util.failed.to.find.handlerchain.file", + resolvingClass.getName(), name); + } + } + return null; + } + + private static String addPackagePath(String file, Package pkg) { + String tmp = pkg.getName(); + tmp = tmp.replace('.', '/'); + tmp += "/" + file; + return tmp; + } } diff --git a/jaxws/src/java.xml.ws/share/classes/module-info.java b/jaxws/src/java.xml.ws/share/classes/module-info.java new file mode 100644 index 00000000000..799e0f23395 --- /dev/null +++ b/jaxws/src/java.xml.ws/share/classes/module-info.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.xml.ws { + requires public java.activation; + requires public java.xml; + requires public java.xml.bind; + requires java.annotations.common; + requires java.desktop; + requires java.logging; + requires java.management; + requires java.rmi; + requires jdk.httpserver; + + uses javax.xml.ws.spi.Provider; + uses javax.xml.soap.MessageFactory; + uses javax.xml.soap.SAAJMetaFactory; + uses javax.xml.soap.SOAPConnectionFactory; + uses javax.xml.soap.SOAPFactory; + + exports javax.jws; + exports javax.jws.soap; + exports javax.xml.soap; + exports javax.xml.ws; + exports javax.xml.ws.handler; + exports javax.xml.ws.handler.soap; + exports javax.xml.ws.http; + exports javax.xml.ws.soap; + exports javax.xml.ws.spi; + exports javax.xml.ws.spi.http; + exports javax.xml.ws.wsaddressing; + + exports com.oracle.webservices.internal.api.databinding to + jdk.xml.ws; + exports com.sun.xml.internal.ws.addressing to + jdk.xml.ws, + java.xml.bind; + exports com.sun.xml.internal.ws.addressing.v200408 to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.addressing to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.databinding to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.model to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.server to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.streaming to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.wsdl.parser to + jdk.xml.ws; + exports com.sun.xml.internal.ws.api.wsdl.writer to + jdk.xml.ws; + exports com.sun.xml.internal.ws.binding to + jdk.xml.ws; + exports com.sun.xml.internal.ws.db to + jdk.xml.ws; + exports com.sun.xml.internal.ws.model to + jdk.xml.ws; + exports com.sun.xml.internal.ws.policy.sourcemodel.wspolicy to + jdk.xml.ws; + exports com.sun.xml.internal.ws.spi.db to + jdk.xml.ws; + exports com.sun.xml.internal.ws.streaming to + jdk.xml.ws; + exports com.sun.xml.internal.ws.util to + jdk.xml.ws; + exports com.sun.xml.internal.ws.util.exception to + jdk.xml.ws; + exports com.sun.xml.internal.ws.util.xml to + jdk.xml.ws; + exports com.sun.xml.internal.ws.wsdl.parser to + jdk.xml.ws; + exports com.sun.xml.internal.ws.wsdl.writer to + jdk.xml.ws; + + // XML document content needs to be exported + exports com.sun.xml.internal.ws.runtime.config to java.xml.bind; + + // com.sun.xml.internal.ws.fault.SOAPFaultBuilder uses JAXBContext.newInstance + exports com.sun.xml.internal.ws.fault to java.xml.bind; + + // JAF data handlers + exports com.sun.xml.internal.messaging.saaj.soap to + java.activation; + exports com.sun.xml.internal.ws.encoding to + java.activation; +} + diff --git a/jaxws/src/jdk.xml.bind/share/classes/com/sun/codemodel/internal/fmt/JStaticJavaFile.java b/jaxws/src/jdk.xml.bind/share/classes/com/sun/codemodel/internal/fmt/JStaticJavaFile.java index 9e52348b2b4..e661b8175e7 100644 --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/codemodel/internal/fmt/JStaticJavaFile.java +++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/codemodel/internal/fmt/JStaticJavaFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -33,7 +33,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.net.URL; import java.text.ParseException; import java.util.Iterator; import java.util.List; @@ -69,22 +68,17 @@ public final class JStaticJavaFile extends JResourceFile { private final JPackage pkg; private final String className; - private final URL source; + private final ResourceLoader source; private final JStaticClass clazz; private final LineFilter filter; - public JStaticJavaFile(JPackage _pkg, String className, String _resourceName) { - this( _pkg, className, - SecureLoader.getClassClassLoader(JStaticJavaFile.class).getResource(_resourceName), null ); - } - - public JStaticJavaFile(JPackage _pkg, String _className, URL _source, LineFilter _filter ) { - super(_className+".java"); - if(_source==null) throw new NullPointerException(); + public JStaticJavaFile(JPackage _pkg, String _className, Class loadingClass, LineFilter _filter) { + super(_className + ".java"); + if (loadingClass == null) throw new NullPointerException(); this.pkg = _pkg; this.clazz = new JStaticClass(); this.className = _className; - this.source = _source; + this.source = new ResourceLoader(_className, loadingClass); this.filter = _filter; } @@ -100,14 +94,13 @@ public final class JStaticJavaFile extends JResourceFile { } protected void build(OutputStream os) throws IOException { - InputStream is = source.openStream(); - - BufferedReader r = new BufferedReader(new InputStreamReader(is)); - PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os))); - LineFilter filter = createLineFilter(); int lineNumber=1; - - try { + try ( + InputStream is = source.getResourceAsStream(); + BufferedReader r = new BufferedReader(new InputStreamReader(is)); + PrintWriter w = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os))); + ) { + LineFilter filter = createLineFilter(); String line; while((line=r.readLine())!=null) { line = filter.process(line); @@ -118,9 +111,6 @@ public final class JStaticJavaFile extends JResourceFile { } catch( ParseException e ) { throw new IOException("unable to process "+source+" line:"+lineNumber+"\n"+e.getMessage()); } - - w.close(); - r.close(); } /** @@ -235,5 +225,32 @@ public final class JStaticJavaFile extends JResourceFile { protected JClass substituteParams(JTypeVar[] variables, List bindings) { return this; } - }; + } + + static class ResourceLoader { + Class loadingClass; + String shortName; + + ResourceLoader(String shortName, Class loadingClass) { + this.loadingClass = loadingClass; + this.shortName = shortName; + } + + InputStream getResourceAsStream() { + // some people didn't like our jars to contain files with .java extension, + // so when we build jars, we'' use ".java_". But when we run from the workspace, + // we want the original source code to be used, so we check both here. + // see bug 6211503. + InputStream stream = loadingClass.getResourceAsStream(shortName + ".java"); + if (stream == null) { + stream = loadingClass.getResourceAsStream(shortName + ".java_"); + } + if (stream == null) { + throw new InternalError("Unable to load source code of " + loadingClass.getName() + " as a resource"); + } + return stream; + } + + } + } diff --git a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/generator/bean/BeanGenerator.java b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/generator/bean/BeanGenerator.java index 6b383810edd..01cf43a31ed 100644 --- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/generator/bean/BeanGenerator.java +++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/generator/bean/BeanGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -28,7 +28,6 @@ package com.sun.tools.internal.xjc.generator.bean; import static com.sun.tools.internal.xjc.outline.Aspect.EXPOSED; import java.io.Serializable; -import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; @@ -809,26 +808,14 @@ public final class BeanGenerator implements Outline { } public JClass generateStaticClass(Class src, JPackage out) { - String shortName = getShortName(src.getName()); - - // some people didn't like our jars to contain files with .java extension, - // so when we build jars, we'' use ".java_". But when we run from the workspace, - // we want the original source code to be used, so we check both here. - // see bug 6211503. - URL res = src.getResource(shortName + ".java"); - if (res == null) { - res = src.getResource(shortName + ".java_"); - } - if (res == null) { - throw new InternalError("Unable to load source code of " + src.getName() + " as a resource"); - } - - JStaticJavaFile sjf = new JStaticJavaFile(out, shortName, res, null); + JStaticJavaFile sjf = new JStaticJavaFile(out, getShortName(src), src, null); out.addResourceFile(sjf); return sjf.getJClass(); } - private String getShortName(String name) { + private String getShortName(Class src) { + String name = src.getName(); return name.substring(name.lastIndexOf('.') + 1); } + } diff --git a/jaxws/src/jdk.xml.bind/share/classes/module-info.java b/jaxws/src/jdk.xml.bind/share/classes/module-info.java new file mode 100644 index 00000000000..06faf9dddd2 --- /dev/null +++ b/jaxws/src/jdk.xml.bind/share/classes/module-info.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +module jdk.xml.bind { + requires java.activation; + requires java.compiler; + requires java.desktop; + requires java.logging; + requires java.xml; + requires java.xml.bind; + requires jdk.compiler; + + exports com.sun.codemodel.internal to + jdk.xml.ws; + exports com.sun.codemodel.internal.writer to + jdk.xml.ws; + exports com.sun.istack.internal.tools to + jdk.xml.ws; + exports com.sun.tools.internal.jxc.ap to + jdk.xml.ws; + exports com.sun.tools.internal.jxc.model.nav to + jdk.xml.ws; + exports com.sun.tools.internal.xjc to + jdk.xml.ws; + exports com.sun.tools.internal.xjc.api to + jdk.xml.ws; + exports com.sun.tools.internal.xjc.reader to + jdk.xml.ws; + exports com.sun.tools.internal.xjc.reader.internalizer to + jdk.xml.ws; + exports com.sun.tools.internal.xjc.util to + jdk.xml.ws; + exports com.sun.xml.internal.xsom.parser to + jdk.xml.ws; + + // XML document content needs to be exported + exports com.sun.tools.internal.xjc.reader.xmlschema.bindinfo to + java.xml.bind; + + // com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo uses JAXBContext + exports com.sun.tools.internal.xjc.generator.bean to java.xml.bind; + + uses com.sun.tools.internal.xjc.Plugin; + provides com.sun.tools.internal.xjc.Plugin with com.sun.tools.internal.xjc.addon.accessors.PluginImpl; + provides com.sun.tools.internal.xjc.Plugin with com.sun.tools.internal.xjc.addon.at_generated.PluginImpl; + provides com.sun.tools.internal.xjc.Plugin with com.sun.tools.internal.xjc.addon.code_injector.PluginImpl; + provides com.sun.tools.internal.xjc.Plugin with com.sun.tools.internal.xjc.addon.episode.PluginImpl; + provides com.sun.tools.internal.xjc.Plugin with com.sun.tools.internal.xjc.addon.locator.SourceLocationAddOn; + provides com.sun.tools.internal.xjc.Plugin with com.sun.tools.internal.xjc.addon.sync.SynchronizedMethodAddOn; +} + diff --git a/jaxws/src/jdk.xml.ws/share/classes/module-info.java b/jaxws/src/jdk.xml.ws/share/classes/module-info.java new file mode 100644 index 00000000000..9e5d44da047 --- /dev/null +++ b/jaxws/src/jdk.xml.ws/share/classes/module-info.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module jdk.xml.ws { + requires java.compiler; + requires java.logging; + requires java.rmi; + requires java.xml; + requires java.xml.bind; + requires java.xml.ws; + requires jdk.xml.bind; + + uses com.sun.tools.internal.ws.wscompile.Plugin; + provides com.sun.tools.internal.ws.wscompile.Plugin with com.sun.tools.internal.ws.wscompile.plugin.at_generated.PluginImpl; +} + diff --git a/jdk/.hgtags b/jdk/.hgtags index 8d4f94f1f2c..49cf4dd5ea8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -352,3 +352,4 @@ eee1ced1d8e78293f2a004af818ca474387dbebf jdk-9+103 8701b2bb1d2e1b9abc2a9be0933993c7150a9dbe jdk-9+107 42794e648cfe9fd67461dcbe8b7594241a84bcff jdk-9+108 1c7bad0798900fe58f4db01ae7ffdc84f5baee8c jdk-9+109 +9417e1bcded6af5532c3b26235437ab227758877 jdk-9+110 diff --git a/jdk/make/CompileInterimRmic.gmk b/jdk/make/CompileInterimRmic.gmk index f31db8dfd04..ce60127e6d1 100644 --- a/jdk/make/CompileInterimRmic.gmk +++ b/jdk/make/CompileInterimRmic.gmk @@ -44,8 +44,9 @@ RMIC_PKGS := \ $(eval $(call SetupJavaCompilation,BUILD_INTERIM_RMIC, \ SETUP := GENERATE_OLDBYTECODE, \ SRC := $(JDK_TOPDIR)/src/jdk.rmic/share/classes, \ + EXCLUDE_FILES := module-info.java, \ INCLUDES := $(RMIC_PKGS), \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_rmic_classes, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/override_modules/jdk.rmic, \ COPY := .properties)) ########################################################################################## diff --git a/jdk/make/CompileTools.gmk b/jdk/make/CompileTools.gmk index 27aaffaafdb..46dab28f146 100644 --- a/jdk/make/CompileTools.gmk +++ b/jdk/make/CompileTools.gmk @@ -32,42 +32,12 @@ include SetupJavaCompilers.gmk ################################################################################ -JIMAGE_PKGS := \ - jdk/internal/jimage \ - jdk/internal/jrtfs \ - # - -$(eval $(call SetupJavaCompilation,BUILD_INTERIM_JIMAGE, \ - SETUP := GENERATE_OLDBYTECODE, \ - SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ - INCLUDES := $(JIMAGE_PKGS), \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes)) - -TARGETS += $(BUILD_INTERIM_JIMAGE) - -# Because of the explicit INCLUDES in the compilation setup above, the service provider -# file will not be copied unless META-INF/services would also be added to the INCLUDES. -# Adding META-INF/services would include all files in that directory when only the one -# is needed, which is why this explicit copy is defined instead. -$(eval $(call SetupCopyFiles,COPY_JIMAGE_SERVICE_PROVIDER, \ - SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ - DEST := $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes, \ - FILES := META-INF/services/java.nio.file.spi.FileSystemProvider)) - -TARGETS += $(COPY_JIMAGE_SERVICE_PROVIDER) - -################################################################################ - $(eval $(call SetupJavaCompilation,BUILD_TOOLS_JDK, \ SETUP := GENERATE_OLDBYTECODE, \ - ADD_JAVAC_FLAGS := -Xbootclasspath/p:$(call PathList, \ - $(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes \ - $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes), \ SRC := $(JDK_TOPDIR)/make/src/classes $(BUILDTOOLS_OUTPUTDIR)/interim_cldrconverter_classes, \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \ - COPY := boot.modules ext.modules)) - -$(BUILD_TOOLS_JDK): $(BUILD_INTERIM_JIMAGE) $(COPY_JIMAGE_SERVICE_PROVIDER) + EXCLUDES := build/tools/deps \ + build/tools/jigsaw, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes)) TARGETS += $(BUILD_TOOLS_JDK) diff --git a/make/CheckModules.gmk b/jdk/make/GenerateModuleSummary.gmk similarity index 67% rename from make/CheckModules.gmk rename to jdk/make/GenerateModuleSummary.gmk index 4872c912e49..285de739088 100644 --- a/make/CheckModules.gmk +++ b/jdk/make/GenerateModuleSummary.gmk @@ -28,19 +28,20 @@ default: all include $(SPEC) include MakeBase.gmk +include ModuleTools.gmk -JDEPS_MODULES_XML := $(JDK_OUTPUTDIR)/modules/jdk.jdeps/com/sun/tools/jdeps/resources/jdeps-modules.xml +GENGRAPHS_DIR := $(IMAGES_OUTPUTDIR)/gengraphs +TOOLS_MODULE_SRCDIR := $(JDK_TOPDIR)/make/src/classes/build/tools/jigsaw -# -# Verify access across module boundaries -# -checkdeps: - $(ECHO) "Checking dependencies across JDK modules" - $(JAVA) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \ - -Djdeps.modules.xml=$(JDEPS_MODULES_XML) \ - com.sun.tools.jdeps.Main \ - -verify:access -mp $(JDK_OUTPUTDIR)/modules +$(GENGRAPHS_DIR)/jdk.dot: $(BUILD_JIGSAW_TOOLS) + $(MKDIR) -p $(@D) + $(TOOL_GENGRAPHS) $(GENGRAPHS_DIR) -all: checkdeps +$(GENGRAPHS_DIR)/technology-summary.html: $(TOOLS_MODULE_SRCDIR)/technology-summary.html + $(install-file) -.PHONY: all +$(GENGRAPHS_DIR)/module-summary.html: $(BUILD_JIGSAW_TOOLS) $(GENGRAPHS_DIR)/technology-summary.html + $(MKDIR) -p $(@D) + $(TOOL_MODULESUMMARY) -o $@ -mp $(IMAGES_OUTPUTDIR)/jmods + +all: $(GENGRAPHS_DIR)/jdk.dot $(GENGRAPHS_DIR)/module-summary.html diff --git a/jdk/make/gendata/Gendata-jdk.jdeps.gmk b/jdk/make/ModuleTools.gmk similarity index 57% rename from jdk/make/gendata/Gendata-jdk.jdeps.gmk rename to jdk/make/ModuleTools.gmk index 3616796eed4..2943b9c8d21 100644 --- a/jdk/make/gendata/Gendata-jdk.jdeps.gmk +++ b/jdk/make/ModuleTools.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,20 +23,25 @@ # questions. # -include GendataCommon.gmk +include $(SPEC) +include MakeBase.gmk +include JavaCompilation.gmk +include SetupJavaCompilers.gmk -$(eval $(call IncludeCustomExtension, jdk, gendata/Gendata-jdk.jdeps.gmk)) +TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes -JDEPS_MODULES_XML := $(JDK_OUTPUTDIR)/modules/jdk.jdeps/com/sun/tools/jdeps/resources/jdeps-modules.xml -MODULES_XML += $(TOPDIR)/modules.xml +$(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \ + SETUP := GENERATE_USINGJDKBYTECODE, \ + SRC := $(JDK_TOPDIR)/make/src/classes, \ + INCLUDES := build/tools/deps \ + build/tools/jigsaw, \ + BIN := $(TOOLS_CLASSES_DIR), \ + ADD_JAVAC_FLAGS := -XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED )) -# -# Generate modules.xml for jdeps to use -# It augments $(TOPDIR)/modules.xml to include module membership -# -$(JDEPS_MODULES_XML): $(BUILD_TOOLS_JDK) $(MODULES_XML) - $(MKDIR) -p $(@D) - $(RM) $@ - $(TOOL_GENMODULESXML) -o $@ -mp $(JDK_OUTPUTDIR)/modules $(MODULES_XML) -TARGETS += $(JDEPS_MODULES_XML) +TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \ + build.tools.jigsaw.GenGraphs + +TOOL_MODULESUMMARY := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \ + -XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ + build.tools.jigsaw.ModuleSummary diff --git a/jdk/make/Tools.gmk b/jdk/make/Tools.gmk index a087e3c83ae..1ae471d72b3 100644 --- a/jdk/make/Tools.gmk +++ b/jdk/make/Tools.gmk @@ -41,7 +41,12 @@ BUILD_TOOLS_JDK := $(call SetupJavaCompilationCompileTarget, \ TOOL_ADDJSUM = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.addjsum.AddJsum +ifeq ($(BOOT_JDK_MODULAR), true) + COMPILEFONTCONFIG_ADD_EXPORTS := -XaddExports:java.desktop/sun.awt=ALL-UNNAMED +endif + TOOL_COMPILEFONTCONFIG = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ + $(COMPILEFONTCONFIG_ADD_EXPORTS) \ build.tools.compilefontconfig.CompileFontConfig TOOL_COMPILEPROPERTIES = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ @@ -106,12 +111,18 @@ TOOL_OSX_TOBIN = $(JAVA_SMALL) -Djava.awt.headless=true -cp $(BUILDTOOLS_OUTPUTD TOOL_CLDRCONVERTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.cldrconverter.CLDRConverter -TOOL_GENMODULESXML = $(JAVA_SMALL) -Xbootclasspath/p:$(INTERIM_LANGTOOLS_JAR) \ - -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes $(JDK_OUTPUTDIR)) \ +TOOL_GENMODULESXML = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \ + -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \ build.tools.module.GenJdepsModulesXml -TOOL_IMAGEBUILDER = $(JAVA_SMALL) -Xbootclasspath/p:$(BUILDTOOLS_OUTPUTDIR)/interim_jimage_classes \ - -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes $(JDK_OUTPUTDIR)) \ - build.tools.module.ImageBuilder +TOOL_GENMODULEINFOSOURCE = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \ + -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \ + build.tools.module.GenModuleInfoSource + +TOOL_GENCLASSLOADERMAP = $(JAVA_SMALL) $(INTERIM_LANGTOOLS_BOOTCLASSPATH) \ + -cp $(call PathList, $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes) \ + build.tools.module.GenModuleLoaderMap + +########################################################################################## endif # _TOOLS_GMK diff --git a/jdk/make/copy/Copy-java.base.gmk b/jdk/make/copy/Copy-java.base.gmk index ed8e42ae272..04988de5f85 100644 --- a/jdk/make/copy/Copy-java.base.gmk +++ b/jdk/make/copy/Copy-java.base.gmk @@ -172,6 +172,11 @@ ifeq ($(OPENJDK_TARGET_OS), windows) POLICY_SRC_LIST += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/conf/security/java.policy endif +# Allow imported modules to modify the java.policy +ifneq ($(IMPORT_MODULES_CONF), ) + POLICY_SRC_LIST += $(wildcard $(IMPORT_MODULES_CONF)/java.base/security/java.policy.extra) +endif + POLICY_SRC_LIST += $(POLICY_SRC) $(POLICY_DST): $(POLICY_SRC_LIST) diff --git a/jdk/make/data/jdwp/jdwp.spec b/jdk/make/data/jdwp/jdwp.spec index 8d05bebcc02..a144c896f92 100644 --- a/jdk/make/data/jdwp/jdwp.spec +++ b/jdk/make/data/jdwp/jdwp.spec @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -569,6 +569,21 @@ JDWP "Java(tm) Debug Wire Protocol" (Error VM_DEAD) ) ) + (Command AllModules=22 + "Returns all modules in the target VM." + "

Since JDWP version 9." + (Out + ) + (Reply + (Repeat modules "The number of the modules that follow." + (moduleID module "One of the modules.") + ) + ) + (ErrorSet + (Error NOT_IMPLEMENTED) + (Error VM_DEAD) + ) + ) ) (CommandSet ReferenceType=2 @@ -1029,6 +1044,22 @@ JDWP "Java(tm) Debug Wire Protocol" (Error VM_DEAD) ) ) + (Command Module=19 + "Returns the module that this reference type belongs to." + "

Since JDWP version 9." + (Out + (referenceType refType "The reference type.") + ) + (Reply + (moduleID module "The module this reference type belongs to.") + ) + (ErrorSet + (Error INVALID_CLASS "refType is not the ID of a reference type.") + (Error INVALID_OBJECT "refType is not a known ID.") + (Error NOT_IMPLEMENTED) + (Error VM_DEAD) + ) + ) ) (CommandSet ClassType=3 (Command Superclass=1 @@ -2647,6 +2678,54 @@ JDWP "Java(tm) Debug Wire Protocol" ) ) ) +(CommandSet ModuleReference=18 + (Command Name=1 + "Returns the name of this module." + "

Since JDWP version 9." + (Out + (moduleID module "This module.") + ) + (Reply + (string name "The module's name.") + ) + (ErrorSet + (Error INVALID_MODULE) + (Error NOT_IMPLEMENTED) + (Error VM_DEAD) + ) + ) + (Command ClassLoader=2 + "Returns the class loader of this module." + "

Since JDWP version 9." + (Out + (moduleID module "This module.") + ) + (Reply + (classLoaderObject classLoader "The module's class loader.") + ) + (ErrorSet + (Error INVALID_MODULE) + (Error NOT_IMPLEMENTED) + (Error VM_DEAD) + ) + ) + (Command CanRead=3 + "Returns true if this module can read the source module; false otherwise." + "

Since JDWP version 9." + (Out + (moduleID module "This module.") + (moduleID sourceModule "The source module.") + ) + (Reply + (boolean canRead "true if this module can read the source module; false otherwise.") + ) + (ErrorSet + (Error INVALID_MODULE "This module or sourceModule is not the ID of a module.") + (Error NOT_IMPLEMENTED) + (Error VM_DEAD) + ) + ) +) (CommandSet Event=64 (Command Composite=100 "Several events may occur at a given time in the target VM. " @@ -3054,6 +3133,7 @@ JDWP "Java(tm) Debug Wire Protocol" (Constant INVALID_SLOT =35 "Invalid slot.") (Constant DUPLICATE =40 "Item already set.") (Constant NOT_FOUND =41 "Desired element not found.") + (Constant INVALID_MODULE =42 "Invalid module.") (Constant INVALID_MONITOR =50 "Invalid monitor.") (Constant NOT_MONITOR_OWNER =51 "This thread doesn't own the monitor.") (Constant INTERRUPT =52 "The call has been interrupted before completion.") diff --git a/jdk/make/gendata/GendataBreakIterator.gmk b/jdk/make/gendata/GendataBreakIterator.gmk index 2ca835c23d3..1aa4becefac 100644 --- a/jdk/make/gendata/GendataBreakIterator.gmk +++ b/jdk/make/gendata/GendataBreakIterator.gmk @@ -33,8 +33,6 @@ # They are used at JDK build phase in order to create $(BIFILES) which # are used on runtime instead. # -TEXT_SRCDIR := $(JDK_TOPDIR)/src/java.base/share/classes \ - $(JDK_TOPDIR)/src/jdk.localedata/share/classes TEXT_PKG := sun/text/resources TEXT_PKG_LD := $(TEXT_PKG)/ext TEXT_SOURCES := $(TEXT_PKG)/BreakIteratorRules.java \ @@ -46,11 +44,35 @@ TEXT_SOURCES := $(TEXT_PKG)/BreakIteratorRules.java \ BREAK_ITERATOR_CLASSES := $(BUILDTOOLS_OUTPUTDIR)/break_iterator_classes # These two files should be moved out to a build tool! -$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR, \ +$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_BASE, \ SETUP := GENERATE_OLDBYTECODE, \ - SRC := $(TEXT_SRCDIR), \ - INCLUDE_FILES := $(TEXT_SOURCES), \ - BIN := $(BREAK_ITERATOR_CLASSES))) + SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \ + INCLUDE_FILES := \ + $(TEXT_PKG)/BreakIteratorRules.java \ + $(TEXT_PKG)/BreakIteratorInfo.java, \ + BIN := $(BREAK_ITERATOR_CLASSES)/java.base)) + +$(eval $(call SetupJavaCompilation,BUILD_BREAKITERATOR_LD, \ + SETUP := GENERATE_OLDBYTECODE, \ + SRC := $(JDK_TOPDIR)/src/jdk.localedata/share/classes, \ + INCLUDES := $(TEXT_PKG_LD), \ + INCLUDE_FILES := \ + $(TEXT_PKG_LD)/BreakIteratorRules_th.java \ + $(TEXT_PKG_LD)/BreakIteratorInfo_th.java, \ + BIN := $(BREAK_ITERATOR_CLASSES)/jdk.localedata)) + +ifeq ($(BOOT_JDK_MODULAR), true) + BREAK_ITERATOR_BOOTCLASSPATH := -Xpatch:$(BREAK_ITERATOR_CLASSES) \ + -XaddExports:$(subst $(SPACE),$(COMMA),$(strip \ + java.base/sun.text=ALL-UNNAMED \ + java.base/sun.text.resources=ALL-UNNAMED \ + jdk.localedata/sun.text.resources.ext=ALL-UNNAMED \ + )) +else + BREAK_ITERATOR_BOOTCLASSPATH := -Xbootclasspath/p:$(call PathList, \ + $(BREAK_ITERATOR_CLASSES)/java.base \ + $(BREAK_ITERATOR_CLASSES)/jdk.localedata) +endif # Generate data resource files. # input @@ -67,8 +89,9 @@ BIFILES_TH := $(LD_DATA_PKG_DIR)/WordBreakIteratorData_th \ $(LD_DATA_PKG_DIR)/LineBreakIteratorData_th $(BIFILES): $(BASE_DATA_PKG_DIR)/_the.bifiles -$(BASE_DATA_PKG_DIR)/_the.bifiles: JAVA_FLAGS += -Xbootclasspath/p:$(BREAK_ITERATOR_CLASSES) -$(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKITERATOR) +$(BASE_DATA_PKG_DIR)/_the.bifiles: JAVA_FLAGS += $(BREAK_ITERATOR_BOOTCLASSPATH) +$(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) \ + $(BUILD_BREAKITERATOR_BASE) $(BUILD_BREAKITERATOR_LD) $(call LogInfo, Generating BreakIteratorData) $(call MakeDir, $(@D)) $(RM) $(BIFILES) @@ -78,8 +101,9 @@ $(BASE_DATA_PKG_DIR)/_the.bifiles: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKIT $(TOUCH) $@ $(BIFILES_TH): $(LD_DATA_PKG_DIR)/_the.bifiles_th -$(LD_DATA_PKG_DIR)/_the.bifiles_th: JAVA_FLAGS += -Xbootclasspath/p:$(BREAK_ITERATOR_CLASSES) -$(LD_DATA_PKG_DIR)/_the.bifiles_th: $(BUILD_TOOLS) $(UNICODEDATA) $(BUILD_BREAKITERATOR) +$(LD_DATA_PKG_DIR)/_the.bifiles_th: JAVA_FLAGS += $(BREAK_ITERATOR_BOOTCLASSPATH) +$(LD_DATA_PKG_DIR)/_the.bifiles_th: $(BUILD_TOOLS) $(UNICODEDATA) \ + $(BUILD_BREAKITERATOR_BASE) $(BUILD_BREAKITERATOR_LD) $(call LogInfo, Generating BreakIteratorData_th) $(RM) $(BIFILES_TH) $(TOOL_GENERATEBREAKITERATORDATA) \ diff --git a/jdk/make/gensrc/Gensrc-java.base.gmk b/jdk/make/gensrc/Gensrc-java.base.gmk index e176d88ea7e..1a188a9a786 100644 --- a/jdk/make/gensrc/Gensrc-java.base.gmk +++ b/jdk/make/gensrc/Gensrc-java.base.gmk @@ -33,6 +33,7 @@ include GensrcCharsetMapping.gmk include GensrcCharsetCoder.gmk include GensrcBuffer.gmk include GensrcExceptions.gmk +include GensrcModuleLoaderMap.gmk ################################################################################ diff --git a/jdk/make/gensrc/Gensrc-jdk.jdi.gmk b/jdk/make/gensrc/Gensrc-jdk.jdi.gmk index e634c12b6bb..720b685ef4b 100644 --- a/jdk/make/gensrc/Gensrc-jdk.jdi.gmk +++ b/jdk/make/gensrc/Gensrc-jdk.jdi.gmk @@ -61,30 +61,6 @@ GENSRC_JDK_JDI += $(GENSRC_JDWP) ################################################################################ -define process-provider - $(call MakeDir, $(@D)) - $(CAT) $^ | $(SED) -e "s/^#\[$(OPENJDK_TARGET_OS)\]//" > $@ -endef - -# Filter com.sun.jdi.connect.Connector -$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector: \ - $(JDK_TOPDIR)/src/jdk.jdi/share/classes/META-INF/services/com.sun.jdi.connect.Connector \ - $(HOTSPOT_TOPDIR)/src/jdk.hotspot.agent/share/classes/META-INF/services/com.sun.jdi.connect.Connector - $(process-provider) - -# Copy the same service file into jdk.hotspot.agent so that they are kept the same. -$(SUPPORT_OUTPUTDIR)/gensrc/jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector: \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector - $(install-file) - -# Some platforms don't have the serviceability agent -ifeq ($(INCLUDE_SA), true) - GENSRC_JDK_JDI += $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/META-INF/services/com.sun.jdi.connect.Connector \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.hotspot.agent/META-INF/services/com.sun.jdi.connect.Connector -endif - -################################################################################ - include GensrcProperties.gmk $(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \ diff --git a/jdk/make/gensrc/Gensrc-jdk.dev.gmk b/jdk/make/gensrc/Gensrc-jdk.jlink.gmk similarity index 71% rename from jdk/make/gensrc/Gensrc-jdk.dev.gmk rename to jdk/make/gensrc/Gensrc-jdk.jlink.gmk index 4316c485883..c841345c737 100644 --- a/jdk/make/gensrc/Gensrc-jdk.dev.gmk +++ b/jdk/make/gensrc/Gensrc-jdk.jlink.gmk @@ -29,12 +29,23 @@ include GensrcCommon.gmk include GensrcProperties.gmk -$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \ - SRC_DIRS := $(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/tools/jimage/resources, \ +$(eval $(call SetupCompileProperties, JLINK_PROPERTIES, \ + SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jlink/share/classes/jdk/tools/jlink/resources, \ CLASS := ListResourceBundle, \ )) -TARGETS += $(COMPILE_PROPERTIES) +$(eval $(call SetupCompileProperties, JMOD_PROPERTIES, \ + SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jlink/share/classes/jdk/tools/jmod/resources, \ + CLASS := ListResourceBundle, \ +)) + +$(eval $(call SetupCompileProperties, JIMAGE_PROPERTIES, \ + SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jlink/share/classes/jdk/tools/jimage/resources, \ + CLASS := ListResourceBundle, \ +)) + + +TARGETS += $(JLINK_PROPERTIES) $(JMOD_PROPERTIES) $(JIMAGE_PROPERTIES) ################################################################################ diff --git a/jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk b/jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk deleted file mode 100644 index 11e54a6f635..00000000000 --- a/jdk/make/gensrc/Gensrc-jdk.jvmstat.gmk +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -include GensrcCommon.gmk - -################################################################################ - -define merge-providers - $(MKDIR) -p $(@D) - $(CAT) $^ > $@ -endef - -PROVIDER_FILE := META-INF/services/sun.jvmstat.monitor.MonitoredHostService - -# Merge the local and remote sevice providers into jdk.jvmstat/META-INF/services -$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE): \ - $(JDK_TOPDIR)/src/jdk.jvmstat/share/classes/$(PROVIDER_FILE) \ - $(JDK_TOPDIR)/src/jdk.jvmstat.rmi/share/classes/$(PROVIDER_FILE) - $(merge-providers) - -# Copy the same service file into jdk.jvmstat.rmi so that they are kept the same. -$(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat.rmi/$(PROVIDER_FILE): \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE) - $(install-file) - -################################################################################ - -jdk.jvmstat: $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat/$(PROVIDER_FILE) \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jvmstat.rmi/$(PROVIDER_FILE) - -all: jdk.jvmstat - -.PHONY: all \ No newline at end of file diff --git a/jdk/make/gensrc/GensrcLocaleData.gmk b/jdk/make/gensrc/GensrcLocaleData.gmk index 602a4f4752f..0acc8f9591f 100644 --- a/jdk/make/gensrc/GensrcLocaleData.gmk +++ b/jdk/make/gensrc/GensrcLocaleData.gmk @@ -143,19 +143,6 @@ $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonBaseLo GENSRC_BASELOCALEDATA := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/provider/BaseLocaleDataMetaInfo.java GENSRC_LOCALEDATA := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata/sun/util/resources/provider/NonBaseLocaleDataMetaInfo.java -################################################################################ - -GENSRC_CRBC_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/CoreResourceBundleControl.java -GENSRC_CRBC_CMD := $(JDK_TOPDIR)/make/scripts/localelist.sh - -JRE_NONEXIST_LOCALES := en en_US de_DE es_ES fr_FR it_IT ja_JP ko_KR sv_SE zh - -$(GENSRC_CRBC_DST): $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template \ - $(GENSRC_CRBC_CMD) - $(MKDIR) -p $(@D) - NAWK="$(NAWK)" SED="$(SED)" $(SH) $(GENSRC_CRBC_CMD) "$(JRE_NONEXIST_LOCALES)" $< $@ - -GENSRC_BASELOCALEDATA += $(GENSRC_CRBC_DST) GENSRC_JAVA_BASE += $(GENSRC_BASELOCALEDATA) GENSRC_JDK_LOCALEDATA += $(GENSRC_LOCALEDATA) diff --git a/jdk/make/gensrc/GensrcModuleLoaderMap.gmk b/jdk/make/gensrc/GensrcModuleLoaderMap.gmk new file mode 100644 index 00000000000..7e8fb339f5d --- /dev/null +++ b/jdk/make/gensrc/GensrcModuleLoaderMap.gmk @@ -0,0 +1,164 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +include Modules.gmk + +BOOT_MODULES := +UPGRADEABLE_MDOULES := +AGGREGATOR_MDOULES := +OTHER_PLATFORM_MODULES := + +# Hook to include the corresponding custom file, if present. +$(eval $(call IncludeCustomExtension, jdk, gensrc/GensrcModuleLoaderMap.gmk)) + +BOOT_MODULES += \ + java.base \ + java.datatransfer \ + java.desktop \ + java.httpclient \ + java.instrument \ + java.logging \ + java.management \ + java.naming \ + java.prefs \ + java.rmi \ + java.security.jgss \ + java.security.sasl \ + java.sql \ + java.xml \ + java.xml.crypto \ + jdk.httpserver \ + jdk.management \ + jdk.sctp \ + jdk.security.auth \ + jdk.security.jgss \ + # + +# to be deprivileged +BOOT_MODULES += \ + java.compiler \ + java.scripting \ + java.sql.rowset \ + java.smartcardio \ + jdk.charsets \ + jdk.naming.rmi \ + # + +UPGRADEABLE_MODULES += \ + java.activation \ + java.annotations.common \ + java.corba \ + java.transaction \ + java.xml.bind \ + java.xml.ws \ + # + +AGGREGATOR_MODULES += \ + java.compact1 \ + java.compact2 \ + java.compact3 \ + java.se \ + java.se.ee \ + # + +OTHER_PLATFORM_MODULES += \ + jdk.accessibility \ + jdk.crypto.ec \ + jdk.crypto.pkcs11 \ + jdk.dynalink \ + jdk.jsobject \ + jdk.xml.dom \ + jdk.localedata \ + jdk.naming.dns \ + jdk.scripting.nashorn \ + jdk.zipfs \ + # + +ifeq ($(OPENJDK_TARGET_OS), macsox) + BOOT_MODULES += jdk.deploy.osx +endif +ifeq ($(OPENJDK_TARGET_OS), windows) + OTHER_PLATFORM_MODULES += jdk.crypto.mscapi +endif +ifeq ($(OPENJDK_TARGET_OS), solaris) + OTHER_PLATFORM_MODULES += jdk.crypto.ucrypto +endif + +# Param 1 - Name of module +define ReadImportMetaData + ifneq ($$(wildcard $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties), ) + classloader := + include $(IMPORT_MODULES_MAKE)/$$(strip $1)/build.properties + ifeq ($$(classloader), boot) + BOOT_MODULES += $1 + else ifeq ($$(classloader), ext) + OTHER_PLATFORM_MODULES += $1 + endif + endif +endef + +IMPORTED_MODULES := $(call FindImportedModules) +$(foreach m, $(IMPORTED_MODULES), $(eval $(call ReadImportMetaData, $m))) + + +# Replacing double-comma with a single comma is to workaround the issue +# with some version of make on windows that doesn't substitute spaces +# with one comma properly as with make 4.0 +define SubstComma +$(strip \ + $(subst $(COMMA)$(COMMA),$(COMMA),$(subst $(SPACE),$(COMMA),$(strip $1))) \ +) +endef +BOOT_MODULES_LIST := $(call SubstComma, $(BOOT_MODULES)) +PLATFORM_MODULES_LIST := $(call SubstComma, $(UPGRADEABLE_MODULES) $(AGGREGATOR_MODULES) $(OTHER_PLATFORM_MODULES)) + +VARDEPS_VALUE := $(BOOT_MODULES_LIST) $(PLATFORM_MODULES_LIST) +VARDEPS_FILE := $(call DependOnVariable, VARDEPS_VALUE) + +############################################################################ + +$(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java: \ + $(JDK_TOPDIR)/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java \ + $(VARDEPS_FILE) $(BUILD_TOOLS_JDK) + $(MKDIR) -p $(@D) + $(RM) $@ $@.tmp + $(TOOL_GENCLASSLOADERMAP) -boot $(BOOT_MODULES_LIST) \ + -platform $(PLATFORM_MODULES_LIST) -o $@.tmp $< + $(MV) $@.tmp $@ + +GENSRC_JAVA_BASE += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/module/ModuleLoaderMap.java + +$(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat: \ + $(JDK_TOPDIR)/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat \ + $(VARDEPS_FILE) $(BUILD_TOOLS_JDK) + $(MKDIR) -p $(@D) + $(RM) $@ $@.tmp + $(TOOL_GENCLASSLOADERMAP) -boot $(BOOT_MODULES_LIST) \ + -platform $(PLATFORM_MODULES_LIST) -o $@.tmp $< + $(MV) $@.tmp $@ + +GENSRC_JAVA_BASE += $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat + +################################################################################ diff --git a/jdk/make/launcher/Launcher-java.desktop.gmk b/jdk/make/launcher/Launcher-java.desktop.gmk index 2bb3c4923f2..c9f730f4d71 100644 --- a/jdk/make/launcher/Launcher-java.desktop.gmk +++ b/jdk/make/launcher/Launcher-java.desktop.gmk @@ -31,6 +31,7 @@ $(eval $(call IncludeCustomExtension, jdk, launcher/Launcher-java.desktop.gmk)) ifndef BUILD_HEADLESS_ONLY $(eval $(call SetupBuildLauncher, appletviewer, \ MAIN_CLASS := sun.applet.Main, \ + JAVA_ARGS := -addmods ALL-SYSTEM, \ LIBS_unix := $(X_LIBS), \ )) endif diff --git a/jdk/make/launcher/Launcher-jdk.dev.gmk b/jdk/make/launcher/Launcher-jdk.jlink.gmk similarity index 69% rename from jdk/make/launcher/Launcher-jdk.dev.gmk rename to jdk/make/launcher/Launcher-jdk.jlink.gmk index d874ae9372c..acf8228b6c4 100644 --- a/jdk/make/launcher/Launcher-jdk.dev.gmk +++ b/jdk/make/launcher/Launcher-jdk.jlink.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -27,4 +27,19 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, jimage,\ MAIN_CLASS := jdk.tools.jimage.Main, \ + CFLAGS := -DENABLE_ARG_FILES, \ +)) + +$(eval $(call SetupBuildLauncher, jlink,\ + MAIN_CLASS := jdk.tools.jlink.internal.Main, \ + CFLAGS := -DENABLE_ARG_FILES \ + -DEXPAND_CLASSPATH_WILDCARDS \ + -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \ +)) + +$(eval $(call SetupBuildLauncher, jmod,\ + MAIN_CLASS := jdk.tools.jmod.Main, \ + CFLAGS := -DENABLE_ARG_FILES \ + -DEXPAND_CLASSPATH_WILDCARDS \ + -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \ )) diff --git a/jdk/make/launcher/Launcher-jdk.pack200.gmk b/jdk/make/launcher/Launcher-jdk.pack200.gmk index 818828a2929..af050554a79 100644 --- a/jdk/make/launcher/Launcher-jdk.pack200.gmk +++ b/jdk/make/launcher/Launcher-jdk.pack200.gmk @@ -26,6 +26,7 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, pack200, \ + MAIN_MODULE := java.base, \ MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \ )) diff --git a/jdk/make/launcher/Launcher-jdk.rmic.gmk b/jdk/make/launcher/Launcher-jdk.rmic.gmk index d60c3d9b60b..b0a8b6dc81a 100644 --- a/jdk/make/launcher/Launcher-jdk.rmic.gmk +++ b/jdk/make/launcher/Launcher-jdk.rmic.gmk @@ -26,6 +26,6 @@ include LauncherCommon.gmk $(eval $(call SetupBuildLauncher, rmic, \ - MAIN_CLASS := sun.rmi.rmic.Main, \ + MAIN_CLASS := jdk.rmi.rmic.Main, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS, \ )) diff --git a/jdk/make/launcher/LauncherCommon.gmk b/jdk/make/launcher/LauncherCommon.gmk index d35b8b71348..1bef88f8a42 100644 --- a/jdk/make/launcher/LauncherCommon.gmk +++ b/jdk/make/launcher/LauncherCommon.gmk @@ -63,6 +63,8 @@ JAVA_MANIFEST := $(JDK_TOPDIR)/src/java.base/windows/native/launcher/java.manife # used as the name of the executable. # # Remaining parameters are named arguments. These include: +# MAIN_MODULE The module of the main class to launch if different from the +# current module # MAIN_CLASS The Java main class to launch # JAVA_ARGS Processed into a -DJAVA_ARGS C flag # CFLAGS Additional CFLAGS @@ -97,9 +99,13 @@ define SetupBuildLauncherBody $1_JAVA_ARGS += -ms8m endif + ifeq ($$($1_MAIN_MODULE), ) + $1_MAIN_MODULE := $(MODULE) + endif + ifneq ($$($1_JAVA_ARGS), ) $1_JAVA_ARGS_STR := '{ $$(strip $$(foreach a, \ - $$(addprefix -J, $$($1_JAVA_ARGS)) $$($1_MAIN_CLASS), "$$a"$(COMMA) )) }' + $$(addprefix -J, $$($1_JAVA_ARGS)) -m $$($1_MAIN_MODULE)/$$($1_MAIN_CLASS), "$$a"$(COMMA) )) }' $1_CFLAGS += -DJAVA_ARGS=$$($1_JAVA_ARGS_STR) endif diff --git a/jdk/make/lib/CoreLibraries.gmk b/jdk/make/lib/CoreLibraries.gmk index 9dcf06be11a..f114c9b7d33 100644 --- a/jdk/make/lib/CoreLibraries.gmk +++ b/jdk/make/lib/CoreLibraries.gmk @@ -146,6 +146,7 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBJAVA, \ $(LIBJAVA_CFLAGS), \ System.c_CFLAGS := $(VERSION_CFLAGS), \ jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \ + DISABLED_WARNINGS_gcc := unused-result, \ DISABLED_WARNINGS_solstudio := E_STATEMENT_NOT_REACHED, \ MAPFILE := $(LIBJAVA_MAPFILE), \ LDFLAGS := $(LDFLAGS_JDKLIB) \ diff --git a/jdk/make/lib/Lib-java.instrument.gmk b/jdk/make/lib/Lib-java.instrument.gmk index 44ba88dad40..64f25d0eb82 100644 --- a/jdk/make/lib/Lib-java.instrument.gmk +++ b/jdk/make/lib/Lib-java.instrument.gmk @@ -68,14 +68,14 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBINSTRUMENT, \ LDFLAGS_macosx := -Wl$(COMMA)-all_load, \ LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \ LIBS := $(JDKLIB_LIBS), \ - LIBS_unix := -ljava $(LIBZ), \ + LIBS_unix := -ljava -ljvm $(LIBZ), \ LIBS_linux := -ljli $(LIBDL), \ LIBS_solaris := -ljli $(LIBDL), \ LIBS_aix := -liconv -ljli_static $(LIBDL), \ LIBS_macosx := -liconv -framework Cocoa -framework Security \ -framework ApplicationServices \ $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a, \ - LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib \ + LIBS_windows := jvm.lib $(WIN_JAVA_LIB) advapi32.lib \ $(SUPPORT_OUTPUTDIR)/native/java.base/jli_static.lib, \ VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \ RC_FLAGS := $(RC_FLAGS) \ diff --git a/jdk/make/mapfiles/libawt/mapfile-mawt-vers b/jdk/make/mapfiles/libawt/mapfile-mawt-vers index 8f9ee4135a5..247e29698e2 100644 --- a/jdk/make/mapfiles/libawt/mapfile-mawt-vers +++ b/jdk/make/mapfiles/libawt/mapfile-mawt-vers @@ -200,6 +200,7 @@ SUNWprivate_1.1 { Java_sun_print_CUPSPrinter_initIDs; Java_sun_print_CUPSPrinter_getCupsServer; Java_sun_print_CUPSPrinter_getCupsPort; + Java_sun_print_CUPSPrinter_getCupsDefaultPrinter; Java_sun_print_CUPSPrinter_canConnect; Java_sun_print_CUPSPrinter_getMedia; Java_sun_print_CUPSPrinter_getPageSizes; diff --git a/jdk/make/mapfiles/libawt_headless/mapfile-vers b/jdk/make/mapfiles/libawt_headless/mapfile-vers index 5ea1745e296..ac5101042a2 100644 --- a/jdk/make/mapfiles/libawt_headless/mapfile-vers +++ b/jdk/make/mapfiles/libawt_headless/mapfile-vers @@ -73,6 +73,7 @@ SUNWprivate_1.1 { Java_sun_print_CUPSPrinter_initIDs; Java_sun_print_CUPSPrinter_getCupsServer; Java_sun_print_CUPSPrinter_getCupsPort; + Java_sun_print_CUPSPrinter_getCupsDefaultPrinter; Java_sun_print_CUPSPrinter_canConnect; Java_sun_print_CUPSPrinter_getMedia; Java_sun_print_CUPSPrinter_getPageSizes; diff --git a/jdk/make/mapfiles/libawt_xawt/mapfile-vers b/jdk/make/mapfiles/libawt_xawt/mapfile-vers index 182ed0acfd7..42ef24d90a1 100644 --- a/jdk/make/mapfiles/libawt_xawt/mapfile-vers +++ b/jdk/make/mapfiles/libawt_xawt/mapfile-vers @@ -439,6 +439,7 @@ SUNWprivate_1.1 { Java_sun_print_CUPSPrinter_initIDs; Java_sun_print_CUPSPrinter_getCupsServer; Java_sun_print_CUPSPrinter_getCupsPort; + Java_sun_print_CUPSPrinter_getCupsDefaultPrinter; Java_sun_print_CUPSPrinter_canConnect; Java_sun_print_CUPSPrinter_getMedia; Java_sun_print_CUPSPrinter_getPageSizes; diff --git a/jdk/make/mapfiles/libjava/mapfile-vers b/jdk/make/mapfiles/libjava/mapfile-vers index 852716aac1f..d7b2dcbc0ad 100644 --- a/jdk/make/mapfiles/libjava/mapfile-vers +++ b/jdk/make/mapfiles/libjava/mapfile-vers @@ -137,7 +137,6 @@ SUNWprivate_1.1 { Java_java_lang_ClassLoader_registerNatives; Java_java_lang_Double_longBitsToDouble; Java_java_lang_Double_doubleToRawLongBits; - Java_java_lang_reflect_Proxy_defineClass0; Java_java_lang_Float_intBitsToFloat; Java_java_lang_Float_floatToRawIntBits; Java_java_lang_StackFrameInfo_fillInStackFrames; @@ -165,8 +164,6 @@ SUNWprivate_1.1 { Java_java_lang_StrictMath_expm1; Java_java_lang_Object_getClass; Java_java_lang_Object_registerNatives; - Java_java_lang_Package_getSystemPackage0; - Java_java_lang_Package_getSystemPackages0; Java_java_lang_ProcessEnvironment_environ; Java_java_lang_ProcessHandleImpl_destroy0; Java_java_lang_ProcessHandleImpl_getCurrentPid0; @@ -204,11 +201,11 @@ SUNWprivate_1.1 { Java_java_lang_reflect_Executable_getTypeAnnotationBytes0; Java_java_lang_reflect_Field_getTypeAnnotationBytes0; Java_java_lang_Runtime_freeMemory; - Java_java_lang_Runtime_maxMemory; + Java_java_lang_Runtime_maxMemory; Java_java_lang_Runtime_gc; Java_java_lang_Runtime_runFinalization0; Java_java_lang_Runtime_totalMemory; - Java_java_lang_Runtime_availableProcessors; + Java_java_lang_Runtime_availableProcessors; Java_java_lang_SecurityManager_classDepth; Java_java_lang_SecurityManager_classLoaderDepth0; Java_java_lang_SecurityManager_currentClassLoader0; @@ -273,6 +270,18 @@ SUNWprivate_1.1 { Java_jdk_internal_misc_VM_getgid; Java_jdk_internal_misc_VM_getegid; Java_jdk_internal_misc_VM_initialize; + + Java_java_lang_reflect_Module_defineModule0; + Java_java_lang_reflect_Module_addReads0; + Java_java_lang_reflect_Module_addExports0; + Java_java_lang_reflect_Module_addExportsToAll0; + Java_java_lang_reflect_Module_addExportsToAllUnnamed0; + Java_java_lang_reflect_Module_addPackage0; + + Java_jdk_internal_loader_BootLoader_getSystemPackageLocation; + Java_jdk_internal_loader_BootLoader_getSystemPackageNames; + Java_jdk_internal_loader_BootLoader_setBootLoaderUnnamedModule0; + Java_sun_misc_VMSupport_initAgentProperties; Java_sun_misc_VMSupport_getVMTemporaryDirectory; diff --git a/jdk/make/mapfiles/libjimage/mapfile-vers b/jdk/make/mapfiles/libjimage/mapfile-vers index 68e01c657d8..48eac21b53a 100644 --- a/jdk/make/mapfiles/libjimage/mapfile-vers +++ b/jdk/make/mapfiles/libjimage/mapfile-vers @@ -27,23 +27,7 @@ SUNWprivate_1.1 { global: - JNI_OnLoad; - Java_jdk_internal_jimage_ImageNativeSubstrate_openImage; - Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage; - Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress; - Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress; - Java_jdk_internal_jimage_ImageNativeSubstrate_read; - Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed; - Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes; - Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes; - Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes; - Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets; - Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open; - Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close; - Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource; - Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource; - Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule; - Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources; + Java_jdk_internal_jimage_NativeImageBuffer_getNativeMap; JIMAGE_Open; JIMAGE_Close; JIMAGE_PackageToModule; diff --git a/jdk/make/rmic/Rmic-java.management.gmk b/jdk/make/rmic/Rmic-java.management.gmk index 9eca430ed63..0452d5cbba5 100644 --- a/jdk/make/rmic/Rmic-java.management.gmk +++ b/jdk/make/rmic/Rmic-java.management.gmk @@ -40,7 +40,7 @@ JMX_RMI_CLASSES := javax.management.remote.rmi.RMIConnectionImpl \ $(eval $(call SetupRMICompilation,RMI_GEN, \ CLASSES := $(JMX_RMI_CLASSES), \ CLASSES_DIR := $(CLASSES_DIR)/java.management, \ - STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR), \ + STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR)/java.management, \ RUN_V12 := true, \ KEEP_GENERATED := true, \ )) @@ -50,7 +50,7 @@ $(RMIC_GENSRC_DIR)/_classes.moved: $(RMI_GEN) $(eval classfiles := $(shell $(FIND) $(RMIC_GENSRC_DIR) -name "*.class")) $(foreach src, $(classfiles), \ $(eval target := $(patsubst $(RMIC_GENSRC_DIR)/%, \ - $(STUB_CLASSES_DIR)/java.management/%, $(src))) \ + $(STUB_CLASSES_DIR)/%, $(src))) \ $(MKDIR) -p $(dir $(target)) ; \ $(MV) $(src) $(target) $(NEWLINE)) $(TOUCH) $@ diff --git a/jdk/make/rmic/RmicCommon.gmk b/jdk/make/rmic/RmicCommon.gmk index 8c6affb1015..45fd1de853f 100644 --- a/jdk/make/rmic/RmicCommon.gmk +++ b/jdk/make/rmic/RmicCommon.gmk @@ -31,10 +31,7 @@ include RMICompilation.gmk ########################################################################################## -BTRMIC_CP := $(call PathList, \ - $(BUILDTOOLS_OUTPUTDIR)/interim_rmic_classes $(INTERIM_LANGTOOLS_JAR)) -BTRMIC_ARGS := -cp $(BTRMIC_CP) -RMIC := $(JAVA) $(BTRMIC_ARGS) sun.rmi.rmic.Main +RMIC := $(JAVA) $(INTERIM_OVERRIDE_MODULES_ARGS) sun.rmi.rmic.Main CLASSES_DIR := $(JDK_OUTPUTDIR)/modules # NOTE: If the smart javac dependency management is reintroduced, these classes risk diff --git a/jdk/make/scripts/localelist.sh b/jdk/make/scripts/localelist.sh deleted file mode 100644 index 96fa02b0c9f..00000000000 --- a/jdk/make/scripts/localelist.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2005, 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. -# - -# -# This script is to generate the supported locale list string and replace the -# #LOCALE_LIST# in /src/share/classes/sun/util/CoreResourceBundleControl.java. -# -# NAWK & SED is passed in as environment variables. -# -LOCALE_LIST=$1 -INUT_FILE=$2 -OUTPUT_FILE=$3 - -LOCALES=`(for I in $LOCALE_LIST; do echo $I;done) | sort | uniq` -JAVA_LOCALES= - -toJavaLocale() -{ - NewLocale=`echo $1 | $NAWK ' - BEGIN { - # The following values have to be consistent with java.util.Locale. - javalocales["en"] = "ENGLISH"; - javalocales["fr"] = "FRENCH"; - javalocales["de"] = "GERMAN"; - javalocales["it"] = "ITALIAN"; - javalocales["ja"] = "JAPANESE"; - javalocales["ko"] = "KOREAN"; - javalocales["zh"] = "CHINESE"; - javalocales["zh_CN"] = "SIMPLIFIED_CHINESE"; - javalocales["zh_TW"] = "TRADITIONAL_CHINESE"; - javalocales["fr_FR"] = "FRANCE"; - javalocales["de_DE"] = "GERMANY"; - javalocales["it_IT"] = "ITALY"; - javalocales["ja_JP"] = "JAPAN"; - javalocales["ko_KR"] = "KOREA"; - javalocales["en_GB"] = "UK"; - javalocales["en_US"] = "US"; - javalocales["en_CA"] = "CANADA"; - javalocales["fr_CA"] = "CANADA_FRENCH"; - } - { - if ($0 in javalocales) { - print " Locale." javalocales[$0]; - } else { - split($0, a, "_"); - if (a[3] != "") { - print " new Locale(\"" a[1] "\", \"" a[2] "\", \"" a[3] "\")"; - } else if (a[2] != "") { - print " new Locale(\"" a[1] "\", \"" a[2] "\")"; - } else { - print " new Locale(\"" a[1] "\")"; - } - } - }'` - - JAVA_LOCALES=$JAVA_LOCALES$NewLocale -} - -# count the number of locales -counter=0 -for i in $LOCALES -do - counter=`expr $counter + 1` -done - -index=0 -for locale in $LOCALES -do - index=`expr $index + 1`; - if [ $index != $counter ] - then - toJavaLocale $locale - JAVA_LOCALES=$JAVA_LOCALES"," - else - toJavaLocale $locale - fi -done - -# replace the #LOCALE_LIST# in the precompiled CoreResourceBundleControl.java file. - -$SED -e "s@^#warn .*@// -- This file was mechanically generated: Do not edit! -- //@" \ - -e "s/#LOCALE_LIST#/$JAVA_LOCALES/g" $2 > $3 diff --git a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 500cf2b10e4..b291758402f 100644 --- a/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/jdk/make/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -343,9 +343,7 @@ class ResourceBundleGenerator implements BundleGenerator { if (!all && CLDRConverter.isBaseModule ^ isBaseLocale(id)) { continue; } - if (sb.length() > 0) { - sb.append(' '); - } + sb.append(' '); sb.append(id); } } diff --git a/jdk/make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java b/jdk/make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java index c22fa683c80..f0821e8a366 100644 --- a/jdk/make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java +++ b/jdk/make/src/classes/build/tools/generatebreakiteratordata/GenerateBreakIteratorData.java @@ -62,25 +62,37 @@ public class GenerateBreakIteratorData { CharacterCategory.makeCategoryMap(unicodeData); /* Generate files */ - generateFiles(); + try { + generateFiles(); + } catch (Exception e) { + e.printStackTrace(); + System.exit(1); + } + } + + private static String localizedBundleName(String pkg, String clazz) { + if (language.length() > 0) { + return pkg + ".ext." + clazz + '_' + language; + } else { + return pkg + '.' + clazz; + } } /** * Generate data files whose names are included in * sun.text.resources.BreakIteratorInfo+ */ - private static void generateFiles() { + private static void generateFiles() throws Exception { String[] classNames; ResourceBundle rules, info; - String pkgName = "sun.text.resources" + (language.length() > 0 ? ".ext" : ""); + info = (ResourceBundle) Class.forName( + localizedBundleName("sun.text.resources", "BreakIteratorInfo")).newInstance(); - info = ResourceBundle.getBundle(pkgName + ".BreakIteratorInfo", - new Locale(language, country, valiant)); classNames = info.getStringArray("BreakIteratorClasses"); - rules = ResourceBundle.getBundle(pkgName + ".BreakIteratorRules", - new Locale(language, country, valiant)); + rules = (ResourceBundle) Class.forName( + localizedBundleName("sun.text.resources", "BreakIteratorRules")).newInstance(); if (info.containsKey("CharacterData")) { generateDataFile(info.getString("CharacterData"), diff --git a/jdk/make/src/classes/build/tools/jdwpgen/ModuleTypeNode.java b/jdk/make/src/classes/build/tools/jdwpgen/ModuleTypeNode.java new file mode 100644 index 00000000000..af128520cfd --- /dev/null +++ b/jdk/make/src/classes/build/tools/jdwpgen/ModuleTypeNode.java @@ -0,0 +1,56 @@ +/* + * 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 build.tools.jdwpgen; + +import java.util.*; +import java.io.*; + +class ModuleTypeNode extends AbstractSimpleTypeNode { + + String docType() { + return "moduleID"; + } + + String javaType() { + return "ModuleReferenceImpl"; + } + + String debugValue(String label) { + return "(" + label + "==null?\"NULL\":\"ref=\"+" + label + ".ref())"; + } + + public void genJavaWrite(PrintWriter writer, int depth, + String writeLabel) { + genJavaDebugWrite(writer, depth, writeLabel, + debugValue(writeLabel)); + indent(writer, depth); + writer.println("ps.writeModuleRef(" + writeLabel + ".ref());"); + } + + String javaRead() { + return "ps.readModule()"; + } +} diff --git a/jdk/make/src/classes/build/tools/jdwpgen/Parse.java b/jdk/make/src/classes/build/tools/jdwpgen/Parse.java index 5b172e5dae5..4ac854b09c8 100644 --- a/jdk/make/src/classes/build/tools/jdwpgen/Parse.java +++ b/jdk/make/src/classes/build/tools/jdwpgen/Parse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -80,6 +80,7 @@ class Parse { kindMap.put("field", new FieldTypeNode()); kindMap.put("frame", new FrameTypeNode()); kindMap.put("string", new StringTypeNode()); + kindMap.put("moduleID", new ModuleTypeNode()); kindMap.put("value", new ValueTypeNode()); kindMap.put("byte", new ByteTypeNode()); kindMap.put("location", new LocationTypeNode()); diff --git a/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java new file mode 100644 index 00000000000..da774751e1c --- /dev/null +++ b/jdk/make/src/classes/build/tools/jigsaw/GenGraphs.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.jigsaw; + +import java.io.IOException; +import java.io.PrintStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.function.Function; +import java.util.stream.Collectors; +import static java.lang.module.ModuleDescriptor.Requires.Modifier.PUBLIC; + +/** + * Generate the DOT file for a module graph for each module in the JDK + * after transitive reduction. + */ +public class GenGraphs { + + public static void main(String[] args) throws Exception { + + if (args.length != 1) { + System.err.println("ERROR: specify the output directory"); + System.exit(1); + } + Path dir = Paths.get(args[0]); + Files.createDirectories(dir); + + ModuleFinder finder = ModuleFinder.ofSystem(); + + Set javaSEModules + = new TreeSet<>(finder.findAll().stream() + .map(ModuleReference::descriptor) + .filter(m -> (m.name().startsWith("java.") && + !m.name().equals("java.smartcardio"))) + .collect(Collectors.toSet())); + Set jdkModules + = new TreeSet<>(finder.findAll().stream() + .map(ModuleReference::descriptor) + .filter(m -> !javaSEModules.contains(m)) + .collect(Collectors.toSet())); + + GenGraphs genGraphs = new GenGraphs(javaSEModules, jdkModules); + Set mods = new HashSet<>(); + for (ModuleReference mref: finder.findAll()) { + ModuleDescriptor descriptor = mref.descriptor(); + String name = descriptor.name(); + mods.add(name); + Configuration cf = Configuration.empty() + .resolveRequires(finder, + ModuleFinder.empty(), + Set.of(name)); + genGraphs.genDotFile(dir, name, cf); + } + + Configuration cf = Configuration.empty() + .resolveRequires(finder, + ModuleFinder.empty(), + mods); + genGraphs.genDotFile(dir, "jdk", cf); + + } + + private final Set javaGroup; + private final Set jdkGroup; + + GenGraphs(Set javaGroup, Set jdkGroup) { + this.javaGroup = Collections.unmodifiableSet(javaGroup); + this.jdkGroup = Collections.unmodifiableSet(jdkGroup); + } + + private static final String ORANGE = "#e76f00"; + private static final String BLUE = "#437291"; + private static final String GRAY = "#dddddd"; + + private static final String REEXPORTS = ""; + private static final String REQUIRES = "style=\"dashed\""; + private static final String REQUIRES_BASE = "color=\"" + GRAY + "\""; + + private static final Map weights = new HashMap<>(); + + private static void weight(String s, String t, int w) { + weights.put(s + ":" + t, w); + } + + private static int weightOf(String s, String t) { + int w = weights.getOrDefault(s + ":" + t, 1); + if (w != 1) + return w; + if (s.startsWith("java.") && t.startsWith("java.")) + return 10; + return 1; + } + + static { + int h = 1000; + weight("java.se", "java.compact3", h * 10); + weight("jdk.compact3", "java.compact3", h * 10); + weight("java.compact3", "java.compact2", h * 10); + weight("java.compact2", "java.compact1", h * 10); + weight("java.compact1", "java.logging", h * 10); + weight("java.logging", "java.base", h * 10); + } + + private void genDotFile(Path dir, String name, Configuration cf) throws IOException { + try (PrintStream out + = new PrintStream(Files.newOutputStream(dir.resolve(name + ".dot")))) { + + Map nameToModule = cf.modules().stream() + .map(ResolvedModule::reference) + .map(ModuleReference::descriptor) + .collect(Collectors.toMap(ModuleDescriptor::name, Function.identity())); + + Set descriptors = new TreeSet<>(nameToModule.values()); + + out.format("digraph \"%s\" {%n", name); + out.format("size=\"25,25\";"); + out.format("nodesep=.5;%n"); + out.format("ranksep=1.5;%n"); + out.format("pencolor=transparent;%n"); + out.format("node [shape=plaintext, fontname=\"DejaVuSans\", fontsize=36, margin=\".2,.2\"];%n"); + out.format("edge [penwidth=4, color=\"#999999\", arrowhead=open, arrowsize=2];%n"); + + out.format("subgraph %sse {%n", name.equals("jdk") ? "cluster_" : ""); + descriptors.stream() + .filter(javaGroup::contains) + .map(ModuleDescriptor::name) + .forEach(mn -> out.format(" \"%s\" [fontcolor=\"%s\", group=%s];%n", + mn, ORANGE, "java")); + out.format("}%n"); + descriptors.stream() + .filter(jdkGroup::contains) + .map(ModuleDescriptor::name) + .forEach(mn -> out.format(" \"%s\" [fontcolor=\"%s\", group=%s];%n", + mn, BLUE, "jdk")); + + // transitive reduction + Graph graph = gengraph(cf); + descriptors.forEach(md -> { + String mn = md.name(); + Set requiresPublic = md.requires().stream() + .filter(d -> d.modifiers().contains(PUBLIC)) + .map(d -> d.name()) + .collect(Collectors.toSet()); + + graph.adjacentNodes(mn).forEach(dn -> { + String attr = dn.equals("java.base") ? REQUIRES_BASE + : (requiresPublic.contains(dn) ? REEXPORTS : REQUIRES); + int w = weightOf(mn, dn); + if (w > 1) + attr += "weight=" + w; + out.format(" \"%s\" -> \"%s\" [%s];%n", mn, dn, attr); + }); + }); + + out.println("}"); + } + } + + /** + * Returns a Graph of the given Configuration after transitive reduction. + * + * Transitive reduction of requires public edge and requires edge have + * to be applied separately to prevent the requires public edges + * (e.g. U -> V) from being reduced by a path (U -> X -> Y -> V) + * in which V would not be re-exported from U. + */ + private Graph gengraph(Configuration cf) { + Graph.Builder builder = new Graph.Builder<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + String mn = resolvedModule.reference().descriptor().name(); + builder.addNode(mn); + resolvedModule.reads().stream() + .map(ResolvedModule::name) + .forEach(target -> builder.addEdge(mn, target)); + } + Graph rpg = requiresPublicGraph(cf); + return builder.build().reduce(rpg); + } + + /** + * Returns a Graph containing only requires public edges + * with transitive reduction. + */ + private Graph requiresPublicGraph(Configuration cf) { + Graph.Builder builder = new Graph.Builder<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); + String mn = descriptor.name(); + descriptor.requires().stream() + .filter(d -> d.modifiers().contains(PUBLIC)) + .map(d -> d.name()) + .forEach(d -> builder.addEdge(mn, d)); + } + return builder.build().reduce(); + } +} diff --git a/jdk/make/src/classes/build/tools/jigsaw/Graph.java b/jdk/make/src/classes/build/tools/jigsaw/Graph.java new file mode 100644 index 00000000000..a835da1ad93 --- /dev/null +++ b/jdk/make/src/classes/build/tools/jigsaw/Graph.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.jigsaw; + +import java.io.PrintStream; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Map; +import java.util.Set; + +public class Graph { + private static boolean traceOn = Boolean.getBoolean("build.tools.module.trace"); + private final Set nodes; + private final Map> edges; + private Graph(Set nodes, Map> edges) { + this.nodes = nodes; + this.edges = edges; + } + + public Set nodes() { + return nodes; + } + + public Map> edges() { + return edges; + } + + public Set adjacentNodes(T u) { + return edges.get(u); + } + + /** + * Returns a new Graph after transitive reduction + */ + public Graph reduce() { + Graph.Builder builder = new Builder<>(); + nodes.stream() + .forEach(u -> { + builder.addNode(u); + edges.get(u).stream() + .filter(v -> !pathExists(u, v, false)) + .forEach(v -> builder.addEdge(u, v)); + }); + return builder.build(); + } + + /** + * Returns a new Graph after transitive reduction. All edges in + * the given g takes precedence over this graph. + * + * @throw IllegalArgumentException g must be a subgraph this graph + */ + public Graph reduce(Graph g) { + boolean subgraph = nodes.containsAll(g.nodes) && g.edges.keySet().stream() + .allMatch(u -> adjacentNodes(u).containsAll(g.adjacentNodes(u))); + if (!subgraph) { + throw new IllegalArgumentException("the given argument is not a subgraph of this graph"); + } + + Graph.Builder builder = new Builder<>(); + nodes.stream() + .forEach(u -> { + builder.addNode(u); + // filter the edge if there exists a path from u to v in the given g + // or there exists another path from u to v in this graph + edges.get(u).stream() + .filter(v -> !g.pathExists(u, v) && !pathExists(u, v, false)) + .forEach(v -> builder.addEdge(u, v)); + }); + + // add the overlapped edges from this graph and the given g + g.edges().keySet().stream() + .forEach(u -> g.adjacentNodes(u).stream() + .filter(v -> isAdjacent(u, v)) + .forEach(v -> builder.addEdge(u, v))); + return builder.build(); + } + + private boolean isAdjacent(T u, T v) { + return edges.containsKey(u) && edges.get(u).contains(v); + } + + private boolean pathExists(T u, T v) { + return pathExists(u, v, true); + } + + /** + * Returns true if there exists a path from u to v in this graph. + * If includeAdjacent is false, it returns true if there exists + * another path from u to v of distance > 1 + */ + private boolean pathExists(T u, T v, boolean includeAdjacent) { + if (!nodes.contains(u) || !nodes.contains(v)) { + return false; + } + if (includeAdjacent && isAdjacent(u, v)) { + return true; + } + Deque stack = new LinkedList<>(); + Set visited = new HashSet<>(); + stack.push(u); + while (!stack.isEmpty()) { + T node = stack.pop(); + if (node.equals(v)) { + if (traceOn) { + System.out.format("Edge %s -> %s removed%n", u, v); + } + return true; + } + if (!visited.contains(node)) { + visited.add(node); + edges.get(node).stream() + .filter(e -> includeAdjacent || !node.equals(u) || !e.equals(v)) + .forEach(e -> stack.push(e)); + } + } + assert !visited.contains(v); + return false; + } + + void printGraph(PrintStream out) { + nodes.stream() + .forEach(u -> adjacentNodes(u).stream() + .forEach(v -> out.format("%s -> %s%n", u, v))); + } + + public static class Builder { + final Set nodes = new HashSet<>(); + final Map> edges = new HashMap<>(); + public void addNode(T node) { + if (nodes.contains(node)) { + return; + } + nodes.add(node); + edges.computeIfAbsent(node, _e -> new HashSet<>()); + } + public void addEdge(T u, T v) { + addNode(u); + addNode(v); + edges.get(u).add(v); + } + public Graph build() { + return new Graph<>(nodes, edges); + } + } +} diff --git a/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java new file mode 100644 index 00000000000..c1b15d39219 --- /dev/null +++ b/jdk/make/src/classes/build/tools/jigsaw/ModuleSummary.java @@ -0,0 +1,766 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 build.tools.jigsaw; + +import java.io.IOException; +import java.io.PrintStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import static java.lang.module.ModuleDescriptor.*; +import static build.tools.jigsaw.ModuleSummary.HtmlDocument.Selector.*; +import static build.tools.jigsaw.ModuleSummary.HtmlDocument.Division.*; + +public class ModuleSummary { + private static final String USAGE = "Usage: ModuleSummary -mp

-o [-root mn]*"; + + public static void main(String[] args) throws Exception { + int i=0; + Path modpath = null; + Path outfile = null; + Set roots = new HashSet<>(); + while (i < args.length && args[i].startsWith("-")) { + String arg = args[i++]; + switch (arg) { + case "-mp": + modpath = Paths.get(args[i++]); + break; + case "-o": + outfile = Paths.get(args[i++]); + break; + case "-root": + roots.add(args[i++]); + default: + System.err.println(USAGE); + System.exit(-1); + } + } + if (outfile == null || modpath == null) { + System.err.println(USAGE); + System.exit(1); + } + Path dir = outfile.getParent() != null ? outfile.getParent() : Paths.get("."); + Files.createDirectories(dir); + + Map modules = new HashMap<>(); + Set mrefs = ModuleFinder.ofSystem().findAll(); + for (ModuleReference mref : mrefs) { + String mn = mref.descriptor().name(); + Path jmod = modpath.resolve(mn + ".jmod"); + modules.put(mn, new ModuleSummary(mref, jmod)); + } + + if (roots.isEmpty()) { + roots.addAll(modules.keySet()); + } + genReport(outfile, modules, roots, "JDK Module Summary"); + } + + static void genReport(Path outfile, Map modules, Set roots, String title) + throws IOException + { + Configuration cf = resolve(roots); + try (PrintStream out = new PrintStream(Files.newOutputStream(outfile))) { + HtmlDocument doc = new HtmlDocument(title, modules); + Set descriptors = cf.modules().stream() + .map(ResolvedModule::reference) + .map(ModuleReference::descriptor) + .collect(Collectors.toSet()); + doc.writeTo(out, descriptors); + } + } + + private final String name; + private final ModuleDescriptor descriptor; + private final JmodInfo jmodInfo; + ModuleSummary(ModuleReference mref, Path jmod) throws IOException { + this.name = mref.descriptor().name(); + this.descriptor = mref.descriptor(); + this.jmodInfo = new JmodInfo(jmod); + } + + String name() { + return name; + } + + long uncompressedSize() { + return jmodInfo.size; + } + + long jmodFileSize() { + return jmodInfo.filesize; // estimated compressed size + } + + ModuleDescriptor descriptor() { + return descriptor; + } + + int numClasses() { + return jmodInfo.classCount; + } + + long classBytes() { + return jmodInfo.classBytes; + } + + int numResources() { + return jmodInfo.resourceCount; + } + + long resourceBytes() { + return jmodInfo.resourceBytes; + } + + int numConfigs() { + return jmodInfo.configCount; + } + long configBytes() { + return jmodInfo.configBytes; + } + int numCommands() { + return jmodInfo.nativeCmds.size(); + } + + long commandBytes() { + return jmodInfo.nativeCmds.values().stream() + .mapToLong(l -> l.longValue()).sum() - jmodInfo.debugInfoCmdBytes; + } + int numCommandsDebug() { + return jmodInfo.debugInfoCmdCount; + } + long commandDebugBytes() { + return jmodInfo.debugInfoCmdBytes; + } + int numNativeLibraries() { + return jmodInfo.nativeLibs.size(); + } + + long nativeLibrariesBytes() { + return jmodInfo.nativeLibs.values().stream() + .mapToLong(l -> l.longValue()).sum() - jmodInfo.debugInfoLibBytes; + } + int numNativeLibrariesDebug() { + return jmodInfo.debugInfoLibCount; + } + + long nativeLibrariesDebugBytes() { + return jmodInfo.debugInfoLibBytes; + } + + Map commands() { + return jmodInfo.nativeCmds; + } + + Map nativeLibs() { + return jmodInfo.nativeLibs; + } + + Map configFiles() { + return jmodInfo.configFiles; + } + + + static class JmodInfo { + final long size; + final long filesize; + final int classCount; + final long classBytes; + final int resourceCount; + final long resourceBytes; + final int configCount; + final long configBytes; + final int debugInfoLibCount; + final long debugInfoLibBytes; + final int debugInfoCmdCount; + final long debugInfoCmdBytes; + final Map configFiles = new HashMap<>(); + final Map nativeCmds = new HashMap<>(); + final Map nativeLibs = new HashMap<>(); + + JmodInfo(Path jmod) throws IOException { + long total = 0; + long cBytes = 0, rBytes = 0, cfBytes = 0, dizLibBytes = 0, dizCmdBytes = 0; + int cCount = 0, rCount = 0, cfCount = 0, dizLibCount = 0, dizCmdCount = 0; + try (ZipFile zf = new ZipFile(jmod.toFile())) { + for (Enumeration e = zf.entries(); e.hasMoreElements(); ) { + ZipEntry ze = e.nextElement(); + String fn = ze.getName(); + int pos = fn.indexOf('/'); + String dir = fn.substring(0, pos); + String filename = fn.substring(fn.lastIndexOf('/') + 1); + // name shown in the column + String name = filename; + + long len = ze.getSize(); + total += len; + switch (dir) { + case NATIVE_LIBS: + nativeLibs.put(name, len); + if (filename.endsWith(".diz")) { + dizLibCount++; + dizLibBytes += len; + } + break; + case NATIVE_CMDS: + nativeCmds.put(name, len); + if (filename.endsWith(".diz")) { + dizCmdCount++; + dizCmdBytes += len; + } + break; + case CLASSES: + if (filename.endsWith(".class")) { + cCount++; + cBytes += len; + } else { + rCount++; + rBytes += len; + } + break; + case CONFIG: + configFiles.put(name, len); + cfCount++; + cfBytes += len; + break; + default: + break; + } + } + this.filesize = jmod.toFile().length(); + this.classCount = cCount; + this.classBytes = cBytes; + this.resourceCount = rCount; + this.resourceBytes = rBytes; + this.configCount = cfCount; + this.configBytes = cfBytes; + this.size = total; + this.debugInfoLibCount = dizLibCount; + this.debugInfoLibBytes = dizLibBytes; + this.debugInfoCmdCount = dizCmdCount; + this.debugInfoCmdBytes = dizCmdBytes; + } + } + + static final String NATIVE_LIBS = "native"; + static final String NATIVE_CMDS = "bin"; + static final String CLASSES = "classes"; + static final String CONFIG = "conf"; + + static final String MODULE_ID = "module/id"; + static final String MODULE_MAIN_CLASS = "module/main-class"; + } + + static Configuration resolve(Set roots) { + return Configuration.empty() + .resolveRequires(ModuleFinder.ofSystem(), + ModuleFinder.empty(), + roots); + } + + static class HtmlDocument { + final String title; + final Map modules; + boolean requiresPublicNote = false; + boolean aggregatorNote = false; + boolean totalBytesNote = false; + HtmlDocument(String title, Map modules) { + this.title = title; + this.modules = modules; + } + + void writeTo(PrintStream out, Set selectedModules) { + out.format("%n"); + out.format("%s%n", title); + // stylesheet + Arrays.stream(HtmlDocument.STYLES).forEach(out::println); + out.format("%n"); + + // body begins + out.format("%n"); + + // title and date + out.println(DOCTITLE.toString(title)); + out.println(VERSION.toString(String.format("%tc", new Date()))); + + // total modules and sizes + long totalBytes = selectedModules.stream() + .map(ModuleDescriptor::name) + .map(modules::get) + .mapToLong(ModuleSummary::uncompressedSize) + .sum(); + String[] sections = new String[] { + String.format("%s: %d", "Total modules", selectedModules.size()), + String.format("%s: %,d bytes (%s %s)", "Total size", + totalBytes, + System.getProperty("os.name"), + System.getProperty("os.arch")) + }; + out.println(SECTION.toString(sections)); + + // write table and header + out.println(String.format("", MODULES)); + out.println(header("Module", "Requires", "Exports", + "Services", "Commands/Native Libraries/Configs")); + + // write contents - one row per module + selectedModules.stream() + .sorted(Comparator.comparing(ModuleDescriptor::name)) + .map(m -> modules.get(m.name())) + .map(ModuleTableRow::new) + .forEach(table -> table.writeTo(out)); + + out.format("
"); // end table + out.format(""); + out.println(""); + } + + String header(String... columns) { + StringBuilder sb = new StringBuilder(); + sb.append(""); + Arrays.stream(columns) + .forEach(cn -> sb.append(" ").append(cn).append("").append("\n")); + sb.append(""); + return sb.toString(); + } + + static enum Selector { + MODULES("modules"), + MODULE("module"), + MODULE_DEF("code name def"), + AGGREGATOR("code name def agg"), + REQUIRES("code"), + REQUIRES_PUBLIC("code reexp"), + BR("br"), + CODE("code"), + NUMBER("number"),; + final String name; + Selector(String name) { + this.name = name; + } + @Override + public String toString() { + return name; + } + } + + static enum Division { + DOCTITLE("doctitle"), + VERSION("versions"), + SECTION("section"); + final String name; + + Division(String name) { + this.name = name; + } + + public String toString(String... lines) { + String value = Arrays.stream(lines).collect(Collectors.joining("
\n")); + return "
" + value + "
"; + } + } + + class ModuleTableRow { + private final ModuleSummary ms; + private final Set deps; + private final int maxRows; + private final boolean aggregator; + ModuleTableRow(ModuleSummary ms) { + this.ms = ms; + Configuration cf = resolve(Set.of(ms.name())); + this.deps = cf.modules().stream() + .map(ResolvedModule::reference) + .map(ModuleReference::descriptor) + .collect(Collectors.toSet()); + int count = (ms.numClasses() > 0 ? 1 : 0) + + (ms.numResources() > 0 ? 1 : 0) + + (ms.numConfigs() > 0 ? 1 : 0) + + (ms.numNativeLibraries() > 0 ? 1 : 0) + + (ms.numNativeLibrariesDebug() > 0 ? 1 : 0) + + (ms.numCommands() > 0 ? 1 : 0) + + (ms.numCommandsDebug() > 0 ? 1 : 0); + this.aggregator = ms.numClasses() == 1 && count == 1; // only module-info.class + + // 5 fixed rows (name + 2 transitive count/size + 2 blank rows) + this.maxRows = 5 + count + (aggregator && !aggregatorNote ? 2 : 0); + } + + public void writeTo(PrintStream out) { + out.println(String.format("", ms.name(), MODULE)); + out.println(moduleColumn()); + out.println(requiresColumn()); + out.println(exportsColumn()); + out.println(servicesColumn()); + out.println(otherSectionColumn()); + out.println(""); + out.println(""); + } + + public String moduleColumn() { + // module name + StringBuilder sb = new StringBuilder(" "); + sb.append(""); + sb.append(String.format("", MODULE)).append("\n"); + sb.append(moduleName(ms.name())); + sb.append(blankRow()); + // metadata + sb.append(toTableRow("class", "classes", ms.numClasses(), ms.classBytes())); + sb.append(toTableRow("resource", "resources", ms.numResources(), ms.resourceBytes())); + sb.append(toTableRow("config", "configs", ms.numConfigs(), ms.configBytes())); + sb.append(toTableRow("native library", "native libraries", + ms.numNativeLibraries(), ms.nativeLibrariesBytes())); + sb.append(toTableRow("native library debug", "native libraries debug", + ms.numNativeLibrariesDebug(), ms.nativeLibrariesDebugBytes())); + sb.append(toTableRow("command", "commands", ms.numCommands(), ms.commandBytes())); + sb.append(toTableRow("command debug", "commands debug", + ms.numCommandsDebug(), ms.commandDebugBytes())); + sb.append(blankRow()); + + // transitive dependencies + long reqBytes = deps.stream() + .filter(d -> !d.name().equals(ms.name())) + .mapToLong(d -> modules.get(d.name()).uncompressedSize()) + .sum(); + long reqJmodFileSize = deps.stream() + .mapToLong(d -> modules.get(d.name()).jmodFileSize()) + .sum(); + // size + if (totalBytesNote) { + sb.append(toTableRow("Total bytes", ms.uncompressedSize())); + sb.append(toTableRow("Total bytes of dependencies", reqBytes)); + } else { + // print footnote + sb.append(toTableRow("Total bytes1", ms.uncompressedSize())); + sb.append(toTableRow("Total bytes of dependencies2", reqBytes)); + } + String files = deps.size() == 1 ? "file" : "files"; + sb.append(toTableRow(String.format("Total jmod bytes (%d %s)", deps.size(), files), reqJmodFileSize)); + + if (aggregator && !aggregatorNote) { + aggregatorNote = true; + sb.append(blankRow()); + sb.append(toTableRow("* aggregator is a module with module-info.class only", BR)); + } + if (!totalBytesNote) { + totalBytesNote = true; + sb.append(blankRow()); + sb.append(toTableRow("1sum of all files including debug files", BR)); + sb.append(toTableRow("2sum of direct and indirect dependencies", BR)); + } + sb.append("
").append(""); + return sb.toString(); + } + + private String moduleName(String mn) { + if (aggregator) { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("", AGGREGATOR)) + .append(mn) + .append("").append("  "); + if (!aggregatorNote) { + sb.append("(aggregator*)"); + } else { + sb.append("(aggregator)"); + } + sb.append(""); + return sb.toString(); + } else { + return toTableRow(mn, MODULE_DEF); + } + } + + public String requiresColumn() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("")); + boolean footnote = requiresPublicNote; + ms.descriptor().requires().stream() + .sorted(Comparator.comparing(Requires::name)) + .forEach(r -> { + boolean requiresPublic = r.modifiers().contains(Requires.Modifier.PUBLIC); + Selector sel = requiresPublic ? REQUIRES_PUBLIC : REQUIRES; + String req = String.format("%s", + sel, r.name(), r.name()); + if (!requiresPublicNote && requiresPublic) { + requiresPublicNote = true; + req += "*"; + } + sb.append(req).append("\n").append("
"); + }); + + if (!ms.name().equals("java.base")) { + int directDeps = ms.descriptor().requires().size(); + int indirectDeps = deps.size()-directDeps-1; + for (int i=directDeps; i< (maxRows-1); i++) { + sb.append("
"); + } + sb.append("
"); + sb.append("+").append(indirectDeps).append(" transitive dependencies"); + } + if (footnote != requiresPublicNote) { + sb.append("

").append("* bold denotes requires public"); + } + sb.append(""); + return sb.toString(); + } + + public String exportsColumn() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format(" ", CODE)); + ms.descriptor().exports().stream() + .sorted(Comparator.comparing(Exports::source)) + .filter(e -> !e.isQualified()) + .forEach(e -> sb.append(e.source()).append("
").append("\n")); + sb.append(""); + return sb.toString(); + } + + public String servicesColumn() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format(" ", CODE)); + ms.descriptor().uses().stream() + .sorted() + .forEach(s -> sb.append("uses ").append(s).append("
").append("\n")); + ms.descriptor().provides().entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .flatMap(e -> e.getValue().providers().stream() + .map(p -> String.format("provides %s
    with %s", + e.getKey(), p))) + .forEach(p -> sb.append(p).append("
").append("\n")); + sb.append(""); + return sb.toString(); + } + + public String otherSectionColumn() { + StringBuilder sb = new StringBuilder(); + sb.append(""); + sb.append(String.format("", MODULE)).append("\n"); + // commands + if (ms.numCommands() > 0) { + sb.append(toTableRow("bin/", CODE)); + ms.commands().entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE))); + sb.append(blankRow()); + } + + // native libraries + if (ms.numNativeLibraries() > 0) { + sb.append(toTableRow("lib/", CODE)); + ms.nativeLibs().entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE))); + sb.append(blankRow()); + } + + // config files + if (ms.numConfigs() > 0) { + sb.append(toTableRow("conf/", CODE)); + ms.configFiles().entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .forEach(e -> sb.append(toTableRow(e.getKey(), e.getValue(), CODE))); + } + // totals + sb.append("
").append(""); + return sb.toString(); + } + + private String blankRow() { + return toTableRow(" ", BR); + } + + private String toTableRow(String col, Selector selector) { + TableDataBuilder builder = new TableDataBuilder(); + builder.colspan(selector, 2, col); + return builder.build(); + } + + private String toTableRow(String col1, long col2) { + return toTableRow(col1, col2, BR); + } + + private String toTableRow(String col1, long col2, Selector selector) { + TableDataBuilder builder = new TableDataBuilder(); + builder.data(selector, col1); + builder.data(col2); + return builder.build(); + + } + + private String toTableRow(String singular, String plural, int count, long bytes) { + if (count == 0) { + return ""; + } + TableDataBuilder builder = new TableDataBuilder(); + if (count == 1) { + builder.data(count + " " + singular); + } else { + builder.data(count + " " + plural); + } + builder.data(bytes); + return builder.build(); + } + + class TableDataBuilder { + private final StringBuilder sb; + TableDataBuilder() { + this.sb = new StringBuilder(""); + } + TableDataBuilder data(String s) { + data(BR, s); + return this; + } + TableDataBuilder data(long num) { + data(NUMBER, String.format("%,d", num)); + return this; + } + TableDataBuilder colspan(Selector selector, int columns, String data) { + sb.append(""); + sb.append(""); + sb.append(data).append(""); + return this; + } + + TableDataBuilder data(Selector selector, String data) { + sb.append(""); + sb.append(data).append(""); + return this; + } + String build() { + sb.append(""); + return sb.toString(); + } + } + } + + private static final String[] STYLES = new String[]{ + "", + "", + }; + } +} diff --git a/jdk/make/src/classes/build/tools/jigsaw/technology-summary.html b/jdk/make/src/classes/build/tools/jigsaw/technology-summary.html new file mode 100644 index 00000000000..8414f3521ec --- /dev/null +++ b/jdk/make/src/classes/build/tools/jigsaw/technology-summary.html @@ -0,0 +1,627 @@ + + +JDK Technology Summary + + + +

JCP Technologies in the Modular JDK

+ +

Last updated 2015-03-06 (Added java.datatransfer. Assumes JNLP is modularized, and StAX joins the Java SE Platform.)

+ +

JDK Module Summary | Technologies in the Java SE Documentation

+ + + + + + + + +
Legend
JCP technology in the Java SE Platform only -- in java.base
JCP technology in the Java SE Platform only -- not in java.base
JCP technology in the Java SE Platform and the Java EE Platform
JCP technology in the Java SE Platform based on non-JCP standards
JCP technology in neither the Java SE or EE Platforms
+ +

An upgradeable module contains JCP technology that is in the Java SE Platform but is not exclusive to the Java SE Platform, i.e., the green and pink technologies. Most upgradeable modules are defined by loaders other than the bootstrap.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TechnologyOriginal JSROriginal TargetModuleEvolved ByHistoryProfile/SELoaderUpg?
JMX3Java SEjava.managementUJSR for Java SE3bootNo
Print Service6Java SEjava.desktopUJSR for Java SESEbootNo
Preferences10Java SEjava.prefsUJSR for Java SE3bootNo
Image I/O15Java SEjava.desktopUJSR for Java SESEbootNo
SASL28Java SEjava.security.saslUJSR for Java SE3bootNo
Logging47Java SEjava.loggingUJSR for Java SE1bootNo
NIO51Java SEjava.baseUJSR for Java SE1bootNo
JNLP56Java SEjava.jnlpOriginal JSRN/AbootNo
Beans Persistence57Java SEjava.desktopUJSR for Java SESEbootNo
GSS72Java SEjava.security.jgssUJSR for Java SE3bootNo
XML Digital Signature105Java SEjava.xml.cryptoUJSR for Java SE3bootNo
JDBC Rowset114Java SEjava.sql.rowsetOriginal JSRCo-evolved with JDBC3bootNo
JMX Remote160Java SEjava.managementUJSR for Java SE3bootNo
Profiling (Agent)163Java SEjava.instrumentUJSR for Java SE3bootNo
Profiling (JMX)163Java SEjava.managementUJSR for Java SE3bootNo
Concurrency Utilities166Java SEjava.baseUJSR for Java SE1bootNo
Annotations175Java SEjava.baseUJSR for Java SE1bootNo
StAX173Java SEjava.xmlOriginal JSRFormerly a Standalone Technology2bootNo
Annotations (Language Model)175Java SEjava.compilerUJSR for Java SE3bootNo
Compiler199Java SEjava.compilerOriginal JSRFormerly a Standalone Technology3bootNo
Pack200200Java SEjava.baseUJSR for Java SE1bootNo
NIO.2203Java SEjava.baseUJSR for Java SE1bootNo
JAXP206Java SEjava.xmlUJSR for Java SEFormerly a Standalone Technology2bootNo
JDBC221Java SEjava.sqlOriginal JSRCo-evolved with JDBC Rowset2bootNo
Scripting223Java SEjava.scriptingOriginal JSRFormerly a Standalone Technology1bootNo
Smart Card I/O268Java SEjava.smartcardioOriginal JSRFormerly a Standalone Technology (unlisted)N/AbootNo
Annotation Processing269Java SEjava.compilerOriginal JSRFormerly a Standalone Technology3bootNo
InvokeDynamic292Java SEjava.baseUJSR for Java SE1bootNo
Type Annotations308Java SEjava.baseUJSR for Java SE1bootNo
Type Annotations (Language Model)308Java SEjava.compilerUJSR for Java SE3bootNo
Date and Time310Java SEjava.baseUJSR for Java SE1bootNo
Streams335Java SEjava.baseUJSR for Java SE1bootNo
Collections, Math, I18N, I/O, Net, Reflection------java.baseUJSR for Java SE1bootNo
JCA, JAAS, JSSE------java.baseUJSR for Java SE1bootNo
Applet, AWT, Swing, Java 2D, Beans, A11Y, Sound------java.desktopUJSR for Java SESEbootNo
Data Transfer------java.datatransferUJSR for Java SESEbootNo
JNDI------java.namingUJSR for Java SE3bootNo
RMI------java.rmiUJSR for Java SE2bootNo
JAF925---java.activationOriginal JSRFormerly a Standalone Technology (unlisted)SEextYes
RMI-IIOP, IDL(OMG)---java.corbaUJSR for Java SEFormerly an Endorsed StandardSEextYes
DOM, SAX(W3C)---java.xmlUJSR for Java SEFormerly an Endorsed Standard2bootNo
SAAJ67Java SEjava.xml.wsOriginal JSRFormerly a Standalone Technology (f.k.a. JAXM)SEextYes
Web Services Metadata181Java EEjava.xml.wsOriginal JSRFormerly a Standalone Technology (unlisted)SEextYes
JAXB222Java SEjava.xml.bindOriginal JSRFormerly a Standalone TechnologySEextYes
JAXWS224Java SEjava.xml.wsOriginal JSRFormerly a Standalone TechnologySEextYes
Common Annotations250Java SE,EEjava.annotations.commonOriginal JSRFormerly a Standalone Technology (unlisted)SEextYes
JTA (non-XA)907---java.transactionOriginal JSRFormerly a Standalone Technology (unlisted)SEextYes
JTA (XA)907---java.sqlOriginal JSRFormerly a Standalone Technology (unlisted)2bootNo
+ + diff --git a/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java b/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java deleted file mode 100644 index 17a63e79546..00000000000 --- a/jdk/make/src/classes/build/tools/module/GenJdepsModulesXml.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.module; - -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * GenJdepsModulesXml augments the input modules.xml file(s) - * to include the module membership from the given path to - * the JDK exploded image. The output file is used by jdeps - * to analyze dependencies and enforce module boundaries. - * - * The input modules.xml file defines the modular structure of - * the JDK as described in JEP 200: The Modular JDK - * (http://openjdk.java.net/jeps/200). - * - * $ java build.tools.module.GenJdepsModulesXml \ - * -o com/sun/tools/jdeps/resources/modules.xml \ - * -mp $OUTPUTDIR/modules \ - * top/modules.xml - */ -public final class GenJdepsModulesXml { - private final static String USAGE = - "Usage: GenJdepsModulesXml -o -mp build/modules path-to-modules-xml"; - - public static void main(String[] args) throws Exception { - Path outfile = null; - Path modulepath = null; - int i = 0; - while (i < args.length) { - String arg = args[i]; - if (arg.equals("-o")) { - outfile = Paths.get(args[i+1]); - i = i+2; - } else if (arg.equals("-mp")) { - modulepath = Paths.get(args[i+1]); - i = i+2; - if (!Files.isDirectory(modulepath)) { - System.err.println(modulepath + " is not a directory"); - System.exit(1); - } - } else { - break; - } - } - if (outfile == null || modulepath == null || i >= args.length) { - System.err.println(USAGE); - System.exit(-1); - } - - GenJdepsModulesXml gentool = new GenJdepsModulesXml(modulepath); - Set modules = new HashSet<>(); - for (; i < args.length; i++) { - Path p = Paths.get(args[i]); - modules.addAll(ModulesXmlReader.readModules(p) - .stream() - .map(gentool::buildIncludes) - .collect(Collectors.toSet())); - } - - Files.createDirectories(outfile.getParent()); - ModulesXmlWriter.writeModules(modules, outfile); - } - - final Path modulepath; - public GenJdepsModulesXml(Path modulepath) { - this.modulepath = modulepath; - } - - private static String packageName(Path p) { - return packageName(p.toString().replace(File.separatorChar, '/')); - } - private static String packageName(String name) { - int i = name.lastIndexOf('/'); - return (i > 0) ? name.substring(0, i).replace('/', '.') : ""; - } - - private static boolean includes(String name) { - return name.endsWith(".class"); - } - - public Module buildIncludes(Module module) { - Module.Builder mb = new Module.Builder(module); - Path mclasses = modulepath.resolve(module.name()); - try { - Files.find(mclasses, Integer.MAX_VALUE, (Path p, BasicFileAttributes attr) - -> includes(p.getFileName().toString())) - .map(p -> packageName(mclasses.relativize(p))) - .forEach(mb::include); - } catch (NoSuchFileException e) { - // aggregate module may not have class - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - return mb.build(); - } -} diff --git a/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java new file mode 100644 index 00000000000..255e5ef64ca --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/GenModuleInfoSource.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package build.tools.module; + +import java.io.BufferedWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A build tool to extend the module-info.java in the source tree + * for platform-specific exports, uses, and provides and write + * to the specified output file. + * + * GenModulesList build tool currently generates the modules.list from + * the module-info.java from the source tree that will be used for + * the make target and dependences. + * + * The build currently invokes gensrc-$MODULE.gmk after modules.list + * is generated. Hence, platform-specific requires is not supported. + */ +public class GenModuleInfoSource { + private final static String USAGE = + "Usage: GenModuleInfoSource [option] -o \n" + + "Options are:\n" + + " -exports \n" + + " -exports /\n" + + " -uses \n" + + " -provides /\n"; + + public static void main(String... args) throws Exception { + Path outfile = null; + Path moduleInfoJava = null; + Map> options = new HashMap<>(); + + // validate input arguments + for (int i = 0; i < args.length; i++){ + String option = args[i]; + if (option.startsWith("-")) { + String arg = args[++i]; + if (option.equals("-exports") || + option.equals("-uses") || + option.equals("-provides")) { + options.computeIfAbsent(option, _k -> new HashSet<>()).add(arg); + } else if (option.equals("-o")) { + outfile = Paths.get(arg); + } else { + throw new IllegalArgumentException("invalid option: " + option); + } + } else if (moduleInfoJava != null) { + throw new IllegalArgumentException("more than one module-info.java"); + } else { + moduleInfoJava = Paths.get(option); + if (Files.notExists(moduleInfoJava)) { + throw new IllegalArgumentException(option + " not exist"); + } + } + } + + if (moduleInfoJava == null || outfile == null) { + System.err.println(USAGE); + System.exit(-1); + } + // read module-info.java + Module.Builder builder = ModuleInfoReader.builder(moduleInfoJava); + augment(builder, options); + + // generate new module-info.java + Module module = builder.build(); + Path parent = outfile.getParent(); + if (parent != null) + Files.createDirectories(parent); + + try (BufferedWriter writer = Files.newBufferedWriter(outfile)) { + writer.write(module.toString()); + } + } + + private static void augment(Module.Builder builder, Map> options) { + for (String opt : options.keySet()) { + if (opt.equals("-exports")) { + for (String arg : options.get(opt)) { + int index = arg.indexOf('/'); + if (index > 0) { + String pn = arg.substring(0, index); + String mn = arg.substring(index + 1, arg.length()); + builder.exportTo(pn, mn); + } else { + builder.export(arg); + } + } + } else if (opt.equals("-uses")) { + options.get(opt).stream() + .forEach(builder::use); + } else if (opt.equals("-provides")) { + for (String arg : options.get(opt)) { + int index = arg.indexOf('/'); + if (index <= 0) { + throw new IllegalArgumentException("invalid -provide argument: " + arg); + } + String service = arg.substring(0, index); + String impl = arg.substring(index + 1, arg.length()); + builder.provide(service, impl); + } + } + } + } +} diff --git a/jdk/make/src/classes/build/tools/module/GenModuleLoaderMap.java b/jdk/make/src/classes/build/tools/module/GenModuleLoaderMap.java new file mode 100644 index 00000000000..6719277fac1 --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/GenModuleLoaderMap.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package build.tools.module; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class GenModuleLoaderMap { + private static final String USAGE = + "GenModuleLoaderMap -o -boot m1[,m2]* -platform m3[,m4]* "; + + public static void main(String... args) throws Exception { + // default set of boot modules and ext modules + Stream bootModules = Stream.empty(); + Stream platformModules = Stream.empty(); + Path outfile = null; + Path source = null; + for (int i=0; i < args.length; i++) { + String option = args[i]; + if (option.startsWith("-")) { + String arg = args[++i]; + if (option.equals("-boot")) { + String[] mns = arg.split(","); + bootModules = Stream.concat(bootModules, Arrays.stream(mns)); + } else if (option.equals("-platform")) { + String[] mns = arg.split(","); + platformModules = Stream.concat(platformModules, Arrays.stream(mns)); + } else if (option.equals("-o")) { + outfile = Paths.get(arg); + } else { + throw new IllegalArgumentException("invalid option: " + option); + } + } else { + source = Paths.get(option); + } + } + + if (outfile == null) { + throw new IllegalArgumentException("-o must be specified"); + } + if (Files.notExists(source)) { + throw new IllegalArgumentException(source + " not exist"); + } + + boolean needsQuotes = outfile.toString().contains(".java.tmp"); + + try (BufferedWriter bw = Files.newBufferedWriter(outfile, StandardCharsets.UTF_8); + PrintWriter writer = new PrintWriter(bw)) { + for (String line : Files.readAllLines(source)) { + if (line.contains("@@BOOT_MODULE_NAMES@@")) { + line = patch(line, "@@BOOT_MODULE_NAMES@@", bootModules, needsQuotes); + } else if (line.contains("@@PLATFORM_MODULE_NAMES@@")) { + line = patch(line, "@@PLATFORM_MODULE_NAMES@@", platformModules, needsQuotes); + } + writer.println(line); + } + } + } + + private static String patch(String s, String tag, Stream stream, boolean needsQuotes) { + String mns = null; + if (needsQuotes) { + mns = stream.sorted() + .collect(Collectors.joining("\",\n \"")); + } else { + mns = stream.sorted() + .collect(Collectors.joining("\n")); + } + return s.replace(tag, mns); + } + + /** + * Reads the contents of the given modules file. + */ + private static Set readModuleSet(String name) throws IOException { + try (InputStream is = GenModuleLoaderMap.class.getResourceAsStream(name); + BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + return reader.lines().collect(Collectors.toSet()); + } + } +} diff --git a/jdk/make/src/classes/build/tools/module/GenModulesList.java b/jdk/make/src/classes/build/tools/module/GenModulesList.java deleted file mode 100644 index 66a9f8c76ed..00000000000 --- a/jdk/make/src/classes/build/tools/module/GenModulesList.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.module; - -import java.io.PrintWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; -import java.util.stream.Collectors; - -/** - * $ java build.tools.module.GenModulesList \ - * -o modules.list \ - * top/modules.xml ... - */ -public final class GenModulesList { - private final static String USAGE = - "Usage: GenModulesList -o path-to-modules-xml"; - - private Set modules = new HashSet<>(); - private HashMap nameToModule = new HashMap<>(); - - public static void main(String[] args) throws Exception { - GenModulesList gen = new GenModulesList(); - gen.run(args); - } - - void run(String[] args) throws Exception { - Path outfile = null; - int i = 0; - while (i < args.length) { - String arg = args[i]; - if (arg.equals("-o")) { - outfile = Paths.get(args[i+1]); - i = i+2; - } else { - break; - } - } - if (outfile == null || i >= args.length) { - System.err.println(USAGE); - System.exit(-1); - } - - for (; i < args.length; i++) { - Path p = Paths.get(args[i]); - modules.addAll(ModulesXmlReader.readModules(p)); - } - - modules.stream() - .forEach(m -> nameToModule.put(m.name(), m)); - - Path parent = outfile.getParent(); - if (parent != null) - Files.createDirectories(parent); - - Iterable sortedModules = (new TopoSorter(modules)).result(); - try (PrintWriter writer = new PrintWriter(outfile.toFile())) { - for (Module m : sortedModules) { - if (isNotAggregator(m)) { - String deps = getModuleDependences(m).stream() - .filter(GenModulesList::isNotAggregator) - .map(Module::name) - .collect(Collectors.joining(" ")); - writer.format("%s: %s%n", m.name(), deps); - } - } - } - } - - private Module nameToModule(String name) { - return nameToModule.get(name); - } - - private Set getModuleDependences(Module m) { - return m.requires().stream() - .map(d -> d.name()) - .map(this::nameToModule) - .collect(Collectors.toSet()); - } - - static boolean isNotAggregator(Module m) { - return isNotAggregator(m.name()); - } - - static boolean isNotAggregator(String name) { - return AGGREGATORS.contains(name) ? false : true; - } - - static final List AGGREGATORS = Arrays.asList(new String[] { - "java.se", "java.compact1", "java.compact2", "java.compact3"}); - - class TopoSorter { - final Deque result = new LinkedList<>(); - final Deque nodes = new LinkedList<>(); - - TopoSorter(Collection nodes) { - nodes.stream() - .forEach(m -> this.nodes.add(m)); - - sort(); - } - - public Iterable result() { - return result; - } - - private void sort() { - Deque visited = new LinkedList<>(); - Deque done = new LinkedList<>(); - Module node; - while ((node = nodes.poll()) != null) { - if (!visited.contains(node)) { - visit(node, visited, done); - } - } - } - - private void visit(Module m, Deque visited, Deque done) { - if (visited.contains(m)) { - if (!done.contains(m)) { - throw new IllegalArgumentException("Cyclic detected: " + - m + " " + getModuleDependences(m)); - } - return; - } - visited.add(m); - getModuleDependences(m).stream() - .forEach(x -> visit(x, visited, done)); - done.add(m); - result.addLast(m); - } - } -} diff --git a/jdk/make/src/classes/build/tools/module/ImageBuilder.java b/jdk/make/src/classes/build/tools/module/ImageBuilder.java deleted file mode 100644 index b87d59306c2..00000000000 --- a/jdk/make/src/classes/build/tools/module/ImageBuilder.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.module; - -import jdk.internal.jimage.Archive; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.nio.ByteOrder; -import java.nio.file.Files; -import java.nio.file.InvalidPathException; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import jdk.internal.jimage.ImageFileCreator; - -/** - * A tool for building a runtime image. - * - * java build.tools.module.ImageBuilder --output top/modules.xml,... - * Possible options are: - * --cmds Location of native commands - * --configs Location of config files - * --help Print this usage message - * --classes Location of module classes files - * --libs Location of native libraries - * --mods Comma separated list of module names - * --output Location of the output path - * --endian Byte order of the target runtime; {little,big} - */ -class ImageBuilder { - static class BadArgs extends Exception { - private static final long serialVersionUID = 0L; - BadArgs(String format, Object... args) { - super(String.format(format, args)); - this.format = format; - this.args = args; - } - BadArgs showUsage(boolean b) { - showUsage = b; - return this; - } - final String format; - final Object[] args; - boolean showUsage; - } - - static class Option { - - interface Processing { - - void process(ImageBuilder task, String opt, String arg) throws BadArgs; - } - - final boolean hasArg; - final String[] aliases; - final String description; - final Processing processing; - - Option(boolean hasArg, String description, Processing processing, - String... aliases) { - this.hasArg = hasArg; - this.description = description; - this.processing = processing; - this.aliases = aliases; - } - boolean isHidden() { - return false; - } - boolean matches(String opt) { - for (String a : aliases) { - if (a.equals(opt)) { - return true; - } else if (opt.startsWith("--") && hasArg && opt.startsWith(a + "=")) { - return true; - } - } - return false; - } - boolean ignoreRest() { - return false; - } - void process(ImageBuilder task, String opt, String arg) throws BadArgs { - processing.process(task, opt, arg); - } - String description() { - return description; - } - } - - private static Path CWD = Paths.get(""); - - private static List splitPath(String arg, String separator) - throws BadArgs - { - List paths = new ArrayList<>(); - for (String p: arg.split(separator)) { - if (p.length() > 0) { - try { - Path path = CWD.resolve(p); - if (Files.notExists(path)) - throw new BadArgs("path not found: %s", path); - paths.add(path); - } catch (InvalidPathException x) { - throw new BadArgs("path not valid: %s", p); - } - } - } - return paths; - } - - static Option[] recognizedOptions = { - new Option(true, "Location of native commands", (task, opt, arg) -> { - task.options.cmds = splitPath(arg, File.pathSeparator); - }, "--cmds"), - new Option(true, "Location of config files", (task, opt, arg) -> { - task.options.configs = splitPath(arg, File.pathSeparator); - }, "--configs"), - new Option(false, "Print this usage message", (task, opt, arg) -> { - task.options.help = true; - }, "--help"), - new Option(true, "Location of module classes files", (task, opt, arg) -> { - task.options.classes = splitPath(arg, File.pathSeparator); - }, "--classes"), - new Option(true, "Location of native libraries", (task, opt, arg) -> { - task.options.libs = splitPath(arg, File.pathSeparator); - }, "--libs"), - new Option(true, "Comma separated list of module names", - (task, opt, arg) -> { - for (String mn : arg.split(",")) { - if (mn.isEmpty()) { - throw new BadArgs("Module not found", mn); - } - task.options.mods.add(mn); - } - }, "--mods"), - new Option(true, "Location of the output path", (task, opt, arg) -> { - Path path = Paths.get(arg); - task.options.output = path; - }, "--output"), - new Option(true, "Byte order of the target runtime; {little,big}", - (task, opt, arg) -> { - if (arg.equals("little")) { - task.options.endian = ByteOrder.LITTLE_ENDIAN; - } else if (arg.equals("big")) { - task.options.endian = ByteOrder.BIG_ENDIAN; - } else { - throw new BadArgs("Unknown byte order " + arg); - } - }, "--endian") - }; - - private final Options options = new Options(); - - private PrintWriter log; - void setLog(PrintWriter out) { - log = out; - } - - Set moduleGraph = new java.util.HashSet<>(); - - /** Module list files */ - private static final String BOOT_MODULES = "boot.modules"; - private static final String EXT_MODULES = "ext.modules"; - - /** - * Result codes. - */ - static final int EXIT_OK = 0, // Completed with no errors. - EXIT_ERROR = 1, // Completed but reported errors. - EXIT_CMDERR = 2, // Bad command-line arguments - EXIT_SYSERR = 3, // System error or resource exhaustion. - EXIT_ABNORMAL = 4; // terminated abnormally - - - static class Options { - boolean help; - List classes; - List cmds; - List configs; - List libs; - Set mods = new HashSet<>(); - Path output; - ByteOrder endian = ByteOrder.nativeOrder(); // default, if not specified - } - - public static void main(String[] args) throws Exception { - ImageBuilder builder = new ImageBuilder(); - int rc = builder.run(args); - System.exit(rc); - } - - int run(String[] args) { - if (log == null) - log = new PrintWriter(System.out); - - try { - handleOptions(args); - if (options.help) { - showHelp(); - return EXIT_OK; - } - - if (options.classes == null) - throw new BadArgs("--classes must be specified").showUsage(true); - - Path output = options.output; - if (output == null) - throw new BadArgs("--output must be specified").showUsage(true); - Files.createDirectories(output); - if (Files.list(output).findFirst().isPresent()) - throw new BadArgs("dir not empty", output); - - if (options.mods.isEmpty()) - throw new BadArgs("--mods must be specified").showUsage(true); - - if (moduleGraph.isEmpty()) - throw new BadArgs("modules.xml must be specified").showUsage(true); - - if (options.cmds == null || options.cmds.isEmpty()) - warning("--commands is not set"); - if (options.libs == null || options.libs.isEmpty()) - warning("--libs is not set"); - //if (options.configs == null || options.configs.isEmpty()) - // warning("--configs is not set"); - - // additional option combination validation - - boolean ok = run(); - return ok ? EXIT_OK : EXIT_ERROR; - } catch (BadArgs e) { - reportError(e.format, e.args); - if (e.showUsage) - log.println(USAGE_SUMMARY); - return EXIT_CMDERR; - } catch (Exception x) { - x.printStackTrace(); - return EXIT_ABNORMAL; - } finally { - log.flush(); - } - } - - private boolean run() throws IOException { - createImage(); - return true; - } - - class SimpleResolver { - private final Set initialMods; - private final Map nameToModule = new HashMap<>(); - - SimpleResolver(Set mods, Set graph) { - graph.stream() - .forEach(m -> nameToModule.put(m.name(), m)); - initialMods = mods.stream() - .map(this::nameToModule) - .collect(Collectors.toSet()); - } - - /** Returns the transitive closure, in topological order */ - List resolve() { - List result = new LinkedList<>(); - Set visited = new HashSet<>(); - Set done = new HashSet<>(); - for (Module m : initialMods) { - if (!visited.contains(m)) - visit(m, visited, result, done); - } - return result.stream() - .map(m -> m.name()) - .collect(Collectors.toList()); - } - - private void visit(Module m, Set visited, - List result, Set done) { - if (visited.contains(m)) { - if (!done.contains(m)) - throw new IllegalArgumentException("Cyclic detected: " + - m + " " + getModuleDependences(m)); - return; - } - visited.add(m); - getModuleDependences(m).stream() - .forEach(d -> visit(d, visited, result, done)); - done.add(m); - result.add(m); - } - - private Module nameToModule(String name) { - Module m = nameToModule.get(name); - if (m == null) - throw new RuntimeException("No module definition for " + name); - return m; - } - - private Set getModuleDependences(Module m) { - return m.requires().stream() - .map(d -> d.name()) - .map(this::nameToModule) - .collect(Collectors.toSet()); - } - } - - private List resolve(Set mods ) { - return (new SimpleResolver(mods, moduleGraph)).resolve(); - } - - private void createImage() throws IOException { - Collection modules = resolve(options.mods); - log.print(modules.stream().collect(Collectors.joining(" "))); - ImageFileHelper imageHelper = new ImageFileHelper(modules); - imageHelper.createModularImage(options.output); - - // jspawnhelper, might be in lib or lib/ARCH - Path jspawnhelper = Paths.get("jspawnhelper"); - Path lib = options.output.resolve("lib"); - Optional helper = Files.walk(lib, 2) - .filter(f -> f.getFileName().equals(jspawnhelper)) - .findFirst(); - if (helper.isPresent()) - helper.get().toFile().setExecutable(true, false); - } - - private class ImageFileHelper { - final Collection modules; - final Set bootModules; - final Set extModules; - final Set appModules; - - ImageFileHelper(Collection modules) throws IOException { - this.modules = modules; - this.bootModules = modulesFor(BOOT_MODULES).stream() - .filter(modules::contains) - .collect(Collectors.toSet()); - this.extModules = modulesFor(EXT_MODULES).stream() - .filter(modules::contains) - .collect(Collectors.toSet()); - this.appModules = modules.stream() - .filter(m -> m.length() != 0 && - !bootModules.contains(m) && - !extModules.contains(m)) - .collect(Collectors.toSet()); - } - - void createModularImage(Path output) throws IOException { - Set bootArchives = bootModules.stream() - .map(this::toModuleArchive) - .collect(Collectors.toSet()); - Set extArchives = extModules.stream() - .map(this::toModuleArchive) - .collect(Collectors.toSet()); - Set appArchives = appModules.stream() - .map(this::toModuleArchive) - .collect(Collectors.toSet()); - ImageFileCreator.create(output, "bootmodules", bootArchives, options.endian); - ImageFileCreator.create(output, "extmodules", extArchives, options.endian); - ImageFileCreator.create(output, "appmodules", appArchives, options.endian); - } - - ModuleArchive toModuleArchive(String mn) { - return new ModuleArchive(mn, - moduleToPath(mn, options.classes, false/*true*/), - moduleToPath(mn, options.cmds, false), - moduleToPath(mn, options.libs, false), - moduleToPath(mn, options.configs, false)); - } - - private Path moduleToPath(String name, List paths, boolean expect) { - Set foundPaths = new HashSet<>(); - if (paths != null) { - for (Path p : paths) { - Path rp = p.resolve(name); - if (Files.exists(rp)) - foundPaths.add(rp); - } - } - if (foundPaths.size() > 1) - throw new RuntimeException("Found more that one path for " + name); - if (expect && foundPaths.size() != 1) - throw new RuntimeException("Expected to find classes path for " + name); - return foundPaths.size() == 0 ? null : foundPaths.iterator().next(); - } - - private List modulesFor(String name) throws IOException { - try (InputStream is = ImageBuilder.class.getResourceAsStream(name); - BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { - return reader.lines().collect(Collectors.toList()); - } - } - } - - public void handleOptions(String[] args) throws BadArgs { - // process options - for (int i=0; i < args.length; i++) { - if (args[i].charAt(0) == '-') { - String name = args[i]; - Option option = getOption(name); - String param = null; - if (option.hasArg) { - if (name.startsWith("--") && name.indexOf('=') > 0) { - param = name.substring(name.indexOf('=') + 1, name.length()); - } else if (i + 1 < args.length) { - param = args[++i]; - } - if (param == null || param.isEmpty() || param.charAt(0) == '-') { - throw new BadArgs("Missing arg for %n", name).showUsage(true); - } - } - option.process(this, name, param); - if (option.ignoreRest()) { - i = args.length; - } - } else { - // process rest of the input arguments - Path p = Paths.get(args[i]); - try { - moduleGraph.addAll(ModulesXmlReader.readModules(p) - .stream() - .collect(Collectors.toSet())); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - } - } - - private Option getOption(String name) throws BadArgs { - for (Option o : recognizedOptions) { - if (o.matches(name)) { - return o; - } - } - throw new BadArgs("Unknown option %s", name).showUsage(true); - } - - private void reportError(String format, Object... args) { - log.format("Error: " + format + "%n", args); - } - - private void warning(String format, Object... args) { - log.format("Warning: " + format + "%n", args); - } - - private static final String USAGE = - "ImageBuilder --output path-to-modules-xml\n"; - - private static final String USAGE_SUMMARY = - USAGE + "Use --help for a list of possible options."; - - private void showHelp() { - log.format(USAGE); - log.format("Possible options are:%n"); - 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; - if (o.isHidden() || name.equals("h")) - continue; - - log.format(" --%s\t\t\t%s%n", name, o.description()); - } - } -} diff --git a/jdk/make/src/classes/build/tools/module/Module.java b/jdk/make/src/classes/build/tools/module/Module.java index 8264f3c7c76..e553d92ace8 100644 --- a/jdk/make/src/classes/build/tools/module/Module.java +++ b/jdk/make/src/classes/build/tools/module/Module.java @@ -25,10 +25,17 @@ package build.tools.module; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class Module { - static class Dependence { + public static class Dependence implements Comparable { final String name; final boolean reexport; Dependence(String name) { @@ -43,6 +50,10 @@ public class Module { return name; } + public boolean reexport(){ + return reexport; + } + @Override public int hashCode() { int hash = 5; @@ -55,20 +66,35 @@ public class Module { Dependence d = (Dependence)o; return this.name.equals(d.name) && this.reexport == d.reexport; } + + @Override + public int compareTo(Dependence o) { + int rc = this.name.compareTo(o.name); + return rc != 0 ? rc : Boolean.compare(this.reexport, o.reexport); + } + + @Override + public String toString() { + return String.format("requires %s%s;", + reexport ? "public " : "", name); + } } private final String moduleName; private final Set requires; private final Map> exports; - private final Set packages; + private final Set uses; + private final Map> provides; private Module(String name, - Set requires, - Map> exports, - Set packages) { + Set requires, + Map> exports, + Set uses, + Map> provides) { this.moduleName = name; this.requires = Collections.unmodifiableSet(requires); this.exports = Collections.unmodifiableMap(exports); - this.packages = Collections.unmodifiableSet(packages); + this.uses = Collections.unmodifiableSet(uses); + this.provides = Collections.unmodifiableMap(provides); } public String name() { @@ -83,8 +109,12 @@ public class Module { return exports; } - public Set packages() { - return packages; + public Set uses() { + return uses; + } + + public Map> provides() { + return provides; } @Override @@ -95,8 +125,7 @@ public class Module { Module that = (Module) ob; return (moduleName.equals(that.moduleName) && requires.equals(that.requires) - && exports.equals(that.exports) - && packages.equals(that.packages)); + && exports.equals(that.exports)); } @Override @@ -104,43 +133,55 @@ public class Module { int hc = moduleName.hashCode(); hc = hc * 43 + requires.hashCode(); hc = hc * 43 + exports.hashCode(); - hc = hc * 43 + packages.hashCode(); return hc; } @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("module ").append(moduleName).append(" {").append("\n"); - requires.stream().sorted().forEach(d -> - sb.append(String.format(" requires %s%s%n", d.reexport ? "public " : "", d.name))); - exports.entrySet().stream().filter(e -> e.getValue().isEmpty()) + sb.append(String.format("module %s {%n", moduleName)); + requires.stream() + .sorted() + .map(d -> String.format(" requires %s%s;%n", d.reexport ? "public " : "", d.name)) + .forEach(sb::append); + exports.entrySet().stream() + .filter(e -> e.getValue().isEmpty()) .sorted(Map.Entry.comparingByKey()) - .forEach(e -> sb.append(String.format(" exports %s%n", e.getKey()))); - exports.entrySet().stream().filter(e -> !e.getValue().isEmpty()) + .map(e -> String.format(" exports %s;%n", e.getKey())) + .forEach(sb::append); + exports.entrySet().stream() + .filter(e -> !e.getValue().isEmpty()) .sorted(Map.Entry.comparingByKey()) - .forEach(e -> sb.append(String.format(" exports %s to %s%n", e.getKey(), e.getValue()))); - packages.stream().sorted().forEach(pn -> sb.append(String.format(" includes %s%n", pn))); - sb.append("}"); + .map(e -> String.format(" exports %s to%n%s;%n", e.getKey(), + e.getValue().stream().sorted() + .map(mn -> String.format(" %s", mn)) + .collect(Collectors.joining(",\n")))) + .forEach(sb::append); + uses.stream().sorted() + .map(s -> String.format(" uses %s;%n", s)) + .forEach(sb::append); + provides.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .flatMap(e -> e.getValue().stream().sorted() + .map(impl -> String.format(" provides %s with %s;%n", e.getKey(), impl))) + .forEach(sb::append); + sb.append("}").append("\n"); return sb.toString(); } + /** + * Module Builder + */ static class Builder { private String name; - private final Set requires = new HashSet<>(); - private final Map> exports = new HashMap<>(); - private final Set packages = new HashSet<>(); + final Set requires = new HashSet<>(); + final Map> exports = new HashMap<>(); + final Set uses = new HashSet<>(); + final Map> provides = new HashMap<>(); public Builder() { } - public Builder(Module module) { - name = module.name(); - requires.addAll(module.requires()); - exports.putAll(module.exports()); - packages.addAll(module.packages()); - } - public Builder name(String n) { name = n; return this; @@ -151,28 +192,89 @@ public class Module { return this; } - public Builder include(String p) { - packages.add(p); - return this; + public Builder export(String p) { + Objects.requireNonNull(p); + if (exports.containsKey(p)) { + throw new RuntimeException(name + " already exports " + p + + " " + exports.get(p)); + } + return exportTo(p, Collections.emptySet()); } - public Builder export(String p) { - return exportTo(p, Collections.emptySet()); + public Builder exportTo(String p, String mn) { + Objects.requireNonNull(p); + Objects.requireNonNull(mn); + Set ms = exports.get(p); + if (ms != null && ms.isEmpty()) { + throw new RuntimeException(name + " already has unqualified exports " + p); + } + exports.computeIfAbsent(p, _k -> new HashSet<>()).add(mn); + return this; } public Builder exportTo(String p, Set ms) { Objects.requireNonNull(p); Objects.requireNonNull(ms); if (exports.containsKey(p)) { - throw new RuntimeException(name + " already exports " + p); + throw new RuntimeException(name + " already exports " + p + + " " + exports.get(p)); } exports.put(p, new HashSet<>(ms)); return this; } + public Builder use(String cn) { + uses.add(cn); + return this; + } + + public Builder provide(String s, String impl) { + provides.computeIfAbsent(s, _k -> new HashSet<>()).add(impl); + return this; + } + + public Builder merge(Module m1, Module m2) { + if (!m1.name().equals(m2.name())) { + throw new IllegalArgumentException(m1.name() + " != " + m2.name()); + } + name = m1.name(); + // ## reexports + requires.addAll(m1.requires()); + requires.addAll(m2.requires()); + Stream.concat(m1.exports().keySet().stream(), m2.exports().keySet().stream()) + .distinct() + .forEach(pn -> { + Set s1 = m2.exports().get(pn); + Set s2 = m2.exports().get(pn); + if (s1 == null || s2 == null) { + exportTo(pn, s1 != null ? s1 : s2); + } else if (s1.isEmpty() || s2.isEmpty()) { + // unqualified exports + export(pn); + } else { + exportTo(pn, Stream.concat(s1.stream(), s2.stream()) + .collect(Collectors.toSet())); + } + }); + uses.addAll(m1.uses()); + uses.addAll(m2.uses()); + m1.provides().keySet().stream() + .forEach(s -> m1.provides().get(s).stream() + .forEach(impl -> provide(s, impl))); + m2.provides().keySet().stream() + .forEach(s -> m2.provides().get(s).stream() + .forEach(impl -> provide(s, impl))); + return this; + } + public Module build() { - Module m = new Module(name, requires, exports, packages); + Module m = new Module(name, requires, exports, uses, provides); return m; } + + @Override + public String toString() { + return name != null ? name : "Unknown"; + } } } diff --git a/jdk/make/src/classes/build/tools/module/ModuleArchive.java b/jdk/make/src/classes/build/tools/module/ModuleArchive.java deleted file mode 100644 index c4be7b504a9..00000000000 --- a/jdk/make/src/classes/build/tools/module/ModuleArchive.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package build.tools.module; - -import jdk.internal.jimage.Archive; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import jdk.internal.jimage.Archive.Entry.EntryType; - -/** - * An Archive backed by an exploded representation on disk. - */ -public class ModuleArchive implements Archive { - private final Path classes; - private final Path cmds; - private final Path libs; - private final Path configs; - private final String moduleName; - - private final List opened = new ArrayList<>(); - - public ModuleArchive(String moduleName, Path classes, Path cmds, - Path libs, Path configs) { - this.moduleName = moduleName; - this.classes = classes; - this.cmds = cmds; - this.libs = libs; - this.configs = configs; - } - - @Override - public String moduleName() { - return moduleName; - } - - @Override - public void open() throws IOException { - // NOOP - } - - @Override - public void close() throws IOException { - IOException e = null; - for (InputStream stream : opened) { - try { - stream.close(); - } catch (IOException ex) { - if (e == null) { - e = ex; - } else { - e.addSuppressed(ex); - } - } - } - if (e != null) { - throw e; - } - } - - @Override - public Stream entries() { - List entries = new ArrayList<>(); - try { - /* - * This code should be revisited to avoid buffering of the entries. - * 1) Do we really need sorting classes? This force buffering of entries. - * libs, cmds and configs are not sorted. - * 2) I/O streams should be concatenated instead of buffering into - * entries list. - * 3) Close I/O streams in a close handler. - */ - if (classes != null) { - try (Stream stream = Files.walk(classes)) { - entries.addAll(stream - .filter(p -> !Files.isDirectory(p) - && !classes.relativize(p).toString().startsWith("_the.") - && !classes.relativize(p).toString().endsWith(".bc") - && !classes.relativize(p).toString().equals("javac_state")) - .sorted() - .map(p -> toEntry(p, classes, EntryType.CLASS_OR_RESOURCE)) - .collect(Collectors.toList())); - } - } - if (cmds != null) { - try (Stream stream = Files.walk(cmds)) { - entries.addAll(stream - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, cmds, EntryType.NATIVE_CMD)) - .collect(Collectors.toList())); - } - } - if (libs != null) { - try (Stream stream = Files.walk(libs)) { - entries.addAll(stream - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, libs, EntryType.NATIVE_LIB)) - .collect(Collectors.toList())); - } - } - if (configs != null) { - try (Stream stream = Files.walk(configs)) { - entries.addAll(stream - .filter(p -> !Files.isDirectory(p)) - .map(p -> toEntry(p, configs, EntryType.CONFIG)) - .collect(Collectors.toList())); - } - } - } catch (IOException ioe) { - throw new UncheckedIOException(ioe); - } - return entries.stream(); - } - - private class FileEntry extends Entry { - private final boolean isDirectory; - private final long size; - private final Path entryPath; - FileEntry(Path entryPath, String path, EntryType type, - boolean isDirectory, long size) { - super(ModuleArchive.this, path, path, type); - this.entryPath = entryPath; - this.isDirectory = isDirectory; - this.size = size; - } - - public boolean isDirectory() { - return isDirectory; - } - - @Override - public long size() { - return size; - } - - @Override - public InputStream stream() throws IOException { - InputStream stream = Files.newInputStream(entryPath); - opened.add(stream); - return stream; - } - } - - private Entry toEntry(Path entryPath, Path basePath, EntryType section) { - try { - String path = basePath.relativize(entryPath).toString().replace('\\', '/'); - return new FileEntry(entryPath, path, section, - false, Files.size(entryPath)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } -} - diff --git a/jdk/make/src/classes/build/tools/module/ModuleInfoReader.java b/jdk/make/src/classes/build/tools/module/ModuleInfoReader.java new file mode 100644 index 00000000000..04ff42b39ba --- /dev/null +++ b/jdk/make/src/classes/build/tools/module/ModuleInfoReader.java @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package build.tools.module; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.function.Supplier; +import java.util.regex.Pattern; +import java.util.stream.Stream; + +import build.tools.module.Module.Builder; + +/** + * Source reader of module-info.java + */ +public class ModuleInfoReader { + private final Path sourcefile; + private final Builder builder; + private ModuleInfoReader(Path file) { + this.sourcefile = file; + this.builder = new Builder(); + } + + public static Builder builder(Path file) throws IOException { + ModuleInfoReader reader = new ModuleInfoReader(file); + reader.readFile(); + return reader.builder; + } + + /** + * Reads the source file. + */ + void readFile() throws IOException { + List lines = Files.readAllLines(sourcefile); + boolean done = false; + int lineNumber = 0; + boolean inBlockComment = false; + boolean inRequires = false; + boolean reexports = false; + boolean inProvides = false; + boolean inWith = false; + String serviceIntf = null; + String providerClass = null; + boolean inUses = false; + boolean inExports = false; + boolean inExportsTo = false; + String qualifiedExports = null; + Counter counter = new Counter(); + + for (String line : lines) { + lineNumber++; + if (inBlockComment) { + int c = line.indexOf("*/"); + if (c >= 0) { + line = line.substring(c + 2, line.length()); + inBlockComment = false; + } else { + // skip lines until end of comment block + continue; + } + } + inBlockComment = beginBlockComment(line); + + line = trimComment(line).trim(); + // ignore empty lines + if (line.length() == 0) { + continue; + } + String values; + if (inRequires || inExports | inUses | (inWith && providerClass == null)) { + values = line; + } else { + String[] s = line.split("\\s+"); + String keyword = s[0].trim(); + int nextIndex = keyword.length(); + switch (keyword) { + case "module": + if (s.length != 3 || !s[2].trim().equals("{")) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed"); + } + builder.name(s[1].trim()); + continue; // next line + case "requires": + inRequires = true; + counter.numRequires++; + if (s.length >= 2) { + String ss = s[1].trim(); + if (ss.equals("public")) { + nextIndex = line.indexOf(ss) + ss.length(); + reexports = true; + } + } + break; + case "exports": + inExports = true; + inExportsTo = false; + counter.numExports++; + qualifiedExports = null; + if (s.length >= 3) { + qualifiedExports = s[1].trim(); + nextIndex = line.indexOf(qualifiedExports, nextIndex) + + qualifiedExports.length(); + if (s[2].trim().equals("to")) { + inExportsTo = true; + nextIndex = line.indexOf("to", nextIndex) + "to".length(); + } else { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed: " + s[2]); + } + } + break; + case "to": + if (!inExports || qualifiedExports == null) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed"); + } + inExportsTo = true; + break; + case "uses": + inUses = true; + counter.numUses++; + break; + case "provides": + inProvides = true; + inWith = false; + counter.numProvides++; + serviceIntf = null; + providerClass = null; + if (s.length >= 2) { + serviceIntf = s[1].trim(); + nextIndex = line.indexOf(serviceIntf) + serviceIntf.length(); + } + if (s.length >= 3) { + if (s[2].trim().equals("with")) { + inWith = true; + nextIndex = line.indexOf("with") + "with".length(); + } else { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed: " + s[2]); + } + } + break; + case "with": + if (!inProvides || serviceIntf == null) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed"); + } + inWith = true; + nextIndex = line.indexOf("with") + "with".length(); + break; + case "}": + counter.validate(builder); + done = true; + continue; // next line + default: + throw new RuntimeException(sourcefile + ", \"" + + keyword + "\" on line " + + lineNumber + ", is not recognized"); + } + values = line.substring(nextIndex, line.length()).trim(); + } + + int len = values.length(); + if (len == 0) { + continue; // next line + } + char lastchar = values.charAt(len - 1); + if (lastchar != ',' && lastchar != ';') { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", is malformed:" + + " ',' or ';' is missing."); + } + + values = values.substring(0, len - 1).trim(); + // parse the values specified for a keyword specified + for (String s : values.split(",")) { + s = s.trim(); + if (s.length() > 0) { + if (inRequires) { + if (builder.requires.contains(s)) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + " duplicated requires: \"" + s + "\""); + } + builder.require(s, reexports); + } else if (inExports) { + if (!inExportsTo && qualifiedExports == null) { + builder.export(s); + } else { + builder.exportTo(qualifiedExports, s); + } + } else if (inUses) { + builder.use(s); + } else if (inProvides) { + if (!inWith) { + serviceIntf = s; + } else { + providerClass = s; + builder.provide(serviceIntf, providerClass); + } + } + } + } + if (lastchar == ';') { + inRequires = false; + reexports = false; + inExports = false; + inExportsTo = false; + inProvides = false; + inWith = false; + inUses = false; + } + } + + if (inBlockComment) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", missing \"*/\" to end a block comment"); + } + if (!done) { + throw new RuntimeException(sourcefile + ", line " + + lineNumber + ", missing \"}\" to end module definition" + + " for \"" + builder + "\""); + } + return; + } + + // the naming convention for the module names without dashes + private static final Pattern CLASS_NAME_PATTERN = Pattern.compile("[\\w\\.\\*_$/]+"); + private static boolean beginBlockComment(String line) { + int pos = 0; + while (pos >= 0 && pos < line.length()) { + int c = line.indexOf("/*", pos); + if (c < 0) { + return false; + } + + if (c > 0 && !Character.isWhitespace(line.charAt(c - 1))) { + return false; + } + + int c1 = line.indexOf("//", pos); + if (c1 >= 0 && c1 < c) { + return false; + } + + int c2 = line.indexOf("*/", c + 2); + if (c2 < 0) { + return true; + } + pos = c + 2; + } + return false; + } + private static String trimComment(String line) { + StringBuilder sb = new StringBuilder(); + + int pos = 0; + while (pos >= 0 && pos < line.length()) { + int c1 = line.indexOf("//", pos); + if (c1 > 0 && !Character.isWhitespace(line.charAt(c1 - 1))) { + // not a comment + c1 = -1; + } + + int c2 = line.indexOf("/*", pos); + if (c2 > 0 && !Character.isWhitespace(line.charAt(c2 - 1))) { + // not a comment + c2 = -1; + } + + int c = line.length(); + int n = line.length(); + if (c1 >= 0 || c2 >= 0) { + if (c1 >= 0) { + c = c1; + } + if (c2 >= 0 && c2 < c) { + c = c2; + } + int c3 = line.indexOf("*/", c2 + 2); + if (c == c2 && c3 > c2) { + n = c3 + 2; + } + } + if (c > 0) { + if (sb.length() > 0) { + // add a whitespace if multiple comments on one line + sb.append(" "); + } + sb.append(line.substring(pos, c)); + } + pos = n; + } + return sb.toString(); + } + + + static class Counter { + int numRequires; + int numExports; + int numUses; + int numProvides; + + void validate(Builder builder) { + assertEquals("requires", numRequires, builder.requires.size(), + () -> builder.requires.stream() + .map(Module.Dependence::toString)); + assertEquals("exports", numExports, builder.exports.size(), + () -> builder.exports.entrySet().stream() + .map(e -> "exports " + e.getKey() + " to " + e.getValue())); + assertEquals("uses", numUses, builder.uses.size(), + () -> builder.uses.stream()); + assertEquals("provides", numProvides, + (int)builder.provides.values().stream() + .flatMap(s -> s.stream()) + .count(), + () -> builder.provides.entrySet().stream() + .map(e -> "provides " + e.getKey() + " with " + e.getValue())); + } + + private static void assertEquals(String msg, int expected, int got, + Supplier> supplier) { + if (expected != got){ + System.err.println("ERROR: mismatched " + msg + + " expected: " + expected + " got: " + got ); + supplier.get().sorted() + .forEach(System.err::println); + throw new AssertionError("mismatched " + msg + + " expected: " + expected + " got: " + got + " "); + } + } + } +} diff --git a/jdk/make/src/classes/build/tools/module/boot.modules b/jdk/make/src/classes/build/tools/module/boot.modules deleted file mode 100644 index 0bf1c55fc5d..00000000000 --- a/jdk/make/src/classes/build/tools/module/boot.modules +++ /dev/null @@ -1,36 +0,0 @@ -java.base -java.compiler -java.datatransfer -java.desktop -java.httpclient -java.instrument -java.logging -java.management -java.naming -java.prefs -java.rmi -java.scripting -java.security.jgss -java.security.sasl -java.smartcardio -java.sql -java.sql.rowset -java.xml -java.xml.crypto -jdk.charsets -jdk.deploy -jdk.httpserver -jdk.jfr -jdk.jsobject -jdk.net -jdk.vm.cds -jdk.vm.ci -jdk.management -jdk.management.cmm -jdk.management.jfr -jdk.management.resource -jdk.naming.rmi -jdk.sctp -jdk.security.auth -jdk.security.jgss -jdk.snmp diff --git a/jdk/make/src/classes/build/tools/module/ext.modules b/jdk/make/src/classes/build/tools/module/ext.modules deleted file mode 100644 index d266d40847f..00000000000 --- a/jdk/make/src/classes/build/tools/module/ext.modules +++ /dev/null @@ -1,17 +0,0 @@ -java.activation -java.annotations.common -java.corba -java.transaction -java.xml.bind -java.xml.ws -jdk.accessibility -jdk.crypto.ec -jdk.crypto.mscapi -jdk.crypto.pkcs11 -jdk.crypto.ucrypto -jdk.dynalink -jdk.localedata -jdk.naming.dns -jdk.scripting.nashorn -jdk.xml.dom -jdk.zipfs diff --git a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java index f84f8835901..018a9d579e5 100644 --- a/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java +++ b/jdk/src/demo/share/java2d/J2DBench/src/j2dbench/ResultSet.java @@ -84,7 +84,6 @@ public class ResultSet { "java.util.prefs.PreferencesFactory", "sun.java2d.fontpath", "sun.boot.library.path", - "sun.boot.class.path", }; /* diff --git a/jdk/src/java.base/macosx/classes/module-info.java.extra b/jdk/src/java.base/macosx/classes/module-info.java.extra new file mode 100644 index 00000000000..6815c121dbb --- /dev/null +++ b/jdk/src/java.base/macosx/classes/module-info.java.extra @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +exports jdk.internal.loader to java.desktop; +provides java.security.Provider with apple.security.AppleProvider; diff --git a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties index f29fee3216c..be1687076cc 100644 --- a/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties +++ b/jdk/src/java.base/share/classes/com/sun/java/util/jar/pack/intrinsic.properties @@ -6,7 +6,7 @@ # but may be overridden here, if necessary. # The makefile for this directory must copy this file -# into the target class hierarchy so it will get into rt.jar. +# into the target class hierarchy so it will get into runtime image. # JCOV attributes pack.code.attribute.CoverageTable = NH[PHHII] @@ -14,6 +14,15 @@ pack.code.attribute.CharacterRangeTable = NH[PHPOHIIH] pack.class.attribute.SourceID = RUH pack.class.attribute.CompilationID = RUH +# Module attributes, supported by the tool and not JSR-200 +pack.class.attribute.Module = NH[RUHFH]NH[RUHNH[RUH]]NH[RCH]NH[RCHRCH] +pack.class.attribute.ConcealedPackages = NH[RUH] +pack.class.attribute.Version = RUH +pack.class.attribute.MainClass = RUH +pack.class.attribute.TargetPlatform = RUHRUHRUH +pack.class.attribute.Hashes = RUHNH[RUHRUH] + + # Note: Zero-length ("marker") attributes do not need to be specified here. # They are automatically defined to have an empty layout. #pack.class.attribute.Deprecated = diff --git a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java index ee25d91c6cd..dbf10bd757d 100644 --- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java +++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; -import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import static java.io.ObjectStreamClass.processQueue; @@ -212,20 +212,20 @@ public class ObjectInputStream /** marker for unshared objects in internal handle table */ private static final Object unsharedMarker = new Object(); - /** table mapping primitive type names to corresponding class objects */ - private static final HashMap> primClasses - = new HashMap<>(8, 1.0F); - static { - primClasses.put("boolean", boolean.class); - primClasses.put("byte", byte.class); - primClasses.put("char", char.class); - primClasses.put("short", short.class); - primClasses.put("int", int.class); - primClasses.put("long", long.class); - primClasses.put("float", float.class); - primClasses.put("double", double.class); - primClasses.put("void", void.class); - } + /** + * immutable table mapping primitive type names to corresponding + * class objects + */ + private static final Map> primClasses = + Map.of("boolean", boolean.class, + "byte", byte.class, + "char", char.class, + "short", short.class, + "int", int.class, + "long", long.class, + "float", float.class, + "double", double.class, + "void", void.class); private static class Caches { /** cache of subclass security audit results */ @@ -713,9 +713,11 @@ public class ObjectInputStream classObjs[i] = cl; } try { - return Proxy.getProxyClass( + @SuppressWarnings("deprecation") + Class proxyClass = Proxy.getProxyClass( hasNonPublicInterface ? nonPublicLoader : latestLoader, classObjs); + return proxyClass; } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } 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 af75faf371a..fa6971dabfa 100644 --- a/jdk/src/java.base/share/classes/java/lang/Class.java +++ b/jdk/src/java.base/share/classes/java/lang/Class.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package java.lang; +import java.lang.annotation.Annotation; +import java.lang.module.ModuleReader; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; @@ -33,15 +35,19 @@ import java.lang.reflect.Member; import java.lang.reflect.Field; import java.lang.reflect.Executable; import java.lang.reflect.Method; +import java.lang.reflect.Module; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.AnnotatedType; +import java.lang.reflect.Proxy; import java.lang.ref.SoftReference; +import java.io.IOException; import java.io.InputStream; import java.io.ObjectStreamField; +import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -55,9 +61,11 @@ import java.util.Map; import java.util.HashMap; import java.util.Objects; import java.util.StringJoiner; +import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; -import jdk.internal.HotSpotIntrinsicCandidate; import sun.reflect.CallerSensitive; import sun.reflect.ConstantPool; import sun.reflect.Reflection; @@ -69,8 +77,6 @@ import sun.reflect.generics.repository.MethodRepository; import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.scope.ClassScope; import sun.security.util.SecurityConstants; -import java.lang.annotation.Annotation; -import java.lang.reflect.Proxy; import sun.reflect.annotation.*; import sun.reflect.misc.ReflectUtil; @@ -378,6 +384,86 @@ public final class Class implements java.io.Serializable, Class caller) throws ClassNotFoundException; + + /** + * Returns the {@code Class} with the given + * binary name in the given module. + * + *

This method attempts to locate, load, and link the class or interface. + * It does not run the class initializer. If the class is not found, this + * method returns {@code null}.

+ * + *

If the class loader of the given module defines other modules and + * the given name is a class defined in a different module, this method + * returns {@code null} after the class is loaded.

+ * + *

This method does not check whether the requested class is + * accessible to its caller.

+ * + * @apiNote + * This method returns {@code null} on failure rather than + * throwing a {@link ClassNotFoundException}, as is done by + * the {@link #forName(String, boolean, ClassLoader)} method. + * The security check is a stack-based permission check if the caller + * loads a class in another module. + * + * @param module A module + * @param name The binary name + * of the class + * @return {@code Class} object of the given name defined in the given module; + * {@code null} if not found. + * + * @throws NullPointerException if the given module or name is {@code null} + * + * @throws LinkageError if the linkage fails + * + * @throws SecurityException + *
    + *
  • if the caller is not the specified module and + * {@code RuntimePermission("getClassLoader")} permission is denied; or
  • + *
  • access to the module content is denied. For example, + * permission check will be performed when a class loader calls + * {@link ModuleReader#open(String)} to read the bytes of a class file + * in a module.
  • + *
+ * + * @since 9 + */ + @CallerSensitive + public static Class forName(Module module, String name) { + Objects.requireNonNull(module); + Objects.requireNonNull(name); + + Class caller = Reflection.getCallerClass(); + if (caller != null && caller.getModule() != module) { + // if caller is null, Class.forName is the last java frame on the stack. + // java.base has all permissions + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + + PrivilegedAction pa = module::getClassLoader; + ClassLoader cl = AccessController.doPrivileged(pa); + if (module.isNamed() && cl != null) { + return cl.loadLocalClass(module, name); + } + + final Class c; + if (cl != null) { + c = cl.loadLocalClass(name); + } else { + c = BootLoader.loadClassOrNull(name); + } + + if (c != null && c.getModule() == module) { + return c; + } else { + return null; + } + } + /** * Creates a new instance of the class represented by this {@code Class} * object. The class is instantiated as if by a {@code new} @@ -453,13 +539,11 @@ public final class Class implements java.io.Serializable, } Constructor tmpConstructor = cachedConstructor; // Security check (same as in java.lang.reflect.Constructor) - int modifiers = tmpConstructor.getModifiers(); - if (!Reflection.quickCheckMemberAccess(this, modifiers)) { - Class caller = Reflection.getCallerClass(); - if (newInstanceCallerCache != caller) { - Reflection.ensureMemberAccess(caller, this, null, modifiers); - newInstanceCallerCache = caller; - } + Class caller = Reflection.getCallerClass(); + if (newInstanceCallerCache != caller) { + int modifiers = tmpConstructor.getModifiers(); + Reflection.ensureMemberAccess(caller, this, null, modifiers); + newInstanceCallerCache = caller; } // Run constructor try { @@ -717,6 +801,29 @@ public final class Class implements java.io.Serializable, // Package-private to allow ClassLoader access ClassLoader getClassLoader0() { return classLoader; } + /** + * Returns the module that this class or interface is a member of. + * + * If this class represents an array type then this method returns the + * {@code Module} for the element type. If this class represents a + * primitive type or void, then the {@code Module} object for the + * {@code java.base} module is returned. + * + * If this class is in an unnamed module then the {@link + * ClassLoader#getUnnamedModule() unnamed} {@code Module} of the class + * loader for this class is returned. + * + * @return the module that this class or interface is a member of + * + * @since 9 + */ + public Module getModule() { + return module; + } + + // set by VM + private transient Module module; + // Initialized in JVM not by private constructor // This field is filtered from reflection access, i.e. getDeclaredField // will throw NoSuchFieldException @@ -808,24 +915,60 @@ public final class Class implements java.io.Serializable, } /** - * Gets the package for this class. The class loader of this class is used - * to find the package. If the class was loaded by the bootstrap class - * loader the set of packages loaded from CLASSPATH is searched to find the - * package of the class. Null is returned if no package object was created - * by the class loader of this class. + * Gets the package of this class. * - *

Packages have attributes for versions and specifications only if the - * information was defined in the manifests that accompany the classes, and - * if the class loader created the package instance with the attributes - * from the manifest. + *

If this class represents an array type, a primitive type or void, + * this method returns {@code null}. * - * @return the package of the class, or null if no package - * information is available from the archive or codebase. + * @return the package of this class. */ public Package getPackage() { - return Package.getPackage(this); + if (isPrimitive() || isArray()) { + return null; + } + ClassLoader cl = getClassLoader0(); + return cl != null ? cl.definePackage(this) + : BootLoader.definePackage(this); } + /** + * Returns the fully qualified package name. + * + *

If this class is a top level class, then this method returns the fully + * qualified name of the package that the class is a member of, or the + * empty string if the class is in an unnamed package. + * + *

If this class is a member class, then this method is equivalent to + * invoking {@code getPackageName()} on the {@link #getEnclosingClass + * enclosing class}. + * + *

If this class is a {@link #isLocalClass local class} or an {@link + * #isAnonymousClass() anonymous class}, then this method is equivalent to + * invoking {@code getPackageName()} on the {@link #getDeclaringClass + * 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. + * + * @return the fully qualified package name + * + * @since 9 + * @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() : ""; + this.packageName = pn; + } + return pn; + } + + // cached package name + private String packageName; /** * Returns the interfaces directly implemented by the class or interface @@ -2213,15 +2356,19 @@ public final class Class implements java.io.Serializable, } /** - * Finds a resource with a given name. The rules for searching resources + * Finds a resource with a given name. If this class is in a named {@link + * Module Module}, and the caller of this method is in the same module, + * then this method will attempt to find the resource in that module. + * Otherwise, the rules for searching resources * associated with a given class are implemented by the defining * {@linkplain ClassLoader class loader} of the class. This method * delegates to this object's class loader. If this object was loaded by * the bootstrap class loader, the method delegates to {@link * ClassLoader#getSystemResourceAsStream}. * - *

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

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: * *

    * @@ -2242,26 +2389,60 @@ public final class Class implements java.io.Serializable, *
* * @param name name of the desired resource - * @return A {@link java.io.InputStream} object or {@code null} if - * no resource with this name is found + * @return A {@link java.io.InputStream} object or {@code null} if + * no resource with this name is found * @throws NullPointerException If {@code name} is {@code null} * @since 1.1 */ - public InputStream getResourceAsStream(String name) { + @CallerSensitive + public InputStream getResourceAsStream(String name) { name = resolveName(name); - ClassLoader cl = getClassLoader0(); - if (cl==null) { - // A system class. - return ClassLoader.getSystemResourceAsStream(name); + + // if this Class and the caller are in the same named module + // then attempt to get an input stream to the resource in the + // module + Module module = getModule(); + if (module.isNamed()) { + Class caller = Reflection.getCallerClass(); + if (caller != null && caller.getModule() == module) { + ClassLoader cl = getClassLoader0(); + String mn = module.getName(); + try { + + // special-case built-in class loaders to avoid the + // need for a URL connection + if (cl == null) { + return BootLoader.findResourceAsStream(mn, name); + } else if (cl instanceof BuiltinClassLoader) { + return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name); + } else { + URL url = cl.findResource(mn, name); + return (url != null) ? url.openStream() : null; + } + + } catch (IOException | SecurityException e) { + return null; + } + } + } + + // this Class and caller not in the same named module + ClassLoader cl = getClassLoader0(); + if (cl == null) { + return ClassLoader.getSystemResourceAsStream(name); + } else { + return cl.getResourceAsStream(name); } - return cl.getResourceAsStream(name); } /** - * Finds a resource with a given name. The rules for searching resources + * Finds a resource with a given name. If this class is in a named {@link + * Module Module}, and the caller of this method is in the same module, + * then this method will attempt to find the resource in that module. + * Otherwise, the rules for searching resources * associated with a given class are implemented by the defining * {@linkplain ClassLoader class loader} of the class. This method - * delegates to this object's class loader. If this object was loaded by + * delegates to this object's class loader. If this object was loaded by * the bootstrap class loader, the method delegates to {@link * ClassLoader#getSystemResource}. * @@ -2287,22 +2468,43 @@ public final class Class implements java.io.Serializable, * * * @param name name of the desired resource - * @return A {@link java.net.URL} object or {@code null} if no - * resource with this name is found + * @return A {@link java.net.URL} object; {@code null} if no + * resource with this name is found or the resource cannot + * be located by a URL. * @since 1.1 */ - public java.net.URL getResource(String name) { + @CallerSensitive + public URL getResource(String name) { name = resolveName(name); - ClassLoader cl = getClassLoader0(); - if (cl==null) { - // A system class. - return ClassLoader.getSystemResource(name); + + // if this Class and the caller are in the same named module + // then attempt to get URL to the resource in the module + Module module = getModule(); + if (module.isNamed()) { + Class caller = Reflection.getCallerClass(); + if (caller != null && caller.getModule() == module) { + String mn = getModule().getName(); + ClassLoader cl = getClassLoader0(); + try { + if (cl == null) { + return BootLoader.findResource(mn, name); + } else { + return cl.findResource(mn, name); + } + } catch (IOException ioe) { + return null; + } + } + } + + ClassLoader cl = getClassLoader0(); + if (cl == null) { + return ClassLoader.getSystemResource(name); + } else { + return cl.getResource(name); } - return cl.getResource(name); } - - /** protection domain returned when the internal domain is null */ private static java.security.ProtectionDomain allPermDomain; @@ -2845,15 +3047,15 @@ public final class Class implements java.io.Serializable, private void remove(int i) { if (methods[i] != null && methods[i].isDefault()) defaults--; - methods[i] = null; - } + methods[i] = null; + } private boolean matchesNameAndDescriptor(Method m1, Method m2) { return m1.getReturnType() == m2.getReturnType() && m1.getName() == m2.getName() && // name is guaranteed to be interned arrayContentsEq(m1.getParameterTypes(), m2.getParameterTypes()); - } + } void compactAndTrim() { int newPos = 0; 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 1bb15800454..fa6a652067b 100644 --- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java @@ -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 @@ -22,38 +22,44 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package java.lang; import java.io.InputStream; import java.io.IOException; import java.io.File; import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Field; +import java.lang.reflect.Module; import java.net.URL; import java.security.AccessController; import java.security.AccessControlContext; import java.security.CodeSource; import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; import java.security.cert.Certificate; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.Stack; -import java.util.Map; import java.util.NoSuchElementException; import java.util.Vector; -import java.util.Hashtable; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; import jdk.internal.perf.PerfCounter; -import sun.misc.Resource; -import sun.misc.URLClassPath; +import jdk.internal.module.ServicesCatalog; +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.ClassLoaders; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.Unsafe; +import jdk.internal.misc.VM; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; @@ -90,9 +96,7 @@ import sun.security.util.SecurityConstants; * associated parent class loader. When requested to find a class or * resource, a ClassLoader instance will delegate the search for the * class or resource to its parent class loader before attempting to find the - * class or resource itself. The virtual machine's built-in class loader, - * called the "bootstrap class loader", does not itself have a parent but may - * serve as the parent of a ClassLoader instance. + * class or resource itself. * *

Class loaders that support concurrent loading of classes are known as * parallel capable class loaders and are required to register @@ -101,19 +105,39 @@ import sun.security.util.SecurityConstants; * #registerAsParallelCapable ClassLoader.registerAsParallelCapable} * method. Note that the ClassLoader class is registered as parallel * capable by default. However, its subclasses still need to register themselves - * if they are parallel capable.
+ * if they are parallel capable. * In environments in which the delegation model is not strictly * hierarchical, class loaders need to be parallel capable, otherwise class * loading can lead to deadlocks because the loader lock is held for the * duration of the class loading process (see {@link #loadClass * loadClass} methods). * - *

Normally, the Java virtual machine loads classes from the local file - * system in a platform-dependent manner. For example, on UNIX systems, the - * virtual machine loads classes from the directory defined by the - * CLASSPATH environment variable. + *

Run-time Built-in Class Loaders

* - *

However, some classes may not originate from a file; they may originate + * The Java run-time has the following built-in class loaders: + * + *

    + *
  • Bootstrap class loader. + * It is the virtual machine's built-in class loader, typically represented + * as {@code null}, and does not have a parent.
  • + *
  • {@linkplain #getPlatformClassLoader() Platform class loader}. + * All platform classes are visible to the platform class loader + * that can be used as the parent of a {@code ClassLoader} instance. + * Platform classes include Java SE platform APIs, their implementation + * classes and JDK-specific run-time classes that are defined by the + * platform class loader or its ancestors.
  • + *
  • {@linkplain #getSystemClassLoader() System class loader}. + * It is also known as application class + * loader and is distinct from the platform class loader. + * The system class loader is typically used to define classes on the + * application class path, module path, and JDK-specific tools. + * The platform class loader is a parent or an ancestor of the system class + * loader that all platform classes are visible to it.
  • + *
+ * + *

Normally, the Java virtual machine loads classes from the local file + * system in a platform-dependent manner. + * However, some classes may not originate from a file; they may originate * from other sources, such as the network, or they could be constructed by an * application. The method {@link #defineClass(String, byte[], int, int) * defineClass} converts an array of bytes into an instance of class @@ -159,8 +183,8 @@ import sun.security.util.SecurityConstants; * *

Binary names

* - *

Any class name provided as a {@link String} parameter to methods in - * ClassLoader must be a binary name as defined by + *

Any class name provided as a {@code String} parameter to methods in + * {@code ClassLoader} must be a binary name as defined by * The Java™ Language Specification. * *

Examples of valid class names include: @@ -171,9 +195,12 @@ import sun.security.util.SecurityConstants; * "java.net.URLClassLoader$3$1" * * - * {@code Class} objects for array classes are not created by {@code ClassLoader}; - * use the {@link Class#forName} method instead. + *

Any package name provided as a {@code String} parameter to methods in + * {@code ClassLoader} must be either the empty string (denoting an unnamed package) + * or a fully qualified name as defined by + * The Java™ Language Specification. * + * @jls 6.7 Fully Qualified Names * @jls 13.1 The Form of a Binary * @see #resolveClass(Class) * @since 1.0 @@ -190,6 +217,9 @@ public abstract class ClassLoader { // must be added *after* it. private final ClassLoader parent; + // the unnamed module for this ClassLoader + private final Module unnamedModule; + /** * Encapsulates the set of parallel capable loader types. */ @@ -241,7 +271,7 @@ public abstract class ClassLoader { // is parallel capable and the appropriate lock object for class loading. private final ConcurrentHashMap parallelLockMap; - // Hashtable that maps packages to certs + // Maps packages to certs private final Map package2certs; // Shared among all packages with unsigned classes @@ -265,11 +295,39 @@ public abstract class ClassLoader { classes.addElement(c); } - // The packages defined in this class loader. Each package name is mapped - // to its corresponding Package object. - private final ConcurrentHashMap packages + // The packages defined in this class loader. Each package name is + // mapped to its corresponding NamedPackage object. + // + // The value is a Package object if ClassLoader::definePackage, + // Class::getPackage, ClassLoader::getDefinePackage(s) or + // Package::getPackage(s) method is called to define it. + // Otherwise, the value is a NamedPackage object. + private final ConcurrentHashMap packages = new ConcurrentHashMap<>(); + /* + * Returns a named package for the given module. + */ + private NamedPackage getNamedPackage(String pn, Module m) { + NamedPackage p = packages.get(pn); + if (p == null) { + p = new NamedPackage(pn, m); + + NamedPackage value = packages.putIfAbsent(pn, p); + if (value != null) { + // Package object already be defined for the named package + p = value; + // if definePackage is called by this class loader to define + // a package in a named module, this will return Package + // object of the same name. Package object may contain + // unexpected information but it does not impact the runtime. + // this assertion may be helpful for troubleshooting + assert value.module() == m; + } + } + return p; + } + private static Void checkCreateClassLoader() { SecurityManager security = System.getSecurityManager(); if (security != null) { @@ -280,6 +338,9 @@ public abstract class ClassLoader { private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; + this.unnamedModule + = SharedSecrets.getJavaLangReflectModuleAccess() + .defineUnnamedModule(this); if (ParallelLoaders.isRegistered(this.getClass())) { parallelLockMap = new ConcurrentHashMap<>(); package2certs = new ConcurrentHashMap<>(); @@ -437,6 +498,74 @@ public abstract class ClassLoader { } } + /** + * Loads the class with the specified binary name + * in a module defined to this class loader. This method returns {@code null} + * if the class could not be found. + * + * @apiNote This method does not delegate to the parent class loader. + * + * @implSpec The default implementation of this method searches for classes + * in the following order: + * + *

    + *
  1. Invoke {@link #findLoadedClass(String)} to check if the class + * has already been loaded.
  2. + *
  3. Invoke the {@link #findClass(String, String)} method to find the + * class in the given module.
  4. + *
+ * + * @param module + * The module + * @param name + * The binary name of the class + * + * @return The resulting {@code Class} object in a module defined by + * this class loader, or {@code null} if the class could not be found. + */ + final Class loadLocalClass(Module module, String name) { + synchronized (getClassLoadingLock(name)) { + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + if (c == null) { + c = findClass(module.getName(), name); + } + if (c != null && c.getModule() == module) { + return c; + } else { + return null; + } + } + } + + /** + * Loads the class with the specified binary name + * defined by this class loader. This method returns {@code null} + * if the class could not be found. + * + * @apiNote This method does not delegate to the parent class loader. + * + * @param name + * The binary name of the class + * + * @return The resulting {@code Class} object in a module defined by + * this class loader, or {@code null} if the class could not be found. + */ + final Class loadLocalClass(String name) { + synchronized (getClassLoadingLock(name)) { + // First, check if the class has already been loaded + Class c = findLoadedClass(name); + if (c == null) { + try { + return findClass(name); + } catch (ClassNotFoundException e) { + // ignore + } + } + return c; + } + } + /** * Returns the lock object for class loading operations. * For backward compatibility, the default implementation of this method @@ -531,6 +660,32 @@ public abstract class ClassLoader { throw new ClassNotFoundException(name); } + /** + * Finds the class with the given binary name + * in a module defined to this class loader. + * Class loader implementations that support the loading from modules + * should override this method. + * + * @apiNote This method returns {@code null} rather than throwing + * {@code ClassNotFoundException} if the class could not be found + * + * @implSpec The default implementation returns {@code null}. + * + * @param moduleName + * The module name + * @param name + * The binary name of the class + * + * @return The resulting {@code Class} object, or {@code null} + * if the class could not be found. + * + * @since 9 + */ + protected Class findClass(String moduleName, String name) { + return null; + } + + /** * Converts an array of bytes into an instance of class Class. * Before the Class can be used it must be resolved. This method @@ -580,55 +735,63 @@ public abstract class ClassLoader { } /** - * Converts an array of bytes into an instance of class Class. - * Before the Class can be used it must be resolved. + * Converts an array of bytes into an instance of class {@code Class}. + * Before the {@code Class} can be used it must be resolved. * *

This method assigns a default {@link java.security.ProtectionDomain - * ProtectionDomain} to the newly defined class. The - * ProtectionDomain is effectively granted the same set of + * ProtectionDomain} to the newly defined class. The + * {@code ProtectionDomain} is effectively granted the same set of * permissions returned when {@link * java.security.Policy#getPermissions(java.security.CodeSource) - * Policy.getPolicy().getPermissions(new CodeSource(null, null))} - * is invoked. The default domain is created on the first invocation of - * {@link #defineClass(String, byte[], int, int) defineClass}, + * Policy.getPolicy().getPermissions(new CodeSource(null, null))} + * is invoked. The default protection domain is created on the first invocation + * of {@link #defineClass(String, byte[], int, int) defineClass}, * and re-used on subsequent invocations. * - *

To assign a specific ProtectionDomain to the class, use + *

To assign a specific {@code ProtectionDomain} to the class, use * the {@link #defineClass(String, byte[], int, int, - * java.security.ProtectionDomain) defineClass} method that takes a - * ProtectionDomain as one of its arguments.

+ * java.security.ProtectionDomain) defineClass} method that takes a + * {@code ProtectionDomain} as one of its arguments.

+ * + *

+ * This method defines a package in this class loader corresponding to the + * package of the {@code Class} (if such a package has not already been defined + * in this class loader). The name of the defined package is derived from + * the binary name of the class specified by + * the byte array {@code b}. + * Other properties of the defined package are as specified by {@link Package}. * * @param name * The expected binary name of the class, or - * null if not known + * {@code null} if not known * * @param b * The bytes that make up the class data. The bytes in positions - * off through off+len-1 should have the format + * {@code off} through {@code off+len-1} should have the format * of a valid class file as defined by * The Java™ Virtual Machine Specification. * * @param off - * The start offset in b of the class data + * The start offset in {@code b} of the class data * * @param len * The length of the class data * - * @return The Class object that was created from the specified + * @return The {@code Class} object that was created from the specified * class data. * * @throws ClassFormatError * If the data did not contain a valid class * * @throws IndexOutOfBoundsException - * If either off or len is negative, or if - * off+len is greater than b.length. + * If either {@code off} or {@code len} is negative, or if + * {@code off+len} is greater than {@code b.length}. * * @throws SecurityException * If an attempt is made to add this class to a package that * contains classes that were signed by a different set of * certificates than this class (which is unsigned), or if - * name begins with "java.". + * {@code name} begins with "{@code java.}". * * @see #loadClass(String, boolean) * @see #resolveClass(Class) @@ -654,7 +817,8 @@ public abstract class ClassLoader { if (!checkName(name)) throw new NoClassDefFoundError("IllegalName: " + name); - if ((name != null) && name.startsWith("java.")) { + if ((name != null) && name.startsWith("java.") + && this != getBuiltinPlatformClassLoader()) { throw new SecurityException ("Prohibited package name: " + name.substring(0, name.lastIndexOf('.'))); @@ -663,13 +827,14 @@ public abstract class ClassLoader { pd = defaultDomain; } - if (name != null) checkCerts(name, pd.getCodeSource()); + if (name != null) { + checkCerts(name, pd.getCodeSource()); + } return pd; } - private String defineClassSourceLocation(ProtectionDomain pd) - { + private String defineClassSourceLocation(ProtectionDomain pd) { CodeSource cs = pd.getCodeSource(); String source = null; if (cs != null && cs.getLocation() != null) { @@ -678,8 +843,10 @@ public abstract class ClassLoader { return source; } - private void postDefineClass(Class c, ProtectionDomain pd) - { + private void postDefineClass(Class c, ProtectionDomain pd) { + // define a named package, if not present + getNamedPackage(c.getPackageName(), c.getModule()); + if (pd.getCodeSource() != null) { Certificate certs[] = pd.getCodeSource().getCertificates(); if (certs != null) @@ -688,69 +855,80 @@ public abstract class ClassLoader { } /** - * Converts an array of bytes into an instance of class Class, - * with an optional ProtectionDomain. If the domain is - * null, then a default domain will be assigned to the class as - * specified in the documentation for {@link #defineClass(String, byte[], - * int, int)}. Before the class can be used it must be resolved. + * Converts an array of bytes into an instance of class {@code Class}, + * with a given {@code ProtectionDomain}. + * + *

If the given {@code ProtectionDomain} is {@code null}, + * then a default protection domain will be assigned to the class as specified + * in the documentation for {@link #defineClass(String, byte[], int, int)}. + * Before the class can be used it must be resolved. * *

The first class defined in a package determines the exact set of * certificates that all subsequent classes defined in that package must * contain. The set of certificates for a class is obtained from the - * {@link java.security.CodeSource CodeSource} within the - * ProtectionDomain of the class. Any classes added to that + * {@link java.security.CodeSource CodeSource} within the + * {@code ProtectionDomain} of the class. Any classes added to that * package must contain the same set of certificates or a - * SecurityException will be thrown. Note that if - * name is null, this check is not performed. + * {@code SecurityException} will be thrown. Note that if + * {@code name} is {@code null}, this check is not performed. * You should always pass in the binary name of the * class you are defining as well as the bytes. This ensures that the * class you are defining is indeed the class you think it is. * - *

The specified name cannot begin with "java.", since - * all classes in the "java.* packages can only be defined by the - * bootstrap class loader. If name is not null, it - * must be equal to the binary name of the class - * specified by the byte array "b", otherwise a {@link - * NoClassDefFoundError NoClassDefFoundError} will be thrown.

+ *

If the specified {@code name} begins with "{@code java.}", it can + * only be defined by the {@linkplain #getPlatformClassLoader() + * platform class loader} or its ancestors; otherwise {@code SecurityException} + * will be thrown. If {@code name} is not {@code null}, it must be equal to + * the binary name of the class + * specified by the byte array {@code b}, otherwise a {@link + * NoClassDefFoundError NoClassDefFoundError} will be thrown. + * + *

This method defines a package in this class loader corresponding to the + * package of the {@code Class} (if such a package has not already been defined + * in this class loader). The name of the defined package is derived from + * the binary name of the class specified by + * the byte array {@code b}. + * Other properties of the defined package are as specified by {@link Package}. * * @param name * The expected binary name of the class, or - * null if not known + * {@code null} if not known * * @param b * The bytes that make up the class data. The bytes in positions - * off through off+len-1 should have the format + * {@code off} through {@code off+len-1} should have the format * of a valid class file as defined by * The Java™ Virtual Machine Specification. * * @param off - * The start offset in b of the class data + * The start offset in {@code b} of the class data * * @param len * The length of the class data * * @param protectionDomain - * The ProtectionDomain of the class + * The {@code ProtectionDomain} of the class * - * @return The Class object created from the data, - * and optional ProtectionDomain. + * @return The {@code Class} object created from the data, + * and {@code ProtectionDomain}. * * @throws ClassFormatError * If the data did not contain a valid class * * @throws NoClassDefFoundError - * If name is not equal to the binary - * name of the class specified by b + * If {@code name} is not {@code null} and not equal to the + * binary name of the class specified by {@code b} * * @throws IndexOutOfBoundsException - * If either off or len is negative, or if - * off+len is greater than b.length. + * If either {@code off} or {@code len} is negative, or if + * {@code off+len} is greater than {@code b.length}. * * @throws SecurityException * If an attempt is made to add this class to a package that * contains classes that were signed by a different set of - * certificates than this class, or if name begins with - * "java.". + * 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. */ protected final Class defineClass(String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) @@ -764,15 +942,16 @@ public abstract class ClassLoader { } /** - * Converts a {@link java.nio.ByteBuffer ByteBuffer} - * into an instance of class Class, - * with an optional ProtectionDomain. If the domain is - * null, then a default domain will be assigned to the class as + * Converts a {@link java.nio.ByteBuffer ByteBuffer} into an instance + * of class {@code Class}, with the given {@code ProtectionDomain}. + * If the given {@code ProtectionDomain} is {@code null}, then a default + * protection domain will be assigned to the class as * specified in the documentation for {@link #defineClass(String, byte[], * int, int)}. Before the class can be used it must be resolved. * *

The rules about the first class defined in a package determining the - * set of certificates for the package, and the restrictions on class names + * set of certificates for the package, the restrictions on class names, + * and the defined package of the class * are identical to those specified in the documentation for {@link * #defineClass(String, byte[], int, int, ProtectionDomain)}. * @@ -803,23 +982,23 @@ public abstract class ClassLoader { * The Java™ Virtual Machine Specification. * * @param protectionDomain - * The ProtectionDomain of the class, or null. + * The {@code ProtectionDomain} of the class, or {@code null}. * - * @return The Class object created from the data, - * and optional ProtectionDomain. + * @return The {@code Class} object created from the data, + * and {@code ProtectionDomain}. * * @throws ClassFormatError * If the data did not contain a valid class. * * @throws NoClassDefFoundError - * If name is not equal to the binary - * name of the class specified by b + * If {@code name} is not {@code null} and not equal to the + * binary name of the class specified by {@code b} * * @throws SecurityException * If an attempt is made to add this class to a package that * contains classes that were signed by a different set of - * certificates than this class, or if name begins with - * "java.". + * certificates than this class, or if {@code name} begins with + * "{@code java.}". * * @see #defineClass(String, byte[], int, int, ProtectionDomain) * @@ -1002,8 +1181,7 @@ public abstract class ClassLoader { * Returns a class loaded by the bootstrap class loader; * or return null if not found. */ - private Class findBootstrapClassOrNull(String name) - { + Class findBootstrapClassOrNull(String name) { if (!checkName(name)) return null; return findBootstrapClass(name); @@ -1051,13 +1229,44 @@ public abstract class ClassLoader { } - // -- Resource -- + // -- Resources -- + + /** + * Returns a URL to a resource in a module defined to this class loader. + * Class loader implementations that support the loading from modules + * should override this method. + * + * @implSpec The default implementation returns {@code null}. + * + * @param moduleName + * The module name + * @param name + * The resource name + * + * @return A URL to the resource; {@code null} if the resource could not be + * found, a URL could not be constructed to locate the resource, + * access to the resource is denied by the security manager, or + * there isn't a module of the given name defined to the class + * loader. + * + * @throws IOException + * If I/O errors occur + * + * @see java.lang.module.ModuleReader#find(String) + * @since 9 + */ + protected URL findResource(String moduleName, String name) throws IOException { + return null; + } /** * Finds the resource with the given name. A resource is some data * (images, audio, text, etc) that can be accessed by class code in a way * that is independent of the location of the code. * + * Resources in a named module are private to that module. This method does + * not find resource in named modules. + * *

The name of a resource is a '/'-separated path name that * identifies the resource. * @@ -1084,7 +1293,7 @@ public abstract class ClassLoader { if (parent != null) { url = parent.getResource(name); } else { - url = getBootstrapResource(name); + url = BootLoader.findResource(name); } if (url == null) { url = findResource(name); @@ -1097,6 +1306,9 @@ public abstract class ClassLoader { * (images, audio, text, etc) that can be accessed by class code in a way * that is independent of the location of the code. * + * Resources in a named module are private to that module. This method does + * not find resources in named modules. + * *

The name of a resource is a /-separated path name that * identifies the resource. * @@ -1131,7 +1343,7 @@ public abstract class ClassLoader { if (parent != null) { tmp[0] = parent.getResources(name); } else { - tmp[0] = getBootstrapResources(name); + tmp[0] = BootLoader.findResources(name); } tmp[1] = findResources(name); @@ -1142,6 +1354,9 @@ public abstract class ClassLoader { * Finds the resource with the given name. Class loader implementations * should override this method to specify where to find resources. * + * Resources in a named module are private to that module. This method does + * not find resources in named modules defined to this class loader. + * * @param name * The resource name * @@ -1160,6 +1375,9 @@ public abstract class ClassLoader { * implementations should override this method to specify where to load * resources from. * + * Resources in a named module are private to that module. This method does + * not find resources in named modules defined to this class loader. + * * @param name * The resource name * @@ -1204,6 +1422,9 @@ public abstract class ClassLoader { * classes. This method locates the resource through the system class * loader (see {@link #getSystemClassLoader()}). * + * Resources in a named module are private to that module. This method does + * not find resources in named modules. + * * @param name * The resource name * @@ -1215,7 +1436,7 @@ public abstract class ClassLoader { public static URL getSystemResource(String name) { ClassLoader system = getSystemClassLoader(); if (system == null) { - return getBootstrapResource(name); + return BootLoader.findResource(name); } return system.getResource(name); } @@ -1226,6 +1447,9 @@ public abstract class ClassLoader { * {@link java.util.Enumeration Enumeration} of {@link * java.net.URL URL} objects. * + * Resources in a named module are private to that module. This method does + * not find resources in named modules. + * *

The search order is described in the documentation for {@link * #getSystemResource(String)}.

* @@ -1245,47 +1469,17 @@ public abstract class ClassLoader { { ClassLoader system = getSystemClassLoader(); if (system == null) { - return getBootstrapResources(name); + return BootLoader.findResources(name); } return system.getResources(name); } - /** - * Find resources from the VM's built-in classloader. - */ - private static URL getBootstrapResource(String name) { - URLClassPath ucp = getBootstrapClassPath(); - Resource res = ucp.getResource(name); - return res != null ? res.getURL() : null; - } - - /** - * Find resources from the VM's built-in classloader. - */ - private static Enumeration getBootstrapResources(String name) - throws IOException - { - final Enumeration e = - getBootstrapClassPath().getResources(name); - return new Enumeration<> () { - public URL nextElement() { - return e.nextElement().getURL(); - } - public boolean hasMoreElements() { - return e.hasMoreElements(); - } - }; - } - - // Returns the URLClassPath that is used for finding system resources. - static URLClassPath getBootstrapClassPath() { - return sun.misc.Launcher.getBootstrapClassPath(); - } - - /** * Returns an input stream for reading the specified resource. * + * Resources in a named module are private to that module. This method does + * not find resources in named modules. + * *

The search order is described in the documentation for {@link * #getResource(String)}.

* @@ -1311,6 +1505,9 @@ public abstract class ClassLoader { * used to load classes. This method locates the resource through the * system class loader (see {@link #getSystemClassLoader()}). * + * Resources in a named module are private to that module. This method does + * not find resources in named modules. + * * @param name * The resource name * @@ -1370,14 +1567,55 @@ public abstract class ClassLoader { return parent; } + /** + * Returns the unnamed {@code Module} for this class loader. + * + * @return The unnamed Module for this class loader + * + * @see Module#isNamed() + * @since 9 + */ + public final Module getUnnamedModule() { + return unnamedModule; + } + + /** + * Returns the platform class loader for delegation. All + * platform classes are visible to + * the platform class loader. + * + * @return The platform {@code ClassLoader}. + * + * @throws SecurityException + * If a security manager exists and the caller's class loader is + * not {@code null} and the caller's class loader is not the same + * as or an ancestor of the platform class loader, + * and the {@link SecurityManager#checkPermission(java.security.Permission) + * checkPermission} method denies {@code RuntimePermission("getClassLoader")} + * to access the platform class loader. + * + * @since 9 + */ + @CallerSensitive + public static ClassLoader getPlatformClassLoader() { + SecurityManager sm = System.getSecurityManager(); + ClassLoader loader = getBuiltinPlatformClassLoader(); + if (sm != null) { + checkClassLoaderPermission(loader, Reflection.getCallerClass()); + } + return loader; + } + /** * Returns the system class loader for delegation. This is the default * delegation parent for new ClassLoader instances, and is * typically the class loader used to start the application. * *

This method is first invoked early in the runtime's startup - * sequence, at which point it creates the system class loader and sets it - * as the context class loader of the invoking Thread. + * sequence, at which point it creates the system class loader. This + * class loader will be the context class loader for the main application + * thread (for example, the thread that invokes the {@code main} method of + * the main class). * *

The default system class loader is an implementation-dependent * instance of this class. @@ -1390,7 +1628,10 @@ public abstract class ClassLoader { * type ClassLoader which is used as the delegation parent. An * instance is then created using this constructor with the default system * class loader as the parameter. The resulting class loader is defined - * to be the system class loader. + * to be the system class loader. During construction, the class loader + * should take great care to avoid calling {@code getSystemClassLoader()}. + * If circular initialization of the system class loader is detected then + * an unspecified error or exception is thrown. * *

If a security manager is present, and the invoker's class loader is * not null and the invoker's class loader is not the same as or @@ -1403,6 +1644,11 @@ public abstract class ClassLoader { * access to the system class loader. If not, a * SecurityException will be thrown.

* + * @implNote The system property to override the system class loader is not + * examined until the VM is almost fully initialized. Code that executes + * this method during startup should take care not to cache the return + * value until the system is fully initialized. + * * @return The system ClassLoader for delegation, or * null if none * @@ -1427,45 +1673,69 @@ public abstract class ClassLoader { */ @CallerSensitive public static ClassLoader getSystemClassLoader() { - initSystemClassLoader(); - if (scl == null) { - return null; + switch (VM.initLevel()) { + case 0: + case 1: + case 2: + // the system class loader is the built-in app class loader during startup + return getBuiltinAppClassLoader(); + case 3: + throw new InternalError("getSystemClassLoader should only be called after VM booted"); + case 4: + // system fully initialized + assert VM.isBooted() && scl != null; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + checkClassLoaderPermission(scl, Reflection.getCallerClass()); + } + return scl; + default: + throw new InternalError("should not reach here"); } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - checkClassLoaderPermission(scl, Reflection.getCallerClass()); - } - return scl; } - private static synchronized void initSystemClassLoader() { - if (!sclSet) { - if (scl != null) - throw new IllegalStateException("recursive invocation"); - sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); - if (l != null) { - Throwable oops = null; - scl = l.getClassLoader(); - try { - scl = AccessController.doPrivileged( - new SystemClassLoaderAction(scl)); - } catch (PrivilegedActionException pae) { - oops = pae.getCause(); - if (oops instanceof InvocationTargetException) { - oops = oops.getCause(); - } - } - if (oops != null) { - if (oops instanceof Error) { - throw (Error) oops; - } else { - // wrap the exception - throw new Error(oops); - } - } - } - sclSet = true; + static ClassLoader getBuiltinPlatformClassLoader() { + return ClassLoaders.platformClassLoader(); + } + + static ClassLoader getBuiltinAppClassLoader() { + return ClassLoaders.appClassLoader(); + } + + /* + * Initialize the system class loader that may be a custom class on the + * application class path or application module path. + * + * @see java.lang.System#initPhase3 + */ + static synchronized ClassLoader initSystemClassLoader() { + if (VM.initLevel() != 3) { + throw new InternalError("system class loader cannot be set at initLevel " + + VM.initLevel()); } + + // detect recursive initialization + if (scl != null) { + throw new IllegalStateException("recursive invocation"); + } + + ClassLoader builtinLoader = getBuiltinAppClassLoader(); + + // All are privileged frames. No need to call doPrivileged. + String cn = System.getProperty("java.system.class.loader"); + if (cn != null) { + try { + // custom class loader is only supported to be loaded from unnamed module + Constructor ctor = Class.forName(cn, false, builtinLoader) + .getDeclaredConstructor(ClassLoader.class); + scl = (ClassLoader) ctor.newInstance(builtinLoader); + } catch (Exception e) { + throw new Error(e); + } + } else { + scl = builtinLoader; + } + return scl; } // Returns true if the specified class loader can be found in this class @@ -1524,26 +1794,102 @@ public abstract class ClassLoader { } } - // The class loader for the system + // The system class loader // @GuardedBy("ClassLoader.class") - private static ClassLoader scl; - - // Set to true once the system class loader has been set - // @GuardedBy("ClassLoader.class") - private static boolean sclSet; - + private static volatile ClassLoader scl; // -- Package -- /** - * Defines a package by name in this ClassLoader. This allows - * class loaders to define the packages for their classes. Packages must - * be created before the class is defined, and package names must be - * unique within a class loader and cannot be redefined or changed once - * created. + * Define a Package of the given Class object. + * + * If the given class represents an array type, a primitive type or void, + * this method returns {@code null}. + * + * This method does not throw IllegalArgumentException. + */ + Package definePackage(Class c) { + if (c.isPrimitive() || c.isArray()) { + return null; + } + + return definePackage(c.getPackageName(), c.getModule()); + } + + /** + * Defines a Package of the given name and module + * + * This method does not throw IllegalArgumentException. + * + * @param name package name + * @param m module + */ + Package definePackage(String name, Module m) { + if (name.isEmpty() && m.isNamed()) { + throw new InternalError("unnamed package in " + m); + } + + // check if Package object is already defined + NamedPackage pkg = packages.get(name); + if (pkg instanceof Package) + return (Package)pkg; + + return (Package)packages.compute(name, (n, p) -> toPackage(n, p, m)); + } + + /* + * Returns a Package object for the named package + */ + private Package toPackage(String name, NamedPackage p, Module m) { + // define Package object if the named package is not yet defined + if (p == null) + return NamedPackage.toPackage(name, m); + + // otherwise, replace the NamedPackage object with Package object + if (p instanceof Package) + return (Package)p; + + return NamedPackage.toPackage(p.packageName(), p.module()); + } + + /** + * Defines a package by name in this {@code ClassLoader}. + *

+ * Package names must be unique within a class loader and + * cannot be redefined or changed once created. + *

+ * If a class loader wishes to define a package with specific properties, + * such as version information, then the class loader should call this + * {@code definePackage} method before calling {@code defineClass}. + * Otherwise, the + * {@link #defineClass(String, byte[], int, int, ProtectionDomain) defineClass} + * method will define a package in this class loader corresponding to the package + * of the newly defined class; the properties of this defined package are + * specified by {@link Package}. + * + * @apiNote + * A class loader that wishes to define a package for classes in a JAR + * typically uses the specification and implementation titles, versions, and + * vendors from the JAR's manifest. If the package is specified as + * {@linkplain java.util.jar.Attributes.Name#SEALED sealed} in the JAR's manifest, + * the {@code URL} of the JAR file is typically used as the {@code sealBase}. + * If classes of package {@code 'p'} defined by this class loader + * are loaded from multiple JARs, the {@code Package} object may contain + * different information depending on the first class of package {@code 'p'} + * defined and which JAR's manifest is read first to explicitly define + * package {@code 'p'}. + * + *

It is strongly recommended that a class loader does not call this + * method to explicitly define packages in named modules; instead, + * the package will be automatically defined when a class is {@linkplain + * #defineClass(String, byte[], int, int, ProtectionDomain) being defined}. + * If it is desirable to define {@code Package} explicitly, it should ensure + * that all packages in a named module are defined with the properties + * specified by {@link Package}. Otherwise, some {@code Package} objects + * in a named module may be for example sealed with different seal base. * * @param name - * The package name + * The package name * * @param specTitle * The specification title @@ -1564,89 +1910,155 @@ public abstract class ClassLoader { * The implementation vendor * * @param sealBase - * If not null, then this package is sealed with - * respect to the given code source {@link java.net.URL - * URL} object. Otherwise, the package is not sealed. + * If not {@code null}, then this package is sealed with + * respect to the given code source {@link java.net.URL URL} + * object. Otherwise, the package is not sealed. * - * @return The newly defined Package object + * @return The newly defined {@code Package} object + * + * @throws NullPointerException + * if {@code name} is {@code null}. * * @throws IllegalArgumentException - * If package name duplicates an existing package either in this - * class loader or one of its ancestors + * if a package of the given {@code name} is already + * defined by this class loader * * @since 1.2 + * + * @see + * The JAR File Specification: Package Versioning + * @see + * The JAR File Specification: Package Sealing */ protected Package definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) - throws IllegalArgumentException { - Package pkg = getPackage(name); - if (pkg != null) { + Objects.requireNonNull(name); + + // definePackage is not final and may be overridden by custom class loader + Package p = new Package(name, specTitle, specVersion, specVendor, + implTitle, implVersion, implVendor, + sealBase, this); + + if (packages.putIfAbsent(name, p) != null) throw new IllegalArgumentException(name); - } - pkg = new Package(name, specTitle, specVersion, specVendor, - implTitle, implVersion, implVendor, - sealBase, this); - if (packages.putIfAbsent(name, pkg) != null) { - throw new IllegalArgumentException(name); - } - return pkg; + + return p; } /** - * Returns a Package that has been defined by this class loader - * or any of its ancestors. + * Returns a {@code Package} of the given name that has been + * defined by this class loader. + * + * @param name The package name + * + * @return The {@code Package} of the given name defined by this class loader, + * or {@code null} if not found + * + * @since 9 + */ + public final Package getDefinedPackage(String name) { + NamedPackage p = packages.get(name); + if (p == null) + return null; + + return definePackage(name, p.module()); + } + + /** + * Returns all of the {@code Package}s defined by this class loader. + * The returned array has no duplicated {@code Package}s of the same name. + * + * @apiNote This method returns an array rather than a {@code Set} or {@code Stream} + * for consistency with the existing {@link #getPackages} method. + * + * @return The array of {@code Package} objects defined by this class loader; + * or an zero length array if no package has been defined by this class loader. + * + * @since 9 + */ + public final Package[] getDefinedPackages() { + return packages().toArray(Package[]::new); + } + + /** + * Finds a package by name in this class loader and its ancestors. + *

+ * If this class loader defines a {@code Package} of the given name, + * the {@code Package} is returned. Otherwise, the ancestors of + * this class loader are searched recursively (parent by parent) + * for a {@code Package} of the given name. * * @param name - * The package name + * The package name * - * @return The Package corresponding to the given name, or - * null if not found + * @return The {@code Package} corresponding to the given name defined by + * this class loader or its ancestors, or {@code null} if not found. + * + * @deprecated + * If multiple class loaders delegate to each other and define classes + * with the same package name, and one such loader relies on the lookup + * behavior of {@code getPackage} to return a {@code Package} from + * a parent loader, then the properties exposed by the {@code Package} + * may not be as expected in the rest of the program. + * For example, the {@code Package} will only expose annotations from the + * {@code package-info.class} file defined by the parent loader, even if + * annotations exist in a {@code package-info.class} file defined by + * a child loader. A more robust approach is to use the + * {@link ClassLoader#getDefinedPackage} method which returns + * a {@code Package} for the specified class loader. * * @since 1.2 */ + @Deprecated protected Package getPackage(String name) { - Package pkg = packages.get(name); + Package pkg = getDefinedPackage(name); if (pkg == null) { if (parent != null) { pkg = parent.getPackage(name); } else { - pkg = Package.getSystemPackage(name); + pkg = BootLoader.getDefinedPackage(name); } } return pkg; } /** - * Returns all of the Packages defined by this class loader and - * its ancestors. + * Returns all of the {@code Package}s defined by this class loader + * and its ancestors. The returned array may contain more than one + * {@code Package} object of the same package name, each defined by + * a different class loader in the class loader hierarchy. * - * @return The array of Package objects defined by this - * ClassLoader + * @return The array of {@code Package} objects defined by this + * class loader and its ancestors * * @since 1.2 */ protected Package[] getPackages() { - Package[] pkgs; - if (parent != null) { - pkgs = parent.getPackages(); - } else { - pkgs = Package.getSystemPackages(); + Stream pkgs = packages(); + ClassLoader ld = parent; + while (ld != null) { + pkgs = Stream.concat(ld.packages(), pkgs); + ld = ld.parent; } - - Map map = packages; - if (pkgs != null) { - map = new HashMap<>(packages); - for (Package pkg : pkgs) { - map.putIfAbsent(pkg.getName(), pkg); - } - } - return map.values().toArray(new Package[map.size()]); + return Stream.concat(BootLoader.packages(), pkgs) + .toArray(Package[]::new); } + + // package-private + + /** + * Returns a stream of Packages defined in this class loader + */ + Stream packages() { + return packages.values().stream() + .map(p -> definePackage(p.packageName(), p.module())); + } + // -- Native library access -- /** @@ -2183,29 +2595,53 @@ public abstract class ClassLoader { // Retrieves the assertion directives from the VM. private static native AssertionStatusDirectives retrieveDirectives(); -} -class SystemClassLoaderAction - implements PrivilegedExceptionAction { - private ClassLoader parent; - - SystemClassLoaderAction(ClassLoader parent) { - this.parent = parent; + /** + * Returns the ServiceCatalog for modules defined to this class loader + * or {@code null} if this class loader does not have a services catalog. + */ + ServicesCatalog getServicesCatalog() { + return servicesCatalog; } - public ClassLoader run() throws Exception { - String cls = System.getProperty("java.system.class.loader"); - if (cls == null) { - return parent; + /** + * Returns the ServiceCatalog for modules defined to this class loader, + * creating it if it doesn't already exist. + */ + ServicesCatalog createOrGetServicesCatalog() { + ServicesCatalog catalog = servicesCatalog; + if (catalog == null) { + catalog = new ServicesCatalog(); + boolean set = trySetObjectField("servicesCatalog", catalog); + if (!set) { + // beaten by someone else + catalog = servicesCatalog; + } } + return catalog; + } - Constructor ctor = Class.forName(cls, true, parent) - .getDeclaredConstructor(new Class[] { ClassLoader.class }); - ClassLoader sys = (ClassLoader) ctor.newInstance( - new Object[] { parent }); - Thread.currentThread().setContextClassLoader(sys); - return sys; + // the ServiceCatalog for modules associated with this class loader. + private volatile ServicesCatalog servicesCatalog; + + + /** + * Attempts to atomically set a volatile field in this object. Returns + * {@code true} if not beaten by another thread. Avoids the use of + * AtomicReferenceFieldUpdater in this class. + */ + private boolean trySetObjectField(String name, Object obj) { + Unsafe unsafe = Unsafe.getUnsafe(); + Class k = ClassLoader.class; + long offset; + try { + Field f = k.getDeclaredField(name); + offset = unsafe.objectFieldOffset(f); + } catch (NoSuchFieldException e) { + throw new InternalError(e); + } + return unsafe.compareAndSwapObject(this, offset, null, obj); } } diff --git a/jdk/src/java.base/share/classes/java/lang/NamedPackage.java b/jdk/src/java.base/share/classes/java/lang/NamedPackage.java new file mode 100644 index 00000000000..5d86cc7fd9c --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/NamedPackage.java @@ -0,0 +1,90 @@ +/* + * 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 java.lang; + +import java.lang.module.Configuration; +import java.lang.module.ModuleReference; +import java.lang.reflect.Module; +import java.net.URI; + +/** + * A NamedPackage represents a package by name in a specific module. + * + * A class loader will automatically create NamedPackage for each + * package when a class is defined. Package object is lazily + * defined until Class::getPackage, Package::getPackage(s), or + * ClassLoader::getDefinedPackage(s) method is called. + * + * NamedPackage allows ClassLoader to keep track of the runtime + * packages with minimal footprint and avoid constructing Package + * object. + */ +class NamedPackage { + private final String name; + private final Module module; + + NamedPackage(String pn, Module module) { + if (pn.isEmpty() && module.isNamed()) { + throw new InternalError("unnamed package in " + module); + } + this.name = pn.intern(); + this.module = module; + } + + /** + * Returns the name of this package. + */ + String packageName() { + return name; + } + + /** + * Returns the module of this named package. + */ + Module module() { + return module; + } + + /** + * Returns the location of the module if this named package is in + * a named module; otherwise, returns null. + */ + URI location() { + if (module.isNamed() && module.getLayer() != null) { + Configuration cf = module.getLayer().configuration(); + ModuleReference mref + = cf.findModule(module.getName()).get().reference(); + return mref.location().orElse(null); + } + return null; + } + + /** + * Creates a Package object of the given name and module. + */ + static Package toPackage(String name, Module module) { + return new Package(name, module); + } +} 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 2ab9fe3c4bf..5b80278b097 100644 --- a/jdk/src/java.base/share/classes/java/lang/Package.java +++ b/jdk/src/java.base/share/classes/java/lang/Package.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -25,85 +25,94 @@ package java.lang; +import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.URL; +import java.lang.reflect.Module; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.jar.JarInputStream; -import java.util.jar.Manifest; -import java.util.jar.Attributes; -import java.util.jar.Attributes.Name; -import java.util.Map; - -import sun.net.www.ParseUtil; +import jdk.internal.loader.BootLoader; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; -import java.lang.annotation.Annotation; /** - * {@code Package} objects contain version information - * about the implementation and specification of a Java package. - * This versioning information is retrieved and made available - * by the {@link ClassLoader} instance that - * loaded the class(es). Typically, it is stored in the manifest that is - * distributed with the classes. + * Represents metadata about a run-time package associated with a class loader. + * Metadata includes annotations, versioning, and sealing. + *

+ * Annotations for the run-time package are read from {@code package-info.class} + * at the same code source as classes in the run-time package. + *

+ * The set of classes that make up the run-time package may implement a + * particular specification. The specification title, version, and vendor + * (indicating the owner/maintainer of the specification) can be provided + * when the {@code Package} is defined. An application can ask if the + * {@code Package} is compatible with a particular specification version + * by using the {@link #isCompatibleWith Package.isCompatibleWith(String)} + * method. In addition, information about the actual classes that make up the + * run-time package can be provided when the Package is defined. + * This information consists of an implementation title, version, and vendor + * (indicating the supplier of the classes). + *

+ * A {@code Package} may be explicitly defined with + * the {@link ClassLoader#definePackage(String, String, String, String, + * String, String, String, URL)} method. + * The caller supplies the specification and implementation titles, versions, and + * vendors. The caller also indicates whether the package is + * {@linkplain java.util.jar.Attributes.Name#SEALED sealed}. + * If a {@code Package} is not explicitly defined for a run-time package when + * a class in that run-time package is defined, then a {@code Package} is + * automatically defined by the class's defining class loader, as follows. + *

+ * A {@code Package} automatically defined for classes in a named module has + * the following properties: + *

    + *
  • The name of the package is derived from the {@linkplain Class#getName() binary names} + * of the classes. Since classes in a named module must be in a named package, + * the derived name is never empty.
  • + *
  • The package is sealed with the {@linkplain java.lang.module.ModuleReference#location() + * module location} as the code source, if known.
  • + *
  • The specification and implementation titles, versions, and vendors + * are unspecified.
  • + *
  • Any annotations on the package are read from {@code package-info.class} + * as specified above.
  • + *
+ *

+ * A {@code Package} automatically defined for classes in an unnamed module + * has the following properties: + *

    + *
  • The name of the package is either {@code ""} (for classes in an unnamed package) + * or derived from the {@linkplain Class#getName() binary names} of the classes + * (for classes in a named package).
  • + *
  • The package is not sealed.
  • + *
  • The specification and implementation titles, versions, and vendors + * are unspecified.
  • + *
  • Any annotations on the package are read from {@code package-info.class} + * as specified above.
  • + *
* - *

The set of classes that make up the package may implement a - * particular specification and if so the specification title, version number, - * and vendor strings identify that specification. - * An application can ask if the package is - * compatible with a particular version, see the {@link - * #isCompatibleWith isCompatibleWith} - * method for details. + *

+ * A {@code Package} can be obtained with the {@link Package#getPackage + * Package.getPackage(String)} and {@link ClassLoader#getDefinedPackage + * ClassLoader.getDefinedPackage(String)} methods. + * Every {@code Package} defined by a class loader can be obtained + * with the {@link Package#getPackages Package.getPackages()} and + * {@link ClassLoader#getDefinedPackages} methods. * - *

Specification version numbers use a syntax that consists of nonnegative - * decimal integers separated by periods ".", for example "2.0" or - * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent - * major, minor, micro, etc. versions. The version specification is described - * by the following formal grammar: - *

- *
- *
SpecificationVersion: - *
Digits RefinedVersionopt - - *
RefinedVersion: - *
{@code .} Digits - *
{@code .} Digits RefinedVersion + * @jvms 5.3 Run-time package + * @see + * The JAR File Specification: Package Versioning + * @see + * The JAR File Specification: Package Sealing + * @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL) * - *
Digits: - *
Digit - *
Digits - * - *
Digit: - *
any character for which {@link Character#isDigit} returns {@code true}, - * e.g. 0, 1, 2, ... - *
- *
- * - *

The implementation title, version, and vendor strings identify an - * implementation and are made available conveniently to enable accurate - * reporting of the packages involved when a problem occurs. The contents - * all three implementation strings are vendor specific. The - * implementation version strings have no specified syntax and should - * only be compared for equality with desired version identifiers. - * - *

Within each {@code ClassLoader} instance all classes from the same - * java package have the same Package object. The static methods allow a package - * to be found by name or the set of all packages known to the current class - * loader to be found. - * - * @see ClassLoader#definePackage * @since 1.2 */ -public class Package implements java.lang.reflect.AnnotatedElement { +public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement { /** * Return the name of this package. * @@ -112,47 +121,72 @@ public class Package implements java.lang.reflect.AnnotatedElement { * for example, {@code java.lang} */ public String getName() { - return pkgName; + return packageName(); } - /** * Return the title of the specification that this package implements. - * @return the specification title, null is returned if it is not known. + * @return the specification title, {@code null} is returned if it is not known. */ public String getSpecificationTitle() { - return specTitle; + return versionInfo.specTitle; } /** * Returns the version number of the specification * that this package implements. - * This version string must be a sequence of nonnegative decimal + * This version string must be a sequence of non-negative decimal * integers separated by "."'s and may have leading zeros. * When version strings are compared the most significant * numbers are compared. - * @return the specification version, null is returned if it is not known. + * + * + *

Specification version numbers use a syntax that consists of non-negative + * decimal integers separated by periods ".", for example "2.0" or + * "1.2.3.4.5.6.7". This allows an extensible number to be used to represent + * major, minor, micro, etc. versions. The version specification is described + * by the following formal grammar: + *

+ *
+ *
SpecificationVersion: + *
Digits RefinedVersionopt + + *
RefinedVersion: + *
{@code .} Digits + *
{@code .} Digits RefinedVersion + * + *
Digits: + *
Digit + *
Digits + * + *
Digit: + *
any character for which {@link Character#isDigit} returns {@code true}, + * e.g. 0, 1, 2, ... + *
+ *
+ * + * @return the specification version, {@code null} is returned if it is not known. */ public String getSpecificationVersion() { - return specVersion; + return versionInfo.specVersion; } /** * Return the name of the organization, vendor, * or company that owns and maintains the specification * of the classes that implement this package. - * @return the specification vendor, null is returned if it is not known. + * @return the specification vendor, {@code null} is returned if it is not known. */ public String getSpecificationVendor() { - return specVendor; + return versionInfo.specVendor; } /** * Return the title of this package. - * @return the title of the implementation, null is returned if it is not known. + * @return the title of the implementation, {@code null} is returned if it is not known. */ public String getImplementationTitle() { - return implTitle; + return versionInfo.implTitle; } /** @@ -162,19 +196,20 @@ public class Package implements java.lang.reflect.AnnotatedElement { * runtime. It may be compared for equality with other * package version strings used for this implementation * by this vendor for this package. - * @return the version of the implementation, null is returned if it is not known. + * @return the version of the implementation, {@code null} is returned if it is not known. */ public String getImplementationVersion() { - return implVersion; + return versionInfo.implVersion; } /** - * Returns the name of the organization, - * vendor or company that provided this implementation. - * @return the vendor that implemented this package.. + * Returns the vendor that implemented this package, {@code null} + * is returned if it is not known. + * @return the vendor that implemented this package, {@code null} + * is returned if it is not known. */ public String getImplementationVendor() { - return implVendor; + return versionInfo.implVendor; } /** @@ -183,17 +218,29 @@ public class Package implements java.lang.reflect.AnnotatedElement { * @return true if the package is sealed, false otherwise */ public boolean isSealed() { - return sealBase != null; + return module().isNamed() || versionInfo.sealBase != null; } /** * Returns true if this package is sealed with respect to the specified - * code source url. + * code source {@code url}. * - * @param url the code source url - * @return true if this package is sealed with respect to url + * @param url the code source URL + * @return true if this package is sealed with respect to the given {@code url} */ public boolean isSealed(URL url) { + Objects.requireNonNull(url); + + URL sealBase = null; + if (versionInfo != VersionInfo.NULL_VERSION_INFO) { + sealBase = versionInfo.sealBase; + } else { + try { + URI uri = location(); + sealBase = uri != null ? uri.toURL() : null; + } catch (MalformedURLException e) { + } + } return url.equals(sealBase); } @@ -216,17 +263,17 @@ public class Package implements java.lang.reflect.AnnotatedElement { * @return true if this package's version number is greater * than or equal to the desired version number * - * @exception NumberFormatException if the desired or current version - * is not of the correct dotted form. + * @exception NumberFormatException if the current version is not known or + * the desired or current version is not of the correct dotted form. */ public boolean isCompatibleWith(String desired) throws NumberFormatException { - if (specVersion == null || specVersion.length() < 1) { + if (versionInfo.specVersion == null || versionInfo.specVersion.length() < 1) { throw new NumberFormatException("Empty version string"); } - String [] sa = specVersion.split("\\.", -1); + String [] sa = versionInfo.specVersion.split("\\.", -1); int [] si = new int[sa.length]; for (int i = 0; i < sa.length; i++) { si[i] = Integer.parseInt(sa[i]); @@ -255,92 +302,71 @@ public class Package implements java.lang.reflect.AnnotatedElement { } /** - * Find a package by name in the callers {@code ClassLoader} instance. - * The callers {@code ClassLoader} instance is used to find the package - * instance corresponding to the named class. If the callers - * {@code ClassLoader} instance is null then the set of packages loaded - * by the system {@code ClassLoader} instance is searched to find the - * named package.

+ * Finds a package by name in the caller's class loader and its + * ancestors. + *

+ * If the caller's class loader defines a {@code Package} of the given name, + * the {@code Package} is returned. Otherwise, the ancestors of the + * caller's class loader are searched recursively (parent by parent) + * for a {@code Package} of the given name. + *

+ * Calling this method is equivalent to calling {@link ClassLoader#getPackage} + * on a {@code ClassLoader} instance which is the caller's class loader. * - * Packages have attributes for versions and specifications only if the class - * loader created the package instance with the appropriate attributes. Typically, - * those attributes are defined in the manifests that accompany the classes. + * @param name A package name, such as "{@code java.lang}". + * @return The {@code Package} of the given name defined by the caller's + * class loader or its ancestors, or {@code null} if not found. * - * @param name a package name, for example, java.lang. - * @return the package of the requested name. It may be null if no package - * information is available from the archive or codebase. + * @deprecated + * If multiple class loaders delegate to each other and define classes + * with the same package name, and one such loader relies on the lookup + * behavior of {@code getPackage} to return a {@code Package} from + * a parent loader, then the properties exposed by the {@code Package} + * may not be as expected in the rest of the program. + * For example, the {@code Package} will only expose annotations from the + * {@code package-info.class} file defined by the parent loader, even if + * annotations exist in a {@code package-info.class} file defined by + * a child loader. A more robust approach is to use the + * {@link ClassLoader#getDefinedPackage} method which returns + * a {@code Package} for the specified class loader. + * + * @see ClassLoader#getDefinedPackage */ @CallerSensitive + @Deprecated + @SuppressWarnings("deprecation") public static Package getPackage(String name) { ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); - if (l != null) { - return l.getPackage(name); - } else { - return getSystemPackage(name); - } + return l != null ? l.getPackage(name) : BootLoader.getDefinedPackage(name); } /** - * Get all the packages currently known for the caller's {@code ClassLoader} - * instance. Those packages correspond to classes loaded via or accessible by - * name to that {@code ClassLoader} instance. If the caller's - * {@code ClassLoader} instance is the bootstrap {@code ClassLoader} - * instance, which may be represented by {@code null} in some implementations, - * only packages corresponding to classes loaded by the bootstrap - * {@code ClassLoader} instance will be returned. + * Returns all of the {@code Package}s defined by the caller's class loader + * and its ancestors. The returned array may contain more than one + * {@code Package} object of the same package name, each defined by + * a different class loader in the class loader hierarchy. + *

+ * Calling this method is equivalent to calling {@link ClassLoader#getPackages} + * on a {@code ClassLoader} instance which is the caller's class loader. * - * @return a new array of packages known to the callers {@code ClassLoader} - * instance. An zero length array is returned if none are known. + * @return The array of {@code Package} objects defined by this + * class loader and its ancestors + * + * @see ClassLoader#getDefinedPackages */ @CallerSensitive public static Package[] getPackages() { - ClassLoader l = ClassLoader.getClassLoader(Reflection.getCallerClass()); - if (l != null) { - return l.getPackages(); - } else { - return getSystemPackages(); - } - } - - /** - * Get the package for the specified class. - * The class's class loader is used to find the package instance - * corresponding to the specified class. If the class loader - * is the bootstrap class loader, which may be represented by - * {@code null} in some implementations, then the set of packages - * loaded by the bootstrap class loader is searched to find the package. - *

- * Packages have attributes for versions and specifications only - * if the class loader created the package - * instance with the appropriate attributes. Typically those - * attributes are defined in the manifests that accompany - * the classes. - * - * @param c the class to get the package of. - * @return the package of the class. It may be null if no package - * information is available from the archive or codebase. */ - static Package getPackage(Class c) { - String name = c.getName(); - int i = name.lastIndexOf('.'); - if (i != -1) { - name = name.substring(0, i); - ClassLoader cl = c.getClassLoader(); - if (cl != null) { - return cl.getPackage(name); - } else { - return getSystemPackage(name); - } - } else { - return null; - } + ClassLoader cl = ClassLoader.getClassLoader(Reflection.getCallerClass()); + return cl != null ? cl.getPackages() : BootLoader.packages().toArray(Package[]::new); } /** * Return the hash code computed from the package name. * @return the hash code computed from the package name. */ + @Override public int hashCode(){ - return pkgName.hashCode(); + return packageName().hashCode(); } /** @@ -350,9 +376,10 @@ public class Package implements java.lang.reflect.AnnotatedElement { * If the package version is defined it is appended. * @return the string representation of the package. */ + @Override public String toString() { - String spec = specTitle; - String ver = specVersion; + String spec = versionInfo.specTitle; + String ver = versionInfo.specVersion; if (spec != null && spec.length() > 0) spec = ", " + spec; else @@ -361,14 +388,20 @@ public class Package implements java.lang.reflect.AnnotatedElement { ver = ", version " + ver; else ver = ""; - return "package " + pkgName + spec + ver; + return "package " + packageName() + spec + ver; } private Class getPackageInfo() { if (packageInfo == null) { - try { - packageInfo = Class.forName(pkgName + ".package-info", false, loader); - } catch (ClassNotFoundException ex) { + // find package-info.class defined by loader + String cn = packageName() + ".package-info"; + PrivilegedAction pa = module()::getClassLoader; + ClassLoader loader = AccessController.doPrivileged(pa); + Class c = loader != null ? loader.loadLocalClass(cn) + : BootLoader.loadClassOrNull(cn); + if (c != null) { + packageInfo = c; + } else { // store a proxy for the package info that has no annotations class PackageInfoProxy {} packageInfo = PackageInfoProxy.class; @@ -437,8 +470,12 @@ public class Package implements java.lang.reflect.AnnotatedElement { } /** - * Construct a package instance with the specified version - * information. + * Construct a package instance for an unnamed module + * with the specified version information. + * + * @apiNote + * This method should not be called to define a Package for named module. + * * @param name the name of the package * @param spectitle the title of the specification * @param specversion the version of the specification @@ -446,216 +483,73 @@ public class Package implements java.lang.reflect.AnnotatedElement { * @param impltitle the title of the implementation * @param implversion the version of the implementation * @param implvendor the organization that maintains the implementation + * @param sealbase code source where this Package comes from + * @param loader defining class loader */ Package(String name, String spectitle, String specversion, String specvendor, String impltitle, String implversion, String implvendor, URL sealbase, ClassLoader loader) { - pkgName = name; - implTitle = impltitle; - implVersion = implversion; - implVendor = implvendor; - specTitle = spectitle; - specVersion = specversion; - specVendor = specvendor; - sealBase = sealbase; - this.loader = loader; + super(Objects.requireNonNull(name), + loader != null ? loader.getUnnamedModule() + : BootLoader.getUnnamedModule()); + + this.versionInfo = VersionInfo.getInstance(spectitle, specversion, + specvendor, impltitle, + implversion, implvendor, + sealbase); + } + + Package(String name, Module module) { + super(name, module); + this.versionInfo = VersionInfo.NULL_VERSION_INFO; } /* - * Construct a package using the attributes from the specified manifest. - * - * @param name the package name - * @param man the optional manifest for the package - * @param url the optional code source url for the package + * Versioning information. Only for packages in unnamed modules. */ - private Package(String name, Manifest man, URL url, ClassLoader loader) { - String path = name.replace('.', '/').concat("/"); - String sealed = null; - String specTitle= null; - String specVersion= null; - String specVendor= null; - String implTitle= null; - String implVersion= null; - String implVendor= null; - URL sealBase= null; - Attributes attr = man.getAttributes(path); - if (attr != null) { - specTitle = attr.getValue(Name.SPECIFICATION_TITLE); - specVersion = attr.getValue(Name.SPECIFICATION_VERSION); - specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); - implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); - implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); - implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); - sealed = attr.getValue(Name.SEALED); - } - attr = man.getMainAttributes(); - if (attr != null) { - if (specTitle == null) { - specTitle = attr.getValue(Name.SPECIFICATION_TITLE); - } - if (specVersion == null) { - specVersion = attr.getValue(Name.SPECIFICATION_VERSION); - } - if (specVendor == null) { - specVendor = attr.getValue(Name.SPECIFICATION_VENDOR); - } - if (implTitle == null) { - implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE); - } - if (implVersion == null) { - implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION); - } - if (implVendor == null) { - implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR); - } - if (sealed == null) { - sealed = attr.getValue(Name.SEALED); - } - } - if ("true".equalsIgnoreCase(sealed)) { - sealBase = url; - } - pkgName = name; - this.specTitle = specTitle; - this.specVersion = specVersion; - this.specVendor = specVendor; - this.implTitle = implTitle; - this.implVersion = implVersion; - this.implVendor = implVendor; - this.sealBase = sealBase; - this.loader = loader; - } + static class VersionInfo { + static final VersionInfo NULL_VERSION_INFO + = new VersionInfo(null, null, null, null, null, null, null); - /* - * Returns the loaded system package for the specified name. - */ - static Package getSystemPackage(String name) { - Package pkg = pkgs.get(name); - if (pkg == null) { - name = name.replace('.', '/').concat("/"); - String fn = getSystemPackage0(name); - if (fn != null) { - pkg = defineSystemPackage(name, fn); + private final String specTitle; + private final String specVersion; + private final String specVendor; + private final String implTitle; + private final String implVersion; + private final String implVendor; + private final URL sealBase; + + static VersionInfo getInstance(String spectitle, String specversion, + String specvendor, String impltitle, + String implversion, String implvendor, + URL sealbase) { + if (spectitle == null && specversion == null && + specvendor == null && impltitle == null && + implvendor == null && sealbase == null) { + return NULL_VERSION_INFO; } - } - return pkg; - } - - /* - * Return an array of loaded system packages. - */ - static Package[] getSystemPackages() { - // First, update the system package map with new package names - String[] names = getSystemPackages0(); - for (String name : names) { - if (!pkgs.containsKey(name)) { - defineSystemPackage(name, getSystemPackage0(name)); - } - } - return pkgs.values().toArray(new Package[pkgs.size()]); - } - - private static Package defineSystemPackage(final String iname, - final String fn) - { - // Convert to "."-separated package name - String name = iname.substring(0, iname.length() - 1).replace('/', '.'); - // Creates a cached manifest for the file name, allowing - // only-once, lazy reads of manifest from jar files - CachedManifest cachedManifest = createCachedManifest(fn); - pkgs.putIfAbsent(name, new Package(name, cachedManifest.getManifest(), - cachedManifest.getURL(), null)); - // Ensure we only expose one Package object - return pkgs.get(name); - } - - private static CachedManifest createCachedManifest(String fn) { - if (!manifests.containsKey(fn)) { - manifests.putIfAbsent(fn, new CachedManifest(fn)); - } - return manifests.get(fn); - } - - // The map of loaded system packages - private static final ConcurrentHashMap pkgs - = new ConcurrentHashMap<>(); - - // Maps each directory or zip file name to its corresponding manifest, if - // it exists - private static final ConcurrentHashMap manifests - = new ConcurrentHashMap<>(); - - private static class CachedManifest { - private static final Manifest EMPTY_MANIFEST = new Manifest(); - private final String fileName; - private final URL url; - private volatile Manifest manifest; - - CachedManifest(final String fileName) { - this.fileName = fileName; - this.url = AccessController.doPrivileged(new PrivilegedAction<>() { - public URL run() { - final File file = new File(fileName); - if (file.isFile()) { - try { - return ParseUtil.fileToEncodedURL(file); - } catch (MalformedURLException e) { - } - } - return null; - } - }); + return new VersionInfo(spectitle, specversion, specvendor, + impltitle, implversion, implvendor, + sealbase); } - public URL getURL() { - return url; - } - - public Manifest getManifest() { - if (url == null) { - return EMPTY_MANIFEST; - } - Manifest m = manifest; - if (m != null) { - return m; - } - synchronized (this) { - m = manifest; - if (m != null) { - return m; - } - m = AccessController.doPrivileged(new PrivilegedAction<>() { - public Manifest run() { - try (FileInputStream fis = new FileInputStream(fileName); - JarInputStream jis = new JarInputStream(fis, false)) { - return jis.getManifest(); - } catch (IOException e) { - return null; - } - } - }); - manifest = m = (m == null ? EMPTY_MANIFEST : m); - } - return m; + private VersionInfo(String spectitle, String specversion, + String specvendor, String impltitle, + String implversion, String implvendor, + URL sealbase) + { + this.implTitle = impltitle; + this.implVersion = implversion; + this.implVendor = implvendor; + this.specTitle = spectitle; + this.specVersion = specversion; + this.specVendor = specvendor; + this.sealBase = sealbase; } } - private static native String getSystemPackage0(String name); - private static native String[] getSystemPackages0(); - - /* - * Private storage for the package name and attributes. - */ - private final String pkgName; - private final String specTitle; - private final String specVersion; - private final String specVendor; - private final String implTitle; - private final String implVersion; - private final String implVendor; - private final URL sealBase; - private final transient ClassLoader loader; - private transient Class packageInfo; + private final VersionInfo versionInfo; + private Class packageInfo; } diff --git a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java index 5c7fbde5810..0750af15b03 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java +++ b/jdk/src/java.base/share/classes/java/lang/StackFrameInfo.java @@ -29,6 +29,7 @@ import jdk.internal.misc.SharedSecrets; import static java.lang.StackWalker.Option.*; import java.lang.StackWalker.StackFrame; +import java.lang.reflect.Module; import java.util.Optional; import java.util.OptionalInt; @@ -133,4 +134,21 @@ class StackFrameInfo implements StackFrame { static native void fillInStackFrames(int startIndex, Object[] stackframes, int fromIndex, int toIndex); + + @Override + public StackTraceElement toStackTraceElement() { + ensureMethodInfoInitialized(); + + Module module = declaringClass.getModule(); + String moduleName = module.isNamed() ? module.getName() : null; + String moduleVersion = null; + if (module.isNamed() && module.getDescriptor().version().isPresent()) { + moduleVersion = module.getDescriptor().version().get().toString(); + } + return new StackTraceElement(moduleName, moduleVersion, + getClassName(), getMethodName(), + fileName, + lineNumber); + } + } 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 fa9758f3f22..3710678e4eb 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java +++ b/jdk/src/java.base/share/classes/java/lang/StackTraceElement.java @@ -41,6 +41,8 @@ import java.util.Objects; */ public final class StackTraceElement implements java.io.Serializable { // Normally initialized by VM (public constructor added in 1.5) + private String moduleName; + private String moduleVersion; private String declaringClass; private String methodName; private String fileName; @@ -48,7 +50,9 @@ public final class StackTraceElement implements java.io.Serializable { /** * Creates a stack trace element representing the specified execution - * point. + * point. The {@link #getModuleName module name} and {@link + * #getModuleVersion module version} of the stack trace element will + * be {@code null}. * * @param declaringClass the fully qualified name of the class containing * the execution point represented by the stack trace element @@ -68,6 +72,40 @@ public final class StackTraceElement implements java.io.Serializable { */ public StackTraceElement(String declaringClass, String methodName, String fileName, int lineNumber) { + this(null, null, declaringClass, methodName, fileName, lineNumber); + } + + /** + * Creates a stack trace element representing the specified execution + * point. + * + * @param moduleName the module name if the class containing the + * execution point represented by the stack trace is in a named + * module; can be {@code null} + * @param moduleVersion the module version if the class containing the + * execution point represented by the stack trace is in a named + * module that has a version; can be {@code null} + * @param declaringClass the fully qualified name of the class containing + * the execution point represented by the stack trace element + * @param methodName the name of the method containing the execution point + * represented by the stack trace element + * @param fileName the name of the file containing the execution point + * represented by the stack trace element, or {@code null} if + * this information is unavailable + * @param lineNumber the line number of the source line containing the + * execution point represented by this stack trace element, or + * a negative number if this information is unavailable. A value + * of -2 indicates that the method containing the execution point + * is a native method + * @throws NullPointerException if {@code declaringClass} is {@code null} + * or {@code methodName} is {@code null} + * @since 9 + */ + public StackTraceElement(String moduleName, String moduleVersion, + String declaringClass, String methodName, + String fileName, int lineNumber) { + this.moduleName = moduleName; + this.moduleVersion = moduleVersion; this.declaringClass = Objects.requireNonNull(declaringClass, "Declaring class is null"); this.methodName = Objects.requireNonNull(methodName, "Method name is null"); this.fileName = fileName; @@ -111,6 +149,34 @@ public final class StackTraceElement implements java.io.Serializable { return lineNumber; } + /** + * Returns the module name of the module containing the execution point + * represented by this stack trace element. + * + * @return the module name of the {@code Module} containing the execution + * point represented by this stack trace element; {@code null} + * if the module name is not available. + * @since 9 + * @see java.lang.reflect.Module#getName() + */ + public String getModuleName() { + return moduleName; + } + + /** + * Returns the module version of the module containing the execution point + * represented by this stack trace element. + * + * @return the module version of the {@code Module} containing the execution + * point represented by this stack trace element; {@code null} + * if the module version is not available. + * @since 9 + * @see java.lang.module.ModuleDescriptor.Version + */ + public String getModuleVersion() { + return moduleVersion; + } + /** * Returns the fully qualified name of the class containing the * execution point represented by this stack trace element. @@ -154,32 +220,42 @@ public final class StackTraceElement implements java.io.Serializable { * examples may be regarded as typical: *

    *
  • - * {@code "MyClass.mash(MyClass.java:9)"} - Here, {@code "MyClass"} - * is the fully-qualified name of the class containing the - * execution point represented by this stack trace element, + * {@code "MyClass.mash(my.module@9.0/MyClass.java:101)"} - Here, + * {@code "MyClass"} is the fully-qualified name of the class + * containing the execution point represented by this stack trace element, * {@code "mash"} is the name of the method containing the execution - * point, {@code "MyClass.java"} is the source file containing the - * execution point, and {@code "9"} is the line number of the source + * point, {@code "my.module"} is the module name, {@code "9.0"} is the + * module version, and {@code "101"} is the line number of the source * line containing the execution point. *
  • - * {@code "MyClass.mash(MyClass.java)"} - As above, but the line - * number is unavailable. + * {@code "MyClass.mash(my.module@9.0/MyClass.java)"} - As above, but the + * line number is unavailable. *
  • - * {@code "MyClass.mash(Unknown Source)"} - As above, but neither - * the file name nor the line number are available. + * {@code "MyClass.mash(my.module@9.0/Unknown Source)"} - As above, but + * neither the file name nor the line number are available. *
  • - * {@code "MyClass.mash(Native Method)"} - As above, but neither - * the file name nor the line number are available, and the method - * containing the execution point is known to be a native method. + * {@code "MyClass.mash(my.module@9.0/Native Method)"} - As above, but + * neither the file name nor the line number are available, and the + * method containing the execution point is known to be a native method. *
+ * If the execution point is not in a named module, {@code "my.module@9.0/"} + * will be omitted from the above. + * * @see Throwable#printStackTrace() */ public String toString() { - return getClassName() + "." + methodName + - (isNativeMethod() ? "(Native Method)" : - (fileName != null && lineNumber >= 0 ? - "(" + fileName + ":" + lineNumber + ")" : - (fileName != null ? "("+fileName+")" : "(Unknown Source)"))); + String mid = ""; + if (moduleName != null) { + mid = moduleName; + if (moduleVersion != null) + mid += "@" + moduleVersion; + mid += "/"; + } + return getClassName() + "." + methodName + "(" + mid + + (isNativeMethod() ? "Native Method)" : + (fileName != null && lineNumber >= 0 ? + fileName + ":" + lineNumber + ")" : + (fileName != null ? ""+fileName+")" : "Unknown Source)"))); } /** @@ -190,6 +266,8 @@ public final class StackTraceElement implements java.io.Serializable { *
{@code
      *     equals(a.getFileName(), b.getFileName()) &&
      *     a.getLineNumber() == b.getLineNumber()) &&
+     *     equals(a.getModuleName(), b.getModuleName()) &&
+     *     equals(a.getModuleVersion(), b.getModuleVersion()) &&
      *     equals(a.getClassName(), b.getClassName()) &&
      *     equals(a.getMethodName(), b.getMethodName())
      * }
@@ -208,6 +286,8 @@ public final class StackTraceElement implements java.io.Serializable { return false; StackTraceElement e = (StackTraceElement)obj; return e.declaringClass.equals(declaringClass) && + Objects.equals(moduleName, e.moduleName) && + Objects.equals(moduleVersion, e.moduleVersion) && e.lineNumber == lineNumber && Objects.equals(methodName, e.methodName) && Objects.equals(fileName, e.fileName); @@ -218,6 +298,8 @@ public final class StackTraceElement implements java.io.Serializable { */ public int hashCode() { int result = 31*declaringClass.hashCode() + methodName.hashCode(); + result = 31*result + Objects.hashCode(moduleName); + result = 31*result + Objects.hashCode(moduleVersion); result = 31*result + Objects.hashCode(fileName); result = 31*result + lineNumber; return result; 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 f628459dfb3..636762e17d4 100644 --- a/jdk/src/java.base/share/classes/java/lang/StackWalker.java +++ b/jdk/src/java.base/share/classes/java/lang/StackWalker.java @@ -170,15 +170,8 @@ public final class StackWalker { * Gets a {@code StackTraceElement} for this stack frame. * * @return {@code StackTraceElement} for this stack frame. - * - * */ - public default StackTraceElement toStackTraceElement() { - int lineNumber = isNativeMethod() ? -2 - : getLineNumber().orElse(-1); - return new StackTraceElement(getClassName(), getMethodName(), - getFileName().orElse(null), - lineNumber); - } + */ + public StackTraceElement toStackTraceElement(); } /** 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 c0c7c05156a..92fee1a4337 100644 --- a/jdk/src/java.base/share/classes/java/lang/System.java +++ b/jdk/src/java.base/share/classes/java/lang/System.java @@ -24,9 +24,23 @@ */ package java.lang; -import java.io.*; -import java.lang.reflect.Executable; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.Console; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Layer; +import java.lang.reflect.Modifier; +import java.lang.reflect.Module; +import java.net.URL; import java.security.AccessControlContext; import java.util.Properties; import java.util.PropertyPermission; @@ -35,6 +49,8 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; +import java.util.stream.Stream; + import java.util.Objects; import java.util.ResourceBundle; import java.util.function.Supplier; @@ -51,6 +67,10 @@ import jdk.internal.logger.LoggerFinderLoader; import jdk.internal.logger.LazyLoggers; import jdk.internal.logger.LocalizedLoggerWrapper; +import jdk.internal.module.ModuleBootstrap; +import jdk.internal.module.Modules; +import jdk.internal.module.ServicesCatalog; + /** * The System class contains several useful class fields * and methods. It cannot be instantiated. @@ -65,7 +85,6 @@ import jdk.internal.logger.LocalizedLoggerWrapper; * @since 1.0 */ public final class System { - /* register the natives via the static initializer. * * VM will invoke the initializeSystemClass method to complete @@ -619,6 +638,24 @@ public final class System { * getProperties operation, it may choose to permit the * {@link #getProperty(String)} operation. * + * @implNote In addition to the standard system properties, the {@code + * java} launcher may create the Java Virtual Machine with system + * properties that have the following keys: + * + * + * + * + * + * + * + * + * + * + * + *
KeyDescription of Associated Value
{@code jdk.module.path}Application module path
{@code jdk.upgrade.module.path}The upgrade module path
{@code jdk.module.main}The module name of the initial/main module
{@code jdk.module.main.class}The main class name of the initial module
+ * These properties may also be set by custom launchers that use the JNI + * invocation API to create the Java Virtual Machine. + * * @return the system properties * @exception SecurityException if a security manager exists and its * checkPropertiesAccess method doesn't allow access @@ -1795,11 +1832,10 @@ public final class System { return new PrintStream(new BufferedOutputStream(fos, 128), true); } - /** * Initialize the system class. Called after thread initialization. */ - private static void initializeSystemClass() { + private static void initPhase1() { // VM might invoke JNU_NewStringPlatform() to set those encoding // sensitive properties (user.home, user.name, boot.class.path, etc.) @@ -1828,7 +1864,6 @@ public final class System { // certain system properties that are not intended for public access. VM.saveAndRemoveProperties(props); - lineSeparator = props.getProperty("line.separator"); VersionProps.init(); @@ -1862,9 +1897,81 @@ public final class System { // Subsystems that are invoked during initialization can invoke // VM.isBooted() in order to avoid doing things that should - // wait until the application class loader has been set up. + // wait until the VM is fully initialized. The initialization level + // is incremented from 0 to 1 here to indicate the first phase of + // initialization has completed. // IMPORTANT: Ensure that this remains the last initialization action! - VM.booted(); + VM.initLevel(1); + } + + // @see #initPhase2() + private static Layer bootLayer; + + /* + * Invoked by VM. Phase 2 module system initialization. + * Only classes in java.base can be loaded in this phase. + */ + private static void initPhase2() { + // initialize the module system + System.bootLayer = ModuleBootstrap.boot(); + + // base module needs to be loose (CODETOOLS-7901619) + Module base = Object.class.getModule(); + Modules.addReads(base, null); + + // module system initialized + VM.initLevel(2); + } + + /* + * Invoked by VM. Phase 3 is the final system initialization: + * 1. set security manager + * 2. set system class loader + * 3. set TCCL + * + * This method must be called after the module system initialization. + * The security manager and system class loader may be custom class from + * the application classpath or modulepath. + */ + private static void initPhase3() { + // set security manager + String cn = System.getProperty("java.security.manager"); + if (cn != null) { + if (cn.isEmpty() || "default".equals(cn)) { + System.setSecurityManager(new SecurityManager()); + } else { + try { + Class c = Class.forName(cn, false, ClassLoader.getBuiltinAppClassLoader()); + Constructor ctor = c.getConstructor(); + // Must be a public subclass of SecurityManager with + // a public no-arg constructor + if (!SecurityManager.class.isAssignableFrom(c) || + !Modifier.isPublic(c.getModifiers()) || + !Modifier.isPublic(ctor.getModifiers())) { + throw new Error("Could not create SecurityManager: " + ctor.toString()); + } + // custom security manager implementation may be in unnamed module + // or a named module but non-exported package + ctor.setAccessible(true); + SecurityManager sm = (SecurityManager) ctor.newInstance(); + System.setSecurityManager(sm); + } catch (Exception e) { + throw new Error("Could not create SecurityManager", e); + } + } + } + + // initializing the system class loader + VM.initLevel(3); + + // system class loader initialized + ClassLoader scl = ClassLoader.initSystemClassLoader(); + + // set TCCL + Thread.currentThread().setContextClassLoader(scl); + + // system is fully initialized + VM.initLevel(4); } private static void setJavaLangAccess() { @@ -1910,6 +2017,27 @@ public final class System { public void invokeFinalize(Object o) throws Throwable { o.finalize(); } + public Layer getBootLayer() { + return bootLayer; + } + public ServicesCatalog getServicesCatalog(ClassLoader cl) { + return cl.getServicesCatalog(); + } + public ServicesCatalog createOrGetServicesCatalog(ClassLoader cl) { + return cl.createOrGetServicesCatalog(); + } + public Class findBootstrapClassOrNull(ClassLoader cl, String name) { + return cl.findBootstrapClassOrNull(name); + } + public URL findResource(ClassLoader cl, String mn, String name) throws IOException { + return cl.findResource(mn, name); + } + public Stream packages(ClassLoader cl) { + return cl.packages(); + } + public Package definePackage(ClassLoader cl, String name, Module module) { + return cl.definePackage(name, module); + } public String fastUUID(long lsb, long msb) { return Long.fastUUID(lsb, msb); } diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java index 90d0d590697..3d9d59fc89e 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -788,7 +788,8 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; static void setSpeciesDataToConcreteBMHClass(Class cbmh, SpeciesData speciesData) { try { Field F_SPECIES_DATA = cbmh.getDeclaredField("SPECIES_DATA"); - assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null; + // ## FIXME: annotation parser can't create proxy classes until module system is fully initialzed + // assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null; F_SPECIES_DATA.set(null, speciesData); } catch (ReflectiveOperationException ex) { throw newInternalError(ex); diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java index 50e28e56cab..3c6b0d14d50 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MemberName.java @@ -33,6 +33,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Member; import java.lang.reflect.Modifier; +import java.lang.reflect.Module; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -475,8 +476,9 @@ import java.util.Objects; /** Utility method to query whether this member is accessible from a given lookup class. */ public boolean isAccessibleFrom(Class lookupClass) { + int mode = (ALL_ACCESS|MethodHandles.Lookup.PACKAGE|MethodHandles.Lookup.MODULE); return VerifyAccess.isMemberAccessible(this.getDeclaringClass(), this.getDeclaringClass(), flags, - lookupClass, ALL_ACCESS|MethodHandles.Lookup.PACKAGE); + lookupClass, mode); } /** Initialize a query. It is not resolved. */ @@ -851,7 +853,20 @@ import java.util.Objects; public IllegalAccessException makeAccessException(String message, Object from) { message = message + ": "+ toString(); - if (from != null) message += ", from " + from; + if (from != null) { + if (from == MethodHandles.publicLookup()) { + message += ", from public Lookup"; + } else { + Module m; + if (from instanceof MethodHandles.Lookup) { + MethodHandles.Lookup lookup = (MethodHandles.Lookup)from; + m = lookup.lookupClass().getModule(); + } else { + m = from.getClass().getModule(); + } + message += ", from " + from + " (" + m + ")"; + } + } return new IllegalAccessException(message); } private String message() { diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 9b4029cc7b5..ed1dccc8041 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -1191,14 +1191,9 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; Class tClass = T.class; String tName = tClass.getName(); String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; - java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); - int len = uconn.getContentLength(); - byte[] bytes = new byte[len]; - try (java.io.InputStream str = uconn.getInputStream()) { - int nr = str.read(bytes); - if (nr != len) throw new java.io.IOException(tResource); + try (java.io.InputStream in = tClass.getResourceAsStream(tResource)) { + values[0] = in.readAllBytes(); } - values[0] = bytes; } catch (java.io.IOException ex) { throw new InternalError(ex); } 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 70791273212..0766cfc2047 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 @@ -26,7 +26,13 @@ package java.lang.invoke; import java.lang.reflect.*; -import java.util.*; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; +import java.util.Arrays; +import java.util.Objects; +import java.security.AccessController; +import java.security.PrivilegedAction; import sun.invoke.util.ValueConversions; import sun.invoke.util.VerifyAccess; @@ -44,6 +50,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import java.util.stream.Stream; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; + /** * This class consists exclusively of static methods that operate on or return * method handles. They fall into several categories: @@ -94,18 +103,19 @@ public class MethodHandles { /** * Returns a {@link Lookup lookup object} which is trusted minimally. - * It can only be used to create method handles to - * publicly accessible fields and methods. + * It can only be used to create method handles to public members in + * public classes in packages that are exported unconditionally. *

- * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class} - * of this lookup object will be {@link java.lang.Object}. + * 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. * *

* Discussion: * The lookup class can be changed to any other class {@code C} using an expression of the form * {@link Lookup#in publicLookup().in(C.class)}. - * Since all classes have equal access to public names, - * such a change would confer no new access rights. + * but may change the lookup context by virtue of changing the class loader. * A public lookup object is always subject to * security manager checks. * Also, it cannot access @@ -113,7 +123,15 @@ public class MethodHandles { * @return a lookup object which is trusted minimally */ public static Lookup publicLookup() { - return Lookup.PUBLIC_LOOKUP; + // 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; + } } /** @@ -386,7 +404,7 @@ public class MethodHandles { * to a subset of members normally accessible to the lookup class. * For example, the {@link MethodHandles#publicLookup publicLookup} * method produces a lookup object which is only allowed to access - * public members in public classes. + * public members in public classes of exported packages. * The caller sensitive method {@link MethodHandles#lookup lookup} * produces a lookup object with full capabilities relative to * its caller class, to emulate all supported bytecode behaviors. @@ -558,12 +576,24 @@ public class MethodHandles { */ public static final int PACKAGE = Modifier.STATIC; - private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE); + /** A single-bit mask representing {@code module} access (default access), + * which may contribute to the result of {@link #lookupModes lookupModes}. + * The value is {@code 0x10}, which does not correspond meaningfully to + * any particular {@linkplain java.lang.reflect.Modifier modifier bit}. + * In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup} + * with this lookup mode can access all public types in the module of the + * lookup class and public types in packages exported by other modules + * to the module of the lookup class. + * @since 9 + */ + public static final int MODULE = PACKAGE << 1; + + private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE); private static final int TRUSTED = -1; private static int fixmods(int mods) { - mods &= (ALL_MODES - PACKAGE); - return (mods != 0) ? mods : PACKAGE; + mods &= (ALL_MODES - PACKAGE - MODULE); + return (mods != 0) ? mods : (PACKAGE | MODULE); } /** Tells which class is performing the lookup. It is this class against @@ -589,11 +619,14 @@ public class MethodHandles { * {@linkplain #PUBLIC PUBLIC (0x01)}, * {@linkplain #PRIVATE PRIVATE (0x02)}, * {@linkplain #PROTECTED PROTECTED (0x04)}, - * and {@linkplain #PACKAGE PACKAGE (0x08)}. + * {@linkplain #PACKAGE PACKAGE (0x08)}, + * and {@linkplain #MODULE MODULE (0x10)}. *

* 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. + * 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. * 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. @@ -630,6 +663,12 @@ 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.) @@ -641,6 +680,11 @@ public class MethodHandles { * then no members, not even public members, will be accessible. * (In all other cases, public members will continue to be accessible.) *
+ *

+ * The resulting lookup's capabilities for loading classes + * (used during {@link #findClass} invocations) + * are determined by the lookup class' loader, + * which may change due to this operation. * * @param requestedLookupClass the desired lookup class for the new lookup object * @return a lookup object which reports the desired lookup class @@ -652,7 +696,17 @@ public class MethodHandles { return new Lookup(requestedLookupClass, ALL_MODES); if (requestedLookupClass == this.lookupClass) return this; // keep same capabilities + int newModes = (allowedModes & (ALL_MODES & ~PROTECTED)); + 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()) { + newModes = 0; + } else { + newModes &= ~MODULE; + } + } if ((newModes & PACKAGE) != 0 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) { newModes &= ~(PACKAGE|PRIVATE); @@ -668,6 +722,7 @@ public class MethodHandles { // No permissions. newModes = 0; } + checkUnprivilegedlookupClass(requestedLookupClass, newModes); return new Lookup(requestedLookupClass, newModes); } @@ -675,12 +730,6 @@ public class MethodHandles { // Make sure outer class is initialized first. static { IMPL_NAMES.getClass(); } - /** Version of lookup which is trusted minimally. - * It can only be used to create method handles to - * publicly accessible members. - */ - static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC); - /** Package-private version of lookup which is trusted. */ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED); @@ -708,12 +757,13 @@ public class MethodHandles { * allowed access, and is chosen as follows: *

    *
  • If no access is allowed, the suffix is "/noaccess". - *
  • If only public access is allowed, the suffix is "/public". - *
  • If only public and package access are allowed, the suffix is "/package". - *
  • If only public, package, and private access are allowed, the suffix is "/private". + *
  • If only public access to types in exported packages is allowed, the suffix is "/public". + *
  • 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". *
* If none of the above cases apply, it is the case that full - * access (public, package, private, and protected) is allowed. + * access (public, module, package, private, and protected) is allowed. * In this case, no suffix is added. * This is true only of an object obtained originally from * {@link java.lang.invoke.MethodHandles#lookup MethodHandles.lookup}. @@ -735,7 +785,9 @@ public class MethodHandles { return cname + "/noaccess"; case PUBLIC: return cname + "/public"; - case PUBLIC|PACKAGE: + case PUBLIC|MODULE: + return cname + "/module"; + case PUBLIC|MODULE|PACKAGE: return cname + "/package"; case ALL_MODES & ~PROTECTED: return cname + "/private"; @@ -939,13 +991,17 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object. The static * initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, its class + * loader, and the {@linkplain #lookupModes() lookup modes}. In particular, the method first attempts to + * load the requested class, and then determines whether the class is accessible to this lookup object. * * @param targetName the fully qualified name of the class to be looked up. * @return the requested class. * @exception SecurityException if a security manager is present and it * refuses access * @throws LinkageError if the linkage fails - * @throws ClassNotFoundException if the class does not exist. + * @throws ClassNotFoundException if the class cannot be loaded by the lookup class' loader. * @throws IllegalAccessException if the class is not accessible, using the allowed access * modes. * @exception SecurityException if a security manager is present and it @@ -960,6 +1016,9 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Determines if a class can be accessed from the lookup context defined by this {@code Lookup} object. The * static initializer of the class is not run. + *

+ * The lookup context here is determined by the {@linkplain #lookupClass() lookup class} and the + * {@linkplain #lookupModes() lookup modes}. * * @param targetClass the class to be access-checked * @@ -1455,7 +1514,7 @@ return mh1; Objects.requireNonNull(refc); Class caller = lookupClassOrNull(); if (caller != null && !VerifyAccess.isClassAccessible(refc, caller, allowedModes)) - throw new MemberName(refc).makeAccessException("symbolic reference class is not public", this); + throw new MemberName(refc).makeAccessException("symbolic reference class is not accessible", this); } /** Check name for an illegal leading "<" character. */ @@ -1584,8 +1643,6 @@ return mh1; if (Modifier.isFinal(mods) && MethodHandleNatives.refKindIsSetter(refKind)) throw m.makeAccessException("unexpected set of a final field", this); - if (Modifier.isPublic(mods) && Modifier.isPublic(refc.getModifiers()) && allowedModes != 0) - return; // common case int requestedModes = fixmods(mods); // adjust 0 => PACKAGE if ((requestedModes & allowedModes) != 0) { if (VerifyAccess.isMemberAccessible(refc, m.getDeclaringClass(), @@ -1615,7 +1672,7 @@ return mh1; if (!classOK) return "class is not public"; if (Modifier.isPublic(mods)) - return "access to public member failed"; // (how?) + return "access to public member failed"; // (how?, module not readable?) if (Modifier.isPrivate(mods)) return "member is private"; if (Modifier.isProtected(mods)) @@ -1876,6 +1933,61 @@ 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; + static { + PrivilegedAction> pa = new PrivilegedAction>() { + public Class run() { + return createClass(); + } + }; + PUBLIC_LOOKUP_CLASS = AccessController.doPrivileged(pa); + } + + /** + * 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 giving read access to elements of an array. * The type of the method handle will have a return type of the array's diff --git a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 853db2cbf73..b87e1672d2a 100644 --- a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -91,7 +91,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.*; * can call with more than 255 slots. This limits the number of static and * dynamic arguments one can pass to bootstrap method. Since there are potential * concatenation strategies that use {@code MethodHandle} combinators, we need - * to reserve a few empty slots on the parameter lists to to capture the + * to reserve a few empty slots on the parameter lists to capture the * temporal results. This is why bootstrap methods in this factory do not accept * more than 200 argument slots. Users requiring more than 200 argument slots in * concatenation are expected to split the large concatenation in smaller @@ -691,8 +691,8 @@ public final class StringConcatFactory { case BC_SB_SIZED: case BC_SB_SIZED_EXACT: { if (CACHE_ENABLE) { - Package pkg = hostClass.getPackage(); - return (pkg != null ? pkg.getName().replace('.', '/') + "/" : "") + "Stubs$$StringConcat"; + String pkgName = hostClass.getPackageName(); + return (pkgName != null && !pkgName.isEmpty() ? pkgName.replace('.', '/') + "/" : "") + "Stubs$$StringConcat"; } else { return hostClass.getName().replace('.', '/') + "$$StringConcat"; } 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 new file mode 100644 index 00000000000..ae9a2313ff0 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java @@ -0,0 +1,431 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.module; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * The configuration that is the result of resolution or resolution with + * 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 {@code requires} clauses. + * + * The dependence graph is augmented with edges that take account of + * implicitly declared dependences ({@code requires public}) 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 public 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 a parent configuration and where the readability graph may have + * edges from modules in the configuration to modules in a parent configuration. + *

+ * + *

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 public} 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}.

+ * + *

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.

+ * + *
{@code
+ *    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
+ *
+ *    Configuration parent = Layer.boot().configuration();
+ *
+ *    Configuration cf = parent.resolveRequires(finder,
+ *                                              ModuleFinder.empty(),
+ *                                              Set.of("myapp"));
+ *    cf.modules().forEach(m -> {
+ *        System.out.format("%s -> %s%n",
+ *            m.name(),
+ *            m.reads().stream()
+ *                .map(ResolvedModule::name)
+ *                .collect(Collectors.joining(", ")));
+ *    });
+ * }
+ * + * @since 9 + * @see java.lang.reflect.Layer + */ +public final class Configuration { + + // @see Configuration#empty() + private static final Configuration EMPTY_CONFIGURATION = new Configuration(); + + private final Configuration parent; + + private final Map> graph; + private final Set modules; + private final Map nameToModule; + + private Configuration() { + this.parent = null; + this.graph = Collections.emptyMap(); + this.modules = Collections.emptySet(); + this.nameToModule = Collections.emptyMap(); + } + + private Configuration(Configuration parent, Resolver resolver) { + Map> graph = resolver.finish(this); + + Map nameToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : graph.keySet()) { + nameToModule.put(resolvedModule.name(), resolvedModule); + } + + this.parent = parent; + this.graph = graph; + this.modules = Collections.unmodifiableSet(graph.keySet()); + this.nameToModule = Collections.unmodifiableMap(nameToModule); + } + + + /** + * Resolves a collection of root modules, with this configuration as its + * parent, to create a new configuration. + * + *

Each root module is located using the given {@code before} module + * finder. If a module is not found then it is located in the parent + * configuration as if by invoking the {@link #findModule(String) + * findModule} method. If not found then the module is located using the + * given {@code after} module finder. The same search order is used to + * locate transitive dependences. Root modules or dependences that are + * located in a parent configuration are resolved no further and are not + * included in the resulting 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 then, in conjunction with the + * module exports and service use, checked for consistency.

+ * + *

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

+ * + *
    + *
  • A root module, or a direct or transitive dependency, is not + * found.

  • + * + *
  • An error occurs when attempting to find a module. + * Possible errors include I/O errors, errors detected parsing a module + * descriptor ({@code module-info.class}) or two versions of the same + * module are found in the same directory.

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

  • + * + *
  • Two or more modules in the configuration export the same + * package to a module that reads both. This includes the case where a + * module {@code M} containing package {@code p} reads another module + * that exports {@code p} to {@code M}.

  • + * + *
  • A module {@code M} declares that it "{@code uses p.S}" or + * "{@code provides p.S with ...}" but package {@code p} is neither in + * 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.

  • + * + *
+ * + * @param before + * 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 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 + * + * @throws ResolutionException + * If resolution or the post-resolution checks fail for any of the + * reasons listed + * @throws SecurityException + * If locating a module is denied by the security manager + */ + public Configuration resolveRequires(ModuleFinder before, + ModuleFinder after, + Collection roots) + { + Objects.requireNonNull(before); + Objects.requireNonNull(after); + Objects.requireNonNull(roots); + + Resolver resolver = new Resolver(before, this, after); + resolver.resolveRequires(roots); + + return new Configuration(this, resolver); + } + + + /** + * 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 {@link #resolveRequires + * resolveRequires} 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 + * 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.

+ * + *

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

+ * + * @param before + * 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 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 + * + * @throws ResolutionException + * If resolution or the post-resolution checks fail for any of the + * reasons listed + * @throws SecurityException + * If locating a module is denied by the security manager + */ + public Configuration resolveRequiresAndUses(ModuleFinder before, + ModuleFinder after, + Collection roots) + { + Objects.requireNonNull(before); + Objects.requireNonNull(after); + Objects.requireNonNull(roots); + + Resolver resolver = new Resolver(before, this, after); + resolver.resolveRequires(roots).resolveUses(); + + return new Configuration(this, resolver); + } + + + /** + * Returns the empty configuration. The empty configuration does + * not contain any modules and does not have a parent. + * + * @return The empty configuration + */ + public static Configuration empty() { + return EMPTY_CONFIGURATION; + } + + + /** + * Returns this configuration's parent unless this is the {@linkplain #empty + * empty configuration}, which has no parent. + * + * @return This configuration's parent + */ + public Optional parent() { + return Optional.ofNullable(parent); + } + + + /** + * Returns an immutable set of the resolved modules in this configuration. + * + * @return A possibly-empty unmodifiable set of the resolved modules + * in this configuration + */ + public Set modules() { + return modules; + } + + + /** + * Finds a resolved module in this configuration, or if not in this + * configuration, the {@linkplain #parent parent} configurations. + * + * @param name + * The module name of the resolved module to find + * + * @return The resolved module with the given name or an empty {@code + * Optional} if there isn't a module with this name in this + * configuration or any parent configuration + */ + public Optional findModule(String name) { + Objects.requireNonNull(name); + if (parent == null) + return Optional.empty(); + ResolvedModule m = nameToModule.get(name); + if (m != null) + return Optional.of(m); + return parent().flatMap(x -> x.findModule(name)); + } + + + Set descriptors() { + if (modules.isEmpty()) { + return Collections.emptySet(); + } else { + return modules.stream() + .map(ResolvedModule::reference) + .map(ModuleReference::descriptor) + .collect(Collectors.toSet()); + } + } + + Set reads(ResolvedModule m) { + return Collections.unmodifiableSet(graph.get(m)); + } + + /** + * Returns a string describing this configuration. + * + * @return A string describing this configuration + */ + @Override + public String toString() { + return modules().stream() + .map(ResolvedModule::name) + .collect(Collectors.joining(", ")); + } +} diff --git a/jdk/src/java.base/share/classes/java/lang/module/Dependence.java b/jdk/src/java.base/share/classes/java/lang/module/Dependence.java new file mode 100644 index 00000000000..24538c056d6 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/Dependence.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.module; + +import java.util.*; +import java.util.stream.*; + + +class Dependence { + + private Dependence() { } + + static Stream toStringStream(Set s) { + return s.stream().map(e -> e.toString().toLowerCase()); + } + + static String toString(Set mods, String what) { + return (Stream.concat(toStringStream(mods), Stream.of(what))) + .collect(Collectors.joining(" ")); + } + +} 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 new file mode 100644 index 00000000000..d76f2935e7e --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/FindException.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.module; + +/** + * Thrown by module finders when finding a module fails. + * + * @see ModuleFinder + * @since 9 + */ + +public class FindException extends RuntimeException { + private static final long serialVersionUID = -5817081036963388391L; + + /** + * Constructs a {@code FindException} with no detail message. + */ + public FindException() { + } + + /** + * Constructs a {@code FindException} with the given detail + * message. + * + * @param msg + * The detail message; can be {@code null} + */ + public FindException(String msg) { + super(msg); + } + + /** + * Constructs a {@code FindException} with the given cause. + * + * @param cause + * The cause; can be {@code null} + */ + public FindException(Throwable cause) { + super(cause); + } + + /** + * Constructs a {@code FindException} with the given detail message + * and cause. + * + * @param msg + * The detail message; can be {@code null} + * @param cause + * The cause; can be {@code null} + */ + public FindException(String msg, Throwable cause) { + super(msg, cause); + } +} 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 new file mode 100644 index 00000000000..981f23a5189 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.module; + +/** + * Thrown when reading a module descriptor and the module descriptor is found + * to be malformed or otherwise cannot be interpreted as a module descriptor. + * + * @see ModuleDescriptor#read + * @since 9 + */ +public class InvalidModuleDescriptorException extends RuntimeException { + private static final long serialVersionUID = 4863390386809347380L; + + /** + * Constructs an {@code InvalidModuleDescriptorException} with no detail + * message. + */ + public InvalidModuleDescriptorException() { + } + + /** + * Constructs an {@code InvalidModuleDescriptorException} with the + * specified detail message. + * + * @param msg + * The detail message; can be {@code null} + */ + public InvalidModuleDescriptorException(String msg) { + super(msg); + } +} 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 new file mode 100644 index 00000000000..495f371422f --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -0,0 +1,1996 @@ +/* + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.module; + +import java.io.InputStream; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +import static jdk.internal.module.Checks.*; +import static java.util.Objects.*; + +import jdk.internal.module.Checks; +import jdk.internal.module.Hasher.DependencyHashes; + + +/** + * A module descriptor. + * + *

A {@code ModuleDescriptor} is typically created from the binary form + * of a module declaration. The associated {@link ModuleDescriptor.Builder} + * class can also be used to create a {@code ModuleDescriptor} from its + * components.

+ * + *

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

+ * + * @since 9 + * @see java.lang.reflect.Module + */ + +public class ModuleDescriptor + implements Comparable +{ + + /** + *

A dependence upon a module

+ * + * @see ModuleDescriptor#requires() + * @since 9 + */ + + public final static class Requires + implements Comparable + { + + /** + * A modifier on a module dependence. + * + * @since 9 + */ + public static enum Modifier { + + /** + * The dependence causes any module which depends on the current + * module to have an implicitly declared dependence on the module + * named by the {@code Requires}. + */ + PUBLIC, + + /** + * The dependence was not explicitly or implicitly declared in the + * source of the module declaration. + */ + SYNTHETIC, + + /** + * The dependence was implicitly declared in the source of the module + * declaration. + */ + MANDATED; + + } + + private final Set mods; + private final String name; + + private Requires(Set ms, String mn) { + this(ms, mn, true); + } + private Requires(Set ms, String mn, boolean check) { + if (ms == null || ms.isEmpty()) { + mods = Collections.emptySet(); + } else { + mods = check ? Collections.unmodifiableSet(EnumSet.copyOf(ms)) + : ms; + } + this.name = check ? requireModuleName(mn) : mn; + } + + /** + * Returns the set of modifiers. + * + * @return A possibly-empty unmodifiable set of modifiers + */ + public Set modifiers() { + return mods; + } + + /** + * Return the module name. + * + * @return The module name + */ + public String name() { + return name; + } + + /** + * 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.

+ * + * @return A negative integer, zero, or a positive integer if this module + * dependence is less than, equal to, or greater than the given + * module dependence + */ + @Override + public int compareTo(Requires that) { + int c = this.name().compareTo(that.name()); + if (c != 0) + return c; + // same name, compare by modifiers + return Long.compare(this.modsValue(), that.modsValue()); + } + + /** + * 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; + } + + /** + * Tests this module dependence for equality with the given object. + * + *

If the given object is not a {@code Requires} then this method + * returns {@code false}. Two module dependence objects are equal if + * the module names are equal and set of modifiers are equal.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * dependence that is equal to this module dependence + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Requires)) + return false; + Requires that = (Requires)ob; + return (name.equals(that.name) && mods.equals(that.mods)); + } + + /** + * Computes a hash code for this module dependence. + * + *

The hash code is based upon the module name and modifiers. It + * satisfies the general contract of the {@link Object#hashCode + * Object.hashCode} method.

+ * + * @return The hash-code value for this module dependence + */ + @Override + public int hashCode() { + return name.hashCode() * 43 + mods.hashCode(); + } + + /** + * Returns a string describing module dependence. + * + * @return A string describing module dependence + */ + @Override + public String toString() { + return Dependence.toString(mods, name); + } + + } + + + + /** + *

A module export, may be qualified or unqualified.

+ * + * @see ModuleDescriptor#exports() + * @since 9 + */ + + public final static class Exports { + + private final String source; + private final Set targets; // empty if unqualified export + + /** + * Constructs a qualified export. + */ + private Exports(String source, Set targets) { + this(source, targets, true); + } + + private Exports(String source, Set targets, boolean check) { + this.source = check ? requirePackageName(source) : source; + targets = check ? Collections.unmodifiableSet(new HashSet<>(targets)) + : Collections.unmodifiableSet(targets); + if (targets.isEmpty()) + throw new IllegalArgumentException("Empty target set"); + if (check) + targets.stream().forEach(Checks::requireModuleName); + this.targets = targets; + } + + /** + * Constructs an unqualified export. + */ + private Exports(String source) { + this(source, true); + } + private Exports(String source, boolean check) { + this.source = check ? requirePackageName(source) : source; + this.targets = Collections.emptySet(); + } + + /** + * Returns {@code true} if this is a qualified export. + * + * @return {@code true} if this is a qualified export + */ + public boolean isQualified() { + return !targets.isEmpty(); + } + + /** + * Returns the package name. + * + * @return The package name + */ + public String source() { + return source; + } + + /** + * For a qualified export, returns the non-empty and immutable set + * of the module names to which the package is exported. For an + * unqualified export, returns an empty set. + * + * @return The set of target module names or for an unqualified + * export, an empty set + */ + public Set targets() { + return targets; + } + + /** + * Computes a hash code for this module export. + * + *

The hash code is based upon the package name, and for a + * qualified export, the set of modules names to which the package + * is exported. It satisfies the general contract of the {@link + * Object#hashCode Object.hashCode} method. + * + * @return The hash-code value for this module export + */ + @Override + public int hashCode() { + return hash(source, targets); + } + + /** + * Tests this module export for equality with the given object. + * + *

If the given object is not a {@code Exports} then this method + * returns {@code false}. Two module exports objects are equal if the + * package names are equal and the set of target module names is equal. + *

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * dependence that is equal to this module dependence + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Exports)) + return false; + Exports other = (Exports)ob; + return Objects.equals(this.source, other.source) && + Objects.equals(this.targets, other.targets); + } + + /** + * Returns a string describing module export. + * + * @return A string describing module export + */ + @Override + public String toString() { + if (targets.isEmpty()) + return source; + else + return source + " to " + targets; + } + + } + + + + /** + *

A service that a module provides one or more implementations of.

+ * + * @see ModuleDescriptor#provides() + * @since 9 + */ + + public final static class Provides { + + private final String service; + private final Set providers; + + private Provides(String service, Set providers) { + this(service, providers, true); + } + + private Provides(String service, Set providers, boolean check) { + this.service = check ? requireServiceTypeName(service) : service; + providers = check ? Collections.unmodifiableSet(new HashSet<>(providers)) + : Collections.unmodifiableSet(providers); + if (providers.isEmpty()) + throw new IllegalArgumentException("Empty providers set"); + if (check) + providers.forEach(Checks::requireServiceProviderName); + this.providers = providers; + } + + /** + * Returns the fully qualified class name of the service type. + * + * @return The fully qualified class name of the service type. + */ + public String service() { return service; } + + /** + * Returns the set of the fully qualified class names of the providers. + * + * @return A non-empty and unmodifiable set of the fully qualified class + * names of the providers. + */ + public Set providers() { return providers; } + + /** + * Computes a hash code for this provides. + * + *

The hash code is based upon the service type and the set of + * providers. It satisfies the general contract of the {@link + * Object#hashCode Object.hashCode} method.

+ * + * @return The hash-code value for this module provides + */ + @Override + public int hashCode() { + return hash(service, providers); + } + + /** + * Tests this provides for equality with the given object. + * + *

If the given object is not a {@code Provides} then this method + * returns {@code false}. Two {@code Provides} objects are equal if the + * service type is equal and the set of providers is equal.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a + * {@code Provides} that is equal to this {@code Provides} + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Provides)) + return false; + Provides other = (Provides)ob; + return Objects.equals(this.service, other.service) && + Objects.equals(this.providers, other.providers); + } + + /** + * Returns a string describing this provides. + * + * @return A string describing this provides + */ + @Override + public String toString() { + return service + " with " + providers; + } + + } + + + + /** + * A module's version string. + * + *

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 + * 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 + * nor punctuation characters, or vice versa. + * + *

    + * + *
  • The version number is a sequence of tokens separated by + * {@code '.'} characters, terminated by the first {@code '-'} or {@code + * '+'} character.
  • + * + *
  • The pre-release version is a sequence of tokens separated + * by {@code '.'} or {@code '-'} characters, terminated by the first + * {@code '+'} character.
  • + * + *
  • The build version is a sequence of tokens separated by + * {@code '.'}, {@code '-'}, or {@code '+'} characters. + * + *
+ * + *

When comparing two version strings, the elements of their + * corresponding components are compared in pointwise fashion. If one + * component is longer than the other, but otherwise equal to it, then the + * first component is considered the greater of the two; otherwise, if two + * corresponding elements are integers then they are compared as such; + * otherwise, at least one of the elements is a string, so the other is + * converted into a string if it is an integer and the two are compared + * lexicographically. Trailing integer elements with the value zero are + * ignored. + * + *

Given two version strings, if their version numbers differ then the + * result of comparing them is the result of comparing their version + * numbers; otherwise, if one of them has a pre-release version but the + * other does not then the first is considered to precede the second, + * otherwise the result of comparing them is the result of comparing their + * pre-release versions; otherwise, the result of comparing them is the + * result of comparing their build versions. + * + * @see ModuleDescriptor#version() + * @since 9 + */ + + public final static class Version + implements Comparable + { + + private final String version; + + // If Java had disjunctive types then we'd write List here + // + private final List sequence; + private final List pre; + private final List build; + + // Take a numeric token starting at position i + // Append it to the given list + // Return the index of the first character not taken + // Requires: s.charAt(i) is (decimal) numeric + // + private static int takeNumber(String s, int i, List acc) { + char c = s.charAt(i); + int d = (c - '0'); + int n = s.length(); + while (++i < n) { + c = s.charAt(i); + if (c >= '0' && c <= '9') { + d = d * 10 + (c - '0'); + continue; + } + break; + } + acc.add(d); + return i; + } + + // Take a string token starting at position i + // Append it to the given list + // Return the index of the first character not taken + // Requires: s.charAt(i) is not '.' + // + private static int takeString(String s, int i, List acc) { + int b = i; + int n = s.length(); + while (++i < n) { + char c = s.charAt(i); + if (c != '.' && c != '-' && c != '+' && !(c >= '0' && c <= '9')) + continue; + break; + } + acc.add(s.substring(b, i)); + return i; + } + + // Syntax: tok+ ( '-' tok+)? ( '+' tok+)? + // First token string is sequence, second is pre, third is build + // Tokens are separated by '.' or '-', or by changes between alpha & numeric + // Numeric tokens are compared as decimal integers + // Non-numeric tokens are compared lexicographically + // A version with a non-empty pre is less than a version with same seq but no pre + // Tokens in build may contain '-' and '+' + // + private Version(String v) { + + if (v == null) + throw new IllegalArgumentException("Null version string"); + int n = v.length(); + if (n == 0) + throw new IllegalArgumentException("Empty version string"); + + int i = 0; + char c = v.charAt(i); + if (!(c >= '0' && c <= '9')) + throw new IllegalArgumentException(v + + ": Version string does not start" + + " with a number"); + + List sequence = new ArrayList<>(4); + List pre = new ArrayList<>(2); + List build = new ArrayList<>(2); + + i = takeNumber(v, i, sequence); + + while (i < n) { + c = v.charAt(i); + if (c == '.') { + i++; + continue; + } + if (c == '-' || c == '+') { + i++; + break; + } + if (c >= '0' && c <= '9') + i = takeNumber(v, i, sequence); + else + i = takeString(v, i, sequence); + } + + if (c == '-' && i >= n) + throw new IllegalArgumentException(v + ": Empty pre-release"); + + while (i < n) { + c = v.charAt(i); + if (c >= '0' && c <= '9') + i = takeNumber(v, i, pre); + else + i = takeString(v, i, pre); + if (i >= n) + break; + c = v.charAt(i); + if (c == '.' || c == '-') { + i++; + continue; + } + if (c == '+') { + i++; + break; + } + } + + if (c == '+' && i >= n) + throw new IllegalArgumentException(v + ": Empty pre-release"); + + while (i < n) { + c = v.charAt(i); + if (c >= '0' && c <= '9') + i = takeNumber(v, i, build); + else + i = takeString(v, i, build); + if (i >= n) + break; + c = v.charAt(i); + if (c == '.' || c == '-' || c == '+') { + i++; + continue; + } + } + + this.version = v; + this.sequence = sequence; + this.pre = pre; + this.build = build; + } + + /** + * Parses the given string as a version string. + * + * @param v + * The string to parse + * + * @return The resulting {@code Version} + * + * @throws IllegalArgumentException + * If {@code v} is {@code null}, an empty string, or cannot be + * parsed as a version string + */ + public static Version parse(String v) { + return new Version(v); + } + + @SuppressWarnings("unchecked") + private int cmp(Object o1, Object o2) { + return ((Comparable)o1).compareTo(o2); + } + + private int compareTokens(List ts1, List ts2) { + int n = Math.min(ts1.size(), ts2.size()); + for (int i = 0; i < n; i++) { + Object o1 = ts1.get(i); + Object o2 = ts2.get(i); + if ((o1 instanceof Integer && o2 instanceof Integer) + || (o1 instanceof String && o2 instanceof String)) + { + int c = cmp(o1, o2); + if (c == 0) + continue; + return c; + } + // Types differ, so convert number to string form + int c = o1.toString().compareTo(o2.toString()); + if (c == 0) + continue; + return c; + } + List rest = ts1.size() > ts2.size() ? ts1 : ts2; + int e = rest.size(); + for (int i = n; i < e; i++) { + Object o = rest.get(i); + if (o instanceof Integer && ((Integer)o) == 0) + continue; + return ts1.size() - ts2.size(); + } + return 0; + } + + /** + * Compares this module version to another module version. Module + * versions are compared as described in the class description. + * + * @param that + * The module version to compare + * + * @return A negative integer, zero, or a positive integer as this + * module version is less than, equal to, or greater than the + * given module version + */ + @Override + public int compareTo(Version that) { + int c = compareTokens(this.sequence, that.sequence); + if (c != 0) return c; + if (this.pre.isEmpty()) { + if (!that.pre.isEmpty()) return +1; + } else { + if (that.pre.isEmpty()) return -1; + } + c = compareTokens(this.pre, that.pre); + if (c != 0) return c; + return compareTokens(this.build, that.build); + } + + /** + * Tests this module version for equality with the given object. + * + *

If the given object is not a {@code Version} then this method + * returns {@code false}. Two module version are equal if their + * corresponding components are equal.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * reference that is equal to this module reference + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof Version)) + return false; + return compareTo((Version)ob) == 0; + } + + /** + * Computes a hash code for this module version. + * + *

The hash code is based upon the components of the version and + * satisfies the general contract of the {@link Object#hashCode + * Object.hashCode} method.

+ * + * @return The hash-code value for this module version + */ + @Override + public int hashCode() { + return version.hashCode(); + } + + /** + * Returns the string from which this version was parsed. + * + * @return The string from which this version was parsed. + */ + @Override + public String toString() { + return version; + } + + } + + + + // From module declarations + private final String name; + private final Set requires; + private final Set exports; + private final Set uses; + private final Map provides; + + // 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; + + // "Extended" information, added post-compilation by tools + private final Version version; + private final String mainClass; + private final String osName; + private final String osArch; + private final String osVersion; + private final Set conceals; + private final Set packages; + private final DependencyHashes hashes; + + private ModuleDescriptor(String name, + boolean automatic, + boolean synthetic, + Map requires, + Set uses, + Map exports, + Map provides, + Version version, + String mainClass, + String osName, + String osArch, + String osVersion, + Set conceals, + DependencyHashes hashes) + { + + this.name = name; + this.automatic = automatic; + this.synthetic = synthetic; + + Set rqs = new HashSet<>(requires.values()); + assert (rqs.stream().map(Requires::name).sorted().distinct().count() + == rqs.size()) + : "Module " + name + " has duplicate requires"; + this.requires = emptyOrUnmodifiableSet(rqs); + + Set exs = new HashSet<>(exports.values()); + assert (exs.stream().map(Exports::source).sorted().distinct().count() + == exs.size()) + : "Module " + name + " has duplicate exports"; + this.exports = emptyOrUnmodifiableSet(exs); + + this.uses = emptyOrUnmodifiableSet(uses); + this.provides = emptyOrUnmodifiableMap(provides); + + this.version = version; + this.mainClass = mainClass; + this.osName = osName; + this.osArch = osArch; + this.osVersion = osVersion; + this.hashes = hashes; + + assert !exports.keySet().stream().anyMatch(conceals::contains) + : "Module " + name + ": Package sets overlap"; + this.conceals = emptyOrUnmodifiableSet(conceals); + this.packages = computePackages(this.exports, this.conceals); + } + + /** + * Clones the given module descriptor with an augmented set of packages + */ + ModuleDescriptor(ModuleDescriptor md, Set pkgs) { + this.name = md.name; + this.automatic = md.automatic; + this.synthetic = md.synthetic; + + this.requires = md.requires; + this.exports = md.exports; + this.uses = md.uses; + this.provides = md.provides; + + this.version = md.version; + this.mainClass = md.mainClass; + this.osName = md.osName; + this.osArch = md.osArch; + this.osVersion = md.osVersion; + this.hashes = null; // need to ignore + + this.packages = emptyOrUnmodifiableSet(pkgs); + this.conceals = computeConcealedPackages(this.exports, this.packages); + } + + /** + * Creates a module descriptor from its components. This method is intended + * for use by the jlink plugin. + */ + ModuleDescriptor(String name, + boolean automatic, + boolean synthetic, + Set requires, + Set uses, + Set exports, + Map provides, + Version version, + String mainClass, + String osName, + String osArch, + String osVersion, + Set conceals, + Set packages) { + this.name = name; + this.automatic = automatic; + this.synthetic = synthetic; + this.requires = Collections.unmodifiableSet(requires); + this.exports = Collections.unmodifiableSet(exports); + this.uses = Collections.unmodifiableSet(uses); + this.provides = Collections.unmodifiableMap(provides); + this.conceals = Collections.unmodifiableSet(conceals); + this.packages = Collections.unmodifiableSet(packages); + + this.version = version; + this.mainClass = mainClass; + this.osName = osName; + this.osArch = osArch; + this.osVersion = osVersion; + this.hashes = null; + } + + /** + *

The module name.

+ * + * @return The module name + */ + public String name() { + return name; + } + + /** + *

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.

+ * + * @return {@code true} if this is an automatic module + */ + public boolean isAutomatic() { + return automatic; + } + + /** + *

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).

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

The dependences of this module.

+ * + * @return A possibly-empty unmodifiable set of {@link Requires} objects + */ + public Set requires() { + return requires; + } + + /** + *

The service dependences of this module.

+ * + * @return A possibly-empty unmodifiable set of the fully qualified class + * names of the service types used + */ + public Set uses() { + return uses; + } + + /** + *

The services that this module provides.

+ * + * @return The possibly-empty unmodifiable map of the services that this + * module provides. The map key is fully qualified class name of + * the service type. + */ + public Map provides() { + return provides; + } + + /** + *

The module exports.

+ * + * @return A possibly-empty unmodifiable set of exported packages + */ + public Set exports() { + return exports; + } + + /** + * Returns this module's version. + * + * @return This module's version + */ + public Optional version() { + return Optional.ofNullable(version); + } + + /** + * Returns a string containing this module's name and, if present, its + * version. + * + * @return A string containing this module's name and, if present, its + * version. + */ + public String toNameAndVersion() { + if (version != null) { + return name() + "@" + version; + } else { + return name(); + } + } + + /** + * Returns the module's main class. + * + * @return The fully qualified class name of this module's main class + */ + public Optional mainClass() { + return Optional.ofNullable(mainClass); + } + + /** + * Returns the operating system name if this module is operating system + * specific. + * + * @return The operating system name or an empty {@code Optional} + * if this module is not operating system specific + */ + public Optional osName() { + return Optional.ofNullable(osName); + } + + /** + * Returns the operating system architecture if this 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 + */ + public Optional osArch() { + return Optional.ofNullable(osArch); + } + + /** + * Returns the operating system version if this 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 + */ + public Optional osVersion() { + return Optional.ofNullable(osVersion); + } + + /** + * Returns the names of the packages defined in, but not exported by, this + * module. + * + * @return A possibly-empty unmodifiable set of the concealed packages + */ + public Set conceals() { + return conceals; + } + + /** + * Returns the names of all the packages defined in this module, whether + * exported or concealed. + * + * @return A possibly-empty unmodifiable set of the all packages + */ + public Set packages() { + return packages; + } + + /** + * Returns the object with the hashes of the dependences. + */ + Optional hashes() { + return Optional.ofNullable(hashes); + } + + + /** + * A builder used for building {@link ModuleDescriptor} objects. + * + *

Example usage:

+ * + *
{@code
+     *     ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1")
+     *         .requires("m2")
+     *         .exports("p")
+     *         .build();
+     * }
+ * + * @apiNote A {@code Builder} cannot be used to create an {@link + * ModuleDescriptor#isAutomatic() automatic} or a {@link + * ModuleDescriptor#isSynthetic() synthetic} module. + * + * @since 9 + */ + public static final class Builder { + + final String name; + final boolean automatic; + boolean synthetic; + final Map requires = new HashMap<>(); + final Set uses = new HashSet<>(); + final Map exports = new HashMap<>(); + final Map provides = new HashMap<>(); + Set conceals = Collections.emptySet(); + Version version; + String osName; + String osArch; + String osVersion; + String mainClass; + DependencyHashes hashes; + + /** + * Initializes a new builder with the given module name. + * + * @param name + * The module name + * + * @throws IllegalArgumentException + * If the module name is {@code null} or is not a legal Java + * identifier + */ + public Builder(String name) { + this(name, false); + } + + /* package */ Builder(String name, boolean automatic) { + this.name = requireModuleName(name); + this.automatic = automatic; + } + + /** + * Adds a dependence on a module. + * + * @param req + * The dependence + * + * @return This builder + * + * @throws IllegalArgumentException + * If the dependence is on the module that this builder was + * initialized to build + * @throws IllegalStateException + * If the dependence on the module has already been declared + */ + public Builder requires(Requires req) { + String mn = req.name(); + if (name.equals(mn)) + throw new IllegalArgumentException("Dependence on self"); + if (requires.containsKey(mn)) + throw new IllegalStateException("Dependence upon " + mn + + " already declared"); + requires.put(mn, req); + return this; + } + + /** + * Adds a dependence on a module with the given (and possibly empty) + * set of modifiers. + * + * @param mods + * The set of modifiers + * @param mn + * The module name + * + * @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 + * was initialized to build + * @throws IllegalStateException + * If the dependence on the module has already been declared + */ + public Builder requires(Set mods, String mn) { + if (name.equals(mn)) + throw new IllegalArgumentException("Dependence on self"); + if (requires.containsKey(mn)) + throw new IllegalStateException("Dependence upon " + mn + + " already declared"); + requires.put(mn, new Requires(mods, mn)); // checks mn + return this; + } + + /** + * Adds a dependence on a module with an empty set of modifiers. + * + * @param mn + * The module name + * + * @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 + * was initialized to build + * @throws IllegalStateException + * If the dependence on the module has already been declared + */ + public Builder requires(String mn) { + return requires(EnumSet.noneOf(Requires.Modifier.class), mn); + } + + /** + * Adds a dependence on a module with the given modifier. + * + * @param mod + * The modifier + * @param mn + * The module name + * + * @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 + * was initialized to build + * @throws IllegalStateException + * If the dependence on the module has already been declared + */ + public Builder requires(Requires.Modifier mod, String mn) { + return requires(EnumSet.of(mod), mn); + } + + /** + * Adds a service dependence. + * + * @param st + * The service type + * + * @return This builder + * + * @throws IllegalArgumentException + * If the service type is {@code null} or is not a legal Java + * identifier + * @throws IllegalStateException + * If a dependency on the service type has already been declared + */ + public Builder uses(String st) { + if (uses.contains(requireServiceTypeName(st))) + throw new IllegalStateException("Dependence upon service " + + st + " already declared"); + uses.add(st); + return this; + } + + /** + * Ensures that the given package name has not been declared as an + * exported or concealed package. + */ + private void ensureNotExportedOrConcealed(String pn) { + if (exports.containsKey(pn)) + throw new IllegalStateException("Export of package " + + pn + " already declared"); + if (conceals.contains(pn)) + throw new IllegalStateException("Concealed package " + + pn + " already declared"); + } + + /** + * Adds an export. + * + * @param e + * The export + * + * @return This builder + * + * @throws IllegalStateException + * If the package is already declared as an exported or + * concealed package + */ + public Builder exports(Exports e) { + String pn = e.source(); + ensureNotExportedOrConcealed(pn); + exports.put(pn, e); + return this; + } + + /** + * Adds an export 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 an exported or + * concealed package + */ + public Builder exports(String pn, Set targets) { + ensureNotExportedOrConcealed(pn); + exports.put(pn, new Exports(pn, targets)); // checks pn and targets + return this; + } + + /** + * Adds an export to a target module. + * + * @param pn + * The package name + * @param target + * The target module name + * + * @return This builder + * + * @throws IllegalArgumentException + * If the package name or target module is {@code null} or is + * not a legal Java identifier + * @throws IllegalStateException + * If the package is already declared as an exported or + * concealed package + */ + public Builder exports(String pn, String target) { + return exports(pn, Collections.singleton(target)); + } + + /** + * Adds an 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 an exported or + * concealed package + */ + public Builder exports(String pn) { + ensureNotExportedOrConcealed(pn); + exports.put(pn, new Exports(pn)); // checks pn + return this; + } + + // Used by ModuleInfo, after a packageFinder is invoked + /* package */ Set exportedPackages() { + return exports.keySet(); + } + + /** + * Provides a service with one or more implementations. + * + * @param p + * The provides + * + * @return This builder + * + * @throws IllegalStateException + * If the providers for the service type have already been + * declared + */ + public Builder provides(Provides p) { + String st = p.service(); + if (provides.containsKey(st)) + throw new IllegalStateException("Providers of service " + + st + " already declared"); + provides.put(st, p); + return this; + } + + /** + * Provides service {@code st} with implementations {@code pcs}. + * + * @param st + * The service type + * @param pcs + * The set of provider class names + * + * @return This builder + * + * @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 set + * of provider class names is empty + * @throws IllegalStateException + * If the providers for the service type have already been + * declared + */ + public Builder provides(String st, Set pcs) { + if (provides.containsKey(st)) + throw new IllegalStateException("Providers of service " + + st + " already declared"); + provides.put(st, new Provides(st, pcs)); // checks st and pcs + return this; + } + + /** + * Provides service {@code st} with implementation {@code pc}. + * + * @param st + * The service type + * @param pc + * The provider 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 st, String pc) { + return provides(st, Collections.singleton(pc)); + } + + /** + * Adds a set of (possible empty) concealed packages. + * + * @param pns + * The set of package names of the concealed packages + * + * @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 a concealed or + * exported package + */ + public Builder conceals(Set pns) { + pns.forEach(this::conceals); + return this; + } + + /** + * Adds a concealed package. + * + * @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 concealed or exported + * package + */ + public Builder conceals(String pn) { + Checks.requirePackageName(pn); + ensureNotExportedOrConcealed(pn); + if (conceals.isEmpty()) + conceals = new HashSet<>(); + conceals.add(pn); + return this; + } + + /** + * Sets the module version. + * + * @param v + * The version + * + * @return This builder + * + * @throws IllegalStateException + * If the module version is already set + */ + public Builder version(Version v) { + if (version != null) + throw new IllegalStateException("module version already set"); + version = requireNonNull(v); + return this; + } + + /** + * Sets the module version. + * + * @param v + * The version string to parse + * + * @return This 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 = Version.parse(v); + return this; + } + + /** + * Sets the module main class. + * + * @param mc + * The module main class + * + * @return This builder + * + * @throws IllegalArgumentException + * If {@code mainClass} is null or is not a legal Java identifier + * @throws IllegalStateException + * If the module main class is already set + */ + public Builder mainClass(String mc) { + if (mainClass != null) + throw new IllegalStateException("main class already set"); + mainClass = requireJavaIdentifier("main class name", mc); + return this; + } + + /** + * Sets the operating system name. + * + * @param name + * The operating system name + * + * @return This builder + * + * @throws IllegalArgumentException + * If {@code name} is null or the empty String + * @throws IllegalStateException + * If the operating system name is already set + */ + public Builder osName(String name) { + if (osName != null) + throw new IllegalStateException("OS name already set"); + if (name == null || name.isEmpty()) + throw new IllegalArgumentException("OS name is null or empty"); + osName = name; + return this; + } + + /** + * Sets the operating system architecture. + * + * @param arch + * The operating system architecture + * + * @return This builder + * + * @throws IllegalArgumentException + * If {@code name} is null or the empty String + * @throws IllegalStateException + * If the operating system architecture is already set + */ + public Builder osArch(String arch) { + if (osArch != null) + throw new IllegalStateException("OS arch already set"); + if (arch == null || arch.isEmpty()) + throw new IllegalArgumentException("OS arch is null or empty"); + osArch = arch; + return this; + } + + /** + * Sets the operating system version. + * + * @param version + * The operating system version + * + * @return This builder + * + * @throws IllegalArgumentException + * If {@code name} is null or the empty String + * @throws IllegalStateException + * If the operating system version is already set + */ + public Builder osVersion(String version) { + if (osVersion != null) + throw new IllegalStateException("OS version already set"); + if (version == null || version.isEmpty()) + throw new IllegalArgumentException("OS version is null or empty"); + osVersion = version; + return this; + } + + /* package */ Builder hashes(DependencyHashes hashes) { + this.hashes = hashes; + return this; + } + + + /* package */ Builder synthetic(boolean v) { + this.synthetic = v; + return this; + } + + /** + * Builds and returns a {@code ModuleDescriptor} from its components. + * + * @return The module descriptor + */ + public ModuleDescriptor build() { + assert name != null; + + return new ModuleDescriptor(name, + automatic, + synthetic, + requires, + uses, + exports, + provides, + version, + mainClass, + osName, + osArch, + osVersion, + conceals, + hashes); + } + + } + + + /** + * 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. + * + * @param that + * The object to which this module descriptor is to be compared + * + * @return A negative integer, zero, or a positive integer if this module + * descriptor is less than, equal to, or greater than the given + * module descriptor + */ + @Override + public int compareTo(ModuleDescriptor that) { + 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); + } + + /** + * Tests this module descriptor for equality with the given object. + * + *

If the given object is not a {@code ModuleDescriptor} then this + * method returns {@code false}. Two module descriptors are equal if each + * of their corresponding components is equal.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * descriptor that is equal to this module descriptor + */ + @Override + public boolean equals(Object ob) { + if (ob == this) + return true; + if (!(ob instanceof ModuleDescriptor)) + return false; + ModuleDescriptor that = (ModuleDescriptor)ob; + return (name.equals(that.name) + && automatic == that.automatic + && synthetic == that.synthetic + && requires.equals(that.requires) + && uses.equals(that.uses) + && exports.equals(that.exports) + && provides.equals(that.provides) + && Objects.equals(version, that.version) + && Objects.equals(mainClass, that.mainClass) + && Objects.equals(osName, that.osName) + && Objects.equals(osArch, that.osArch) + && Objects.equals(osVersion, that.osVersion) + && Objects.equals(conceals, that.conceals) + && Objects.equals(hashes, that.hashes)); + } + + private transient int hash; // cached hash code + + /** + * Computes a hash code for this module descriptor. + * + *

The hash code is based upon the components of the module descriptor, + * and satisfies the general contract of the {@link Object#hashCode + * Object.hashCode} method.

+ * + * @return The hash-code value for this module descriptor + */ + @Override + public int hashCode() { + int hc = hash; + if (hc == 0) { + hc = name.hashCode(); + hc = hc * 43 + Boolean.hashCode(automatic); + hc = hc * 43 + Boolean.hashCode(synthetic); + hc = hc * 43 + requires.hashCode(); + hc = hc * 43 + uses.hashCode(); + hc = hc * 43 + exports.hashCode(); + hc = hc * 43 + provides.hashCode(); + hc = hc * 43 + Objects.hashCode(version); + hc = hc * 43 + Objects.hashCode(mainClass); + hc = hc * 43 + Objects.hashCode(osName); + hc = hc * 43 + Objects.hashCode(osArch); + hc = hc * 43 + Objects.hashCode(osVersion); + hc = hc * 43 + Objects.hashCode(conceals); + hc = hc * 43 + Objects.hashCode(hashes); + if (hc != 0) hash = hc; + } + return hc; + } + + /** + * Returns a string describing this descriptor. + * + * @return A string describing this descriptor + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Module { name: ").append(toNameAndVersion()); + if (!requires.isEmpty()) + sb.append(", ").append(requires); + if (!uses.isEmpty()) + sb.append(", ").append(uses); + if (!exports.isEmpty()) + sb.append(", exports: ").append(exports); + if (!provides.isEmpty()) { + sb.append(", provides: ["); + for (Map.Entry entry : provides.entrySet()) { + sb.append(entry.getKey()) + .append(" with ") + .append(entry.getValue()); + } + sb.append("]"); + } + sb.append(" }"); + return sb.toString(); + } + + /** + * Reads the binary form of a module declaration from an input stream + * as a module descriptor. + * + *

If the descriptor encoded in the input stream does not indicate a + * set of concealed packages then the {@code packageFinder} will be + * invoked. The packages it returns, except for those indicated as + * exported in the encoded descriptor, will be considered to be concealed. + * 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, + * or reported as an {@code InvalidModuleDescriptorException}. If this + * method fails with an {@code InvalidModuleDescriptorException} or {@code + * IOException} then it may do so after some, but not all, bytes have + * been read from the input stream. It is strongly recommended that the + * stream be promptly closed and discarded if an exception occurs.

+ * + * @apiNote The {@code packageFinder} parameter is for use when reading + * module descriptors from legacy module-artifact formats that do not + * record the set of concealed packages in the descriptor itself. + * + * @param in + * The input stream + * @param packageFinder + * A supplier that can produce a set of package names + * + * @return The module descriptor + * + * @throws InvalidModuleDescriptorException + * If an invalid module descriptor is detected + * @throws IOException + * If an I/O error occurs reading from the input stream or {@code + * UncheckedIOException} is thrown by the package finder + */ + public static ModuleDescriptor read(InputStream in, + Supplier> packageFinder) + throws IOException + { + return ModuleInfo.read(in, requireNonNull(packageFinder)); + } + + /** + * Reads the binary form of a module declaration from an input stream + * as a module descriptor. + * + * @param in + * The input stream + * + * @return The module descriptor + * + * @throws InvalidModuleDescriptorException + * If an invalid module descriptor is detected + * @throws IOException + * If an I/O error occurs reading from the input stream + */ + public static ModuleDescriptor read(InputStream in) throws IOException { + return ModuleInfo.read(in, null); + } + + /** + * Reads the binary form of a module declaration from a byte buffer + * as a module descriptor. + * + *

If the descriptor encoded in the byte buffer does not indicate a + * set of concealed packages then the {@code packageFinder} will be + * invoked. The packages it returns, except for those indicated as + * exported in the encoded descriptor, will be considered to be + * concealed.

+ * + *

The module descriptor is read from the buffer stating at index + * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position() + * position} when this method is invoked. Upon return the buffer's position + * will be equal to {@code p + n} where {@code n} is the number of bytes + * read from the buffer.

+ * + *

If there are bytes following the module descriptor then it is + * implementation specific as to whether those bytes are read, ignored, + * or reported as an {@code InvalidModuleDescriptorException}. If this + * method fails with an {@code InvalidModuleDescriptorException} then it + * may do so after some, but not all, bytes have been read.

+ * + * @apiNote The {@code packageFinder} parameter is for use when reading + * module descriptors from legacy module-artifact formats that do not + * record the set of concealed packages in the descriptor itself. + * + * @param bb + * The byte buffer + * @param packageFinder + * A supplier that can produce a set of package names + * + * @return The module descriptor + * + * @throws InvalidModuleDescriptorException + * If an invalid module descriptor is detected + */ + public static ModuleDescriptor read(ByteBuffer bb, + Supplier> packageFinder) + { + return ModuleInfo.read(bb, requireNonNull(packageFinder)); + } + + /** + * Reads the binary form of a module declaration from a byte buffer + * as a module descriptor. + * + * @param bb + * The byte buffer + * + * @return The module descriptor + * + * @throws InvalidModuleDescriptorException + * If an invalid module descriptor is detected + */ + public static ModuleDescriptor read(ByteBuffer bb) { + return ModuleInfo.read(bb, null); + } + + + /** + * Computes the set of packages from exports and concealed packages. + * It returns the concealed packages set if there is no exported package. + */ + private static Set computePackages(Set exports, + Set conceals) + { + if (exports.isEmpty()) + return conceals; + + Set pkgs = new HashSet<>(conceals); + exports.stream().map(Exports::source).forEach(pkgs::add); + return emptyOrUnmodifiableSet(pkgs); + } + + /** + * Computes the set of concealed packages from exports and all packages. + * It returns the packages set if there are no exported packages. + */ + private static Set computeConcealedPackages(Set exports, + Set pkgs) + { + if (exports.isEmpty()) + return pkgs; + + Set conceals = new HashSet<>(pkgs); + exports.stream().map(Exports::source).forEach(conceals::remove); + return emptyOrUnmodifiableSet(conceals); + } + + private static Map emptyOrUnmodifiableMap(Map map) { + if (map.isEmpty()) { + return Collections.emptyMap(); + } else if (map.size() == 1) { + Map.Entry entry = map.entrySet().iterator().next(); + return Collections.singletonMap(entry.getKey(), entry.getValue()); + } else { + return Collections.unmodifiableMap(map); + } + } + + private static Set emptyOrUnmodifiableSet(Set set) { + if (set.isEmpty()) { + return Collections.emptySet(); + } else if (set.size() == 1) { + return Collections.singleton(set.iterator().next()); + } else { + return Collections.unmodifiableSet(set); + } + } + + static { + /** + * Setup the shared secret to allow code in other packages create + * ModuleDescriptor and associated objects directly. + */ + jdk.internal.misc.SharedSecrets + .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() { + @Override + public Requires newRequires(Set ms, String mn) { + return new Requires(ms, mn, false); + } + + @Override + public Exports newExports(String source, Set targets) { + return new Exports(source, targets, false); + } + + @Override + public Exports newExports(String source) { + return new Exports(source, false); + } + + @Override + public Provides newProvides(String service, Set providers) { + return new Provides(service, providers, false); + } + + @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, + boolean automatic, + boolean synthetic, + Set requires, + Set uses, Set exports, + Map provides, + Version version, + String mainClass, + String osName, + String osArch, + String osVersion, + Set conceals, + Set packages) { + return new ModuleDescriptor(name, + automatic, + synthetic, + requires, + uses, + exports, + provides, + version, + mainClass, + osName, + osArch, + osVersion, + conceals, + packages); + } + }); + } + +} 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 new file mode 100644 index 00000000000..83d8fc59aaf --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleFinder.java @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.module; + +import java.io.File; +import java.io.FilePermission; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.AccessController; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * A finder of modules. A {@code ModuleFinder} is used to find modules during + * 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 + * example, will locate the first occurrence of a module of a given name and + * will ignore other modules of that name that appear in directories later in + * the sequence.

+ * + *

Example usage:

+ * + *
{@code
+ *     Path dir1, dir2, dir3;
+ *
+ *     ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
+ *
+ *     Optional omref = finder.find("jdk.foo");
+ *     if (omref.isPresent()) { ... }
+ *
+ * }
+ * + *

The {@link #find(String) find} and {@link #findAll() findAll} methods + * defined here can fail for several reasons. These include include I/O errors, + * errors detected parsing a module descriptor ({@code module-info.class}), or + * in the case of {@code ModuleFinder} returned by {@link #of ModuleFinder.of}, + * that two or more modules with the same name are found in a directory. + * When an error is detected then these methods throw {@link FindException + * FindException} with an appropriate {@link Throwable#getCause cause}. + * The behavior of a {@code ModuleFinder} after a {@code FindException} is + * thrown is undefined. For example, invoking {@code find} after an exception + * is thrown may or may not scan the same modules that lead to the exception. + * It is recommended that a module finder be discarded after an exception is + * thrown.

+ * + *

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

+ * + * @since 9 + */ + +public interface ModuleFinder { + + /** + * Finds a reference to a module of a given name. + * + *

A {@code ModuleFinder} provides a consistent view of the + * modules that it locates. If {@code find} is invoked several times to + * locate the same module (by name) then it will return the same result + * each time. If a module is located then it is guaranteed to be a member + * of the set of modules returned by the {@link #findAll() findAll} + * method.

+ * + * @param name + * The name of the module to find + * + * @return A reference to a module with the given name or an empty + * {@code Optional} if not found + * + * @throws FindException + * If an error occurs finding the module + * + * @throws SecurityException + * If denied by the security manager + */ + Optional find(String name); + + /** + * Returns the set of all module references that this finder can locate. + * + *

A {@code ModuleFinder} provides a consistent view of the modules + * that it locates. If {@link #findAll() findAll} is invoked several times + * then it will return the same (equals) result each time. For each {@code + * ModuleReference} element in the returned set then it is guaranteed that + * {@link #find find} will locate the {@code ModuleReference} if invoked + * 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. + * + * @return The set of all module references that this finder locates + * + * @throws FindException + * If an error occurs finding all modules + * + * @throws SecurityException + * If denied by the security manager + */ + Set findAll(); + + /** + * Returns a module finder that locates the system modules. The + * system modules are typically linked into the Java run-time image. + * The module finder will always find {@code java.base}. + * + *

If there is a security manager set then its {@link + * SecurityManager#checkPermission(Permission) checkPermission} method is + * invoked to check that the caller has been granted {@link FilePermission} + * to recursively read the directory that is the value of the system + * property {@code java.home}.

+ * + * @return A {@code ModuleFinder} that locates the system modules + * + * @throws SecurityException + * If denied by the security manager + */ + static ModuleFinder ofSystem() { + String home; + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + PrivilegedAction pa = () -> System.getProperty("java.home"); + home = AccessController.doPrivileged(pa); + Permission p = new FilePermission(home + File.separator + "-", "read"); + sm.checkPermission(p); + } else { + home = System.getProperty("java.home"); + } + + Path modules = Paths.get(home, "lib", "modules"); + if (Files.isRegularFile(modules)) { + return new SystemModuleFinder(); + } else { + Path mlib = Paths.get(home, "modules"); + if (Files.isDirectory(mlib)) { + return of(mlib); + } else { + throw new InternalError("Unable to detect the run-time image"); + } + } + } + + /** + * Returns a module finder that locates modules on the file system by + * searching a sequence of directories and/or packaged modules. + * + * Each element in the given array is one of: + *
    + *
  1. A path to a directory of modules.

  2. + *
  3. A path to the top-level directory of an + * exploded module.

  4. + *
  5. A path to a packaged module.

  6. + *
+ * + * The module finder locates modules by searching each directory, exploded + * module, or packaged module in array index order. It finds the first + * occurrence of a module with a given name and ignores other modules of + * that name that appear later in the sequence. + * + *

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 + * directory is treated as an exploded module rather than a directory of + * modules.

+ * + *

The module finder returned by this method supports modules that are + * packaged as JAR files. A JAR file with a {@code module-info.class} in + * the top-level directory of the 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: + * + *

    + * + *
  • The module {@link ModuleDescriptor#name() name}, and {@link + * ModuleDescriptor#version() version} if applicable, is derived from + * the file name of the JAR file as follows:

    + * + *
      + * + *
    • The {@code .jar} suffix is removed.

    • + * + *
    • If the name matches the regular expression {@code + * "-(\\d+(\\.|$))"} then the module name will be derived from the + * subsequence proceeding the hyphen of the first occurrence. The + * subsequence after the hyphen is parsed as a {@link + * ModuleDescriptor.Version} and ignored if it cannot be parsed as + * a {@code Version}.

    • + * + *
    • For the module name, then all non-alphanumeric + * characters ({@code [^A-Za-z0-9])} are replaced with a dot + * ({@code "."}), all repeating dots are replaced with one dot, + * and all leading and trailing dots are removed.

    • + * + *
    • As an example, a JAR file named {@code foo-bar.jar} will + * derive a module name {@code foo.bar} and no version. A JAR file + * named {@code foo-1.2.3-SNAPSHOT.jar} will derive a module name + * {@code foo} and {@code 1.2.3-SNAPSHOT} as the version.

    • + * + *
  • + * + *
  • It {@link ModuleDescriptor#requires() requires} {@code + * java.base}.

  • + * + *
  • All entries in the JAR file with names ending with {@code + * .class} are assumed to be class files where the name corresponds + * to the fully qualified name of the class. The packages of all + * classes are {@link ModuleDescriptor#exports() exported}.

  • + * + *
  • The contents of all entries starting with {@code + * META-INF/services/} are assumed to be service configuration files + * (see {@link java.util.ServiceLoader}). The name of the file + * (that follows {@code META-INF/services/}) 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.

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

  • + * + *
+ * + *

In addition to JAR files, an implementation may also support modules + * that are packaged in other implementation specific module formats. As + * with automatic modules, the contents of a packaged or exploded module + * may need to be scanned in order to determine the packages in + * the module. If a {@code .class} file that corresponds to a class in an + * unnamed package is encountered then {@code FindException} is thrown.

+ * + *

Finders created by this method are lazy and do not eagerly check + * that the given file paths are directories or packaged modules. + * Consequently, the {@code find} or {@code findAll} methods will only + * fail if invoking these methods results in searching a directory or + * packaged module and an error is encountered. Paths to files that do not + * exist are ignored.

+ * + * @param entries + * A possibly-empty array of paths to directories of modules + * or paths to packaged or exploded modules + * + * @return A {@code ModuleFinder} that locates modules on the file system + */ + static ModuleFinder of(Path... entries) { + return new ModulePath(entries); + } + + /** + * Returns a module finder that is the equivalent to composing two + * module finders. The resulting finder will locate modules references + * using {@code first}; if not found then it will attempt to locate module + * references using {@code second}. + * + *

The {@link #findAll() findAll} method of the resulting module finder + * will locate all modules located by the first module finder. It will + * also locate all modules located by the second module finder that are not + * located by the first module finder.

+ * + * @apiNote This method will eventually be changed to take a sequence of + * module finders. + * + * @param first + * The first module finder + * @param second + * The second module finder + * + * @return A {@code ModuleFinder} that composes two module finders + */ + static ModuleFinder compose(ModuleFinder first, ModuleFinder second) { + Objects.requireNonNull(first); + Objects.requireNonNull(second); + + return new ModuleFinder() { + Set allModules; + + @Override + public Optional find(String name) { + Optional om = first.find(name); + if (!om.isPresent()) + om = second.find(name); + return om; + } + @Override + public Set findAll() { + if (allModules == null) { + allModules = Stream.concat(first.findAll().stream(), + second.findAll().stream()) + .map(a -> a.descriptor().name()) + .distinct() + .map(this::find) + .map(Optional::get) + .collect(Collectors.toSet()); + } + return allModules; + } + }; + } + + /** + * Returns an empty module finder. The empty finder does not find any + * modules. + * + * @apiNote This is useful when using methods such as {@link + * Configuration#resolveRequires resolveRequires} where two finders are + * specified. An alternative is {@code ModuleFinder.of()}. + * + * @return A {@code ModuleFinder} that does not find any modules + */ + static ModuleFinder empty() { + // an alternative implementation of ModuleFinder.of() + return new ModuleFinder() { + @Override public Optional find(String name) { + Objects.requireNonNull(name); + return Optional.empty(); + } + @Override public Set findAll() { + return Collections.emptySet(); + } + }; + } + +} diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java new file mode 100644 index 00000000000..f9e0bfac224 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java @@ -0,0 +1,790 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.module; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.nio.ByteBuffer; +import java.nio.BufferUnderflowException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import jdk.internal.module.Hasher.DependencyHashes; + +import static jdk.internal.module.ClassFileConstants.*; + + +/** + * Read module information from a {@code module-info} class file. + * + * @implNote The rationale for the hand-coded reader is startup performance + * and fine control over the throwing of InvalidModuleDescriptorException. + */ + +final class ModuleInfo { + + // supplies the set of packages when ConcealedPackages not present + private final Supplier> packageFinder; + + // indicates if the Hashes attribute should be parsed + private final boolean parseHashes; + + // the builder, created when parsing + private ModuleDescriptor.Builder builder; + + private ModuleInfo(Supplier> pf, boolean ph) { + packageFinder = pf; + parseHashes = ph; + } + + private ModuleInfo(Supplier> pf) { + this(pf, true); + } + + /** + * Reads a {@code module-info.class} from the given input stream. + * + * @throws InvalidModuleDescriptorException + * @throws IOException + */ + public static ModuleDescriptor read(InputStream in, + Supplier> pf) + throws IOException + { + try { + return new ModuleInfo(pf).doRead(new DataInputStream(in)); + } catch (IllegalArgumentException iae) { + // IllegalArgumentException means a malformed class + throw invalidModuleDescriptor(iae.getMessage()); + } catch (EOFException x) { + throw truncatedModuleDescriptor(); + } + } + + /** + * Reads a {@code module-info.class} from the given byte buffer. + * + * @throws InvalidModuleDescriptorException + * @throws UncheckedIOException + */ + public static ModuleDescriptor read(ByteBuffer bb, + Supplier> pf) + { + try { + return new ModuleInfo(pf).doRead(new DataInputWrapper(bb)); + } catch (IllegalArgumentException iae) { + // IllegalArgumentException means a malformed class + throw invalidModuleDescriptor(iae.getMessage()); + } catch (EOFException x) { + throw truncatedModuleDescriptor(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Reads a {@code module-info.class} from the given byte buffer + * but ignore the {@code Hashes} attribute. + * + * @throws InvalidModuleDescriptorException + * @throws UncheckedIOException + */ + static ModuleDescriptor readIgnoringHashes(ByteBuffer bb, + Supplier> pf) + { + try { + return new ModuleInfo(pf, false).doRead(new DataInputWrapper(bb)); + } catch (IllegalArgumentException iae) { + throw invalidModuleDescriptor(iae.getMessage()); + } catch (EOFException x) { + throw truncatedModuleDescriptor(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Reads the input as a module-info class file. + * + * @throws IOException + * @throws InvalidModuleDescriptorException + * @throws IllegalArgumentException if thrown by the ModuleDescriptor.Builder + * because an identifier is not a legal Java identifier, duplicate + * exports, and many other reasons + */ + private ModuleDescriptor doRead(DataInput in) throws IOException { + + int magic = in.readInt(); + if (magic != 0xCAFEBABE) + throw invalidModuleDescriptor("Bad magic number"); + + int minor_version = in.readUnsignedShort(); + int major_version = in.readUnsignedShort(); + if (major_version < 53) { + // throw invalidModuleDescriptor"Must be >= 53.0"); + } + + ConstantPool cpool = new ConstantPool(in); + + int access_flags = in.readUnsignedShort(); + if (access_flags != ACC_MODULE) + throw invalidModuleDescriptor("access_flags should be ACC_MODULE"); + + int this_class = in.readUnsignedShort(); + String mn = cpool.getClassName(this_class); + int suffix = mn.indexOf("/module-info"); + if (suffix < 1) + throw invalidModuleDescriptor("this_class not of form name/module-info"); + mn = mn.substring(0, suffix).replace('/', '.'); + builder = new ModuleDescriptor.Builder(mn); + + int super_class = in.readUnsignedShort(); + if (super_class > 0) + throw invalidModuleDescriptor("bad #super_class"); + + int interfaces_count = in.readUnsignedShort(); + if (interfaces_count > 0) + throw invalidModuleDescriptor("Bad #interfaces"); + + int fields_count = in.readUnsignedShort(); + if (fields_count > 0) + throw invalidModuleDescriptor("Bad #fields"); + + int methods_count = in.readUnsignedShort(); + if (methods_count > 0) + throw invalidModuleDescriptor("Bad #methods"); + + int attributes_count = in.readUnsignedShort(); + + // the names of the attributes found in the class file + Set attributes = new HashSet<>(); + + for (int i = 0; i < attributes_count ; i++) { + int name_index = in.readUnsignedShort(); + String attribute_name = cpool.getUtf8(name_index); + int length = in.readInt(); + + boolean added = attributes.add(attribute_name); + if (!added && isAttributeAtMostOnce(attribute_name)) { + throw invalidModuleDescriptor("More than one " + + attribute_name + " attribute"); + } + + switch (attribute_name) { + + case MODULE : + readModuleAttribute(mn, in, cpool); + break; + + case CONCEALED_PACKAGES : + readConcealedPackagesAttribute(in, cpool); + break; + + case VERSION : + readVersionAttribute(in, cpool); + break; + + case MAIN_CLASS : + readMainClassAttribute(in, cpool); + break; + + case TARGET_PLATFORM : + readTargetPlatformAttribute(in, cpool); + break; + + case HASHES : + if (parseHashes) { + readHashesAttribute(in, cpool); + } else { + in.skipBytes(length); + } + break; + + default: + if (isAttributeDisallowed(attribute_name)) { + throw invalidModuleDescriptor(attribute_name + + " attribute not allowed"); + } else { + in.skipBytes(length); + } + + } + } + + // the Module attribute is required + if (!attributes.contains(MODULE)) { + throw invalidModuleDescriptor(MODULE + " attribute not found"); + } + + // If the ConcealedPackages attribute is not present then the + // packageFinder is used to to find any non-exported packages. + if (!attributes.contains(CONCEALED_PACKAGES) && packageFinder != null) { + Set pkgs; + try { + pkgs = new HashSet<>(packageFinder.get()); + } catch (UncheckedIOException x) { + throw x.getCause(); + } + pkgs.removeAll(builder.exportedPackages()); + builder.conceals(pkgs); + } + + // Was the Synthetic attribute present? + if (attributes.contains(SYNTHETIC)) + builder.synthetic(true); + + return builder.build(); + } + + /** + * Reads the Module attribute. + */ + private void readModuleAttribute(String mn, DataInput in, ConstantPool cpool) + throws IOException + { + int requires_count = in.readUnsignedShort(); + if (requires_count == 0 && !mn.equals("java.base")) { + throw invalidModuleDescriptor("The requires table must have" + + " at least one entry"); + } + for (int i=0; i mods; + if (flags == 0) { + mods = Collections.emptySet(); + } else { + mods = new HashSet<>(); + if ((flags & ACC_PUBLIC) != 0) + mods.add(Modifier.PUBLIC); + if ((flags & ACC_SYNTHETIC) != 0) + mods.add(Modifier.SYNTHETIC); + if ((flags & ACC_MANDATED) != 0) + mods.add(Modifier.MANDATED); + } + builder.requires(mods, dn); + } + + int exports_count = in.readUnsignedShort(); + if (exports_count > 0) { + for (int i=0; i 0) { + Set targets = new HashSet<>(exports_to_count); + for (int j=0; j 0) { + for (int i=0; i 0) { + Map> pm = new HashMap<>(); + for (int i=0; i providers = pm.get(sn); + if (providers == null) { + providers = new HashSet<>(); + pm.put(sn, providers); + } + providers.add(cn); + } + for (Map.Entry> e : pm.entrySet()) { + builder.provides(e.getKey(), e.getValue()); + } + } + } + + /** + * Reads the ConcealedPackages attribute + */ + private void readConcealedPackagesAttribute(DataInput in, ConstantPool cpool) + throws IOException + { + int package_count = in.readUnsignedShort(); + for (int i=0; i map = new HashMap<>(hash_count); + for (int i=0; i notAllowed = predefinedNotAllowed; + if (notAllowed == null) { + notAllowed = Set.of( + "ConstantValue", + "Code", + "StackMapTable", + "Exceptions", + "EnclosingMethod", + "Signature", + "LineNumberTable", + "LocalVariableTable", + "LocalVariableTypeTable", + "RuntimeVisibleAnnotations", + "RuntimeInvisibleAnnotations", + "RuntimeVisibleParameterAnnotations", + "RuntimeInvisibleParameterAnnotations", + "RuntimeVisibleTypeAnnotations", + "RuntimeInvisibleTypeAnnotations", + "AnnotationDefault", + "BootstrapMethods", + "MethodParameters"); + predefinedNotAllowed = notAllowed; + } + return notAllowed.contains(name); + } + + // lazily created set the pre-defined attributes that are not allowed + private static volatile Set predefinedNotAllowed; + + + + /** + * The constant pool in a class file. + */ + private static class ConstantPool { + static final int CONSTANT_Utf8 = 1; + static final int CONSTANT_Integer = 3; + static final int CONSTANT_Float = 4; + static final int CONSTANT_Long = 5; + static final int CONSTANT_Double = 6; + static final int CONSTANT_Class = 7; + static final int CONSTANT_String = 8; + static final int CONSTANT_Fieldref = 9; + static final int CONSTANT_Methodref = 10; + static final int CONSTANT_InterfaceMethodref = 11; + static final int CONSTANT_NameAndType = 12; + static final int CONSTANT_MethodHandle = 15; + static final int CONSTANT_MethodType = 16; + static final int CONSTANT_InvokeDynamic = 18; + + private static class Entry { + protected Entry(int tag) { + this.tag = tag; + } + final int tag; + } + + private static class IndexEntry extends Entry { + IndexEntry(int tag, int index) { + super(tag); + this.index = index; + } + final int index; + } + + private static class Index2Entry extends Entry { + Index2Entry(int tag, int index1, int index2) { + super(tag); + this.index1 = index1; + this.index2 = index2; + } + final int index1, index2; + } + + private static class ValueEntry extends Entry { + ValueEntry(int tag, Object value) { + super(tag); + this.value = value; + } + final Object value; + } + + final Entry[] pool; + + ConstantPool(DataInput in) throws IOException { + int count = in.readUnsignedShort(); + pool = new Entry[count]; + + for (int i = 1; i < count; i++) { + int tag = in.readUnsignedByte(); + switch (tag) { + + case CONSTANT_Utf8: + String svalue = in.readUTF(); + pool[i] = new ValueEntry(tag, svalue); + break; + + case CONSTANT_Class: + case CONSTANT_String: + int index = in.readUnsignedShort(); + pool[i] = new IndexEntry(tag, index); + break; + + case CONSTANT_Double: + double dvalue = in.readDouble(); + pool[i] = new ValueEntry(tag, dvalue); + i++; + break; + + case CONSTANT_Fieldref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Methodref: + case CONSTANT_InvokeDynamic: + case CONSTANT_NameAndType: + int index1 = in.readUnsignedShort(); + int index2 = in.readUnsignedShort(); + pool[i] = new Index2Entry(tag, index1, index2); + break; + + case CONSTANT_MethodHandle: + int refKind = in.readUnsignedByte(); + index = in.readUnsignedShort(); + pool[i] = new Index2Entry(tag, refKind, index); + break; + + case CONSTANT_MethodType: + index = in.readUnsignedShort(); + pool[i] = new IndexEntry(tag, index); + break; + + case CONSTANT_Float: + float fvalue = in.readFloat(); + pool[i] = new ValueEntry(tag, fvalue); + break; + + case CONSTANT_Integer: + int ivalue = in.readInt(); + pool[i] = new ValueEntry(tag, ivalue); + break; + + case CONSTANT_Long: + long lvalue = in.readLong(); + pool[i] = new ValueEntry(tag, lvalue); + i++; + break; + + default: + throw invalidModuleDescriptor("Bad constant pool entry: " + + i); + } + } + } + + String getClassName(int index) { + checkIndex(index); + Entry e = pool[index]; + if (e.tag != CONSTANT_Class) { + throw invalidModuleDescriptor("CONSTANT_Class expected at entry: " + + index); + } + return getUtf8(((IndexEntry) e).index); + } + + String getUtf8(int index) { + checkIndex(index); + Entry e = pool[index]; + if (e.tag != CONSTANT_Utf8) { + throw invalidModuleDescriptor("CONSTANT_Utf8 expected at entry: " + + index); + } + return (String) (((ValueEntry) e).value); + } + + void checkIndex(int index) { + if (index < 1 || index >= pool.length) + throw invalidModuleDescriptor("Index into constant pool out of range"); + } + } + + /** + * A DataInput implementation that reads from a ByteBuffer. + */ + private static class DataInputWrapper implements DataInput { + private final ByteBuffer bb; + + DataInputWrapper(ByteBuffer bb) { + this.bb = bb; + } + + @Override + public void readFully(byte b[]) throws IOException { + readFully(b, 0, b.length); + } + + @Override + public void readFully(byte b[], int off, int len) throws IOException { + try { + bb.get(b, off, len); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public int skipBytes(int n) { + int skip = Math.min(n, bb.remaining()); + bb.position(bb.position() + skip); + return skip; + } + + @Override + public boolean readBoolean() throws IOException { + try { + int ch = bb.get(); + return (ch != 0); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public byte readByte() throws IOException { + try { + return bb.get(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public int readUnsignedByte() throws IOException { + try { + return ((int) bb.get()) & 0xff; + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public short readShort() throws IOException { + try { + return bb.getShort(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public int readUnsignedShort() throws IOException { + try { + return ((int) bb.getShort()) & 0xffff; + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public char readChar() throws IOException { + try { + return bb.getChar(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public int readInt() throws IOException { + try { + return bb.getInt(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public long readLong() throws IOException { + try { + return bb.getLong(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public float readFloat() throws IOException { + try { + return bb.getFloat(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public double readDouble() throws IOException { + try { + return bb.getDouble(); + } catch (BufferUnderflowException e) { + throw new EOFException(); + } + } + + @Override + public String readLine() { + throw new RuntimeException("not implemented"); + } + + @Override + public String readUTF() throws IOException { + // ### Need to measure the performance and feasibility of using + // the UTF-8 decoder instead. + return DataInputStream.readUTF(this); + } + } + + /** + * Returns an InvalidModuleDescriptorException with the given detail + * message + */ + private static InvalidModuleDescriptorException + invalidModuleDescriptor(String msg) { + return new InvalidModuleDescriptorException(msg); + } + + /** + * Returns an InvalidModuleDescriptorException with a detail message to + * indicate that the class file is truncated. + */ + private static InvalidModuleDescriptorException truncatedModuleDescriptor() { + return invalidModuleDescriptor("Truncated module-info.class"); + } + +} diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java new file mode 100644 index 00000000000..fbd1b471381 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java @@ -0,0 +1,590 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.module; + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor.Requires; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import jdk.internal.module.Checks; +import jdk.internal.module.ConfigurableModuleFinder; +import jdk.internal.perf.PerfCounter; + + +/** + * A {@code ModuleFinder} that locates modules on the file system by searching + * a sequence of directories or packaged modules. + * + * The {@code ModuleFinder} can be configured to work in either the run-time + * or link-time phases. In both cases it locates modular JAR and exploded + * modules. When configured for link-time then it additionally locates + * modules in JMOD files. + */ + +class ModulePath implements ConfigurableModuleFinder { + private static final String MODULE_INFO = "module-info.class"; + + // the entries on this module path + private final Path[] entries; + private int next; + + // true if in the link phase + private boolean isLinkPhase; + + // map of module name to module reference map for modules already located + private final Map cachedModules = new HashMap<>(); + + ModulePath(Path... entries) { + this.entries = entries.clone(); + for (Path entry : this.entries) { + Objects.requireNonNull(entry); + } + } + + @Override + public void configurePhase(Phase phase) { + isLinkPhase = (phase == Phase.LINK_TIME); + } + + @Override + public Optional find(String name) { + Objects.requireNonNull(name); + + // try cached modules + ModuleReference m = cachedModules.get(name); + if (m != null) + return Optional.of(m); + + // the module may not have been encountered yet + while (hasNextEntry()) { + scanNextEntry(); + m = cachedModules.get(name); + if (m != null) + return Optional.of(m); + } + return Optional.empty(); + } + + @Override + public Set findAll() { + // need to ensure that all entries have been scanned + while (hasNextEntry()) { + scanNextEntry(); + } + return cachedModules.values().stream().collect(Collectors.toSet()); + } + + /** + * Returns {@code true} if there are additional entries to scan + */ + private boolean hasNextEntry() { + return next < entries.length; + } + + /** + * Scans the next entry on the module path. A no-op if all entries have + * already been scanned. + * + * @throws FindException if an error occurs scanning the next entry + */ + private void scanNextEntry() { + if (hasNextEntry()) { + + long t0 = System.nanoTime(); + + Path entry = entries[next]; + Map modules = scan(entry); + next++; + + // update cache, ignoring duplicates + int initialSize = cachedModules.size(); + for (Map.Entry e : modules.entrySet()) { + cachedModules.putIfAbsent(e.getKey(), e.getValue()); + } + + // update counters + int added = cachedModules.size() - initialSize; + moduleCount.add(added); + + scanTime.addElapsedTimeFrom(t0); + } + } + + + /** + * Scan the given module path entry. If the entry is a directory then it is + * a directory of modules or an exploded module. If the entry is a regular + * file then it is assumed to be a packaged module. + * + * @throws FindException if an error occurs scanning the entry + */ + private Map scan(Path entry) { + + BasicFileAttributes attrs; + try { + attrs = Files.readAttributes(entry, BasicFileAttributes.class); + } catch (NoSuchFileException e) { + return Collections.emptyMap(); + } catch (IOException ioe) { + throw new FindException(ioe); + } + + try { + + 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 + return scanDirectory(entry); + } + } + + if (attrs.isRegularFile() || attrs.isDirectory()) { + // packaged or exploded module + ModuleReference mref = readModule(entry, attrs); + if (mref != null) { + String name = mref.descriptor().name(); + return Collections.singletonMap(name, mref); + } + } + + // not recognized + throw new FindException("Unrecognized module: " + entry); + + } catch (IOException ioe) { + throw new FindException(ioe); + } + } + + + /** + * Scans the given directory for packaged or exploded modules. + * + * @return a map of module name to ModuleReference for the modules found + * in the directory + * + * @throws IOException if an I/O error occurs + * @throws FindException if an error occurs scanning the entry or the + * directory contains two or more modules with the same name + */ + private Map scanDirectory(Path dir) + throws IOException + { + // The map of name -> mref of modules found in this directory. + Map nameToReference = new HashMap<>(); + + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { + for (Path entry : stream) { + BasicFileAttributes attrs; + try { + attrs = Files.readAttributes(entry, BasicFileAttributes.class); + } catch (NoSuchFileException ignore) { + // file has been removed or moved, ignore for now + continue; + } + + ModuleReference mref = readModule(entry, attrs); + + // module found + if (mref != null) { + + // can have at most one version of a module in the directory + String name = mref.descriptor().name(); + if (nameToReference.put(name, mref) != null) { + throw new FindException("Two versions of module " + + name + " found in " + dir); + } + + } + + } + } + + return nameToReference; + } + + + /** + * Locates a packaged or exploded module, returning a {@code ModuleReference} + * to the module. Returns {@code null} if the module is not recognized + * as a packaged or exploded module. + * + * @throws IOException if an I/O error occurs + * @throws FindException if an error occurs parsing the module descriptor + */ + private ModuleReference readModule(Path entry, BasicFileAttributes attrs) + throws IOException + { + try { + + ModuleReference mref = null; + if (attrs.isDirectory()) { + mref = readExplodedModule(entry); + } if (attrs.isRegularFile()) { + if (entry.toString().endsWith(".jar")) { + mref = readJar(entry); + } else if (isLinkPhase && entry.toString().endsWith(".jmod")) { + mref = readJMod(entry); + } + } + return mref; + + } catch (InvalidModuleDescriptorException e) { + throw new FindException("Error reading module: " + entry, e); + } + } + + + // -- jmod files -- + + private Set jmodPackages(ZipFile zf) { + return zf.stream() + .filter(e -> e.getName().startsWith("classes/") && + e.getName().endsWith(".class")) + .map(e -> toPackageName(e)) + .filter(pkg -> pkg.length() > 0) // module-info + .distinct() + .collect(Collectors.toSet()); + } + + /** + * Returns a {@code ModuleReference} to a module in jmod file on the + * file system. + */ + private ModuleReference readJMod(Path file) throws IOException { + try (ZipFile zf = new ZipFile(file.toString())) { + ZipEntry ze = zf.getEntry("classes/" + MODULE_INFO); + if (ze == null) { + throw new IOException(MODULE_INFO + " is missing: " + file); + } + ModuleDescriptor md; + try (InputStream in = zf.getInputStream(ze)) { + md = ModuleDescriptor.read(in, () -> jmodPackages(zf)); + } + return ModuleReferences.newJModModule(md, file); + } + } + + + // -- JAR files -- + + private static final String SERVICES_PREFIX = "META-INF/services/"; + + /** + * Returns a container with the service type corresponding to the name of + * a services configuration file. + * + * For example, if called with "META-INF/services/p.S" then this method + * returns a container with the value "p.S". + */ + private Optional toServiceName(String cf) { + assert cf.startsWith(SERVICES_PREFIX); + int index = cf.lastIndexOf("/") + 1; + if (index < cf.length()) { + String prefix = cf.substring(0, index); + if (prefix.equals(SERVICES_PREFIX)) { + String sn = cf.substring(index); + if (Checks.isJavaIdentifier(sn)) + return Optional.of(sn); + } + } + return Optional.empty(); + } + + /** + * Reads the next line from the given reader and trims it of comments and + * leading/trailing white space. + * + * Returns null if the reader is at EOF. + */ + private String nextLine(BufferedReader reader) throws IOException { + String ln = reader.readLine(); + if (ln != null) { + int ci = ln.indexOf('#'); + if (ci >= 0) + ln = ln.substring(0, ci); + ln = ln.trim(); + } + return ln; + } + + /** + * Treat the given JAR file as a module as follows: + * + * 1. The module name (and optionally the version) is derived from the file + * name of the JAR file + * 2. The packages of all .class files in the JAR file are exported + * 3. It has no module-private/concealed packages + * 4. 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 + * is mapped to the module descriptor mainClass + * + * @apiNote This needs to move to somewhere where it can be used by tools, + * maybe even a standard API if automatic modules are a Java SE feature. + */ + private ModuleDescriptor deriveModuleDescriptor(JarFile jf) + throws IOException + { + // Derive module name and version from JAR file name + + String fn = jf.getName(); + int i = fn.lastIndexOf(File.separator); + if (i != -1) + fn = fn.substring(i+1); + + // drop .jar + String mn = fn.substring(0, fn.length()-4); + String vs = null; + + // find first occurrence of -${NUMBER}. or -${NUMBER}$ + Matcher matcher = Pattern.compile("-(\\d+(\\.|$))").matcher(mn); + if (matcher.find()) { + int start = matcher.start(); + + // attempt to parse the tail as a version string + try { + String tail = mn.substring(start+1); + ModuleDescriptor.Version.parse(tail); + vs = tail; + } catch (IllegalArgumentException ignore) { } + + mn = mn.substring(0, start); + } + + // finally clean up the module name + mn = mn.replaceAll("[^A-Za-z0-9]", ".") // replace non-alphanumeric + .replaceAll("(\\.)(\\1)+", ".") // collapse repeating dots + .replaceAll("^\\.", "") // drop leading dots + .replaceAll("\\.$", ""); // drop trailing dots + + + // Builder throws IAE if module name is empty or invalid + ModuleDescriptor.Builder builder + = new ModuleDescriptor.Builder(mn, true) + .requires(Requires.Modifier.MANDATED, "java.base"); + if (vs != null) + builder.version(vs); + + // scan the entries in the JAR file to locate the .class and service + // configuration file + Stream stream = jf.stream() + .map(e -> e.getName()) + .filter(e -> (e.endsWith(".class") || e.startsWith(SERVICES_PREFIX))) + .distinct(); + Map> map + = stream.collect(Collectors.partitioningBy(s -> s.endsWith(".class"), + Collectors.toSet())); + Set classFiles = map.get(Boolean.TRUE); + Set configFiles = map.get(Boolean.FALSE); + + // all packages are exported + classFiles.stream() + .map(c -> toPackageName(c)) + .distinct() + .forEach(p -> builder.exports(p)); + + // map names of service configuration files to service names + Set serviceNames = configFiles.stream() + .map(this::toServiceName) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(Collectors.toSet()); + + // parse each service configuration file + for (String sn : serviceNames) { + JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn); + Set providerClasses = new HashSet<>(); + try (InputStream in = jf.getInputStream(entry)) { + BufferedReader reader + = new BufferedReader(new InputStreamReader(in, "UTF-8")); + String cn; + while ((cn = nextLine(reader)) != null) { + if (Checks.isJavaIdentifier(cn)) { + providerClasses.add(cn); + } + } + } + if (!providerClasses.isEmpty()) + builder.provides(sn, providerClasses); + } + + // Main-Class attribute if it exists + Manifest man = jf.getManifest(); + if (man != null) { + Attributes attrs = man.getMainAttributes(); + String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS); + if (mainClass != null) + builder.mainClass(mainClass); + } + + return builder.build(); + } + + private Set jarPackages(JarFile jf) { + return jf.stream() + .filter(e -> e.getName().endsWith(".class")) + .map(e -> toPackageName(e)) + .filter(pkg -> pkg.length() > 0) // module-info + .distinct() + .collect(Collectors.toSet()); + } + + /** + * Returns a {@code ModuleReference} to a module in modular JAR file on + * the file system. + */ + private ModuleReference readJar(Path file) throws IOException { + try (JarFile jf = new JarFile(file.toString())) { + + ModuleDescriptor md; + JarEntry entry = jf.getJarEntry(MODULE_INFO); + if (entry == null) { + + // no module-info.class so treat it as automatic module + try { + md = deriveModuleDescriptor(jf); + } catch (IllegalArgumentException iae) { + throw new FindException( + "Unable to derive module descriptor for: " + + jf.getName(), iae); + } + + } else { + md = ModuleDescriptor.read(jf.getInputStream(entry), + () -> jarPackages(jf)); + } + + return ModuleReferences.newJarModule(md, file); + } + } + + + // -- exploded directories -- + + private Set explodedPackages(Path dir) { + try { + return Files.find(dir, Integer.MAX_VALUE, + ((path, attrs) -> attrs.isRegularFile() && + path.toString().endsWith(".class"))) + .map(path -> toPackageName(dir.relativize(path))) + .filter(pkg -> pkg.length() > 0) // module-info + .distinct() + .collect(Collectors.toSet()); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + /** + * Returns a {@code ModuleReference} to an exploded module on the file + * system or {@code null} if {@code module-info.class} not found. + */ + private ModuleReference readExplodedModule(Path dir) throws IOException { + Path mi = dir.resolve(MODULE_INFO); + ModuleDescriptor md; + try (InputStream in = Files.newInputStream(mi)) { + md = ModuleDescriptor.read(new BufferedInputStream(in), + () -> explodedPackages(dir)); + } catch (NoSuchFileException e) { + // for now + return null; + } + return ModuleReferences.newExplodedModule(md, dir); + } + + + // + + // p/q/T.class => p.q + private String toPackageName(String cn) { + assert cn.endsWith(".class"); + int start = 0; + int index = cn.lastIndexOf("/"); + if (index > start) { + return cn.substring(start, index).replace('/', '.'); + } else { + return ""; + } + } + + private String toPackageName(ZipEntry entry) { + String name = entry.getName(); + assert name.endsWith(".class"); + // jmod classes in classes/, jar in / + int start = name.startsWith("classes/") ? 8 : 0; + int index = name.lastIndexOf("/"); + if (index > start) { + return name.substring(start, index).replace('/', '.'); + } else { + return ""; + } + } + + private String toPackageName(Path path) { + String name = path.toString(); + assert name.endsWith(".class"); + int index = name.lastIndexOf(File.separatorChar); + if (index != -1) { + return name.substring(0, index).replace(File.separatorChar, '.'); + } else { + return ""; + } + } + + private static final PerfCounter scanTime + = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.scanTime"); + private static final PerfCounter moduleCount + = PerfCounter.newPerfCounter("jdk.module.finder.modulepath.modules"); +} 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 new file mode 100644 index 00000000000..140886d8626 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.module; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.Optional; + + +/** + * Provides access to the content of a module. + * + *

A module reader is intended for cases where access to the resources in a + * module is required, regardless of whether the module has been loaded. + * A framework that scans a collection of packaged modules on the file system, + * for example, may use a module reader to access a specific resource in each + * module. A module reader is also intended to be used by {@code ClassLoader} + * implementations that load classes and resources from modules.

+ * + *

A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon + * creation and is closed by invoking the {@link #close close} method. Failure + * to close a module reader may result in a resource leak. The {@code + * try-with-resources} statement provides a useful construct to ensure that + * module readers are closed.

+ * + *

A {@code ModuleReader} implementation may require permissions to access + * resources in the module. Consequently the {@link #find find}, {@link #open + * open} and {@link #read read} methods may throw {@code SecurityException} if + * access is denied by the security manager.

+ * + * @see ModuleReference + * @since 9 + */ + +public interface ModuleReader extends Closeable { + + /** + * Finds a resource, returning a URI to the resource in the module. + * + * @param name + * The name of the resource to open for reading + * + * @return A URI to the resource; an empty {@code Optional} if the resource + * is not found or a URI cannot be constructed to locate the + * resource + * + * @throws IOException + * If an I/O error occurs or the module reader is closed + * @throws SecurityException + * If denied by the security manager + * + * @see ClassLoader#getResource(String) + */ + Optional find(String name) throws IOException; + + /** + * Opens a resource, returning an input stream to read the resource in + * the module. + * + * @implSpec The default implementation invokes the {@link #find(String) + * find} method to get a URI to the resource. If found, then it attempts + * to construct a {@link java.net.URL URL} and open a connection to the + * resource. + * + * @param name + * The name of the resource to open for reading + * + * @return An input stream to read the resource or an empty + * {@code Optional} if not found + * + * @throws IOException + * If an I/O error occurs or the module reader is closed + * @throws SecurityException + * If denied by the security manager + */ + default Optional open(String name) throws IOException { + Optional ouri = find(name); + if (ouri.isPresent()) { + return Optional.of(ouri.get().toURL().openStream()); + } else { + return Optional.empty(); + } + } + + /** + * Reads a resource, returning a byte buffer with the contents of the + * resource. + * + * The element at the returned buffer's position is the first byte of the + * resource, the element at the buffer's limit is the last byte of the + * resource. Once consumed, the {@link #release(ByteBuffer) release} method + * must be invoked. Failure to invoke the {@code release} method may result + * in a resource leak. + * + * @apiNote This method is intended for high-performance class loading. It + * is not capable (or intended) to read arbitrary large resources that + * could potentially be 2GB or larger. The rational for using this method + * in conjunction with the {@code release} method is to allow module reader + * implementations manage buffers in an efficient manner. + * + * @implSpec The default implementation invokes the {@link #open(String) + * open} method and reads all bytes from the input stream into a byte + * buffer. + * + * @param name + * The name of the resource to read + * + * @return A byte buffer containing the contents of the resource or an + * empty {@code Optional} if not found + * + * @throws IOException + * If an I/O error occurs or the module reader is closed + * @throws SecurityException + * If denied by the security manager + * + * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain) + */ + default Optional read(String name) throws IOException { + Optional in = open(name); + if (in.isPresent()) { + byte[] bytes = in.get().readAllBytes(); + return Optional.of(ByteBuffer.wrap(bytes)); + } else { + return Optional.empty(); + } + } + + /** + * Release a byte buffer. This method should be invoked after consuming + * the contents of the buffer returned by the {@code read} method. + * The behavior of this method when invoked to release a buffer that has + * already been released, or the behavior when invoked to release a buffer + * after a {@code ModuleReader} is closed is implementation specific and + * therefore not specified. + * + * @param bb + * The byte buffer to release + * + * @implSpec The default implementation does nothing. + */ + default void release(ByteBuffer bb) { } + + /** + * Closes the module reader. Once closed then subsequent calls to locate or + * read a resource will fail by returning {@code Optional.empty()} or + * throwing {@code IOException}. + * + *

A module reader is not required to be asynchronously closeable. If a + * thread is reading a resource and another thread invokes the close method, + * then the second thread may block until the read operation is complete. + * + *

The behavior of {@code InputStream}s obtained using the {@link + * #open(String) open} method and used after the module reader is closed + * is implementation specific and therefore not specified. + */ + @Override + void close() throws IOException; + +} 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 new file mode 100644 index 00000000000..781e7d3d088 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.module; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; + +import jdk.internal.module.Hasher.HashSupplier; + + +/** + * A reference to a module's content. + * + *

A module reference contains the module's descriptor and its location, if + * known. It also has the ability to create a {@link ModuleReader} in order to + * access the module's content, which may be inside the Java run-time system + * itself or in an artifact such as a modular JAR file. + * + * @see ModuleFinder + * @see ModuleReader + * @since 9 + */ + +public final class ModuleReference { + + private final ModuleDescriptor descriptor; + private final URI location; + private final Supplier readerSupplier; + + // the function that computes the hash of this module reference + private final HashSupplier hasher; + + // cached hash string to avoid needing to compute it many times + private String cachedHash; + + /** + * Constructs a new instance of this class. + */ + ModuleReference(ModuleDescriptor descriptor, + URI location, + Supplier readerSupplier, + HashSupplier hasher) + { + this.descriptor = Objects.requireNonNull(descriptor); + this.location = location; + this.readerSupplier = Objects.requireNonNull(readerSupplier); + this.hasher = hasher; + } + + + /** + * Constructs a new instance of this class. + * + *

The {@code readSupplier} parameter is the supplier of the {@link + * ModuleReader} that may be used to read the module content. Its {@link + * Supplier#get() get()} method throws {@link UncheckedIOException} if an + * I/O error occurs opening the module content. The {@code get()} method + * throws {@link SecurityException} if opening the module is denied by the + * security manager. + * + * @param descriptor + * The module descriptor + * @param location + * The module location or {@code null} if not known + * @param readerSupplier + * The {@code Supplier} of the {@code ModuleReader} + */ + public ModuleReference(ModuleDescriptor descriptor, + URI location, + Supplier readerSupplier) + { + this(descriptor, location, readerSupplier, null); + } + + + /** + * Returns the module descriptor. + * + * @return The module descriptor + */ + public ModuleDescriptor descriptor() { + return descriptor; + } + + + /** + * Returns the location of this module's content, if known. + * + *

This URI, when present, is 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 + * java.security.SecureClassLoader SecureClassLoader}. + * + * @return The location or an empty {@code Optional} if not known + */ + public Optional location() { + return Optional.ofNullable(location); + } + + + /** + * Opens the module content for reading. + * + *

This method opens the module content by invoking the {@link + * Supplier#get() get()} method of the {@code readSupplier} specified at + * construction time.

+ * + * @return A {@code ModuleReader} to read the module + * + * @throws IOException + * If an I/O error occurs + * @throws SecurityException + * If denied by the security manager + */ + public ModuleReader open() throws IOException { + try { + return readerSupplier.get(); + } catch (UncheckedIOException e) { + throw e.getCause(); + } + + } + + + /** + * Computes the hash of this module, returning it as a hex string. + * Returns {@code null} if the hash cannot be computed. + * + * @throws java.io.UncheckedIOException if an I/O error occurs + */ + String computeHash(String algorithm) { + String result = cachedHash; + if (result != null) + return result; + if (hasher == null) + return null; + cachedHash = result = hasher.generate(algorithm); + return result; + } + + private int hash; + + /** + * Computes a hash code for this module reference. + * + *

The hash code is based upon the components of the reference, and + * satisfies the general contract of the {@link Object#hashCode + * Object.hashCode} method.

+ * + * @return The hash-code value for this module reference + */ + @Override + public int hashCode() { + int hc = hash; + if (hc == 0) { + hc = Objects.hash(descriptor, location, readerSupplier, hasher); + if (hc != 0) hash = hc; + } + return hc; + } + + /** + * Tests this module reference for equality with the given object. + * + *

If the given object is not a {@code ModuleReference} then this + * method returns {@code false}. Two module references are equal if their + * module descriptors are equal, their locations are equal or both unknown, + * and were created with equal supplier objects to access the module + * content.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * reference that is equal to this module reference + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof ModuleReference)) + return false; + ModuleReference that = (ModuleReference)ob; + + return Objects.equals(this.descriptor, that.descriptor) + && Objects.equals(this.location, that.location) + && Objects.equals(this.readerSupplier, that.readerSupplier) + && Objects.equals(this.hasher, that.hasher); + } + + /** + * Returns a string describing this module reference. + * + * @return A string describing this module reference + */ + @Override + public String toString() { + return ("[module " + descriptor().name() + + ", location=" + location + "]"); + } + +} diff --git a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java new file mode 100644 index 00000000000..05448e25b33 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.module; + +import java.io.File; +import java.io.IOError; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +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.Objects; +import java.util.Optional; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Supplier; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.Hasher; +import jdk.internal.module.Hasher.HashSupplier; +import jdk.internal.module.ModulePatcher; +import sun.net.www.ParseUtil; + + +/** + * A factory for creating ModuleReference implementations where the modules are + * packaged as modular JAR file, JMOD files or where the modules are exploded + * on the file system. + */ + +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 -Xpatch is specified. + */ + private static ModuleReference newModule(ModuleDescriptor md, + URI uri, + Supplier supplier, + HashSupplier hasher) { + + ModuleReference mref = new ModuleReference(md, uri, supplier, hasher); + + if (JLA.getBootLayer() == null) + mref = ModulePatcher.interposeIfNeeded(mref); + + return mref; + } + + /** + * Creates a ModuleReference to a module packaged as a modular JAR. + */ + static ModuleReference newJarModule(ModuleDescriptor md, Path file) { + URI uri = file.toUri(); + Supplier supplier = () -> new JarModuleReader(file, uri); + HashSupplier hasher = (algorithm) -> Hasher.generate(file, algorithm); + return newModule(md, uri, supplier, hasher); + } + + /** + * Creates a ModuleReference to a module packaged as a JMOD. + */ + static ModuleReference newJModModule(ModuleDescriptor md, Path file) { + URI uri = file.toUri(); + Supplier supplier = () -> new JModModuleReader(file, uri); + HashSupplier hasher = (algorithm) -> Hasher.generate(file, algorithm); + return newModule(md, file.toUri(), supplier, hasher); + } + + /** + * Creates a ModuleReference to an exploded module. + */ + static ModuleReference newExplodedModule(ModuleDescriptor md, Path dir) { + Supplier supplier = () -> new ExplodedModuleReader(dir); + return newModule(md, dir.toUri(), supplier, null); + } + + + /** + * A base module reader that encapsulates machinery required to close the + * module reader safely. + */ + static abstract class SafeCloseModuleReader implements ModuleReader { + + // RW lock to support safe close + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Lock readLock = lock.readLock(); + private final Lock writeLock = lock.writeLock(); + private volatile boolean closed; + + SafeCloseModuleReader() { } + + /** + * Returns a URL to resource. This method is invoked by the find + * method to do the actual work of finding the resource. + */ + abstract Optional implFind(String name) throws IOException; + + /** + * Returns an input stream for reading a resource. This method is + * invoked by the open method to do the actual work of opening + * an input stream to the resource. + */ + abstract Optional implOpen(String name) throws IOException; + + /** + * Closes the module reader. This method is invoked by close to do the + * actual work of closing the module reader. + */ + abstract void implClose() throws IOException; + + @Override + public final Optional find(String name) throws IOException { + readLock.lock(); + try { + if (!closed) { + return implFind(name); + } else { + throw new IOException("ModuleReader is closed"); + } + } finally { + readLock.unlock(); + } + } + + + @Override + public final Optional open(String name) throws IOException { + readLock.lock(); + try { + if (!closed) { + return implOpen(name); + } else { + throw new IOException("ModuleReader is closed"); + } + } finally { + readLock.unlock(); + } + } + + @Override + public void close() throws IOException { + writeLock.lock(); + try { + if (!closed) { + closed = true; + implClose(); + } + } finally { + writeLock.unlock(); + } + } + } + + + /** + * A ModuleReader for a modular JAR file. + */ + static class JarModuleReader extends SafeCloseModuleReader { + private final JarFile jf; + private final URI uri; + + static JarFile newJarFile(Path path) { + try { + return new JarFile(path.toFile()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + JarModuleReader(Path path, URI uri) { + this.jf = newJarFile(path); + this.uri = uri; + } + + private JarEntry getEntry(String name) { + return jf.getJarEntry(Objects.requireNonNull(name)); + } + + @Override + Optional implFind(String name) throws IOException { + JarEntry je = getEntry(name); + if (je != null) { + String encodedPath = ParseUtil.encodePath(name, false); + String uris = "jar:" + uri + "!/" + encodedPath; + return Optional.of(URI.create(uris)); + } else { + return Optional.empty(); + } + } + + @Override + Optional implOpen(String name) throws IOException { + JarEntry je = getEntry(name); + if (je != null) { + return Optional.of(jf.getInputStream(je)); + } else { + return Optional.empty(); + } + } + + @Override + void implClose() throws IOException { + jf.close(); + } + } + + + /** + * A ModuleReader for a JMOD file. + */ + static class JModModuleReader extends SafeCloseModuleReader { + private final ZipFile zf; + private final URI uri; + + static ZipFile newZipFile(Path path) { + try { + return new ZipFile(path.toFile()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + JModModuleReader(Path path, URI uri) { + this.zf = newZipFile(path); + this.uri = uri; + } + + private ZipEntry getEntry(String name) { + return zf.getEntry("classes/" + Objects.requireNonNull(name)); + } + + @Override + Optional implFind(String name) { + ZipEntry ze = getEntry(name); + if (ze != null) { + String encodedPath = ParseUtil.encodePath(name, false); + String uris = "jmod:" + uri + "!/" + encodedPath; + return Optional.of(URI.create(uris)); + } else { + return Optional.empty(); + } + } + + @Override + Optional implOpen(String name) throws IOException { + ZipEntry ze = getEntry(name); + if (ze != null) { + return Optional.of(zf.getInputStream(ze)); + } else { + return Optional.empty(); + } + } + + @Override + void implClose() throws IOException { + zf.close(); + } + } + + + /** + * A ModuleReader for an exploded module. + */ + static class ExplodedModuleReader implements ModuleReader { + private final Path dir; + private volatile boolean closed; + + ExplodedModuleReader(Path dir) { + this.dir = dir; + + // when running with a security manager then check that the caller + // has access to the directory. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + boolean unused = Files.isDirectory(dir); + } + } + + /** + * 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; + */ + private void ensureOpen() throws IOException { + if (closed) throw new IOException("ModuleReader is closed"); + } + + @Override + public Optional find(String name) throws IOException { + ensureOpen(); + Path path = toPath(name); + if (path != null && Files.isRegularFile(path)) { + try { + return Optional.of(path.toUri()); + } catch (IOError e) { + throw (IOException) e.getCause(); + } + } else { + return Optional.empty(); + } + } + + @Override + public Optional open(String name) throws IOException { + ensureOpen(); + Path path = toPath(name); + if (path != null && Files.isRegularFile(path)) { + return Optional.of(Files.newInputStream(path)); + } else { + return Optional.empty(); + } + } + + @Override + public Optional read(String name) throws IOException { + ensureOpen(); + Path path = toPath(name); + if (path != null && Files.isRegularFile(path)) { + return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path))); + } else { + return Optional.empty(); + } + } + + @Override + public void close() { + closed = true; + } + } + +} 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 new file mode 100644 index 00000000000..fb14cfe8200 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ResolutionException.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.module; + +/** + * Thrown when resolving a set of modules or binding fails. + * + * @see Configuration + * @since 9 + */ +public class ResolutionException extends RuntimeException { + private static final long serialVersionUID = -1031186845316729450L; + + /** + * Constructs a {@code ResolutionException} with no detail message. + */ + public ResolutionException() { } + + /** + * Constructs a {@code ResolutionException} with the given detail + * message. + * + * @param msg + * The detail message; can be {@code null} + */ + public ResolutionException(String msg) { + super(msg); + } + + /** + * Constructs an instance of this exception with the given cause. + * + * @param cause + * The cause; can be {@code null} + */ + public ResolutionException(Throwable cause) { + super(cause); + } + + /** + * Constructs a {@code ResolutionException} with the given detail message + * and cause. + * + * @param msg + * The detail message; can be {@code null} + * @param cause + * The cause; can be {@code null} + */ + public ResolutionException(String msg, Throwable cause) { + super(msg, cause); + } + +} 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 new file mode 100644 index 00000000000..05ef3c4dc1c --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/ResolvedModule.java @@ -0,0 +1,159 @@ +/* + * 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 java.lang.module; + +import java.util.Objects; +import java.util.Set; + +/** + * A module in a graph of resolved modules. + * + *

{@code ResolvedModule} defines the {@link #configuration configuration} + * method to get the configuration that the resolved module is in. It defines + * the {@link #reference() reference} method to get the reference to the + * module's content. + * + * @since 9 + * @see Configuration#modules() + */ +public final class ResolvedModule { + + private final Configuration cf; + private final ModuleReference mref; + + ResolvedModule(Configuration cf, ModuleReference mref) { + this.cf = Objects.requireNonNull(cf); + this.mref = Objects.requireNonNull(mref); + } + + /** + * Returns the configuration that this resolved module is in. + * + * @return The configuration that this resolved module is in + */ + public Configuration configuration() { + return cf; + } + + /** + * Returns the reference to the module's content. + * + * @return The reference to the module's content + */ + public ModuleReference reference() { + return mref; + } + + /** + * Returns the module descriptor. + * + * This convenience method is the equivalent to invoking: + *

 {@code
+     *     reference().descriptor()
+     * }
+ * + * @return The module descriptor + */ + ModuleDescriptor descriptor() { + return reference().descriptor(); + } + + /** + * Returns the module name. + * + * This convenience method is the equivalent to invoking: + *
 {@code
+     *     reference().descriptor().name()
+     * }
+ * + * @return The module name + */ + public String name() { + return reference().descriptor().name(); + } + + /** + * Returns the set of resolved modules that this resolved module reads. + * + * @return A possibly-empty unmodifiable set of resolved modules that + * this resolved module reads + */ + public Set reads() { + return cf.reads(this); + } + + /** + * Computes a hash code for this resolved module. + * + *

The hash code is based upon the components of the resolved module + * and satisfies the general contract of the {@link Object#hashCode + * Object.hashCode} method.

+ * + * @return The hash-code value for this resolved module + */ + @Override + public int hashCode() { + return cf.hashCode() ^ mref.hashCode(); + } + + /** + * Tests this resolved module for equality with the given object. + * + *

If the given object is not a {@code ResolvedModule} then this + * method returns {@code false}. Two {@code ResolvedModule} objects are + * equal if they are in the same configuration and have equal references + * to the module content.

+ * + *

This method satisfies the general contract of the {@link + * java.lang.Object#equals(Object) Object.equals} method.

+ * + * @param ob + * the object to which this object is to be compared + * + * @return {@code true} if, and only if, the given object is a module + * reference that is equal to this module reference + */ + @Override + public boolean equals(Object ob) { + if (!(ob instanceof ResolvedModule)) + return false; + + ResolvedModule that = (ResolvedModule) ob; + return Objects.equals(this.cf, that.cf) + && Objects.equals(this.mref, that.mref); + } + + /** + * Returns a string describing this resolved module. + * + * @return A string describing this resolved module + */ + @Override + public String toString() { + return System.identityHashCode(cf) + "/" + name(); + } + +} 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 new file mode 100644 index 00000000000..37eb0b1bc77 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java @@ -0,0 +1,823 @@ +/* + * 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 + * 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.module; + +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.reflect.Layer; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +import jdk.internal.module.Hasher; + +/** + * The resolver used by {@link Configuration#resolveRequires} and + * {@link Configuration#resolveRequiresAndUses}. + */ + +final class Resolver { + + private final ModuleFinder beforeFinder; + private final Configuration parent; + private final ModuleFinder afterFinder; + + // maps module name to module reference + private final Map nameToReference = new HashMap<>(); + + + Resolver(ModuleFinder beforeFinder, + Configuration parent, + ModuleFinder afterFinder) { + this.beforeFinder = beforeFinder; + this.parent = parent; + this.afterFinder = afterFinder; + } + + + /** + * Resolves the given named modules. + * + * @throws ResolutionException + */ + Resolver resolveRequires(Collection roots) { + + long start = trace_start("Resolve"); + + // create the visit stack to get us started + Deque q = new ArrayDeque<>(); + for (String root : roots) { + + // find root module + ModuleReference mref = findWithBeforeFinder(root); + if (mref == null) { + if (parent.findModule(root).isPresent()) { + // in parent, nothing to do + continue; + } + mref = findWithAfterFinder(root); + if (mref == null) { + fail("Module %s not found", root); + } + } + + if (TRACE) { + trace("Root module %s located", root); + if (mref.location().isPresent()) + trace(" (%s)", mref.location().get()); + } + + assert mref.descriptor().name().equals(root); + nameToReference.put(root, mref); + q.push(mref.descriptor()); + } + + resolve(q); + + if (TRACE) { + long duration = System.currentTimeMillis() - start; + Set names = nameToReference.keySet(); + trace("Resolver completed in %s ms", duration); + names.stream().sorted().forEach(name -> trace(" %s", name)); + } + + return this; + } + + /** + * Resolve all modules in the given queue. On completion the queue will be + * empty and any resolved modules will be added to {@code nameToReference}. + * + * @return The set of module resolved by this invocation of resolve + */ + private Set resolve(Deque q) { + Set resolved = new HashSet<>(); + + while (!q.isEmpty()) { + ModuleDescriptor descriptor = q.poll(); + assert nameToReference.containsKey(descriptor.name()); + + // process dependences + for (ModuleDescriptor.Requires requires : descriptor.requires()) { + String dn = requires.name(); + + // find dependence + ModuleReference mref = findWithBeforeFinder(dn); + if (mref == null) { + if (parent.findModule(dn).isPresent()) + continue; + + mref = findWithAfterFinder(dn); + if (mref == null) { + fail("Module %s not found, required by %s", + dn, descriptor.name()); + } + } + + if (!nameToReference.containsKey(dn)) { + nameToReference.put(dn, mref); + q.offer(mref.descriptor()); + resolved.add(mref.descriptor()); + + if (TRACE) { + trace("Module %s located, required by %s", + dn, descriptor.name()); + if (mref.location().isPresent()) + trace(" (%s)", mref.location().get()); + } + } + + } + + resolved.add(descriptor); + } + + return resolved; + } + + /** + * Augments the set of resolved modules with modules induced by the + * service-use relation. + */ + Resolver resolveUses() { + + long start = trace_start("Bind"); + + // Scan the finders for all available service provider modules. As + // java.base uses services then then module finders will be scanned + // anyway. + Map> availableProviders = new HashMap<>(); + for (ModuleReference mref : findAll()) { + ModuleDescriptor descriptor = mref.descriptor(); + if (!descriptor.provides().isEmpty()) { + + for (String sn : descriptor.provides().keySet()) { + // computeIfAbsent + Set providers = availableProviders.get(sn); + if (providers == null) { + providers = new HashSet<>(); + availableProviders.put(sn, providers); + } + providers.add(mref); + } + + } + } + + // create the visit stack + Deque q = new ArrayDeque<>(); + + // the initial set of modules that may use services + Set candidateConsumers = new HashSet<>(); + Configuration p = parent; + while (p != null) { + candidateConsumers.addAll(p.descriptors()); + p = p.parent().orElse(null); + } + for (ModuleReference mref : nameToReference.values()) { + candidateConsumers.add(mref.descriptor()); + } + + + // Where there is a consumer of a service then resolve all modules + // that provide an implementation of that service + do { + for (ModuleDescriptor descriptor : candidateConsumers) { + if (!descriptor.uses().isEmpty()) { + for (String service : descriptor.uses()) { + Set mrefs = availableProviders.get(service); + if (mrefs != null) { + for (ModuleReference mref : mrefs) { + ModuleDescriptor provider = mref.descriptor(); + if (!provider.equals(descriptor)) { + + trace("Module %s provides %s, used by %s", + provider.name(), service, descriptor.name()); + + String pn = provider.name(); + if (!nameToReference.containsKey(pn)) { + + if (TRACE && mref.location().isPresent()) + trace(" (%s)", mref.location().get()); + + nameToReference.put(pn, mref); + q.push(provider); + } + } + } + } + } + } + } + + candidateConsumers = resolve(q); + + } while (!candidateConsumers.isEmpty()); + + + if (TRACE) { + long duration = System.currentTimeMillis() - start; + Set names = nameToReference.keySet(); + trace("Bind completed in %s ms", duration); + names.stream().sorted().forEach(name -> trace(" %s", name)); + } + + return this; + } + + + /** + * Execute post-resolution checks and returns the module graph of resolved + * modules as {@code Map}. The resolved modules will be in the given + * configuration. + */ + Map> finish(Configuration cf) { + + detectCycles(); + + checkPlatformConstraints(); + + checkHashes(); + + Map> graph = makeGraph(cf); + + checkExportSuppliers(graph); + + return graph; + } + + + /** + * Checks the given module graph for cycles. + * + * For now the implementation is a simple depth first search on the + * dependency graph. We'll replace this later, maybe with Tarjan. + */ + private void detectCycles() { + visited = new HashSet<>(); + visitPath = new LinkedHashSet<>(); // preserve insertion order + for (ModuleReference mref : nameToReference.values()) { + visit(mref.descriptor()); + } + visited.clear(); + } + + // the modules that were visited + private Set visited; + + // the modules in the current visit path + private Set visitPath; + + private void visit(ModuleDescriptor descriptor) { + if (!visited.contains(descriptor)) { + boolean added = visitPath.add(descriptor); + if (!added) { + throw new ResolutionException("Cycle detected: " + + cycleAsString(descriptor)); + } + for (ModuleDescriptor.Requires requires : descriptor.requires()) { + String dn = requires.name(); + + ModuleReference mref = nameToReference.get(dn); + if (mref != null) { + ModuleDescriptor other = mref.descriptor(); + if (other != descriptor) { + // dependency is in this configuration + visit(other); + } + } + } + visitPath.remove(descriptor); + visited.add(descriptor); + } + } + + /** + * Returns a String with a list of the modules in a detected cycle. + */ + private String cycleAsString(ModuleDescriptor descriptor) { + List list = new ArrayList<>(visitPath); + list.add(descriptor); + int index = list.indexOf(descriptor); + return list.stream() + .skip(index) + .map(ModuleDescriptor::name) + .collect(Collectors.joining(" -> ")); + } + + + /** + * 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 + * the hash of the dependency's module reference. + */ + private void checkHashes() { + + for (ModuleReference mref : nameToReference.values()) { + ModuleDescriptor descriptor = mref.descriptor(); + + // get map of module names to hash + Optional ohashes = descriptor.hashes(); + if (!ohashes.isPresent()) + continue; + Hasher.DependencyHashes hashes = ohashes.get(); + + // check dependences + for (ModuleDescriptor.Requires d : descriptor.requires()) { + String dn = d.name(); + String recordedHash = hashes.hashFor(dn); + + if (recordedHash != null) { + + ModuleReference other = nameToReference.get(dn); + if (other == null) { + other = parent.findModule(dn) + .map(ResolvedModule::reference) + .orElse(null); + } + if (other == null) + throw new InternalError(dn + " not found"); + + String actualHash = other.computeHash(hashes.algorithm()); + if (actualHash == null) + fail("Unable to compute the hash of module %s", dn); + + if (!recordedHash.equals(actualHash)) { + fail("Hash of %s (%s) differs to expected hash (%s)", + dn, actualHash, recordedHash); + } + + } + + } + } + + } + + + /** + * Computes and sets the readability graph for the modules in the given + * Resolution object. + * + * The readability graph is created by propagating "requires" through the + * "public requires" edges of the module dependence graph. So if the module + * dependence graph has m1 requires m2 && m2 requires public m3 then the + * resulting readability graph will contain m1 reads m2, m1 + * reads m3, and m2 reads m3. + * + * TODO: Use a more efficient algorithm, maybe cache the requires public + * in parent configurations. + */ + private Map> makeGraph(Configuration cf) { + + // the "reads" graph starts as a module dependence graph and + // is iteratively updated to be the readability graph + Map> g1 = new HashMap<>(); + + // the "requires public" graph, contains requires public edges only + Map> g2 = new HashMap<>(); + + + // need "requires public" from the modules in parent configurations as + // there may be selected modules that have a dependency on modules in + // the parent configuration. + + Configuration p = parent; + while (p != null) { + for (ModuleDescriptor descriptor : p.descriptors()) { + ResolvedModule x = p.findModule(descriptor.name()).orElse(null); + if (x == null) + throw new InternalError(); + for (ModuleDescriptor.Requires requires : descriptor.requires()) { + if (requires.modifiers().contains(Modifier.PUBLIC)) { + String dn = requires.name(); + ResolvedModule y = p.findModule(dn).orElse(null); + if (y == null) + throw new InternalError(dn + " not found"); + g2.computeIfAbsent(x, k -> new HashSet<>()).add(y); + } + } + } + + p = p.parent().orElse(null); + } + + // populate g1 and g2 with the dependences from the selected modules + for (ModuleReference mref : nameToReference.values()) { + ModuleDescriptor descriptor = mref.descriptor(); + ResolvedModule x = new ResolvedModule(cf, mref); + + Set reads = new HashSet<>(); + g1.put(x, reads); + + Set requiresPublic = new HashSet<>(); + g2.put(x, requiresPublic); + + for (ModuleDescriptor.Requires requires : descriptor.requires()) { + String dn = requires.name(); + + ResolvedModule y; + ModuleReference other = nameToReference.get(dn); + if (other != null) { + y = new ResolvedModule(cf, other); // cache? + } else { + y = parent.findModule(dn).orElse(null); + if (y == null) + throw new InternalError("unable to find " + dn); + } + + // m requires other => m reads other + reads.add(y); + + // m requires public other + if (requires.modifiers().contains(Modifier.PUBLIC)) { + requiresPublic.add(y); + } + + } + + // automatic modules reads all selected modules and all modules + // in parent configurations + if (descriptor.isAutomatic()) { + String name = descriptor.name(); + + // reads all selected modules + // requires public` all selected automatic modules + for (ModuleReference mref2 : nameToReference.values()) { + ModuleDescriptor descriptor2 = mref2.descriptor(); + if (!name.equals(descriptor2.name())) { + ResolvedModule m = new ResolvedModule(cf, mref2); + reads.add(m); + if (descriptor2.isAutomatic()) + requiresPublic.add(m); + } + } + + // reads all modules in parent configurations + // `requires public` all automatic modules in parent configurations + p = parent; + while (p != null) { + for (ResolvedModule m : p.modules()) { + reads.add(m); + if (m.reference().descriptor().isAutomatic()) + requiresPublic.add(m); + } + p = p.parent().orElse(null); + } + + } + + } + + // Iteratively update g1 until there are no more requires public to propagate + boolean changed; + Map> changes = new HashMap<>(); + do { + changed = false; + for (Entry> entry : g1.entrySet()) { + + ResolvedModule m1 = entry.getKey(); + Set m1Reads = entry.getValue(); + + for (ResolvedModule m2 : m1Reads) { + Set m2RequiresPublic = g2.get(m2); + if (m2RequiresPublic != null) { + for (ResolvedModule m3 : m2RequiresPublic) { + if (!m1Reads.contains(m3)) { + + // computeIfAbsent + Set s = changes.get(m1); + if (s == null) { + s = new HashSet<>(); + changes.put(m1, s); + } + s.add(m3); + changed = true; + + } + } + } + } + } + + if (changed) { + for (Map.Entry> e : + changes.entrySet()) { + ResolvedModule m = e.getKey(); + g1.get(m).addAll(e.getValue()); + } + changes.clear(); + } + + } while (changed); + + + return g1; + } + + + /** + * Checks the readability graph to ensure that no two modules export the + * same package to a module. This includes the case where module M has + * a local package P and M reads another module that exports P to M. + * Also checks the uses/provides of module M to ensure that it reads a + * module that exports the package of the service type to M. + */ + private void checkExportSuppliers(Map> graph) { + + for (Map.Entry> e : graph.entrySet()) { + ModuleDescriptor descriptor1 = e.getKey().descriptor(); + + // the map of packages that are local or exported to descriptor1 + Map packageToExporter = new HashMap<>(); + + // local packages + Set packages = descriptor1.packages(); + for (String pn : packages) { + packageToExporter.put(pn, descriptor1); + } + + // descriptor1 reads descriptor2 + Set reads = e.getValue(); + for (ResolvedModule endpoint : reads) { + ModuleDescriptor descriptor2 = endpoint.descriptor(); + + for (ModuleDescriptor.Exports export : descriptor2.exports()) { + + if (export.isQualified()) { + if (!export.targets().contains(descriptor1.name())) + continue; + } + + // source is exported to descriptor2 + String source = export.source(); + ModuleDescriptor other + = packageToExporter.put(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()); + } + + } + } + } + + // uses S + 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); + } + } + + // provides S + for (Map.Entry entry : + descriptor1.provides().entrySet()) { + String service = entry.getKey(); + ModuleDescriptor.Provides provides = entry.getValue(); + + String pn = packageName(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()); + } + } + } + + } + + } + + + /** + * 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()); + } + } + + /** + * 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()); + } + } + + /** + * Returns the set of all modules that are observable with the before + * and after ModuleFinders. + */ + private Set findAll() { + try { + + Set beforeModules = beforeFinder.findAll(); + Set afterModules = afterFinder.findAll(); + + if (afterModules.isEmpty()) + return beforeModules; + + if (beforeModules.isEmpty() && parent == Configuration.empty()) + return afterModules; + + Set result = new HashSet<>(beforeModules); + for (ModuleReference mref : afterModules) { + String name = mref.descriptor().name(); + if (!beforeFinder.find(name).isPresent() + && !parent.findModule(name).isPresent()) + result.add(mref); + } + + return result; + + } catch (FindException e) { + // unwrap + throw new ResolutionException(e.getMessage(), e.getCause()); + } + } + + /** + * Returns the package name + */ + private static String packageName(String cn) { + int index = cn.lastIndexOf("."); + return (index == -1) ? "" : cn.substring(0, index); + } + + /** + * Throw ResolutionException with the given format string and arguments + */ + private static void fail(String fmt, Object ... args) { + String msg = String.format(fmt, args); + throw new ResolutionException(msg); + } + + + /** + * Tracing support, limited to boot layer for now. + */ + + private final static boolean TRACE + = Boolean.getBoolean("jdk.launcher.traceResolver") + && (Layer.boot() == null); + + private String op; + + private long trace_start(String op) { + this.op = op; + return System.currentTimeMillis(); + } + + private void trace(String fmt, Object ... args) { + if (TRACE) { + System.out.print("[" + op + "] "); + System.out.format(fmt, args); + System.out.println(); + } + } + +} diff --git a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java new file mode 100644 index 00000000000..67766f9ed5b --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.module; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.net.URI; +import java.net.URLConnection; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + +import jdk.internal.jimage.ImageLocation; +import jdk.internal.jimage.ImageReader; +import jdk.internal.jimage.ImageReaderFactory; +import jdk.internal.module.SystemModules; +import jdk.internal.module.ModulePatcher; +import jdk.internal.perf.PerfCounter; + +/** + * A {@code ModuleFinder} that finds modules that are linked into the + * run-time image. + * + * The modules linked into the run-time image are assumed to have the + * ConcealedPackages attribute. + */ + +class SystemModuleFinder implements ModuleFinder { + + private static final PerfCounter initTime + = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); + private static final PerfCounter moduleCount + = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules"); + private static final PerfCounter packageCount + = 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; + + // the set of modules in the run-time image + private static final Set modules; + + // maps module name to module reference + private static final Map nameToModule; + + /** + * For now, the module references are created eagerly on the assumption + * that service binding will require all modules to be located. + */ + static { + long t0 = System.nanoTime(); + imageReader = ImageReaderFactory.getImageReader(); + + String[] moduleNames = SystemModules.MODULE_NAMES; + ModuleDescriptor[] descriptors = null; + + boolean fastLoad = System.getProperty("jdk.installed.modules.disable") == null; + if (fastLoad) { + // fast loading of ModuleDescriptor of installed modules + descriptors = SystemModules.modules(); + } + + int n = moduleNames.length; + moduleCount.add(n); + + Set mods = new HashSet<>(n); + Map map = new HashMap<>(n); + + for (int i = 0; i < n; i++) { + String mn = moduleNames[i]; + ModuleDescriptor md; + if (fastLoad) { + md = descriptors[i]; + } else { + // fallback to read module-info.class + // if fast loading of ModuleDescriptors is disabled + ImageLocation location = imageReader.findLocation(mn, "module-info.class"); + md = ModuleDescriptor.read(imageReader.getResourceBuffer(location)); + } + if (!md.name().equals(mn)) + throw new InternalError(); + + // create the ModuleReference + + URI uri = URI.create("jrt:/" + mn); + + Supplier readerSupplier = new Supplier<>() { + @Override + public ModuleReader get() { + return new ImageModuleReader(mn, uri); + } + }; + + ModuleReference mref = new ModuleReference(md, uri, readerSupplier); + + // may need a reference to a patched module if -Xpatch specified + mref = ModulePatcher.interposeIfNeeded(mref); + + mods.add(mref); + map.put(mn, mref); + + // counters + packageCount.add(md.packages().size()); + exportsCount.add(md.exports().size()); + } + + modules = Collections.unmodifiableSet(mods); + nameToModule = map; + + initTime.addElapsedTimeFrom(t0); + } + + SystemModuleFinder() { } + + @Override + public Optional find(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(nameToModule.get(name)); + } + + @Override + public Set findAll() { + return modules; + } + + + /** + * A ModuleReader for reading resources from a module linked into the + * run-time image. + */ + static class ImageModuleReader implements ModuleReader { + private final String module; + private volatile boolean closed; + + /** + * If there is a security manager set then check permission to + * connect to the run-time image. + */ + private static void checkPermissionToConnect(URI uri) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + try { + URLConnection uc = uri.toURL().openConnection(); + sm.checkPermission(uc.getPermission()); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + } + + ImageModuleReader(String module, URI uri) { + checkPermissionToConnect(uri); + this.module = module; + } + + /** + * Returns the ImageLocation for the given resource, {@code null} + * if not found. + */ + private ImageLocation findImageLocation(String name) throws IOException { + if (closed) + throw new IOException("ModuleReader is closed"); + + if (imageReader != null) { + return imageReader.findLocation(module, name); + } else { + // not an images build + return null; + } + } + + @Override + public Optional find(String name) throws IOException { + ImageLocation location = findImageLocation(name); + if (location != null) { + URI u = URI.create("jrt:/" + module + "/" + name); + return Optional.of(u); + } else { + return Optional.empty(); + } + } + + @Override + public Optional open(String name) throws IOException { + return read(name).map(this::toInputStream); + } + + private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer? + try { + int rem = bb.remaining(); + byte[] bytes = new byte[rem]; + bb.get(bytes); + return new ByteArrayInputStream(bytes); + } finally { + release(bb); + } + } + + @Override + public Optional read(String name) throws IOException { + ImageLocation location = findImageLocation(name); + if (location != null) { + return Optional.of(imageReader.getResourceBuffer(location)); + } else { + return Optional.empty(); + } + } + + @Override + public void release(ByteBuffer bb) { + ImageReader.releaseByteBuffer(bb); + } + + @Override + public void close() { + // nothing else to do + closed = true; + } + } + +} 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 new file mode 100644 index 00000000000..a1c44d68145 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/module/package-info.java @@ -0,0 +1,39 @@ +/* + * 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 + * 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. + */ + +/** + * Classes to support module descriptors and creating configurations of modules + * by means of resolution and service binding. + * + *

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, + * invoking a method with an array or collection containing a {@code null} element + * will cause a {@code NullPointerException}, unless otherwise specified.

+ * + * @since 9 + */ + +package java.lang.module; diff --git a/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java b/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java index ead17ef1c9f..3b8c2c93894 100644 --- a/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java +++ b/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java @@ -143,7 +143,7 @@ final class Finalizer extends FinalReference { /* Package-private; must /* Called by Runtime.runFinalization() */ static void runFinalization() { - if (!VM.isBooted()) { + if (VM.initLevel() == 0) { return; } @@ -166,7 +166,7 @@ final class Finalizer extends FinalReference { /* Package-private; must /* Invoked by java.lang.Shutdown */ static void runAllFinalizers() { - if (!VM.isBooted()) { + if (VM.initLevel() == 0) { return; } @@ -201,10 +201,10 @@ final class Finalizer extends FinalReference { /* Package-private; must // Finalizer thread starts before System.initializeSystemClass // is called. Wait until JavaLangAccess is available - while (!VM.isBooted()) { + while (VM.initLevel() == 0) { // delay until VM completes initialization try { - VM.awaitBooted(); + VM.awaitInitLevel(1); } catch (InterruptedException x) { // ignore and continue } 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 506e27d760e..5b1545dc73b 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, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,8 @@ package java.lang.reflect; import java.security.AccessController; + +import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.ReflectionFactory; import java.lang.annotation.Annotation; @@ -34,11 +36,14 @@ import java.lang.annotation.Annotation; * 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--for 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. + * 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}. * *

Setting the {@code accessible} flag in a reflected object * permits sophisticated applications with sufficient privilege, such @@ -64,37 +69,49 @@ public class AccessibleObject implements AnnotatedElement { private static final java.security.Permission ACCESS_PERMISSION = new ReflectPermission("suppressAccessChecks"); + static void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) sm.checkPermission(ACCESS_PERMISSION); + } + /** * Convenience method to set the {@code accessible} flag for an * array of objects with a single security check (for efficiency). * - *

First, if there is a security manager, its - * {@code checkPermission} method is called with a + *

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, this method cannot be used to enable access to + * non-public members of {@code AccessibleObject} or {@link Module}. + * + *

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

A {@code SecurityException} is raised if {@code flag} is - * {@code true} but accessibility of any of the elements of the input - * {@code array} may not be changed (for example, if the element - * object is a {@link Constructor} object for the class {@link - * java.lang.Class}). In the event of such a SecurityException, the - * accessibility of objects is set to {@code flag} for array elements - * up to (and excluding) the element for which the exception occurred; the - * accessibility of elements beyond (and including) the element for which - * the exception occurred is unchanged. + *

A {@code SecurityException} is also thrown if any of the elements of + * the input {@code array} is a {@link java.lang.reflect.Constructor} + * object for the class {@code java.lang.Class} and {@code flag} is true. * * @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. * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission + * @see ReflectPermission */ - public static void setAccessible(AccessibleObject[] array, boolean flag) - throws SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) sm.checkPermission(ACCESS_PERMISSION); + @CallerSensitive + public static void setAccessible(AccessibleObject[] array, boolean flag) { + checkPermission(); + if (flag) { + Class caller = Reflection.getCallerClass(); + array = array.clone(); + for (AccessibleObject ao : array) { + ao.checkCanSetAccessible(caller); + } + } for (AccessibleObject ao : array) { - setAccessible0(ao, flag); + ao.setAccessible0(flag); } } @@ -103,45 +120,87 @@ public class AccessibleObject implements AnnotatedElement { * 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. + * that the reflected object should enforce Java language access checks + * while assuming readability (as noted in the class description). * - *

First, if there is a security manager, its - * {@code checkPermission} method is called with a + *

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, this method cannot be used to enable access to + * non-public members of {@code AccessibleObject} or {@link Module}. + * + *

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

A {@code SecurityException} is raised if {@code flag} is - * {@code true} but accessibility of this object may not be changed - * (for example, if this element object is a {@link Constructor} object for - * the class {@link java.lang.Class}). - * - *

A {@code SecurityException} is raised if this object is a {@link - * java.lang.reflect.Constructor} object for the class - * {@code java.lang.Class}, and {@code flag} is true. - * * @param flag the new value for the {@code accessible} flag - * @throws SecurityException if the request is denied. + * @throws InaccessibleObjectException if access cannot be enabled + * @throws SecurityException if the request is denied * @see SecurityManager#checkPermission - * @see java.lang.RuntimePermission + * @see ReflectPermission */ - public void setAccessible(boolean flag) throws SecurityException { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) sm.checkPermission(ACCESS_PERMISSION); - setAccessible0(this, flag); + public void setAccessible(boolean flag) { + AccessibleObject.checkPermission(); + setAccessible0(flag); } - /* Check that you aren't exposing java.lang.Class. or sensitive - fields in java.lang.Class. */ - private static void setAccessible0(AccessibleObject obj, boolean flag) - throws SecurityException - { - if (obj instanceof Constructor && flag == true) { - Constructor c = (Constructor)obj; - if (c.getDeclaringClass() == Class.class) { - throw new SecurityException("Cannot make a java.lang.Class" + - " constructor accessible"); + void setAccessible0(boolean flag) { + this.override = flag; + } + + /** + * If the given AccessibleObject is a {@code Constructor}, {@code Method} + * or {@code Field} then checks that its declaring class is in a package + * that can be accessed by the given caller of setAccessible. + */ + void checkCanSetAccessible(Class caller) { + // do nothing, needs to be overridden by Constructor, Method, Field + } + + void checkCanSetAccessible(Class caller, Class declaringClass) { + Module callerModule = caller.getModule(); + Module declaringModule = declaringClass.getModule(); + + if (callerModule != declaringModule + && callerModule != Object.class.getModule()) { + + // check exports to target module + String pn = packageName(declaringClass); + if (!declaringModule.isExported(pn, callerModule)) { + String msg = "Unable to make member of " + + declaringClass + " accessible: " + + declaringModule + " does not export " + + pn + " to " + callerModule; + Reflection.throwInaccessibleObjectException(msg); + } + + } + + if (declaringClass == Module.class + || declaringClass == AccessibleObject.class) { + int modifiers; + if (this instanceof Executable) { + modifiers = ((Executable) this).getModifiers(); + } else { + modifiers = ((Field) this).getModifiers(); + } + if (!Modifier.isPublic(modifiers)) { + String msg = "Cannot make a non-public member of " + + declaringClass + " accessible"; + Reflection.throwInaccessibleObjectException(msg); } } - obj.override = flag; + } + + /** + * Returns the package name of the given class. + */ + private static String packageName(Class c) { + while (c.isArray()) { + c = c.getComponentType(); + } + String pn = c.getPackageName(); + return (pn != null) ? pn : ""; } /** 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 2e24d47e937..4b38728340e 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 @@ -159,6 +159,35 @@ public final class Constructor extends Executable { return res; } + /** + * {@inheritDoc} + * + *

A {@code SecurityException} is also thrown if this object is a + * {@code Constructor} object for the class {@code Class} and {@code flag} + * is true.

+ * + * @param flag {@inheritDoc} + */ + @Override + @CallerSensitive + public void setAccessible(boolean flag) { + AccessibleObject.checkPermission(); + if (flag) { + checkCanSetAccessible(Reflection.getCallerClass()); + } + setAccessible0(flag); + } + + @Override + void checkCanSetAccessible(Class caller) { + checkCanSetAccessible(caller, clazz); + if (clazz == Class.class) { + // can we change this to InaccessibleObjectException? + throw new SecurityException("Cannot make a java.lang.Class" + + " constructor accessible"); + } + } + @Override boolean hasGenericInformation() { return (getSignature() != null); @@ -411,10 +440,8 @@ public final class Constructor extends Executable { IllegalArgumentException, InvocationTargetException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, null, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, null, modifiers); } if ((clazz.getModifiers() & Modifier.ENUM) != 0) throw new IllegalArgumentException("Cannot reflectively create enum objects"); 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 ff99cf91b03..062676f64b7 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 @@ -157,10 +157,24 @@ class Field extends AccessibleObject implements Member { return res; } + @Override + @CallerSensitive + public void setAccessible(boolean flag) { + AccessibleObject.checkPermission(); + if (flag) checkCanSetAccessible(Reflection.getCallerClass()); + setAccessible0(flag); + } + + @Override + void checkCanSetAccessible(Class caller) { + checkCanSetAccessible(caller, clazz); + } + /** * Returns the {@code Class} object representing the class or interface * that declares the field represented by this {@code Field} object. */ + @Override public Class getDeclaringClass() { return clazz; } @@ -386,10 +400,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).get(obj); } @@ -421,10 +433,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getBoolean(obj); } @@ -456,10 +466,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getByte(obj); } @@ -493,10 +501,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getChar(obj); } @@ -530,10 +536,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getShort(obj); } @@ -567,10 +571,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getInt(obj); } @@ -604,10 +606,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getLong(obj); } @@ -641,10 +641,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getFloat(obj); } @@ -678,10 +676,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } return getFieldAccessor(obj).getDouble(obj); } @@ -757,10 +753,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).set(obj, value); } @@ -794,10 +788,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setBoolean(obj, z); } @@ -831,10 +823,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setByte(obj, b); } @@ -868,10 +858,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setChar(obj, c); } @@ -905,10 +893,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setShort(obj, s); } @@ -942,10 +928,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setInt(obj, i); } @@ -979,10 +963,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setLong(obj, l); } @@ -1016,10 +998,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setFloat(obj, f); } @@ -1053,10 +1033,8 @@ class Field extends AccessibleObject implements Member { throws IllegalArgumentException, IllegalAccessException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } getFieldAccessor(obj).setDouble(obj, d); } 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 new file mode 100644 index 00000000000..d44d5899bde --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.reflect; + +/** + * Thrown when Java language access checks cannot be suppressed. + * + * @see AccessibleObject#setAccessible(boolean) + * @since 9 + */ + +public class InaccessibleObjectException extends RuntimeException { + private static final long serialVersionUID = 4158786093378140901L; + + /** + * Constructs a {@code InaccessibleObjectException} with no detail message. + */ + public InaccessibleObjectException() { + } + + /** + * Constructs a {@code InaccessibleObjectException} with the given detail + * message. + * + * @param msg + * The detail message + */ + public InaccessibleObjectException(String msg) { + super(msg); + } + +} 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 new file mode 100644 index 00000000000..3dde9710e8a --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.reflect; + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ResolvedModule; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jdk.internal.loader.Loader; +import jdk.internal.loader.LoaderPool; +import jdk.internal.misc.SharedSecrets; +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}. + * 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 a {@link #parent() parent}.

+ * + *

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}.

+ * + *

The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and + * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods + * provide convenient ways to create a {@code Layer} where all modules are + * mapped to a single class loader or where each module is mapped to its own + * class loader. The {@link #defineModules defineModules} method is for more + * advanced cases where modules are mapped to custom class loaders by means of + * a function specified to the method.

+ * + *

A Java virtual machine has at least one non-empty layer, the {@link + * #boot() boot} layer, that is created when the Java virtual machine is + * started. The system modules, including {@code java.base}, are in + * the boot layer. The modules in the boot layer are mapped to the bootstrap + * class loader and other class loaders that are built-in into the ava virtual + * machine. The boot layer will often be the {@link #parent() 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 + * Java virtual machine as a {@code Module} that reads every unnamed {@code + * Module} in the Java virtual machine.

+ * + *

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

+ * + *

Example usage:

+ * + *

This example creates a configuration by resolving a module named + * "{@code myapp}" with the configuration for the boot layer as the parent. It + * then creates a new layer with the modules in this configuration. All modules + * are defined to the same class loader.

+ * + *
{@code
+ *     ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
+ *
+ *     Layer parent = Layer.boot();
+ *
+ *     Configuration cf = parent.configuration()
+ *         .resolveRequires(finder, ModuleFinder.empty(), Set.of("myapp"));
+ *
+ *     ClassLoader scl = ClassLoader.getSystemClassLoader();
+ *
+ *     Layer layer = parent.defineModulesWithOneLoader(cf, scl);
+ *
+ *     Class c = layer.findLoader("myapp").loadClass("app.Main");
+ * }
+ * + * @since 9 + * @see Module#getLayer() + */ + +public final class Layer { + + // the empty Layer + private static final Layer EMPTY_LAYER + = new Layer(Configuration.empty(), null, null); + + // the configuration from which this Layer was created + private final Configuration cf; + + // parent layer, null in the case of the empty layer + private final Layer parent; + + // maps module name to jlr.Module + private final Map nameToModule; + + + /** + * Creates a new Layer from the modules in the given configuration. + */ + private Layer(Configuration cf, + Layer parent, + Function clf) + { + this.cf = cf; + this.parent = parent; + + Map map; + if (parent == null) { + map = Collections.emptyMap(); + } else { + map = Module.defineModules(cf, clf, this); + } + this.nameToModule = map; // no need to do defensive copy + } + + + /** + * Creates a new layer, with this layer as its parent, by defining the + * modules in the given {@code Configuration} to the Java virtual machine. + * This method creates one class loader and defines all modules to that + * class loader. + * + *

The class loader created by this method implements direct + * delegation when loading types from modules. When its {@link + * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to + * load a class then it uses the package name of the class to map it to a + * module. This may be a module in this layer and hence defined to the same + * class loader. It may be a package in a module in a parent layer that is + * 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.

+ * + *

Attempting to create a layer with all modules defined to the same + * class loader can fail for the following reasons: + * + *

    + * + *
  • Overlapping packages: Two or more modules in the + * configuration have the same package (exported or concealed).

  • + * + *
  • Split delegation: The resulting class loader would + * need to delegate to more than one class loader in order to load types + * in a specific package.

  • + * + *
+ * + *

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.

+ * + * @param cf + * The configuration for the layer + * @param parentLoader + * The parent class loader for the class loader created by this + * method; may be {@code null} for the bootstrap class loader + * + * @return The newly created layer + * + * @throws IllegalArgumentException + * 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 + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public Layer defineModulesWithOneLoader(Configuration cf, + ClassLoader parentLoader) + { + checkConfiguration(cf); + checkCreateClassLoaderPermission(); + checkGetClassLoaderPermission(); + + Loader loader; + try { + loader = new Loader(cf.modules(), parentLoader); + loader.initRemotePackageMap(cf, this); + } catch (IllegalArgumentException e) { + throw new LayerInstantiationException(e.getMessage()); + } + return new Layer(cf, this, mn -> loader); + } + + + /** + * Creates a new layer, with this layer as its parent, by defining the + * modules in the given {@code Configuration} to the Java virtual machine. + * Each module is defined to its own {@link ClassLoader} created by this + * method. The {@link ClassLoader#getParent() parent} of each class loader + * is the given parent class loader. + * + *

The class loaders created by this method implement direct + * delegation when loading types from modules. When {@link + * ClassLoader#loadClass(String, boolean) loadClass} method is invoked to + * load a class then it uses the package name of the class to map it to a + * module. The package may be in the module defined to the class loader. + * The package may be exported by another module in this layer to the + * module defined to the class loader. It may be in a package exported by a + * 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.

+ * + *

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

+ * + * @param cf + * The configuration for the layer + * @param parentLoader + * The parent class loader for each of the class loaders created by + * this method; may be {@code null} for the bootstrap class loader + * + * @return The newly created layer + * + * @throws IllegalArgumentException + * If the parent of the given configuration is not the configuration + * for this layer + * @throws SecurityException + * If {@code RuntimePermission("createClassLoader")} or + * {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + * + * @see #findLoader + */ + public Layer defineModulesWithManyLoaders(Configuration cf, + ClassLoader parentLoader) + { + checkConfiguration(cf); + checkCreateClassLoaderPermission(); + checkGetClassLoaderPermission(); + + LoaderPool pool = new LoaderPool(cf, this, parentLoader); + return new Layer(cf, this, pool::loaderFor); + } + + + /** + * Creates a new layer, with this layer as its parent, 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. In addition, the caller needs + * to arrange that the class loaders are ready to load from these module + * before there are any attempts to load classes or resources. + * + *

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

+ * + *
    + * + *
  • Two or more modules with the same package (exported or + * concealed) are mapped to the same class loader.

  • + * + *
  • A module is mapped to a class loader that already has a + * module of the same name defined to it.

  • + * + *
  • A module is mapped to a class loader that has already + * defined types in any of the packages in the module.

  • + * + *
+ * + *

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. + *

+ * + * @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. + * + * @param cf + * The configuration for the layer + * @param clf + * The function to map a module name to a class loader + * + * @return The newly created layer + * + * @throws IllegalArgumentException + * 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 + * @throws SecurityException + * If {@code RuntimePermission("getClassLoader")} is denied by + * the security manager + */ + public Layer defineModules(Configuration cf, + Function clf) + { + checkConfiguration(cf); + Objects.requireNonNull(clf); + + checkGetClassLoaderPermission(); + + // For now, no two modules in the boot Layer may contain the same + // package so we use a simple check for the boot Layer to keep + // the overhead at startup to a minimum + if (boot() == null) { + checkBootModulesForDuplicatePkgs(cf); + } else { + checkForDuplicatePkgs(cf, clf); + } + + try { + return new Layer(cf, this, clf); + } catch (IllegalArgumentException iae) { + // IAE is thrown by VM when defining the module fails + throw new LayerInstantiationException(iae.getMessage()); + } + } + + + private void checkConfiguration(Configuration cf) { + Objects.requireNonNull(cf); + + Optional oparent = cf.parent(); + if (!oparent.isPresent() || oparent.get() != this.configuration()) { + throw new IllegalArgumentException( + "Parent of configuration != configuration of this Layer"); + } + } + + private static void checkCreateClassLoaderPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); + } + + private static void checkGetClassLoaderPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + + /** + * Checks a configuration for the boot Layer to ensure that no two modules + * have the same package. + * + * @throws LayerInstantiationException + */ + private static void checkBootModulesForDuplicatePkgs(Configuration cf) { + 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) { + throw fail("Package " + p + " in both module " + + name + " and module " + other); + } + } + } + } + + /** + * Checks a configuration and the module-to-loader mapping to ensure that + * no two modules mapped to the same class loader have the same package. + * It also checks that no two automatic modules have the same package. + * + * @throws LayerInstantiationException + */ + private static void checkForDuplicatePkgs(Configuration cf, + Function clf) + { + // HashMap allows null keys + Map> loaderToPackages = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleDescriptor descriptor = resolvedModule.reference().descriptor(); + ClassLoader loader = clf.apply(descriptor.name()); + + Set loaderPackages + = loaderToPackages.computeIfAbsent(loader, k -> new HashSet<>()); + + for (String pkg : descriptor.packages()) { + boolean added = loaderPackages.add(pkg); + if (!added) { + throw fail("More than one module with package %s mapped" + + " to the same class loader", pkg); + } + } + } + } + + /** + * Creates a LayerInstantiationException with the a message formatted from + * the given format string and arguments. + */ + private static LayerInstantiationException fail(String fmt, Object ... args) { + String msg = String.format(fmt, args); + return new LayerInstantiationException(msg); + } + + + /** + * Returns the configuration for this layer. + * + * @return The configuration for this layer + */ + public Configuration configuration() { + return cf; + } + + + /** + * Returns this layer's parent unless this is the {@linkplain #empty empty + * layer}, which has no parent. + * + * @return This layer's parent + */ + public Optional parent() { + return Optional.ofNullable(parent); + } + + + /** + * Returns a set of the modules in this layer. + * + * @return A possibly-empty unmodifiable set of the modules in this layer + */ + public Set modules() { + return Collections.unmodifiableSet( + nameToModule.values().stream().collect(Collectors.toSet())); + } + + + /** + * Returns the module with the given name in this layer, or if not in this + * layer, the {@linkplain #parent parent} layer. + * + * @param name + * The name of the module to find + * + * @return The module with the given name or an empty {@code Optional} + * if there isn't a module with this name in this layer or any + * parent layer + */ + public Optional findModule(String name) { + Module m = nameToModule.get(Objects.requireNonNull(name)); + if (m != null) + return Optional.of(m); + return parent().flatMap(l -> l.findModule(name)); + } + + + /** + * Returns the {@code ClassLoader} for the module with the given name. If + * a module of the given name is not in this layer then the {@link #parent} + * layer is checked. + * + *

If there is a security manager then its {@code checkPermission} + * method is called with a {@code RuntimePermission("getClassLoader")} + * permission to check that the caller is allowed to get access to the + * class loader.

+ * + * @apiNote This method does not return an {@code Optional} + * because `null` must be used to represent the bootstrap class loader. + * + * @param name + * The name of the module to find + * + * @return The ClassLoader that the module is defined to + * + * @throws IllegalArgumentException if a module of the given name is not + * defined in this layer or any parent of this layer + * + * @throws SecurityException if denied by the security manager + */ + public ClassLoader findLoader(String name) { + Module m = nameToModule.get(Objects.requireNonNull(name)); + if (m != null) + return m.getClassLoader(); + Optional ol = parent(); + if (ol.isPresent()) + return ol.get().findLoader(name); + throw new IllegalArgumentException("Module " + name + + " not known to this layer"); + } + + + /** + * Returns the empty layer. There are no modules in the empty + * layer. It has no parent. + * + * @return The empty layer + */ + public static Layer empty() { + return EMPTY_LAYER; + } + + + /** + * Returns the boot layer. The boot layer contains at least one module, + * {@code java.base}. Its parent is the {@link #empty() empty} layer. + * + * @apiNote This method returns {@code null} during startup and before + * the boot layer is fully initialized. + * + * @return The boot layer + */ + public static Layer boot() { + return SharedSecrets.getJavaLangAccess().getBootLayer(); + } +} 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 new file mode 100644 index 00000000000..ff61c41590f --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.reflect; + +/** + * Thrown when creating a Layer fails. + * + * @see Layer + * + * @since 9 + */ +public class LayerInstantiationException extends RuntimeException { + private static final long serialVersionUID = -906239691613568347L; + + /** + * Constructs a {@code LayerInstantiationException} with no detail message. + */ + public LayerInstantiationException() { + } + + /** + * Constructs a {@code LayerInstantiationException} with the given detail + * message. + * + * @param msg + * The detail message; can be {@code null} + */ + public LayerInstantiationException(String msg) { + super(msg); + } + + /** + * Constructs a {@code LayerInstantiationException} with the given cause. + * + * @param cause + * The cause; can be {@code null} + */ + public LayerInstantiationException(Throwable cause) { + super(cause); + } + + /** + * Constructs a {@code FindException} with the given detail message + * and cause. + * + * @param msg + * The detail message; can be {@code null} + * @param cause + * The cause; can be {@code null} + */ + public LayerInstantiationException(String msg, Throwable cause) { + super(msg, cause); + } + +} + 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 c4a1db292fd..005ed2453b7 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 @@ -176,6 +176,19 @@ public final class Method extends Executable { return res; } + @Override + @CallerSensitive + public void setAccessible(boolean flag) { + AccessibleObject.checkPermission(); + if (flag) checkCanSetAccessible(Reflection.getCallerClass()); + setAccessible0(flag); + } + + @Override + void checkCanSetAccessible(Class caller) { + checkCanSetAccessible(caller, clazz); + } + /** * Used by Excecutable for annotation sharing. */ @@ -508,10 +521,8 @@ public final class Method extends Executable { InvocationTargetException { if (!override) { - if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { - Class caller = Reflection.getCallerClass(); - checkAccess(caller, clazz, obj, modifiers); - } + Class caller = Reflection.getCallerClass(); + checkAccess(caller, clazz, obj, modifiers); } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { 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 new file mode 100644 index 00000000000..406e3a38519 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java @@ -0,0 +1,1216 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.reflect; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.Configuration; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Version; +import java.lang.module.ResolvedModule; +import java.net.URI; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; +import java.util.stream.Stream; + +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.loader.BootLoader; +import jdk.internal.misc.JavaLangReflectModuleAccess; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.ServicesCatalog; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; +import sun.security.util.SecurityConstants; + +/** + * Represents a run-time module, either {@link #isNamed() named} or unnamed. + * + *

Named modules have a {@link #getName() name} and are constructed by the + * 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 + * 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 + * example, {@code "java.lang"}.

+ * + *

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

+ * + * @since 9 + * @see java.lang.Class#getModule + */ + +public final class Module { + + // the layer that contains this module, can be null + private final Layer layer; + + // module name and loader, these fields are read by VM + private final String name; + private final ClassLoader loader; + + // the module descriptor + private final ModuleDescriptor descriptor; + + + /** + * Creates a new named Module. The resulting Module will be defined to the + * VM but will not read any other modules, will not have any exports setup + * and will not be registered in the service catalog. + */ + private Module(Layer layer, + ClassLoader loader, + ModuleDescriptor descriptor, + URI uri) + { + this.layer = layer; + this.name = descriptor.name(); + this.loader = loader; + this.descriptor = descriptor; + + // define module to VM + + Set packages = descriptor.packages(); + int n = packages.size(); + String[] array = new String[n]; + int i = 0; + for (String pn : packages) { + array[i++] = pn.replace('.', '/'); + } + Version version = descriptor.version().orElse(null); + String vs = Objects.toString(version, null); + String loc = Objects.toString(uri, null); + + defineModule0(this, vs, loc, array); + } + + + /** + * Create the unnamed Module for the given ClassLoader. + * + * @see ClassLoader#getUnnamedModule + */ + private Module(ClassLoader loader) { + this.layer = null; + this.name = null; + this.loader = loader; + this.descriptor = null; + + // unnamed modules are loose + this.loose = true; + } + + + /** + * Creates a named module but without defining the module to the VM. + * + * @apiNote This constructor is for VM white-box testing. + */ + Module(ClassLoader loader, ModuleDescriptor descriptor) { + this.layer = null; + this.name = descriptor.name(); + this.loader = loader; + this.descriptor = descriptor; + } + + + + /** + * Returns {@code true} if this module is a named module. + * + * @return {@code true} if this is a named module + * + * @see ClassLoader#getUnnamedModule() + */ + public boolean isNamed() { + return name != null; + } + + /** + * Returns the module name or {@code null} if this module is an unnamed + * module. + * + * @return The module name + */ + public String getName() { + return name; + } + + /** + * Returns the {@code ClassLoader} for this module. + * + *

If there is a security manager then its {@code checkPermission} + * method if first called with a {@code RuntimePermission("getClassLoader")} + * permission to check that the caller is allowed to get access to the + * class loader.

+ * + * @return The class loader for this module + * + * @throws SecurityException + * If denied by the security manager + */ + public ClassLoader getClassLoader() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + return loader; + } + + /** + * Returns the module descriptor for this module or {@code null} if this + * module is an unnamed module. + * + * @return The module descriptor for this module + */ + public ModuleDescriptor getDescriptor() { + return descriptor; + } + + /** + * Returns the layer that contains this module or {@code null} if this + * module is not in a layer. + * + * A module {@code Layer} contains named modules and therefore this + * method always returns {@code null} when invoked on an unnamed module. + * + *

Dynamic modules are named + * modules that are generated at runtime. A dynamic module may or may + * not be in a module Layer.

+ * + * @return The layer that contains this module + * + * @see Proxy + */ + public Layer getLayer() { + if (isNamed()) { + Layer layer = this.layer; + if (layer != null) + return layer; + + // special-case java.base as it is created before the boot Layer + if (loader == null && name.equals("java.base")) { + return SharedSecrets.getJavaLangAccess().getBootLayer(); + } + } + + return null; + } + + + // -- readability -- + + // true if this module reads all unnamed modules (a.k.a. loose module) + private volatile boolean loose; + + // the modules that this module permanently reads + // (will be final when the modules are defined in reverse topology order) + private volatile Set reads; + + // created lazily, additional modules that this module reflectively reads + private volatile WeakSet transientReads; + + + /** + * Indicates if this module reads the given module. This method returns + * {@code true} if invoked to test if this module reads itself. It also + * returns {@code true} if invoked on an unnamed module (as unnamed + * modules read all modules). + * + * @param other + * The other module + * + * @return {@code true} if this module reads {@code other} + * + * @see #addReads(Module) + */ + public boolean canRead(Module other) { + Objects.requireNonNull(other); + + // an unnamed module reads all modules + if (!this.isNamed()) + return true; + + // all modules read themselves + if (other == this) + return true; + + // check if this module reads other + if (other.isNamed()) { + + Set reads = this.reads; // volatile read + if (reads != null && reads.contains(other)) + return true; + + } else { + + // loose modules read all unnamed modules + if (this.loose) + return true; + + } + + // check if this module reads the other module reflectively + WeakSet tr = this.transientReads; // volatile read + if (tr != null && tr.contains(other)) + return true; + + return false; + } + + /** + * If the caller's module is this module then update this module to read + * the given module. + * + * This method is a no-op if {@code other} is this module (all modules can + * read themselves) or this module is an unnamed module (as unnamed modules + * read all modules). + * + * @param other + * The other module + * + * @return this module + * + * @throws IllegalStateException + * If this is a named module and the caller is not this module + * + * @see #canRead + */ + @CallerSensitive + public Module addReads(Module other) { + Objects.requireNonNull(other); + if (this.isNamed()) { + Module caller = Reflection.getCallerClass().getModule(); + if (caller != this) { + throw new IllegalStateException(caller + " != " + this); + } + implAddReads(other, true); + } + return this; + } + + /** + * Updates this module to read another module. + * + * @apiNote This method is for Proxy use and white-box testing. + */ + void implAddReads(Module other) { + implAddReads(other, true); + } + + /** + * Makes the given {@code Module} readable to this module without + * notifying the VM. + * + * @apiNote This method is for VM white-box testing. + */ + void implAddReadsNoSync(Module other) { + implAddReads(other, false); + } + + /** + * Makes the given {@code Module} readable to this module. + * + * If {@code syncVM} is {@code true} then the VM is notified. + */ + private void implAddReads(Module other, boolean syncVM) { + + // nothing to do + if (other == this || !this.isNamed()) + return; + + // if the other is null then change this module to be loose. + if (other == null) { + if (syncVM) + addReads0(this, null); + this.loose = true; + return; + } + + // check if we already read this module + Set reads = this.reads; + if (reads != null && reads.contains(other)) + return; + + // update VM first, just in case it fails + if (syncVM) + addReads0(this, other); + + // add reflective read + WeakSet tr = this.transientReads; + if (tr == null) { + synchronized (this) { + tr = this.transientReads; + if (tr == null) { + tr = new WeakSet<>(); + this.transientReads = tr; + } + } + } + tr.add(other); + } + + + // -- exports -- + + // the packages that are permanently exported + // (will be final when the modules are defined in reverse topology order) + private volatile Map> exports; + + // created lazily, additional exports added at run-time + private volatile Map> transientExports; + + // the special Module to mean exported to all modules + private static final Module EVERYONE_MODULE = new Module(null); + private static final Set EVERYONE = Collections.singleton(EVERYONE_MODULE); + + // the special Module to mean exported to all unnamed modules + private static final Module ALL_UNNAMED_MODULE = new Module(null); + + + /** + * Returns {@code true} if this module exports the given package to at + * least the given module. + * + *

This method always return {@code true} when invoked on an unnamed + * module.

+ * + *

This method does not check if the given module reads this module

+ * + * @param pn + * The package name + * @param other + * The other module + * + * @return {@code true} if this module exports the package to at least the + * given module + */ + public boolean isExported(String pn, Module other) { + Objects.requireNonNull(pn); + Objects.requireNonNull(other); + return implIsExported(pn, other); + } + + /** + * Returns {@code true} if this module exports the given package + * unconditionally. + * + *

This method always return {@code true} when invoked on an unnamed + * module.

+ * + *

This method does not check if the given module reads this module

+ * + * @param pn + * The package name + * + * @return {@code true} if this module exports the package unconditionally + */ + public boolean isExported(String pn) { + Objects.requireNonNull(pn); + return implIsExported(pn, EVERYONE_MODULE); + } + + /** + * Returns {@code true} if this module exports the given package to the + * given module. If the other module is {@code EVERYONE_MODULE} then + * this method tests if the package is exported unconditionally. + */ + private boolean implIsExported(String pn, Module other) { + + // all packages are exported by unnamed modules + if (!isNamed()) + return true; + + // exported via module declaration/descriptor + if (isExportedPermanently(pn, other)) + return true; + + // exported via addExports + if (isExportedReflectively(pn, other)) + return true; + + // not exported or not exported to other + return false; + } + + /** + * Returns {@code true} if this module permanently exports the given + * package to the given module. + */ + private boolean isExportedPermanently(String pn, Module other) { + Map> exports = this.exports; + if (exports != null) { + Set targets = exports.get(pn); + + if (targets != null) { + + // exported to all modules + if (targets.contains(EVERYONE_MODULE)) + return true; + + if (other != EVERYONE_MODULE) { + // exported to other + if (targets.contains(other)) + return true; + + // other is an unnamed module && exported to all unnamed + if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE)) + return true; + } + + } + } + return false; + } + + /** + * Returns {@code true} if this module reflectively exports the given + * package package to the given module. + */ + private boolean isExportedReflectively(String pn, Module other) { + Map> te = this.transientExports; + if (te != null) { + WeakSet targets = te.get(pn); + + if (targets != null) { + + // exported to all modules + if (targets.contains(EVERYONE_MODULE)) + return true; + + if (other != EVERYONE_MODULE) { + + // exported to other + if (targets.contains(other)) + return true; + + // other is an unnamed module && exported to all unnamed + if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE)) + return true; + } + } + + } + return false; + } + + + /** + * If the caller's module is this module then update this module to export + * package {@code pn} to the given module. + * + *

This method has no effect if the package is already exported to the + * given module. If also has no effect if invoked on an unnamed module (as + * unnamed modules export all packages).

+ * + * @param pn + * The package name + * @param other + * The module + * + * @return this module + * + * @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 + */ + @CallerSensitive + public Module addExports(String pn, Module other) { + if (pn == null) + throw new IllegalArgumentException("package is null"); + Objects.requireNonNull(other); + + if (isNamed()) { + Module caller = Reflection.getCallerClass().getModule(); + if (caller != this) { + throw new IllegalStateException(caller + " != " + this); + } + implAddExports(pn, other, true); + } + + return this; + } + + /** + * Updates the exports so that package {@code pn} is exported to module + * {@code other} but without notifying the VM. + * + * @apiNote This method is for VM white-box testing. + */ + void implAddExportsNoSync(String pn, Module other) { + if (other == null) + other = EVERYONE_MODULE; + implAddExports(pn.replace('/', '.'), other, false); + } + + /** + * Updates the exports so that package {@code pn} is exported to module + * {@code other}. + * + * @apiNote This method is for white-box testing. + */ + void implAddExports(String pn, Module other) { + implAddExports(pn, other, true); + } + + /** + * Updates the exports so that package {@code pn} is exported to module + * {@code other}. + * + * If {@code syncVM} is {@code true} then the VM is notified. + */ + private void implAddExports(String pn, Module other, boolean syncVM) { + Objects.requireNonNull(other); + Objects.requireNonNull(pn); + + // unnamed modules export all packages + if (!isNamed()) + return; + + // nothing to do if already exported to other + if (implIsExported(pn, other)) + return; + + // can only export a package in the module + if (!containsPackage(pn)) { + throw new IllegalArgumentException("package " + pn + + " not in contents"); + } + + // update VM first, just in case it fails + if (syncVM) { + String pkgInternalForm = pn.replace('.', '/'); + if (other == EVERYONE_MODULE) { + addExportsToAll0(this, pkgInternalForm); + } else if (other == ALL_UNNAMED_MODULE) { + addExportsToAllUnnamed0(this, pkgInternalForm); + } else { + addExports0(this, pkgInternalForm, other); + } + } + + // create transientExports if needed + Map> te = this.transientExports; // read + if (te == null) { + synchronized (this) { + te = this.transientExports; + if (te == null) { + te = new ConcurrentHashMap<>(); + this.transientExports = te; // volatile write + } + } + } + + // add package name to transientExports if absent + WeakSet s = te.get(pn); + if (s == null) { + s = new WeakSet<>(); + WeakSet prev = te.putIfAbsent(pn, s); + if (prev != null) + s = prev; + } + s.add(other); + } + + + // -- services -- + + // created lazily, additional service types that this module uses + private volatile WeakSet> transientUses; + + /** + * If the caller's module is this module then update this module to add a + * service dependence on the given service type. This method is intended + * for use by frameworks that invoke {@link java.util.ServiceLoader + * ServiceLoader} on behalf of other modules or where the framework is + * passed a reference to the service type by other code. This method is + * a no-op when invoked on an unnamed module. + * + *

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

+ * + * @param st + * The service type + * + * @return this module + * + * @throws IllegalStateException + * If this is a named module and the caller is not this module + * + * @see #canUse(Class) + * @see ModuleDescriptor#uses() + */ + @CallerSensitive + public Module addUses(Class st) { + Objects.requireNonNull(st); + + if (isNamed()) { + + Module caller = Reflection.getCallerClass().getModule(); + if (caller != this) { + throw new IllegalStateException(caller + " != " + this); + } + + if (!canUse(st)) { + WeakSet> uses = this.transientUses; + if (uses == null) { + synchronized (this) { + uses = this.transientUses; + if (uses == null) { + uses = new WeakSet<>(); + this.transientUses = uses; + } + } + } + uses.add(st); + } + + } + + return this; + } + + /** + * Indicates if this module has a service dependence on the given service + * type. This method always returns {@code true} when invoked on an unnamed + * module. + * + * @param st + * The service type + * + * @return {@code true} if this module uses service type {@code st} + * + * @see #addUses(Class) + */ + public boolean canUse(Class st) { + Objects.requireNonNull(st); + + if (!isNamed()) + return true; + + if (descriptor.isAutomatic()) + return true; + + // uses was declared + if (descriptor.uses().contains(st.getName())) + return true; + + // uses added via addUses + WeakSet> uses = this.transientUses; + if (uses != null && uses.contains(st)) + return true; + + return false; + } + + + + // -- 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 boolean containsPackage(String pn) { + if (descriptor.packages().contains(pn)) + return true; + Set extraPackages = this.extraPackages; + if (extraPackages != null && extraPackages.contains(pn)) + return true; + return false; + } + + + /** + * Returns an array of the package names of the packages in this module. + * + *

For named modules, the returned array contains an element for each + * package in the module. It may contain elements corresponding to packages + * added to the module, dynamic modules + * for example, after it was loaded. + * + *

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

+ * + *

A package name appears at most once in the returned array.

+ * + * @apiNote This method returns an array rather than a {@code Set} for + * consistency with other {@code java.lang.reflect} types. + * + * @return an array of the package names of the packages in this module + */ + public String[] getPackages() { + if (isNamed()) { + + Set packages = descriptor.packages(); + Set extraPackages = this.extraPackages; + if (extraPackages == null) { + return packages.toArray(new String[0]); + } else { + return Stream.concat(packages.stream(), + extraPackages.stream()) + .toArray(String[]::new); + } + + } else { + // unnamed module + Stream packages; + if (loader == null) { + packages = BootLoader.packages(); + } else { + packages = SharedSecrets.getJavaLangAccess().packages(loader); + } + return packages.map(Package::getName).toArray(String[]::new); + } + } + + /** + * 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); + } + + /** + * Add a package to this module without notifying the VM. + * + * @apiNote This method is VM white-box testing. + */ + void implAddPackageNoSync(String pn) { + implAddPackage(pn.replace('/', '.'), false); + } + + /** + * Add a package to this module. + * + * If {@code syncVM} is {@code true} then the VM is notified. + */ + private void implAddPackage(String pn, boolean syncVM) { + if (pn.length() == 0) + throw new IllegalArgumentException(" package not allowed"); + + 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); + } + + // update VM first, just in case it fails + if (syncVM) + addPackage0(this, pn.replace('.', '/')); + + // replace with new set + this.extraPackages = extraPackages; // volatile write + } + } + + + // -- creating Module objects -- + + /** + * Find the runtime Module corresponding to the given ReadDependence + * in the given parent Layer (or its parents). + */ + private static Module find(ResolvedModule resolvedModule, Layer layer) { + Configuration cf = resolvedModule.configuration(); + String dn = resolvedModule.name(); + + Module m = null; + while (layer != null) { + if (layer.configuration() == cf) { + Optional om = layer.findModule(dn); + m = om.get(); + assert m.getLayer() == layer; + break; + } + layer = layer.parent().orElse(null); + } + return m; + } + + /** + * Defines each of the module in the given configuration to the runtime. + * + * @return a map of module name to runtime {@code Module} + * + * @throws IllegalArgumentException + * If defining any of the modules to the VM fails + */ + static Map defineModules(Configuration cf, + Function clf, + Layer layer) + { + Map modules = new HashMap<>(); + Map loaders = new HashMap<>(); + + // define each module in the configuration to the VM + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + String name = descriptor.name(); + ClassLoader loader = clf.apply(name); + URI uri = mref.location().orElse(null); + + Module m; + if (loader == null && name.equals("java.base")) { + m = Object.class.getModule(); + } else { + m = new Module(layer, loader, descriptor, uri); + } + + modules.put(name, m); + loaders.put(name, loader); + } + + // setup readability and exports + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + + String mn = descriptor.name(); + Module m = modules.get(mn); + assert m != null; + + // reads + Set reads = new HashSet<>(); + for (ResolvedModule d : resolvedModule.reads()) { + Module m2; + if (d.configuration() == cf) { + String dn = d.reference().descriptor().name(); + m2 = modules.get(dn); + assert m2 != null; + } else { + m2 = find(d, layer.parent().orElse(null)); + } + + reads.add(m2); + + // update VM view + addReads0(m, m2); + } + m.reads = reads; + + // automatic modules reads all unnamed modules + if (descriptor.isAutomatic()) { + m.implAddReads(null, true); + } + + // exports + Map> exports = new HashMap<>(); + for (Exports export : descriptor.exports()) { + String source = export.source(); + String sourceInternalForm = source.replace('.', '/'); + + if (export.isQualified()) { + + // qualified export + Set targets = new HashSet<>(); + for (String target : export.targets()) { + // only export to modules that are in this configuration + Module m2 = modules.get(target); + if (m2 != null) { + targets.add(m2); + addExports0(m, sourceInternalForm, m2); + } + } + if (!targets.isEmpty()) { + exports.put(source, targets); + } + + } else { + + // unqualified export + exports.put(source, EVERYONE); + addExportsToAll0(m, sourceInternalForm); + } + } + m.exports = exports; + } + + // register the modules in the service catalog if they provide services + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + Map services = descriptor.provides(); + if (!services.isEmpty()) { + String name = descriptor.name(); + Module m = modules.get(name); + ClassLoader loader = loaders.get(name); + ServicesCatalog catalog; + if (loader == null) { + catalog = BootLoader.getServicesCatalog(); + } else { + catalog = SharedSecrets.getJavaLangAccess() + .createOrGetServicesCatalog(loader); + } + catalog.register(m); + } + } + + return modules; + } + + + // -- misc -- + + + /** + * Returns an input stream for reading a resource in this module. Returns + * {@code null} if the resource is not in this module or access to the + * resource is denied by the security manager. + * The {@code name} is a {@code '/'}-separated path name that identifies + * the resource. + * + *

If this module is an unnamed module, and the {@code ClassLoader} for + * this module is not {@code null}, then this method is equivalent to + * invoking the {@link ClassLoader#getResourceAsStream(String) + * getResourceAsStream} method on the class loader for this module. + * + * @param name + * The resource name + * + * @return An input stream for reading the resource or {@code null} + * + * @throws IOException + * If an I/O error occurs + * + * @see java.lang.module.ModuleReader#open(String) + */ + public InputStream getResourceAsStream(String name) throws IOException { + Objects.requireNonNull(name); + + URL url = null; + + if (isNamed()) { + String mn = this.name; + + // special-case built-in class loaders to avoid URL connection + if (loader == null) { + return BootLoader.findResourceAsStream(mn, name); + } else if (loader instanceof BuiltinClassLoader) { + return ((BuiltinClassLoader) loader).findResourceAsStream(mn, name); + } + + // use SharedSecrets to invoke protected method + url = SharedSecrets.getJavaLangAccess().findResource(loader, mn, name); + + } else { + + // unnamed module + if (loader == null) { + url = BootLoader.findResource(name); + } else { + return loader.getResourceAsStream(name); + } + + } + + // fallthrough to URL case + if (url != null) { + try { + return url.openStream(); + } catch (SecurityException e) { } + } + + return null; + } + + /** + * Returns the string representation of this module. For a named module, + * the representation is the string {@code "module"}, followed by a space, + * and then the module name. For an unnamed module, the representation is + * the string {@code "unnamed module"}, followed by a space, and then an + * implementation specific identifier for the unnamed module. + * + * @return The string representation of this module + */ + @Override + public String toString() { + if (isNamed()) { + return "module " + name; + } else { + String id = Integer.toHexString(System.identityHashCode(this)); + return "unnamed module @" + id; + } + } + + + // -- supporting classes -- + + + /** + * A "not-a-Set" set of weakly referenced objects that supports concurrent + * access. + */ + private static class WeakSet { + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Lock readLock = lock.readLock(); + private final Lock writeLock = lock.writeLock(); + + private final WeakHashMap map = new WeakHashMap<>(); + + /** + * Adds the specified element to the set. + */ + void add(E e) { + writeLock.lock(); + try { + map.put(e, Boolean.TRUE); + } finally { + writeLock.unlock(); + } + } + + /** + * Returns {@code true} if this set contains the specified element. + */ + boolean contains(E e) { + readLock.lock(); + try { + return map.containsKey(e); + } finally { + readLock.unlock(); + } + } + } + + + // -- native methods -- + + // JVM_DefineModule + private static native void defineModule0(Module module, + String version, + String location, + String[] pns); + + // JVM_AddReadsModule + private static native void addReads0(Module from, Module to); + + // JVM_AddModuleExports + private static native void addExports0(Module from, String pn, Module to); + + // JVM_AddModuleExportsToAll + private static native void addExportsToAll0(Module from, String pn); + + // JVM_AddModuleExportsToAllUnnamed + private static native void addExportsToAllUnnamed0(Module from, String pn); + + // JVM_AddModulePackage + private static native void addPackage0(Module m, String pn); + + /** + * Register shared secret to provide access to package-private methods + */ + static { + SharedSecrets.setJavaLangReflectModuleAccess( + new JavaLangReflectModuleAccess() { + @Override + public Module defineUnnamedModule(ClassLoader loader) { + return new Module(loader); + } + @Override + public Module defineModule(ClassLoader loader, + ModuleDescriptor descriptor, + URI uri) { + return new Module(null, loader, descriptor, uri); + } + @Override + public void addReads(Module m1, Module m2) { + m1.implAddReads(m2, true); + } + @Override + public void addExports(Module m, String pn, Module other) { + m.implAddExports(pn, Objects.requireNonNull(other), true); + } + @Override + public void addExportsToAll(Module m, String pn) { + m.implAddExports(pn, Module.EVERYONE_MODULE, true); + } + @Override + public void addExportsToAllUnnamed(Module m, String pn) { + m.implAddExports(pn, Module.ALL_UNNAMED_MODULE, true); + } + @Override + public void addPackage(Module m, String pn) { + m.implAddPackage(pn, true); + } + }); + } +} 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 f6c6ebd4d2f..ca4a0fd36f3 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 @@ -29,45 +29,48 @@ import java.lang.ref.WeakReference; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiFunction; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.internal.loader.BootLoader; +import jdk.internal.module.Modules; import jdk.internal.misc.VM; +import sun.misc.Unsafe; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; /** - * {@code Proxy} provides static methods for creating dynamic proxy - * classes and instances, and it is also the superclass of all - * dynamic proxy classes created by those methods. * - *

To create a proxy for some interface {@code Foo}: - *

+ * {@code Proxy} provides static methods for creating objects that act like instances
+ * of interfaces but allow for customized method invocation.
+ * To create a proxy instance for some interface {@code Foo}:
+ * 
{@code
  *     InvocationHandler handler = new MyInvocationHandler(...);
- *     Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
- *     Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
- *                     newInstance(handler);
- * 
- * or more simply: - *
  *     Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
- *                                          new Class<?>[] { Foo.class },
+ *                                          new Class[] { Foo.class },
  *                                          handler);
- * 
+ * }
* - *

A dynamic proxy class (simply referred to as a proxy - * class below) is a class that implements a list of interfaces - * specified at runtime when the class is created, with behavior as - * described below. - * - * A proxy interface is such an interface that is implemented - * by a proxy class. - * - * A proxy instance is an instance of a proxy class. + *

+ * A proxy class is a class created at runtime that implements a specified + * list of interfaces, known as proxy interfaces. A proxy instance + * is an instance of a proxy class. * * Each proxy instance has an associated invocation handler * object, which implements the interface {@link InvocationHandler}. @@ -84,65 +87,41 @@ import sun.security.util.SecurityConstants; *

A proxy class has the following properties: * *

    - *
  • Proxy classes are public, final, and not abstract if - * all proxy interfaces are public.
  • - * - *
  • Proxy classes are non-public, final, and not abstract if - * any of the proxy interfaces is non-public.
  • - * *
  • The unqualified name of a proxy class is unspecified. The space * of class names that begin with the string {@code "$Proxy"} * should be, however, reserved for proxy classes. * + *
  • The package and module in which a proxy class is defined is specified + * below. + * + *
  • A proxy class is final and non-abstract. + * *
  • A proxy class extends {@code java.lang.reflect.Proxy}. * *
  • A proxy class implements exactly the interfaces specified at its - * creation, in the same order. - * - *
  • If a proxy class implements a non-public interface, then it will - * be defined in the same package as that interface. Otherwise, the - * package of a proxy class is also unspecified. Note that package - * sealing will not prevent a proxy class from being successfully defined - * in a particular package at runtime, and neither will classes already - * defined by the same class loader and the same package with particular - * signers. - * - *
  • Since a proxy class implements all of the interfaces specified at - * its creation, invoking {@code getInterfaces} on its - * {@code Class} object will return an array containing the same + * creation, in the same order. Invoking {@link Class#getInterfaces getInterfaces} + * on its {@code Class} object will return an array containing the same * list of interfaces (in the order specified at its creation), invoking - * {@code getMethods} on its {@code Class} object will return + * {@link Class#getMethods getMethods} on its {@code Class} object will return * an array of {@code Method} objects that include all of the * methods in those interfaces, and invoking {@code getMethod} will * find methods in the proxy interfaces as would be expected. * - *
  • The {@link Proxy#isProxyClass Proxy.isProxyClass} method will - * return true if it is passed a proxy class-- a class returned by - * {@code Proxy.getProxyClass} or the class of an object returned by - * {@code Proxy.newProxyInstance}-- and false otherwise. - * - *
  • The {@code java.security.ProtectionDomain} of a proxy class + *
  • The {@link java.security.ProtectionDomain} of a proxy class * is the same as that of system classes loaded by the bootstrap class * loader, such as {@code java.lang.Object}, because the code for a * proxy class is generated by trusted system code. This protection - * domain will typically be granted - * {@code java.security.AllPermission}. + * domain will typically be granted {@code java.security.AllPermission}. * - *
  • Each proxy class has one public constructor that takes one argument, - * an implementation of the interface {@link InvocationHandler}, to set - * the invocation handler for a proxy instance. Rather than having to use - * the reflection API to access the public constructor, a proxy instance - * can be also be created by calling the {@link Proxy#newProxyInstance - * Proxy.newProxyInstance} method, which combines the actions of calling - * {@link Proxy#getProxyClass Proxy.getProxyClass} with invoking the - * constructor with an invocation handler. + *
  • The {@link Proxy#isProxyClass Proxy.isProxyClass} method can be used + * to determine if a given class is a proxy class. *
* *

A proxy instance has the following properties: * *

    *
  • Given a proxy instance {@code proxy} and one of the - * interfaces implemented by its proxy class {@code Foo}, the + * interfaces, {@code Foo}, implemented by its proxy class, the * following expression will return true: *
      *     {@code proxy instanceof Foo}
    @@ -177,9 +156,82 @@ import sun.security.util.SecurityConstants;
      * like they do for instances of {@code java.lang.Object}.
      * 
* + *

Package and Module Membership of Proxy Class

+ * + * The package and module to which a proxy class belongs are chosen such that + * the accessibility of the proxy class is in line with the accessibility of + * the proxy interfaces. Specifically, the package and the module membership + * of a proxy class defined via the + * {@link Proxy#getProxyClass(ClassLoader, Class[])} or + * {@link Proxy#newProxyInstance(ClassLoader, Class[], InvocationHandler)} + * methods is specified as follows: + * + *
    + *
  1. If all the proxy interfaces are in exported packages: + *
      + *
    1. if all the proxy interfaces are public, then the proxy class is + * public in a package exported by the + * {@linkplain ClassLoader#getUnnamedModule() unnamed module} of the specified + * loader. The name of the package is unspecified.
    2. + * + *
    3. if at least one of all the proxy interfaces is non-public, then + * the proxy class is non-public in the package and module of the + * non-public interfaces. All the non-public interfaces must be in the same + * package and module; otherwise, proxying them is + * not possible.
    4. + *
    + *
  2. + *
  3. If at least one proxy interface is a non-exported package: + *
      + *
    1. if all the proxy interfaces are public, then the proxy class is + * public in a non-exported package of + * dynamic module. + * The names of the package and the module are unspecified.
    2. + * + *
    3. if at least one of all the proxy interfaces is non-public, then + * the proxy class is non-public in the package and module of the + * non-public interfaces. All the non-public interfaces must be in the same + * package and module; otherwise, proxying them is + * not possible.
    4. + *
    + *
  4. + *
+ * + *

+ * 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 + * 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 + * 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. + * + *

Dynamic Modules

+ *

+ * A dynamic module is a named module generated at runtime. A proxy class + * defined in a dynamic module is encapsulated and not accessible to any module. + * Calling {@link Constructor#newInstance(Object...)} on a proxy class in + * a dynamic module will throw {@code IllegalAccessException}; + * {@code Proxy.newProxyInstance} method should be used instead. + * + *

+ * A dynamic module can read the modules of all of the superinterfaces of a proxy class + * and the modules of the types referenced by all public method signatures + * of a proxy class. If a superinterface or a referenced type, say {@code T}, + * is in a non-exported package, the {@linkplain java.lang.reflect.Module module} + * of {@code T} is updated to export the package of {@code T} to the dynamic module. + * *

Methods Duplicated in Multiple Proxy Interfaces

* - *

When two or more interfaces of a proxy class contain a method with + *

When two or more proxy interfaces contain a method with * the same name and parameter signature, the order of the proxy class's * interfaces becomes significant. When such a duplicate method * is invoked on a proxy instance, the {@code Method} object passed @@ -225,19 +277,12 @@ import sun.security.util.SecurityConstants; * @since 1.3 */ public class Proxy implements java.io.Serializable { - private static final long serialVersionUID = -2222568056686623797L; /** parameter types of a proxy class constructor */ private static final Class[] constructorParams = { InvocationHandler.class }; - /** - * a cache of proxy classes - */ - private static final WeakCache[], Class> - proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory()); - /** * the invocation handler for this proxy instance. * @serial @@ -276,67 +321,13 @@ public class Proxy implements java.io.Serializable { * a proxy class for those interfaces will be generated dynamically * and defined by the class loader. * - *

There are several restrictions on the parameters that may be - * passed to {@code Proxy.getProxyClass}: - * - *

    - *
  • All of the {@code Class} objects in the - * {@code interfaces} array must represent interfaces, not - * classes or primitive types. - * - *
  • No two elements in the {@code interfaces} array may - * refer to identical {@code Class} objects. - * - *
  • All of the interface types must be visible by name through the - * specified class loader. In other words, for class loader - * {@code cl} and every interface {@code i}, the following - * expression must be true: - *
    -     *     Class.forName(i.getName(), false, cl) == i
    -     * 
    - * - *
  • All non-public interfaces must be in the same package; - * otherwise, it would not be possible for the proxy class to - * implement all of the interfaces, regardless of what package it is - * defined in. - * - *
  • For any set of member methods of the specified interfaces - * that have the same signature: - *
      - *
    • If the return type of any of the methods is a primitive - * type or void, then all of the methods must have that same - * return type. - *
    • Otherwise, one of the methods must have a return type that - * is assignable to all of the return types of the rest of the - * methods. - *
    - * - *
  • The resulting proxy class must not exceed any limits imposed - * on classes by the virtual machine. For example, the VM may limit - * the number of interfaces that a class may implement to 65535; in - * that case, the size of the {@code interfaces} array must not - * exceed 65535. - *
- * - *

If any of these restrictions are violated, - * {@code Proxy.getProxyClass} will throw an - * {@code IllegalArgumentException}. If the {@code interfaces} - * array argument or any of its elements are {@code null}, a - * {@code NullPointerException} will be thrown. - * - *

Note that the order of the specified proxy interfaces is - * significant: two requests for a proxy class with the same combination - * of interfaces but in a different order will result in two distinct - * proxy classes. - * * @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class * to implement * @return a proxy class that is defined in the specified class loader * and that implements the specified interfaces - * @throws IllegalArgumentException if any of the restrictions on the - * parameters that may be passed to {@code getProxyClass} - * are violated + * @throws IllegalArgumentException if any of the + * restrictions on the parameters are violated * @throws SecurityException if a security manager, s, is present * and any of the following conditions is met: *

    @@ -352,22 +343,32 @@ public class Proxy implements java.io.Serializable { * invocation of {@link SecurityManager#checkPackageAccess * s.checkPackageAccess()} denies access to {@code intf}. *
- * @throws NullPointerException if the {@code interfaces} array * argument or any of its elements are {@code null} + * + * @deprecated Proxy classes generated in a named module are encapsulated and not + * accessible to code outside its module. + * {@link Constructor#newInstance(Object...) Constructor.newInstance} will throw + * {@code IllegalAccessException} when it is called on an inaccessible proxy class. + * Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)} + * to create a proxy instance instead. + * + * @see Package and Module Membership of Proxy Class */ + @Deprecated @CallerSensitive public static Class getProxyClass(ClassLoader loader, Class... interfaces) throws IllegalArgumentException { - final Class[] intfs = interfaces.clone(); + final List> intfs = List.of(interfaces); // interfaces cloned final SecurityManager sm = System.getSecurityManager(); + final Class caller = Reflection.getCallerClass(); if (sm != null) { - checkProxyAccess(Reflection.getCallerClass(), loader, intfs); + checkProxyAccess(caller, loader, intfs); } - return getProxyClass0(loader, intfs); + return new ProxyBuilder(loader, intfs).build(); } /* @@ -386,11 +387,11 @@ public class Proxy implements java.io.Serializable { * the defining loader of the interface. If the caller's class loader * is not the same as the defining loader of the interface, the VM * will throw IllegalAccessError when the generated proxy class is - * being defined via the defineClass0 method. + * being defined. */ private static void checkProxyAccess(Class caller, ClassLoader loader, - Class... interfaces) + List> interfaces) { SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -398,26 +399,10 @@ public class Proxy implements java.io.Serializable { if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) { sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); } - ReflectUtil.checkProxyPackageAccess(ccl, interfaces); + ReflectUtil.checkProxyPackageAccess(ccl, interfaces.toArray(EMPTY_CLASS_ARRAY)); } } - /** - * Generate a proxy class. Must call the checkProxyAccess method - * to perform permission checks before calling this. - */ - private static Class getProxyClass0(ClassLoader loader, - Class... interfaces) { - if (interfaces.length > 65535) { - throw new IllegalArgumentException("interface limit exceeded"); - } - - // If the proxy class defined by the given loader implementing - // the given interfaces exists, this will simply return the cached copy; - // otherwise, it will create the proxy class via the ProxyClassFactory - return proxyClassCache.get(loader, interfaces); - } - /* * a key used for proxy class with 0 implemented interfaces */ @@ -495,11 +480,12 @@ public class Proxy implements java.io.Serializable { private final WeakReference>[] refs; @SuppressWarnings("unchecked") - KeyX(Class[] interfaces) { - hash = Arrays.hashCode(interfaces); - refs = (WeakReference>[])new WeakReference[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - refs[i] = new WeakReference<>(interfaces[i]); + KeyX(List> interfaces) { + hash = Arrays.hashCode(interfaces.toArray()); + refs = (WeakReference>[])new WeakReference[interfaces.size()]; + int i = 0; + for (Class intf : interfaces) { + refs[i++] = new WeakReference<>(intf); } } @@ -535,14 +521,14 @@ public class Proxy implements java.io.Serializable { * A function that maps an array of interfaces to an optimal key where * Class objects representing interfaces are weakly referenced. */ - private static final class KeyFactory - implements BiFunction[], Object> + private static final class KeyFactory + implements BiFunction>, Object> { @Override - public Object apply(ClassLoader classLoader, Class[] interfaces) { - switch (interfaces.length) { - case 1: return new Key1(interfaces[0]); // the most frequent - case 2: return new Key2(interfaces[0], interfaces[1]); + public Object apply(T t, List> interfaces) { + switch (interfaces.size()) { + case 1: return new Key1(interfaces.get(0)); // the most frequent + case 2: return new Key2(interfaces.get(0), interfaces.get(1)); case 0: return key0; default: return new KeyX(interfaces); } @@ -550,53 +536,19 @@ public class Proxy implements java.io.Serializable { } /** - * A factory function that generates, defines and returns the proxy class given - * the ClassLoader and array of interfaces. + * A factory function that generates, defines and returns the proxy class + * given the ClassLoader and array of interfaces. */ - private static final class ProxyClassFactory - implements BiFunction[], Class> - { + private static final class ProxyClassFactory { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + // prefix for all proxy class names private static final String proxyClassNamePrefix = "$Proxy"; // next number to use for generation of unique proxy class names private static final AtomicLong nextUniqueNumber = new AtomicLong(); - @Override - public Class apply(ClassLoader loader, Class[] interfaces) { - - Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); - for (Class intf : interfaces) { - /* - * Verify that the class loader resolves the name of this - * interface to the same Class object. - */ - Class interfaceClass = null; - try { - interfaceClass = Class.forName(intf.getName(), false, loader); - } catch (ClassNotFoundException e) { - } - if (interfaceClass != intf) { - throw new IllegalArgumentException( - intf + " is not visible from class loader"); - } - /* - * Verify that the Class object actually represents an - * interface. - */ - if (!interfaceClass.isInterface()) { - throw new IllegalArgumentException( - interfaceClass.getName() + " is not an interface"); - } - /* - * Verify that this interface is not a duplicate. - */ - if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { - throw new IllegalArgumentException( - "repeated interface: " + interfaceClass.getName()); - } - } - + private static Class defineProxyClass(Module m, List> interfaces) { String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; @@ -608,38 +560,49 @@ public class Proxy implements java.io.Serializable { for (Class intf : interfaces) { int flags = intf.getModifiers(); if (!Modifier.isPublic(flags)) { - accessFlags = Modifier.FINAL; - String name = intf.getName(); - int n = name.lastIndexOf('.'); - String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); + accessFlags = Modifier.FINAL; // non-public, final + String pkg = intf.getPackageName(); if (proxyPkg == null) { proxyPkg = pkg; } else if (!pkg.equals(proxyPkg)) { throw new IllegalArgumentException( - "non-public interfaces from different packages"); + "non-public interfaces from different packages"); } } } if (proxyPkg == null) { - // if no non-public proxy interfaces, use com.sun.proxy package - proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; + // all proxy interfaces are public + proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName() + : PROXY_PACKAGE_PREFIX; + } else if (proxyPkg.isEmpty() && m.isNamed()) { + throw new IllegalArgumentException( + "Unnamed package cannot be added to " + m); + } + + // add the package to the runtime module if not exists + if (m.isNamed()) { + m.addPackage(proxyPkg); } /* * Choose a name for the proxy class to generate. */ long num = nextUniqueNumber.getAndIncrement(); - String proxyName = proxyPkg + proxyClassNamePrefix + num; + String proxyName = proxyPkg.isEmpty() ? proxyClassNamePrefix + num + : proxyPkg + "." + proxyClassNamePrefix + num; + + ClassLoader loader = getLoader(m); + trace(proxyName, m, loader, interfaces); /* * Generate the specified proxy class. */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( - proxyName, interfaces, accessFlags); + proxyName, interfaces.toArray(EMPTY_CLASS_ARRAY), accessFlags); try { - return defineClass0(loader, proxyName, - proxyClassFile, 0, proxyClassFile.length); + return UNSAFE.defineClass(proxyName, proxyClassFile, 0, proxyClassFile.length, + loader, null); } catch (ClassFormatError e) { /* * A ClassFormatError here means that (barring bugs in the @@ -651,16 +614,410 @@ public class Proxy implements java.io.Serializable { throw new IllegalArgumentException(e.toString()); } } + + /** + * Test if the given class is a proxy class + */ + static boolean isProxyClass(Class c) { + return proxyCache.containsValue(c); + } + + /** + * Returns the proxy class. It will return the cached proxy class + * if exists; otherwise, it will create the proxy class and store in + * the cache. + */ + static Class get(Module module, List> interfaces) { + return proxyCache.get(module, interfaces); + } + + /** + * a cache of proxy classes in the named and unnamed module + */ + private static final WeakCache>, Class> proxyCache = + new WeakCache<>(new KeyFactory(), + new BiFunction>, Class>() { + @Override + public Class apply(Module m, List> interfaces) { + Objects.requireNonNull(m); + return defineProxyClass(m, interfaces); + } + }); + + + private static boolean isExportedType(Class c) { + String pn = c.getPackageName(); + return Modifier.isPublic(c.getModifiers()) && c.getModule().isExported(pn); + } + + private static boolean isPackagePrivateType(Class c) { + return !Modifier.isPublic(c.getModifiers()); + } + + private static String toDetails(Class c) { + String access = "unknown"; + if (isExportedType(c)) { + access = "exported"; + } else if (isPackagePrivateType(c)) { + access = "package-private"; + } else { + access = "module-private"; + } + ClassLoader ld = c.getClassLoader(); + return String.format(" %s/%s %s loader %s", + c.getModule().getName(), c.getName(), access, ld); + } + + static void trace(String cn, Module module, ClassLoader loader, List> interfaces) { + if (isDebug()) { + System.out.format("PROXY: %s/%s defined by %s%n", module.getName(), cn, loader); + } + if (isDebug("debug")) { + interfaces.stream() + .forEach(c -> System.out.println(toDetails(c))); + } + } + + private static final String DEBUG = + AccessController.doPrivileged(new PrivilegedAction<>() { + public String run() { + return System.getProperty("jdk.proxy.debug", ""); + } + }); + + private static final boolean isDebug() { + return !DEBUG.isEmpty(); + } + private static final boolean isDebug(String flag) { + return DEBUG.equals(flag); + } } /** - * Returns an instance of a proxy class for the specified interfaces + * Builder for a proxy class. + * + * If the module is not specified in this ProxyBuilder constructor, + * it will map from the given loader and interfaces to the module + * in which the proxy class will be defined. + */ + private static final class ProxyBuilder { + final ClassLoader loader; + final List> interfaces; + final Module module; + ProxyBuilder(ClassLoader loader, List> interfaces) { + if (!VM.isModuleSystemInited()) { + throw new InternalError("Proxy is not supported until module system is fully initialzed"); + } + if (interfaces.size() > 65535) { + throw new IllegalArgumentException("interface limit exceeded"); + } + + Set> refTypes = referencedTypes(loader, interfaces); + + // IAE if violates any restrictions specified in newProxyInstance + validateProxyInterfaces(loader, interfaces, refTypes); + + this.loader = loader; + this.interfaces = interfaces; + this.module = mapToModule(loader, interfaces, refTypes); + assert getLoader(module) == loader; + } + + /** + * Generate a proxy class. If the target module does not have any + * to any interface types, IllegalAccessError will be thrown by the VM + * at defineClass time. + * + * Must call the checkProxyAccess method to perform permission checks + * before calling this. + */ + Class build() { + return ProxyClassFactory.get(module, interfaces); + } + + /** + * Validate the given proxy interfaces and the given referenced types + * are visible to the defining loader. + * + * @throws IllegalArgumentException if it violates the restrictions specified + * in {@link Proxy#newProxyInstance} + */ + static void validateProxyInterfaces(ClassLoader loader, + List> interfaces, + Set> refTypes) + { + Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.size()); + for (Class intf : interfaces) { + /* + * Verify that the class loader resolves the name of this + * interface to the same Class object. + */ + ensureVisible(loader, intf); + + /* + * Verify that the Class object actually represents an + * interface. + */ + if (!intf.isInterface()) { + throw new IllegalArgumentException(intf.getName() + " is not an interface"); + } + + /* + * Verify that this interface is not a duplicate. + */ + if (interfaceSet.put(intf, Boolean.TRUE) != null) { + throw new IllegalArgumentException("repeated interface: " + intf.getName()); + } + } + + for (Class type : refTypes) { + ensureVisible(loader, type); + } + } + + /* + * Returns all types referenced by all public method signatures of + * the proxy interfaces + */ + static Set> referencedTypes(ClassLoader loader, List> interfaces) { + return interfaces.stream() + .flatMap(intf -> Stream.of(intf.getMethods()) + .flatMap(m -> methodRefTypes(m)) + .map(ProxyBuilder::getElementType) + .filter(t -> !t.isPrimitive())) + .collect(Collectors.toSet()); + } + + /* + * Extracts all types referenced on a method signature including + * its return type, parameter types, and exception types. + */ + static Stream> methodRefTypes(Method m) { + return Stream.of(new Class[] { m.getReturnType() }, + m.getParameterTypes(), + m.getExceptionTypes()) + .flatMap(a -> Stream.of(a)); + } + + /** + * Returns the module that the generated proxy class belongs to. + * + * If all proxy interfaces are public and in exported packages, + * then the proxy class is in unnamed module. + * + * If any of proxy interface is package-private, then the proxy class + * is in the same module of the package-private interface. + * + * If all proxy interfaces are public and at least one in a non-exported + * package, then the proxy class is in a dynamic module in a non-exported + * package. Reads edge and qualified exports are added for + * dynamic module to access. + */ + static Module mapToModule(ClassLoader loader, List> interfaces, Set> refTypes) { + Map, Module> modulePrivateTypes = new HashMap<>(); + Map, Module> packagePrivateTypes = new HashMap<>(); + for (Class intf : interfaces) { + Module m = intf.getModule(); + if (Modifier.isPublic(intf.getModifiers())) { + // module-private types + if (!m.isExported(intf.getPackageName())) { + modulePrivateTypes.put(intf, m); + } + } else { + packagePrivateTypes.put(intf, m); + } + } + + // all proxy interfaces are public and exported, the proxy class is in unnamed module + // Such proxy class is accessible to any unnamed module and named module that + // can read unnamed module + if (packagePrivateTypes.isEmpty() && modulePrivateTypes.isEmpty()) { + return loader != null ? loader.getUnnamedModule() : BootLoader.getUnnamedModule(); + } + + if (packagePrivateTypes.size() > 0) { + // all package-private types must be in the same runtime package + // i.e. same package name and same module (named or unnamed) + // + // Configuration will fail if M1 and in M2 defined by the same loader + // and both have the same package p (so no need to check class loader) + if (packagePrivateTypes.size() > 1 && + (packagePrivateTypes.keySet().stream() // more than one package + .map(Class::getPackageName).distinct().count() > 1 || + packagePrivateTypes.values().stream() // or more than one module + .distinct().count() > 1)) { + throw new IllegalArgumentException( + "non-public interfaces from different packages"); + } + + // all package-private types are in the same module (named or unnamed) + Module target = null; + for (Module m : packagePrivateTypes.values()) { + if (getLoader(m) != loader) { + // the specified loader is not the same class loader of the non-public interface + throw new IllegalArgumentException( + "non-public interface is not defined by the given loader"); + } + target = m; + } + + // validate if the target module can access all other interfaces + for (Class intf : interfaces) { + Module m = intf.getModule(); + if (m == target) continue; + + if (!target.canRead(m) || !m.isExported(intf.getPackageName(), target)) { + throw new IllegalArgumentException(target + " can't access " + intf.getName()); + } + } + + // return the module of the package-private interface + return target; + } + + // all proxy interfaces are public and at least one in a non-exported package + // map to dynamic proxy module and add reads edge and qualified exports, if necessary + Module target = getDynamicModule(loader); + + // set up proxy class access to proxy interfaces and superinterfaces + Deque> deque = new LinkedList<>(interfaces); + Set> visited = new HashSet<>(); + while (!deque.isEmpty()) { + Class c = deque.poll(); + if (visited.contains(c)) { + continue; + } + visited.add(c); + ensureAccess(target, c); + + // add all superinterfaces + for (Class intf : c.getInterfaces()) { + deque.add(intf); + } + } + + // set up proxy class access to types referenced in the method signature + refTypes.stream() + .filter(t -> !visited.contains(t)) + .forEach(t -> ensureAccess(target, t)); + return target; + } + + /* + * Ensure the given module can access the given class. + */ + static void ensureAccess(Module target, Class c) { + Module m = c.getModule(); + // add read edge and qualified export for the target module to access + if (!target.canRead(m)) { + Modules.addReads(target, m); + } + String pn = c.getPackageName(); + if (!m.isExported(pn, target)) { + Modules.addExports(m, pn, target); + } + } + + /* + * Ensure the given class is visible to the class loader. + */ + static void ensureVisible(ClassLoader ld, Class c) { + Class type = null; + try { + type = Class.forName(c.getName(), false, ld); + } catch (ClassNotFoundException e) { + } + if (type != c) { + throw new IllegalArgumentException(c.getName() + + " referenced from a method is not visible from class loader"); + } + } + + static Class getElementType(Class type) { + Class e = type; + while (e.isArray()) { + e = e.getComponentType(); + } + return e; + } + + private static final WeakHashMap dynProxyModules = new WeakHashMap<>(); + private static final AtomicInteger counter = new AtomicInteger(); + + /* + * Define a dynamic module for the generated proxy classes in a non-exported package + * named com.sun.proxy.$MODULE. + * + * Each class loader will have one dynamic module. + */ + static Module getDynamicModule(ClassLoader loader) { + return dynProxyModules.computeIfAbsent(loader, ld -> { + // create a dynamic module and setup module access + String mn = "jdk.proxy" + counter.incrementAndGet(); + String pn = PROXY_PACKAGE_PREFIX + "." + mn; + Module m = Modules.defineModule(loader, mn, Collections.singleton(pn)); + Modules.addReads(m, Proxy.class.getModule()); + // java.base to create proxy instance + Modules.addExports(m, pn, Object.class.getModule()); + return m; + }); + } + } + + /** + * Returns a proxy instance for the specified interfaces * that dispatches method invocations to the specified invocation * handler. + *

+ * {@code IllegalArgumentException} will be thrown + * if any of the following restrictions is violated: + *

    + *
  • All of {@code Class} objects in the given {@code interfaces} array + * must represent interfaces, not classes or primitive types. * - *

    {@code Proxy.newProxyInstance} throws - * {@code IllegalArgumentException} for the same reasons that - * {@code Proxy.getProxyClass} does. + *

  • No two elements in the {@code interfaces} array may + * refer to identical {@code Class} objects. + * + *
  • All of the interface types must be visible by name through the + * specified class loader. In other words, for class loader + * {@code cl} and every interface {@code i}, the following + * expression must be true:

    + * {@code Class.forName(i.getName(), false, cl) == i} + * + *

  • All of the types referenced by all + * public method signatures of the specified interfaces + * and those inherited by their superinterfaces + * must be visible by name through the specified class loader. + * + *
  • All non-public interfaces must be in the same package + * and module, defined by the specified class loader and + * the module of the non-public interfaces can access all of + * the interface types; otherwise, it would not be possible for + * the proxy class to implement all of the interfaces, + * regardless of what package it is defined in. + * + *
  • For any set of member methods of the specified interfaces + * that have the same signature: + *
      + *
    • If the return type of any of the methods is a primitive + * type or void, then all of the methods must have that same + * return type. + *
    • Otherwise, one of the methods must have a return type that + * is assignable to all of the return types of the rest of the + * methods. + *
    + * + *
  • The resulting proxy class must not exceed any limits imposed + * on classes by the virtual machine. For example, the VM may limit + * the number of interfaces that a class may implement to 65535; in + * that case, the size of the {@code interfaces} array must not + * exceed 65535. + *
+ * + *

Note that the order of the specified proxy interfaces is + * significant: two requests for a proxy class with the same combination + * of interfaces but in a different order will result in two distinct + * proxy classes. * * @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class @@ -669,9 +1026,8 @@ public class Proxy implements java.io.Serializable { * @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces - * @throws IllegalArgumentException if any of the restrictions on the - * parameters that may be passed to {@code getProxyClass} - * are violated + * @throws IllegalArgumentException if any of the + * restrictions on the parameters are violated * @throws SecurityException if a security manager, s, is present * and any of the following conditions is met: *

    @@ -697,43 +1053,47 @@ public class Proxy implements java.io.Serializable { * argument or any of its elements are {@code null}, or * if the invocation handler, {@code h}, is * {@code null} + * + * @see Package and Module Membership of Proxy Class */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, - InvocationHandler h) - throws IllegalArgumentException - { + InvocationHandler h) { Objects.requireNonNull(h); - final Class[] intfs = interfaces.clone(); + final List> intfs = List.of(interfaces); // interfaces cloned final SecurityManager sm = System.getSecurityManager(); + final Class caller = Reflection.getCallerClass(); if (sm != null) { - checkProxyAccess(Reflection.getCallerClass(), loader, intfs); + checkProxyAccess(caller, loader, intfs); } /* * Look up or generate the designated proxy class. */ - Class cl = getProxyClass0(loader, intfs); + Class cl = new ProxyBuilder(loader, intfs).build(); + return newProxyInstance(cl, caller, h); + } + + private static Object newProxyInstance(Class proxyClass, Class caller, InvocationHandler h) { /* * Invoke its constructor with the designated invocation handler. */ try { + final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - checkNewProxyPermission(Reflection.getCallerClass(), cl); + checkNewProxyPermission(caller, proxyClass); } - final Constructor cons = cl.getConstructor(constructorParams); - if (!Modifier.isPublic(cl.getModifiers())) { - AccessController.doPrivileged(new PrivilegedAction<>() { - public Void run() { - cons.setAccessible(true); - return null; - } - }); - } + final Constructor cons = proxyClass.getConstructor(constructorParams); + AccessController.doPrivileged(new PrivilegedAction() { + public Void run() { + cons.setAccessible(true); + return null; + } + }); return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException | InstantiationException | NoSuchMethodException e) { throw new InternalError(e.toString(), e); @@ -770,11 +1130,17 @@ public class Proxy implements java.io.Serializable { } /** - * Returns true if and only if the specified class was dynamically - * generated to be a proxy class using the {@code getProxyClass} - * method or the {@code newProxyInstance} method. + * Returns the class loader for the given module. + */ + private static ClassLoader getLoader(Module m) { + PrivilegedAction pa = m::getClassLoader; + return AccessController.doPrivileged(pa); + } + + /** + * Returns true if the given class is a proxy class. * - *

    The reliability of this method is important for the ability + * @implNote The reliability of this method is important for the ability * to use it to make security decisions, so its implementation should * not just test if the class in question extends {@code Proxy}. * @@ -784,7 +1150,7 @@ public class Proxy implements java.io.Serializable { * @throws NullPointerException if {@code cl} is {@code null} */ public static boolean isProxyClass(Class cl) { - return Proxy.class.isAssignableFrom(cl) && proxyClassCache.containsValue(cl); + return Proxy.class.isAssignableFrom(cl) && ProxyClassFactory.isProxyClass(cl); } /** @@ -827,6 +1193,6 @@ public class Proxy implements java.io.Serializable { return ih; } - private static native Class defineClass0(ClassLoader loader, String name, - byte[] b, int off, int len); + private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + private static final String PROXY_PACKAGE_PREFIX = ReflectUtil.PROXY_PACKAGE; } 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 cf0a1a2163b..c8cb0257b2a 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,12 +24,12 @@ */ /** - * Provides classes and interfaces for obtaining reflective - * information about classes and objects. Reflection allows - * programmatic access to information about the fields, methods and - * constructors of loaded classes, and the use of reflected fields, - * methods, and constructors to operate on their underlying - * counterparts, within security restrictions. + * Provides classes and interfaces for obtaining reflective information about + * modules, classes and objects. Reflection allows programmatic access to + * information about modules and to the fields, methods and constructors of + * loaded classes, and the use of reflected fields, methods, and constructors + * to operate on their underlying counterparts, within encapsulation and + * security restrictions. * *

    {@code AccessibleObject} allows suppression of access checks if * the necessary {@code ReflectPermission} is available. diff --git a/jdk/src/java.base/share/classes/java/net/URL.java b/jdk/src/java.base/share/classes/java/net/URL.java index 598e4103cf7..cce9cf9425a 100644 --- a/jdk/src/java.base/share/classes/java/net/URL.java +++ b/jdk/src/java.base/share/classes/java/net/URL.java @@ -1213,11 +1213,15 @@ public final class URL implements java.io.Serializable { String packagePrefixList = java.security.AccessController.doPrivileged( new PrivilegedAction<>() { public String run() { - return System.getProperty(protocolPathProp, ""); + return System.getProperty(protocolPathProp, null); } }); - String[] packagePrefixes = packagePrefixList.split("\\|"); + if (packagePrefixList == null) { + // not set + return null; + } + String[] packagePrefixes = packagePrefixList.split("\\|"); URLStreamHandler handler = null; for (int i=0; handler == null && i gate = new ThreadLocal<>(); private static URLStreamHandler lookupViaProviders(final String protocol) { - if (!jdk.internal.misc.VM.isBooted()) - return null; - if (gate.get() != null) throw new Error("Circular loading of URL stream handler providers detected"); @@ -1359,7 +1360,7 @@ public final class URL implements java.io.Serializable { URLStreamHandlerFactory fac; boolean checkedWithFactory = false; - if (isOverrideable(protocol)) { + if (isOverrideable(protocol) && jdk.internal.misc.VM.isBooted()) { // Use the factory (if any). Volatile read makes // URLStreamHandlerFactory appear fully initialized to current thread. fac = factory; 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 1cf064d1afa..c120ab77240 100644 --- a/jdk/src/java.base/share/classes/java/net/URLClassLoader.java +++ b/jdk/src/java.base/share/classes/java/net/URLClassLoader.java @@ -42,7 +42,6 @@ import java.security.SecureClassLoader; import java.util.Enumeration; import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Set; import java.util.WeakHashMap; import java.util.jar.Attributes; @@ -394,7 +393,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { */ private Package getAndVerifyPackage(String pkgname, Manifest man, URL url) { - Package pkg = getPackage(pkgname); + Package pkg = getDefinedPackage(pkgname); if (pkg != null) { // Package found, so check package sealing. if (pkg.isSealed()) { @@ -416,29 +415,6 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { return pkg; } - // Also called by VM to define Package for classes loaded from the CDS - // archive - private void definePackageInternal(String pkgname, Manifest man, URL url) - { - if (getAndVerifyPackage(pkgname, man, url) == null) { - try { - if (man != null) { - definePackage(pkgname, man, url); - } else { - definePackage(pkgname, null, null, null, null, null, null, null); - } - } catch (IllegalArgumentException iae) { - // parallel-capable class loaders: re-verify in case of a - // race condition - if (getAndVerifyPackage(pkgname, man, url) == null) { - // Should never happen - throw new AssertionError("Cannot find package " + - pkgname); - } - } - } - } - /* * Defines a Class using the class bytes obtained from the specified * Resource. The resulting Class must be resolved before it can be @@ -452,7 +428,23 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { String pkgname = name.substring(0, i); // Check if package already loaded. Manifest man = res.getManifest(); - definePackageInternal(pkgname, man, url); + if (getAndVerifyPackage(pkgname, man, url) == null) { + try { + if (man != null) { + definePackage(pkgname, man, url); + } else { + definePackage(pkgname, null, null, null, null, null, null, null); + } + } catch (IllegalArgumentException iae) { + // parallel-capable class loaders: re-verify in case of a + // race condition + if (getAndVerifyPackage(pkgname, man, url) == null) { + // Should never happen + throw new AssertionError("Cannot find package " + + pkgname); + } + } + } } // Now read the class bytes and define the class java.nio.ByteBuffer bb = res.getByteBuffer(); @@ -574,7 +566,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { } }, acc); - return url != null ? ucp.checkURL(url) : null; + return url != null ? URLClassPath.checkURL(url) : null; } /** @@ -609,7 +601,7 @@ public class URLClassLoader extends SecureClassLoader implements Closeable { }, acc); if (u == null) break; - url = ucp.checkURL(u); + url = URLClassPath.checkURL(u); } while (url == null); return url != null; } diff --git a/jdk/src/java.base/share/classes/java/nio/Bits.java b/jdk/src/java.base/share/classes/java/nio/Bits.java index 2b8e8baa49c..d8b3024f781 100644 --- a/jdk/src/java.base/share/classes/java/nio/Bits.java +++ b/jdk/src/java.base/share/classes/java/nio/Bits.java @@ -614,7 +614,7 @@ class Bits { // package-private // which a process may access. All sizes are specified in bytes. static void reserveMemory(long size, int cap) { - if (!memoryLimitSet && VM.isBooted()) { + if (!memoryLimitSet && VM.initLevel() >= 1) { maxMemory = VM.maxDirectMemory(); memoryLimitSet = true; } diff --git a/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java b/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java index a5216b9196d..08ff1f0d740 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java +++ b/jdk/src/java.base/share/classes/java/nio/file/FileSystems.java @@ -30,8 +30,11 @@ import java.net.URI; import java.io.IOException; import java.security.AccessController; import java.security.PrivilegedAction; -import java.util.*; import java.lang.reflect.Constructor; +import java.util.Collections; +import java.util.Map; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; /** * Factory methods for file systems. This class defines the {@link #getDefault @@ -51,8 +54,7 @@ import java.lang.reflect.Constructor; * installed file system providers. Installed providers are loaded using the * service-provider loading facility defined by the {@link ServiceLoader} class. * Installed providers are loaded using the system class loader. If the - * system class loader cannot be found then the extension class loader is used; - * if there is no extension class loader then the bootstrap class loader is used. + * system class loader cannot be found then the platform class loader is used. * Providers are typically installed by placing them in a JAR file on the * application class path, the JAR file contains a * provider-configuration file named {@code java.nio.file.spi.FileSystemProvider} @@ -82,7 +84,16 @@ import java.lang.reflect.Constructor; */ public final class FileSystems { - private FileSystems() { + private FileSystems() { } + + // Built-in file system provider + private static final FileSystemProvider builtinFileSystemProvider = + sun.nio.fs.DefaultFileSystemProvider.create(); + + // built-in file system + private static class BuiltinFileSystemHolder { + static final FileSystem builtinFileSystem = + builtinFileSystemProvider.getFileSystem(URI.create("file:///")); } // lazy initialization of default file system @@ -105,7 +116,7 @@ public final class FileSystems { // returns default provider private static FileSystemProvider getDefaultProvider() { - FileSystemProvider provider = sun.nio.fs.DefaultFileSystemProvider.create(); + FileSystemProvider provider = builtinFileSystemProvider; // if the property java.nio.file.spi.DefaultFileSystemProvider is // set then its value is the name of the default provider (or a list) @@ -173,7 +184,11 @@ public final class FileSystems { * @return the default file system */ public static FileSystem getDefault() { - return DefaultFileSystemHolder.defaultFileSystem; + if (jdk.internal.misc.VM.isBooted()) { + return DefaultFileSystemHolder.defaultFileSystem; + } else { + return BuiltinFileSystemHolder.builtinFileSystem; + } } /** diff --git a/jdk/src/java.base/share/classes/java/nio/file/Files.java b/jdk/src/java.base/share/classes/java/nio/file/Files.java index 8f8a50434e7..982846e6e25 100644 --- a/jdk/src/java.base/share/classes/java/nio/file/Files.java +++ b/jdk/src/java.base/share/classes/java/nio/file/Files.java @@ -1579,9 +1579,8 @@ public final class Files { * list of file type detectors. Installed file type detectors are loaded * using the service-provider loading facility defined by the {@link ServiceLoader} * class. Installed file type detectors are loaded using the system class - * loader. If the system class loader cannot be found then the extension class - * loader is used; If the extension class loader cannot be found then the - * bootstrap class loader is used. File type detectors are typically installed + * loader. If the system class loader cannot be found then the platform class + * loader is used. File type detectors are typically installed * by placing them in a JAR file on the application class path, * the JAR file contains a provider-configuration file * named {@code java.nio.file.spi.FileTypeDetector} in the resource directory diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java index 01498d340a5..3478af25761 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatter.java @@ -619,6 +619,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param timeStyle the formatter style to obtain, not null * @return the time formatter, not null @@ -647,6 +650,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param dateTimeStyle the formatter style to obtain, not null * @return the date-time formatter, not null @@ -675,6 +681,9 @@ public final class DateTimeFormatter { * The returned formatter has a chronology of ISO set to ensure dates in * other calendar systems are correctly converted. * It has no override zone and uses the {@link ResolverStyle#SMART SMART} resolver style. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. * * @param dateStyle the date formatter style to obtain, not null * @param timeStyle the time formatter style to obtain, not null @@ -923,6 +932,7 @@ public final class DateTimeFormatter { *

  • The {@link #ISO_LOCAL_DATE_TIME} *
  • The {@link ZoneOffset#getId() offset ID}. If the offset has seconds then * they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. *
*

@@ -935,7 +945,9 @@ public final class DateTimeFormatter { ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() .parseCaseInsensitive() .append(ISO_LOCAL_DATE_TIME) + .parseLenient() .appendOffsetId() + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } @@ -1160,6 +1172,7 @@ public final class DateTimeFormatter { *

  • If the offset is not available to format or parse then the format is complete. *
  • The {@link ZoneOffset#getId() offset ID} without colons. If the offset has * seconds then they will be handled even though this is not part of the ISO-8601 standard. + * The offset parsing is lenient, which allows the minutes and seconds to be optional. * Parsing is case insensitive. * *

    @@ -1178,7 +1191,9 @@ public final class DateTimeFormatter { .appendValue(MONTH_OF_YEAR, 2) .appendValue(DAY_OF_MONTH, 2) .optionalStart() + .parseLenient() .appendOffset("+HHMMss", "Z") + .parseStrict() .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE); } diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 441ac711110..d7baf69c5b5 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -866,7 +866,9 @@ public final class DateTimeFormatterBuilder { * Appends the zone offset, such as '+01:00', to the formatter. *

    * This appends an instruction to format/parse the offset ID to the builder. - * This is equivalent to calling {@code appendOffset("+HH:MM:ss", "Z")}. + * This is equivalent to calling {@code appendOffset("+HH:mm:ss", "Z")}. + * See {@link #appendOffset(String, String)} for details on formatting + * and parsing. * * @return this, for chaining, not null */ @@ -886,9 +888,18 @@ public final class DateTimeFormatterBuilder { * If the offset cannot be obtained then an exception is thrown unless the * section of the formatter is optional. *

    - * During parsing, the offset is parsed using the format defined below. - * If the offset cannot be parsed then an exception is thrown unless the - * section of the formatter is optional. + * When parsing in strict mode, the input must contain the mandatory + * and optional elements are defined by the specified pattern. + * If the offset cannot be parsed then an exception is thrown unless + * the section of the formatter is optional. + *

    + * When parsing in lenient mode, only the hours are mandatory - minutes + * and seconds are optional. The colons are required if the specified + * pattern contains a colon. If the specified pattern is "+HH", the + * presence of colons is determined by whether the character after the + * hour digits is a colon or not. + * If the offset cannot be parsed then an exception is thrown unless + * the section of the formatter is optional. *

    * The format of the offset is controlled by a pattern which must be one * of the following: @@ -902,6 +913,10 @@ public final class DateTimeFormatterBuilder { *

  • {@code +HH:MM:ss} - hour and minute, with second if non-zero, with colon *
  • {@code +HHMMSS} - hour, minute and second, no colon *
  • {@code +HH:MM:SS} - hour, minute and second, with colon + *
  • {@code +HHmmss} - hour, with minute if non-zero or with minute and + * second if non-zero, no colon + *
  • {@code +HH:mm:ss} - hour, with minute if non-zero or with minute and + * second if non-zero, with colon * * The "no offset" text controls what text is printed when the total amount of * the offset fields to be output is zero. @@ -1256,6 +1271,9 @@ public final class DateTimeFormatterBuilder { * During formatting, the chronology is obtained from the temporal object * being formatted, which may have been overridden by * {@link DateTimeFormatter#withChronology(Chronology)}. + * The {@code FULL} and {@code LONG} styles typically require a time-zone. + * When formatting using these styles, a {@code ZoneId} must be available, + * either by using {@code ZonedDateTime} or {@link DateTimeFormatter#withZone}. *

    * During parsing, if a chronology has already been parsed, then it is used. * Otherwise the default from {@code DateTimeFormatter.withChronology(Chronology)} @@ -3315,7 +3333,7 @@ public final class DateTimeFormatterBuilder { */ static final class OffsetIdPrinterParser implements DateTimePrinterParser { static final String[] PATTERNS = new String[] { - "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS", + "+HH", "+HHmm", "+HH:mm", "+HHMM", "+HH:MM", "+HHMMss", "+HH:MM:ss", "+HHMMSS", "+HH:MM:SS", "+HHmmss", "+HH:mm:ss", }; // order used in pattern builder static final OffsetIdPrinterParser INSTANCE_ID_Z = new OffsetIdPrinterParser("+HH:MM:ss", "Z"); static final OffsetIdPrinterParser INSTANCE_ID_ZERO = new OffsetIdPrinterParser("+HH:MM:ss", "0"); @@ -3362,11 +3380,11 @@ public final class DateTimeFormatterBuilder { int output = absHours; buf.append(totalSecs < 0 ? "-" : "+") .append((char) (absHours / 10 + '0')).append((char) (absHours % 10 + '0')); - if (type >= 3 || (type >= 1 && absMinutes > 0)) { + if ((type >= 3 && type < 9) || (type >= 9 && absSeconds > 0) || (type >= 1 && absMinutes > 0)) { buf.append((type % 2) == 0 ? ":" : "") .append((char) (absMinutes / 10 + '0')).append((char) (absMinutes % 10 + '0')); output += absMinutes; - if (type >= 7 || (type >= 5 && absSeconds > 0)) { + if (type == 7 || type == 8 || (type >= 5 && absSeconds > 0)) { buf.append((type % 2) == 0 ? ":" : "") .append((char) (absSeconds / 10 + '0')).append((char) (absSeconds % 10 + '0')); output += absSeconds; @@ -3384,6 +3402,15 @@ public final class DateTimeFormatterBuilder { public int parse(DateTimeParseContext context, CharSequence text, int position) { int length = text.length(); int noOffsetLen = noOffsetText.length(); + int parseType = type; + if (context.isStrict() == false) { + if ((parseType > 0 && (parseType % 2) == 0) || + (parseType == 0 && length > position + 3 && text.charAt(position + 3) == ':')) { + parseType = 10; + } else { + parseType = 9; + } + } if (noOffsetLen == 0) { if (position == length) { return context.setParsedField(OFFSET_SECONDS, 0, position, position); @@ -3404,9 +3431,9 @@ public final class DateTimeFormatterBuilder { int negative = (sign == '-' ? -1 : 1); int[] array = new int[4]; array[0] = position + 1; - if ((parseNumber(array, 1, text, true) || - parseNumber(array, 2, text, type >=3) || - parseNumber(array, 3, text, false)) == false) { + if ((parseNumber(array, 1, text, true, parseType) || + parseNumber(array, 2, text, parseType >= 3 && parseType < 9, parseType) || + parseNumber(array, 3, text, parseType == 7 || parseType == 8, parseType)) == false) { // success long offsetSecs = negative * (array[1] * 3600L + array[2] * 60L + array[3]); return context.setParsedField(OFFSET_SECONDS, offsetSecs, position, array[0]); @@ -3414,7 +3441,7 @@ public final class DateTimeFormatterBuilder { } // handle special case of empty no offset text if (noOffsetLen == 0) { - return context.setParsedField(OFFSET_SECONDS, 0, position, position + noOffsetLen); + return context.setParsedField(OFFSET_SECONDS, 0, position, position); } return ~position; } @@ -3426,14 +3453,15 @@ public final class DateTimeFormatterBuilder { * @param arrayIndex the index to parse the value into * @param parseText the offset ID, not null * @param required whether this number is required + * @param parseType the offset pattern type * @return true if an error occurred */ - private boolean parseNumber(int[] array, int arrayIndex, CharSequence parseText, boolean required) { - if ((type + 3) / 2 < arrayIndex) { + private boolean parseNumber(int[] array, int arrayIndex, CharSequence parseText, boolean required, int parseType) { + if ((parseType + 3) / 2 < arrayIndex) { return false; // ignore seconds/minutes } int pos = array[0]; - if ((type % 2) == 0 && arrayIndex > 1) { + if ((parseType % 2) == 0 && arrayIndex > 1) { if (pos + 1 > parseText.length() || parseText.charAt(pos) != ':') { return required; } diff --git a/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java b/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java index 310f6598fc9..811bd5b2ee1 100644 --- a/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimePrintContext.java @@ -218,6 +218,13 @@ final class DateTimePrintContext { } return query.queryFrom(this); } + + @Override + public String toString() { + return temporal + + (effectiveChrono != null ? " with chronology " + effectiveChrono : "") + + (effectiveZone != null ? " with zone " + effectiveZone : ""); + } }; } @@ -279,7 +286,8 @@ final class DateTimePrintContext { R getValue(TemporalQuery query) { R result = temporal.query(query); if (result == null && optional == 0) { - throw new DateTimeException("Unable to extract value: " + temporal.getClass()); + throw new DateTimeException("Unable to extract " + + query + " from temporal " + temporal); } return result; } diff --git a/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java b/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java index 6b1777a9471..9df66bb7cd2 100644 --- a/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java +++ b/jdk/src/java.base/share/classes/java/time/temporal/TemporalQueries.java @@ -341,58 +341,118 @@ public final class TemporalQueries { /** * A strict query for the {@code ZoneId}. */ - static final TemporalQuery ZONE_ID = (temporal) -> - temporal.query(TemporalQueries.ZONE_ID); + static final TemporalQuery ZONE_ID = new TemporalQuery<>() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.ZONE_ID); + } + + @Override + public String toString() { + return "ZoneId"; + } + }; /** * A query for the {@code Chronology}. */ - static final TemporalQuery CHRONO = (temporal) -> - temporal.query(TemporalQueries.CHRONO); + static final TemporalQuery CHRONO = new TemporalQuery<>() { + @Override + public Chronology queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.CHRONO); + } + + @Override + public String toString() { + return "Chronology"; + } + }; + /** * A query for the smallest supported unit. */ - static final TemporalQuery PRECISION = (temporal) -> - temporal.query(TemporalQueries.PRECISION); + static final TemporalQuery PRECISION = new TemporalQuery<>() { + @Override + public TemporalUnit queryFrom(TemporalAccessor temporal) { + return temporal.query(TemporalQueries.PRECISION); + } + + @Override + public String toString() { + return "Precision"; + } + }; //----------------------------------------------------------------------- /** * A query for {@code ZoneOffset} returning null if not found. */ - static final TemporalQuery OFFSET = (temporal) -> { - if (temporal.isSupported(OFFSET_SECONDS)) { - return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + static final TemporalQuery OFFSET = new TemporalQuery<>() { + @Override + public ZoneOffset queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(OFFSET_SECONDS)) { + return ZoneOffset.ofTotalSeconds(temporal.get(OFFSET_SECONDS)); + } + return null; + } + + @Override + public String toString() { + return "ZoneOffset"; } - return null; }; /** * A lenient query for the {@code ZoneId}, falling back to the {@code ZoneOffset}. */ - static final TemporalQuery ZONE = (temporal) -> { - ZoneId zone = temporal.query(ZONE_ID); - return (zone != null ? zone : temporal.query(OFFSET)); + static final TemporalQuery ZONE = new TemporalQuery<>() { + @Override + public ZoneId queryFrom(TemporalAccessor temporal) { + ZoneId zone = temporal.query(ZONE_ID); + return (zone != null ? zone : temporal.query(OFFSET)); + } + + @Override + public String toString() { + return "Zone"; + } }; /** * A query for {@code LocalDate} returning null if not found. */ - static final TemporalQuery LOCAL_DATE = (temporal) -> { - if (temporal.isSupported(EPOCH_DAY)) { - return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + static final TemporalQuery LOCAL_DATE = new TemporalQuery<>() { + @Override + public LocalDate queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(EPOCH_DAY)) { + return LocalDate.ofEpochDay(temporal.getLong(EPOCH_DAY)); + } + return null; + } + + @Override + public String toString() { + return "LocalDate"; } - return null; }; /** * A query for {@code LocalTime} returning null if not found. */ - static final TemporalQuery LOCAL_TIME = (temporal) -> { - if (temporal.isSupported(NANO_OF_DAY)) { - return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + static final TemporalQuery LOCAL_TIME = new TemporalQuery<>() { + @Override + public LocalTime queryFrom(TemporalAccessor temporal) { + if (temporal.isSupported(NANO_OF_DAY)) { + return LocalTime.ofNanoOfDay(temporal.getLong(NANO_OF_DAY)); + } + return null; + } + + @Override + public String toString() { + return "LocalTime"; } - return null; }; } diff --git a/jdk/src/java.base/share/classes/java/util/ArrayList.java b/jdk/src/java.base/share/classes/java/util/ArrayList.java index fca4ae228f3..8569de8129f 100644 --- a/jdk/src/java.base/share/classes/java/util/ArrayList.java +++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1281,8 +1281,74 @@ public class ArrayList extends AbstractList public Spliterator spliterator() { checkForComodification(); - return new ArrayListSpliterator<>(ArrayList.this, offset, - offset + this.size, this.modCount); + + return new Spliterator<>() { + private int index = offset; // current index, modified on advance/split + private int fence = -1; // -1 until used; then one past last index + private int expectedModCount; // initialized when fence set + + private int getFence() { // initialize fence to size on first use + int hi; // (a specialized variant appears in method forEach) + if ((hi = fence) < 0) { + expectedModCount = modCount; + hi = fence = offset + size; + } + return hi; + } + + public ArrayListSpliterator trySplit() { + int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; + return (lo >= mid) ? null : // divide range in half unless too small + new ArrayListSpliterator<>(ArrayList.this, lo, index = mid, + expectedModCount); + } + + public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); + int hi = getFence(), i = index; + if (i < hi) { + index = i + 1; + @SuppressWarnings("unchecked") E e = (E)elementData[i]; + action.accept(e); + if (ArrayList.this.modCount != expectedModCount) + throw new ConcurrentModificationException(); + return true; + } + return false; + } + + public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); + int i, hi, mc; // hoist accesses and checks from loop + ArrayList lst = ArrayList.this; + Object[] a; + if ((a = lst.elementData) != null) { + if ((hi = fence) < 0) { + mc = modCount; + hi = offset + size; + } + else + mc = expectedModCount; + if ((i = index) >= 0 && (index = hi) <= a.length) { + for (; i < hi; ++i) { + @SuppressWarnings("unchecked") E e = (E) a[i]; + action.accept(e); + } + if (lst.modCount == mc) + return; + } + } + throw new ConcurrentModificationException(); + } + + public long estimateSize() { + return (long) (getFence() - index); + } + + public int characteristics() { + return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; + } + }; } } diff --git a/jdk/src/java.base/share/classes/java/util/EnumMap.java b/jdk/src/java.base/share/classes/java/util/EnumMap.java index 686a0a9b98e..e6d63cf4ae8 100644 --- a/jdk/src/java.base/share/classes/java/util/EnumMap.java +++ b/jdk/src/java.base/share/classes/java/util/EnumMap.java @@ -718,7 +718,7 @@ public class EnumMap, V> extends AbstractMap } /** - * Returns a shallow copy of this enum map. (The values themselves + * Returns a shallow copy of this enum map. The values themselves * are not cloned. * * @return a shallow copy of this enum map 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 d6d79f5160d..80f7738cde3 100644 --- a/jdk/src/java.base/share/classes/java/util/ResourceBundle.java +++ b/jdk/src/java.base/share/classes/java/util/ResourceBundle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,10 @@ import java.io.InputStream; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.lang.reflect.Module; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; @@ -56,11 +60,16 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.jar.JarEntry; import java.util.spi.ResourceBundleControlProvider; +import java.util.spi.ResourceBundleProvider; +import jdk.internal.misc.JavaUtilResourceBundleAccess; +import jdk.internal.misc.SharedSecrets; import sun.reflect.CallerSensitive; import sun.reflect.Reflection; import sun.util.locale.BaseLocale; import sun.util.locale.LocaleObjectCache; +import sun.util.locale.provider.ResourceBundleProviderSupport; +import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; /** @@ -191,6 +200,56 @@ import sun.util.locale.LocaleObjectCache; * known concrete subclasses {@code ListResourceBundle} and * {@code PropertyResourceBundle} are thread-safe. * + *

    Resource Bundles in Named Modules

    + * + * When resource bundles are deployed in named modules, the following + * module-specific requirements and restrictions are applied. + * + *
      + *
    • Code in a named module that calls {@link #getBundle(String, Locale)} + * will locate resource bundles in the caller's module (caller module).
    • + *
    • If resource bundles are deployed in named modules separate from + * the caller module, those resource bundles need to be loaded from service + * providers of {@link ResourceBundleProvider}. The caller module must declare + * "{@code uses}" and the service interface name is the concatenation of the + * base name of the bundles and the string "{@code Provider}". The + * bundle provider modules containing resource bundles must + * declare "{@code provides}" with the service interface name and + * its implementation class name. For example, if the base name is + * "{@code com.example.app.MyResources}", the caller module must declare + * "{@code uses com.example.app.MyResourcesProvider;}" and a module containing resource + * bundles must declare "{@code provides com.example.app.MyResourcesProvider + * with com.example.app.internal.MyResourcesProviderImpl;}" + * where {@code com.example.app.internal.MyResourcesProviderImpl} is an + * implementation class of {@code com.example.app.MyResourcesProvider}.
    • + *
    • If you want to use non-standard formats in named modules, such as XML, + * {@link ResourceBundleProvider} needs to be used.
    • + *
    • The {@code getBundle} method with a {@code ClassLoader} may not be able to + * find resource bundles using the given {@code ClassLoader} in named modules. + * The {@code getBundle} method with a {@code Module} can be used, instead.
    • + *
    • {@code ResourceBundle.Control} is not supported in named modules. + * If the {@code getBundle} method with a {@code ResourceBundle.Control} is called + * in a named module, the method will throw an {@code UnsupportedOperationException}. + * Any service providers of {@link ResourceBundleControlProvider} are ignored in + * named modules. + *
    • + *
    + * + *

    ResourceBundleProvider Service Providers

    + * + * The {@code getBundle} factory methods load service providers of + * {@link ResourceBundleProvider}, if available, using {@link ServiceLoader}. + * The service type is designated by {@code basename+"Provider"}. For + * example, if the base name is "{@code com.example.app.MyResources}", the service + * type is {@code com.example.app.MyResourcesProvider}. + *

    + * In named modules, the loaded service providers for the given base name are + * used to load resource bundles. If no service provider is available, or if + * none of the service providers returns a resource bundle and the caller module + * doesn't have its own service provider, the {@code getBundle} factory method + * searches for resource bundles local to the caller module. The resource bundle + * formats for local module searching are "java.class" and "java.properties". + * *

    ResourceBundle.Control

    * * The {@link ResourceBundle.Control} class provides information necessary @@ -282,6 +341,7 @@ import sun.util.locale.LocaleObjectCache; * @see ListResourceBundle * @see PropertyResourceBundle * @see MissingResourceException + * @see ResourceBundleProvider * @since 1.1 */ public abstract class ResourceBundle { @@ -289,6 +349,32 @@ public abstract class ResourceBundle { /** initial size of the bundle cache */ private static final int INITIAL_CACHE_SIZE = 32; + static { + SharedSecrets.setJavaUtilResourceBundleAccess( + new JavaUtilResourceBundleAccess() { + @Override + public void setParent(ResourceBundle bundle, + ResourceBundle parent) { + bundle.setParent(parent); + } + + @Override + public ResourceBundle getParent(ResourceBundle bundle) { + return bundle.parent; + } + + @Override + public void setLocale(ResourceBundle bundle, Locale locale) { + bundle.locale = locale; + } + + @Override + public void setName(ResourceBundle bundle, String name) { + bundle.name = name; + } + }); + } + /** constant indicating that no resource bundle exists */ private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() { public Enumeration getKeys() { return null; } @@ -484,6 +570,11 @@ public abstract class ResourceBundle { return cl; } + private static ClassLoader getLoader(Module module) { + PrivilegedAction pa = module::getClassLoader; + return AccessController.doPrivileged(pa); + } + /** * A wrapper of ClassLoader.getSystemClassLoader(). */ @@ -494,23 +585,24 @@ public abstract class ResourceBundle { return new RBClassLoader(); } }); - private static final ClassLoader loader = ClassLoader.getSystemClassLoader(); - private RBClassLoader() { } public Class loadClass(String name) throws ClassNotFoundException { + ClassLoader loader = ClassLoader.getSystemClassLoader(); if (loader != null) { return loader.loadClass(name); } return Class.forName(name); } public URL getResource(String name) { + ClassLoader loader = ClassLoader.getSystemClassLoader(); if (loader != null) { return loader.getResource(name); } return ClassLoader.getSystemResource(name); } public InputStream getResourceAsStream(String name) { + ClassLoader loader = ClassLoader.getSystemClassLoader(); if (loader != null) { return loader.getResourceAsStream(name); } @@ -532,16 +624,18 @@ public abstract class ResourceBundle { /** * Key used for cached resource bundles. The key checks the base - * name, the locale, and the class loader to determine if the - * resource is a match to the requested one. The loader may be - * null, but the base name and the locale must have a non-null - * value. + * name, the locale, the class loader, and the caller module + * to determine if the resource is a match to the requested one. + * The loader may be null, but the base name, the locale and + * module must have a non-null value. */ private static class CacheKey implements Cloneable { - // These three are the actual keys for lookup in Map. + // These four are the actual keys for lookup in Map. private String name; private Locale locale; - private LoaderReference loaderRef; + private KeyElementReference loaderRef; + private KeyElementReference moduleRef; + // bundle format which is necessary for calling // Control.needsReload(). @@ -564,14 +658,24 @@ public abstract class ResourceBundle { // of this instance. private int hashCodeCache; - CacheKey(String baseName, Locale locale, ClassLoader loader) { + // ResourceBundleProviders for loading ResourceBundles + private ServiceLoader providers; + + // Boolean.TRUE if the factory method caller provides a ResourceBundleProvier. + private Boolean callerHasProvider; + + CacheKey(String baseName, Locale locale, ClassLoader loader, Module module) { + Objects.requireNonNull(module); + this.name = baseName; this.locale = locale; if (loader == null) { this.loaderRef = null; } else { - loaderRef = new LoaderReference(loader, referenceQueue, this); + this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this); } + this.moduleRef = new KeyElementReference<>(module, referenceQueue, this); + this.providers = getServiceLoader(module, baseName); calculateHashCode(); } @@ -603,6 +707,23 @@ public abstract class ResourceBundle { return (loaderRef != null) ? loaderRef.get() : null; } + Module getModule() { + return moduleRef.get(); + } + + ServiceLoader getProviders() { + return providers; + } + + boolean hasProviders() { + return providers != null; + } + + boolean callerHasProvider() { + return callerHasProvider == Boolean.TRUE; + } + + @Override public boolean equals(Object other) { if (this == other) { return true; @@ -625,18 +746,22 @@ public abstract class ResourceBundle { if (loaderRef == null) { return otherEntry.loaderRef == null; } - ClassLoader loader = loaderRef.get(); + ClassLoader loader = getLoader(); + Module module = getModule(); return (otherEntry.loaderRef != null) // with a null reference we can no longer find - // out which class loader was referenced; so + // out which class loader or module was referenced; so // treat it as unequal && (loader != null) - && (loader == otherEntry.loaderRef.get()); - } catch ( NullPointerException | ClassCastException e) { + && (loader == otherEntry.getLoader()) + && (module != null) + && (module.equals(otherEntry.getModule())); + } catch (NullPointerException | ClassCastException e) { } return false; } + @Override public int hashCode() { return hashCodeCache; } @@ -648,17 +773,28 @@ public abstract class ResourceBundle { if (loader != null) { hashCodeCache ^= loader.hashCode(); } + Module module = getModule(); + if (module != null) { + hashCodeCache ^= module.hashCode(); + } } + @Override public Object clone() { try { CacheKey clone = (CacheKey) super.clone(); if (loaderRef != null) { - clone.loaderRef = new LoaderReference(loaderRef.get(), - referenceQueue, clone); + clone.loaderRef = new KeyElementReference<>(getLoader(), + referenceQueue, clone); } + clone.moduleRef = new KeyElementReference<>(getModule(), + referenceQueue, clone); + // Clear the reference to ResourceBundleProviders + clone.providers = null; // Clear the reference to a Throwable clone.cause = null; + // Clear callerHasProvider + clone.callerHasProvider = null; return clone; } catch (CloneNotSupportedException e) { //this should never happen @@ -690,6 +826,7 @@ public abstract class ResourceBundle { return cause; } + @Override public String toString() { String l = locale.toString(); if (l.length() == 0) { @@ -713,19 +850,19 @@ public abstract class ResourceBundle { } /** - * References to class loaders are weak references, so that they can be - * garbage collected when nobody else is using them. The ResourceBundle - * class has no reason to keep class loaders alive. + * References to a CacheKey element as a WeakReference so that it can be + * garbage collected when nobody else is using it. */ - private static class LoaderReference extends WeakReference - implements CacheKeyReference { - private CacheKey cacheKey; + private static class KeyElementReference extends WeakReference + implements CacheKeyReference { + private final CacheKey cacheKey; - LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) { + KeyElementReference(T referent, ReferenceQueue q, CacheKey key) { super(referent, q); cacheKey = key; } + @Override public CacheKey getCacheKey() { return cacheKey; } @@ -737,13 +874,14 @@ public abstract class ResourceBundle { */ private static class BundleReference extends SoftReference implements CacheKeyReference { - private CacheKey cacheKey; + private final CacheKey cacheKey; BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) { super(referent, q); cacheKey = key; } + @Override public CacheKey getCacheKey() { return cacheKey; } @@ -770,9 +908,9 @@ public abstract class ResourceBundle { @CallerSensitive public static final ResourceBundle getBundle(String baseName) { + Class caller = Reflection.getCallerClass(); return getBundleImpl(baseName, Locale.getDefault(), - getLoader(Reflection.getCallerClass()), - getDefaultControl(baseName)); + caller, getDefaultControl(caller, baseName)); } /** @@ -795,26 +933,28 @@ public abstract class ResourceBundle { * @param control * the control which gives information for the resource bundle * loading process - * @return a resource bundle for the given base name and the default - * locale - * @exception NullPointerException - * if baseName or control is - * null - * @exception MissingResourceException - * if no resource bundle for the specified base name can be found - * @exception IllegalArgumentException - * if the given control doesn't perform properly - * (e.g., control.getCandidateLocales returns null.) - * Note that validation of control is performed as - * needed. + * @return a resource bundle for the given base name and the default locale + * @throws NullPointerException + * if baseName or control is + * null + * @throws MissingResourceException + * if no resource bundle for the specified base name can be found + * @throws IllegalArgumentException + * if the given control doesn't perform properly + * (e.g., control.getCandidateLocales returns null.) + * Note that validation of control is performed as + * needed. + * @throws UnsupportedOperationException + * if this method is called in a named module * @since 1.6 */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Control control) { - return getBundleImpl(baseName, Locale.getDefault(), - getLoader(Reflection.getCallerClass()), - control); + Class caller = Reflection.getCallerClass(); + Locale targetLocale = Locale.getDefault(); + checkNamedModule(caller); + return getBundleImpl(baseName, targetLocale, caller, control); } /** @@ -842,9 +982,78 @@ public abstract class ResourceBundle { public static final ResourceBundle getBundle(String baseName, Locale locale) { + Class caller = Reflection.getCallerClass(); return getBundleImpl(baseName, locale, - getLoader(Reflection.getCallerClass()), - getDefaultControl(baseName)); + caller, getDefaultControl(caller, baseName)); + } + + /** + * Gets a resource bundle using the specified base name and the default locale + * on behalf of the specified module. This method is equivalent to calling + *
    + * getBundle(baseName, Locale.getDefault(), module) + *
    + * + * @param baseName the base name of the resource bundle, + * a fully qualified class name + * @param module the module for which the resource bundle is searched + * @throws NullPointerException + * if {@code baseName} or {@code module} is {@code null} + * @throws SecurityException + * if a security manager exists and the caller is not the specified + * module and doesn't have {@code RuntimePermission("getClassLoader")} + * @throws MissingResourceException + * if no resource bundle for the specified base name can be found in the + * specified module + * @return a resource bundle for the given base name and the default locale + * @since 9 + * @see ResourceBundleProvider + */ + @CallerSensitive + public static ResourceBundle getBundle(String baseName, Module module) { + return getBundleFromModule(Reflection.getCallerClass(), module, baseName, + Locale.getDefault(), Control.INSTANCE); + } + + /** + * Gets a resource bundle using the specified base name and locale + * on behalf of the specified module. + * + *

    + * If the given {@code module} is a named module, this method will + * load the service providers for {@link java.util.spi.ResourceBundleProvider} + * and also resource bundles local in the given module (refer to the + * Resource Bundles in Named Modules section + * for details). + * + *

    + * If the given {@code module} is an unnamed module, then this method is + * equivalent to calling {@link #getBundle(String, Locale, ClassLoader) + * getBundle(baseName, targetLocale, module.getClassLoader()} to load + * resource bundles that are in unnamed modules visible to the + * class loader of the given unnamed module. It will not find resource + * bundles from named modules. + * + * @param baseName the base name of the resource bundle, + * a fully qualified class name + * @param targetLocale the locale for which a resource bundle is desired + * @param module the module for which the resource bundle is searched + * @throws NullPointerException + * if {@code baseName}, {@code targetLocale}, or {@code module} is + * {@code null} + * @throws SecurityException + * if a security manager exists and the caller is not the specified + * module and doesn't have {@code RuntimePermission("getClassLoader")} + * @throws MissingResourceException + * if no resource bundle for the specified base name and locale can + * be found in the specified {@code module} + * @return a resource bundle for the given base name and locale in the module + * @since 9 + */ + @CallerSensitive + public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) { + return getBundleFromModule(Reflection.getCallerClass(), module, baseName, targetLocale, + Control.INSTANCE); } /** @@ -870,26 +1079,28 @@ public abstract class ResourceBundle { * the control which gives information for the resource * bundle loading process * @return a resource bundle for the given base name and a - * Locale in locales - * @exception NullPointerException - * if baseName, locales or - * control is null - * @exception MissingResourceException - * if no resource bundle for the specified base name in any - * of the locales can be found. - * @exception IllegalArgumentException - * if the given control doesn't perform properly - * (e.g., control.getCandidateLocales returns null.) - * Note that validation of control is performed as - * needed. + * Locale in locales + * @throws NullPointerException + * if baseName, locales or + * control is null + * @throws MissingResourceException + * if no resource bundle for the specified base name in any + * of the locales can be found. + * @throws IllegalArgumentException + * if the given control doesn't perform properly + * (e.g., control.getCandidateLocales returns null.) + * Note that validation of control is performed as + * needed. + * @throws UnsupportedOperationException + * if this method is called in a named module * @since 1.6 */ @CallerSensitive public static final ResourceBundle getBundle(String baseName, Locale targetLocale, Control control) { - return getBundleImpl(baseName, targetLocale, - getLoader(Reflection.getCallerClass()), - control); + Class caller = Reflection.getCallerClass(); + checkNamedModule(caller); + return getBundleImpl(baseName, targetLocale, caller, control); } /** @@ -906,6 +1117,16 @@ public abstract class ResourceBundle { *

    The following describes the default * behavior. * + *

    + * Resource bundles in a named module are private to that module. If + * the caller is in a named module, this method will find resource bundles + * from the service providers of {@link java.util.spi.ResourceBundleProvider} + * and also find resource bundles private to the caller's module. + * If the caller is in a named module and the given {@code loader} is + * different than the caller's class loader, or if the caller is not in + * a named module, this method will not find resource bundles from named + * modules. + * *

    getBundle uses the base name, the specified locale, and * the default locale (obtained from {@link java.util.Locale#getDefault() * Locale.getDefault}) to generate a sequence of default behavior. + * Note that this class is not supported in named modules. * *

    In addition to the callback methods, the {@link * #toBundleName(String, Locale) toBundleName} and {@link @@ -2006,7 +2470,14 @@ public abstract class ResourceBundle { * } * * + * @apiNote {@code ResourceBundle.Control} is not supported + * in named modules. If the {@code ResourceBundle.getBundle} method with + * a {@code ResourceBundle.Control} is called in a named module, the method + * will throw an {@link UnsupportedOperationException}. Any service providers + * of {@link ResourceBundleControlProvider} are ignored in named modules. + * * @since 1.6 + * @see java.util.spi.ResourceBundleProvider */ public static class Control { /** @@ -2623,56 +3094,81 @@ public abstract class ResourceBundle { * @exception IOException * if an error occurred when reading resources using * any I/O operations + * @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale) */ public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { + /* + * Legacy mechanism to locate resource bundle in unnamed module only + * that is visible to the given loader and accessible to the given caller. + * This only finds resources on the class path but not in named modules. + */ String bundleName = toBundleName(baseName, locale); ResourceBundle bundle = null; if (format.equals("java.class")) { try { - @SuppressWarnings("unchecked") - Class bundleClass - = (Class)loader.loadClass(bundleName); - + Class c = loader.loadClass(bundleName); // If the class isn't a ResourceBundle subclass, throw a // ClassCastException. - if (ResourceBundle.class.isAssignableFrom(bundleClass)) { - bundle = bundleClass.newInstance(); + if (ResourceBundle.class.isAssignableFrom(c)) { + @SuppressWarnings("unchecked") + Class bundleClass = (Class)c; + + // This doesn't allow unnamed modules to find bundles in + // named modules other than via the service loader mechanism. + // Otherwise, this will make the newBundle method to be + // caller-sensitive in order to verify access check. + // So migrating resource bundles to named module can't + // just export the package (in general, legacy resource + // bundles have split package if they are packaged separate + // from the consumer.) + if (bundleClass.getModule().isNamed()) { + throw new IllegalAccessException("unnamed modules can't load " + bundleName + + " in named module " + bundleClass.getModule().getName()); + } + try { + // bundle in a unnamed module + Constructor ctor = bundleClass.getConstructor(); + if (!Modifier.isPublic(ctor.getModifiers())) { + return null; + } + + // java.base may not be able to read the bundleClass's module. + PrivilegedAction pa1 = () -> { ctor.setAccessible(true); return null; }; + AccessController.doPrivileged(pa1); + bundle = ctor.newInstance((Object[]) null); + } catch (InvocationTargetException e) { + uncheckedThrow(e); + } } else { - throw new ClassCastException(bundleClass.getName() - + " cannot be cast to ResourceBundle"); + throw new ClassCastException(c.getName() + + " cannot be cast to ResourceBundle"); } - } catch (ClassNotFoundException e) { + } catch (ClassNotFoundException|NoSuchMethodException e) { } } else if (format.equals("java.properties")) { final String resourceName = toResourceName0(bundleName, "properties"); if (resourceName == null) { return bundle; } - final ClassLoader classLoader = loader; + final boolean reloadFlag = reload; InputStream stream = null; try { stream = AccessController.doPrivileged( new PrivilegedExceptionAction<>() { public InputStream run() throws IOException { - InputStream is = null; + URL url = loader.getResource(resourceName); + if (url == null) return null; + + URLConnection connection = url.openConnection(); if (reloadFlag) { - URL url = classLoader.getResource(resourceName); - if (url != null) { - URLConnection connection = url.openConnection(); - if (connection != null) { - // Disable caches to get fresh data for - // reloading. - connection.setUseCaches(false); - is = connection.getInputStream(); - } - } - } else { - is = classLoader.getResourceAsStream(resourceName); + // Disable caches to get fresh data for + // reloading. + connection.setUseCaches(false); } - return is; + return connection.getInputStream(); } }); } catch (PrivilegedActionException e) { @@ -2753,6 +3249,7 @@ public abstract class ResourceBundle { * the Calendar * Epoch. * + *

    * The calling ResourceBundle.getBundle factory method * calls this method on the ResourceBundle.Control * instance used for its current invocation, not on the instance @@ -2877,6 +3374,7 @@ public abstract class ResourceBundle { * @exception NullPointerException * if baseName or locale * is null + * @see java.util.spi.AbstractResourceBundleProvider#toBundleName(String, Locale) */ public String toBundleName(String baseName, Locale locale) { if (locale == Locale.ROOT) { @@ -2951,6 +3449,14 @@ public abstract class ResourceBundle { } } + @SuppressWarnings("unchecked") + private static void uncheckedThrow(Throwable t) throws T { + if (t != null) + throw (T)t; + else + throw new Error("Unknown Exception"); + } + private static class SingleFormatControl extends Control { private static final Control PROPERTIES_ONLY = new SingleFormatControl(FORMAT_PROPERTIES); 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 cf158916d07..8d38e785709 100644 --- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,15 +29,30 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Layer; +import java.lang.reflect.Modifier; +import java.lang.reflect.Module; import java.net.URL; +import java.net.URLConnection; import java.security.AccessController; import java.security.AccessControlContext; import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; + +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.Loader; +import jdk.internal.loader.LoaderPool; +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.VM; +import jdk.internal.module.ServicesCatalog; +import jdk.internal.module.ServicesCatalog.ServiceProvider; + +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; /** @@ -47,8 +62,11 @@ import java.util.NoSuchElementException; * abstract) classes. A service provider is a specific implementation * of a service. The classes in a provider typically implement the interfaces * and subclass the classes defined in the service itself. - * Providers can be made available by adding them to the - * application's class path or by some other platform-specific means. + * Providers may be developed and deployed as modules and made available using + * the application module path. Providers may alternatively be packaged as JAR + * files and made available by adding them to the application class path. The + * advantage of developing a provider as a module is that the provider can be + * fully encapsulated to hide all details of its implementation. * *

    For the purpose of loading, a service is represented by a single type, * that is, a single interface or abstract class. (A concrete class can be @@ -60,27 +78,38 @@ import java.util.NoSuchElementException; * request together with code that can create the actual provider on demand. * The details of provider classes tend to be highly service-specific; no * single class or interface could possibly unify them, so no such type is - * defined here. The only requirement enforced by this facility is that - * provider classes must have a zero-argument constructor so that they can be - * instantiated during loading. + * defined here. A requirement enforced by this facility is that each provider + * class must have a {@code public} zero-argument constructor. * - *

    A service provider is identified by placing a - * provider-configuration file in the resource directory - * META-INF/services. The file's name is the fully-qualified binary name of the service's type. - * The file contains a list of fully-qualified binary names of concrete + *

    An application or library using this loading facility and developed + * and deployed as a named 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 modules 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 + * providers of the service. In the case of {@code load} methods that locate + * service providers using a class loader, then provider modules defined to + * that class loader, or a class loader reachable using {@link + * ClassLoader#getParent() parent} delegation, will be located. + * + *

    A service provider that is packaged as a JAR file for the class path is + * identified by placing a provider-configuration file in the resource + * directory META-INF/services. The file's name is the fully-qualified + * binary name of the service's + * type. The file contains a list of fully-qualified binary names of concrete * provider classes, one per line. Space and tab characters surrounding each * name, as well as blank lines, are ignored. The comment character is * '#' ('\u0023', * NUMBER SIGN); on * each line all characters following the first comment character are ignored. * The file must be encoded in UTF-8. - * - *

    If a particular concrete provider class is named in more than one + * If a particular concrete provider class is named in more than one * configuration file, or is named in the same configuration file more than * once, then the duplicates are ignored. The configuration file naming a - * particular provider need not be in the same jar file or other distribution - * unit as the provider itself. The provider must be accessible from the same + * particular provider need not be in the same JAR file or other distribution + * unit as the provider itself. The provider must be visible from the same * class loader that was initially queried to locate the configuration file; * note that this is not necessarily the class loader from which the file was * actually loaded. @@ -93,7 +122,9 @@ import java.util.NoSuchElementException; * providers, adding each one to the cache in turn. The cache can be cleared * via the {@link #reload reload} method. * - *

    Service loaders always execute in the security context of the caller. + *

    Service loaders always execute in the security context of the caller + * of the iterator methods and may also be restricted by the security + * context of the caller that created the service loader. * Trusted system code should typically invoke the methods in this class, and * the methods of the iterators which they return, from within a privileged * security context. @@ -104,7 +135,6 @@ import java.util.NoSuchElementException; *

    Unless otherwise specified, passing a null argument to any * method in this class will cause a {@link NullPointerException} to be thrown. * - * *

    Example * Suppose we have a service type com.example.CodecSet which is * intended to represent sets of encoder/decoder pairs for some protocol. In @@ -118,30 +148,20 @@ import java.util.NoSuchElementException; * does not support the given encoding. Typical providers support more than * one encoding. * - *

    If com.example.impl.StandardCodecs is an implementation of the - * CodecSet service then its jar file also contains a file named - * - *

    - * META-INF/services/com.example.CodecSet
    - * - *

    This file contains the single line: - * - *

    - * com.example.impl.StandardCodecs    # Standard codecs
    - * *

    The CodecSet class creates and saves a single service instance * at initialization: * - *

    - * private static ServiceLoader<CodecSet> codecSetLoader
    - *     = ServiceLoader.load(CodecSet.class);
    + *
    {@code
    + * private static ServiceLoader codecSetLoader
    + *     = ServiceLoader.load(CodecSet.class);
    + * }
    * *

    To locate an encoder for a given encoding name it defines a static * factory method which iterates through the known and available providers, * returning only when it has located a suitable encoder or has run out of * providers. * - *

    + * 
    {@code
      * public static Encoder getEncoder(String encodingName) {
      *     for (CodecSet cp : codecSetLoader) {
      *         Encoder enc = cp.getEncoder(encodingName);
    @@ -149,10 +169,27 @@ import java.util.NoSuchElementException;
      *             return enc;
      *     }
      *     return null;
    - * }
    + * }} * - *

    A getDecoder method is defined similarly. + *

    A {@code getDecoder} method is defined similarly. * + *

    If the code creating and using the service loader is developed as + * a module then its module descriptor will declare the usage with: + *

    {@code uses com.example.CodecSet;}
    + * + *

    Now suppose that {@code com.example.impl.StandardCodecs} is an + * implementation of the {@code CodecSet} service and developed as a module. + * In that case then the module with the service provider module will declare + * this in its module descriptor: + *

    {@code provides com.example.CodecSet with com.example.impl.StandardCodecs;
    + * }
    + * + *

    On the other hand, suppose {@code com.example.impl.StandardCodecs} is + * packaged in a JAR file for the class path then the JAR file will contain a + * file named: + *

    {@code META-INF/services/com.example.CodecSet}
    + * that contains the single line: + *
    {@code com.example.impl.StandardCodecs    # Standard codecs}
    * *

    Usage Note If * the class path of a class loader that is used for provider loading includes @@ -183,23 +220,43 @@ import java.util.NoSuchElementException; public final class ServiceLoader implements Iterable { - private static final String PREFIX = "META-INF/services/"; // The class or interface representing the service being loaded private final Class service; - // The class loader used to locate, load, and instantiate providers + // The module Layer used to locate providers; null when locating + // providers using a class loader + private final Layer layer; + + // The class loader used to locate, load, and instantiate providers; + // null when locating provider using a module Layer private final ClassLoader loader; // The access control context taken when the ServiceLoader is created private final AccessControlContext acc; // Cached providers, in instantiation order - private LinkedHashMap providers = new LinkedHashMap<>(); + private List providers = new ArrayList<>(); + + // The class names of the cached providers, only used when locating + // service providers via a class loader + private Set providerNames = new HashSet<>(); + + // Incremented when reload is called + private int reloadCount; + + // the service iterator when locating services via a module layer + private LayerLookupIterator layerLookupIterator; + + // The module services iterator when locating services in modules + // defined to a class loader + private ModuleServicesIterator moduleServicesIterator; + + // The current lazy-lookup iterator for locating legacy provider on the + // class path via a class loader + private LazyClassPathIterator lazyClassPathIterator; - // The current lazy-lookup iterator - private LazyIterator lookupIterator; /** * Clear this loader's provider cache so that all providers will be @@ -214,16 +271,110 @@ public final class ServiceLoader */ public void reload() { providers.clear(); - lookupIterator = new LazyIterator(service, loader); + + assert layer == null || loader == null; + if (layer != null) { + layerLookupIterator = new LayerLookupIterator(); + } else { + providerNames.clear(); + moduleServicesIterator = new ModuleServicesIterator(); + lazyClassPathIterator = new LazyClassPathIterator(); + } + + reloadCount++; } - private ServiceLoader(Class svc, ClassLoader cl) { - service = Objects.requireNonNull(svc, "Service interface cannot be null"); - loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl; - acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null; + + /** + * Initializes a new instance of this class for locating service providers + * in a module Layer. + * + * @throws ServiceConfigurationError + * If {@code svc} is not accessible to {@code caller} or that the + * caller's module does not declare that it uses the service type. + */ + private ServiceLoader(Class caller, Layer layer, Class svc) { + + checkModule(caller.getModule(), svc); + + this.service = svc; + this.layer = layer; + this.loader = null; + this.acc = (System.getSecurityManager() != null) + ? AccessController.getContext() + : null; + reload(); } + /** + * Initializes a new instance of this class for locating service providers + * via a class loader. + * + * @throws ServiceConfigurationError + * If {@code svc} is not accessible to {@code caller} or that the + * caller's module does not declare that it uses the service type. + */ + private ServiceLoader(Module callerModule, Class svc, ClassLoader cl) { + if (VM.isBooted()) { + + checkModule(callerModule, svc); + + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + + } else { + + // if we get here then it means that ServiceLoader is being used + // before the VM initialization has completed. At this point then + // only code in the java.base should be executing. + Module base = Object.class.getModule(); + Module svcModule = svc.getModule(); + if (callerModule != base || svcModule != base) { + fail(svc, "not accessible to " + callerModule + " during VM init"); + } + + // restricted to boot loader during startup + cl = null; + } + + this.service = svc; + this.layer = null; + this.loader = cl; + this.acc = (System.getSecurityManager() != null) + ? AccessController.getContext() + : null; + + reload(); + } + + private ServiceLoader(Class caller, Class svc, ClassLoader cl) { + this(caller.getModule(), svc, cl); + } + + + + /** + * Checks that the given service type is accessible to types in the given + * module, and check that the module declare that it uses the service type. + */ + private static void checkModule(Module module, Class svc) { + + // Check that the service type is in a package that is + // exported to the caller. + if (!Reflection.verifyModuleAccess(module, svc)) { + fail(svc, "not accessible to " + module); + } + + // If the caller is in a named module then it should "uses" the + // service type + if (!module.canUse(svc)) { + fail(svc, "use not declared in " + module); + } + + } + private static void fail(Class service, String msg, Throwable cause) throws ServiceConfigurationError { @@ -269,71 +420,373 @@ public final class ServiceLoader if (!Character.isJavaIdentifierPart(cp) && (cp != '.')) fail(service, u, lc, "Illegal provider-class name: " + ln); } - if (!providers.containsKey(ln) && !names.contains(ln)) + if (!providerNames.contains(ln) && !names.contains(ln)) names.add(ln); } return lc + 1; } - // Parse the content of the given URL as a provider-configuration file. - // - // @param service - // The service type for which providers are being sought; - // used to construct error detail strings - // - // @param u - // The URL naming the configuration file to be parsed - // - // @return A (possibly empty) iterator that will yield the provider-class - // names in the given configuration file that are not yet members - // of the returned set - // - // @throws ServiceConfigurationError - // If an I/O error occurs while reading from the given URL, or - // if a configuration-file format error is detected - // + /** + * Parse the content of the given URL as a provider-configuration file. + * + * @param service + * The service type for which providers are being sought; + * used to construct error detail strings + * + * @param u + * The URL naming the configuration file to be parsed + * + * @return A (possibly empty) iterator that will yield the provider-class + * names in the given configuration file that are not yet members + * of the returned set + * + * @throws ServiceConfigurationError + * If an I/O error occurs while reading from the given URL, or + * if a configuration-file format error is detected + * + */ private Iterator parse(Class service, URL u) throws ServiceConfigurationError { - InputStream in = null; - BufferedReader r = null; ArrayList names = new ArrayList<>(); try { - in = u.openStream(); - r = new BufferedReader(new InputStreamReader(in, "utf-8")); - int lc = 1; - while ((lc = parseLine(service, u, r, lc, names)) >= 0); - } catch (IOException x) { - fail(service, "Error reading configuration file", x); - } finally { - try { - if (r != null) r.close(); - if (in != null) in.close(); - } catch (IOException y) { - fail(service, "Error closing configuration file", y); + URLConnection uc = u.openConnection(); + uc.setUseCaches(false); + try (InputStream in = uc.getInputStream(); + BufferedReader r + = new BufferedReader(new InputStreamReader(in, "utf-8"))) + { + int lc = 1; + while ((lc = parseLine(service, u, r, lc, names)) >= 0); } + } catch (IOException x) { + fail(service, "Error accessing configuration file", x); } return names.iterator(); } - // Private inner class implementing fully-lazy provider lookup - // - private class LazyIterator - implements Iterator + /** + * Returns the {@code Constructor} to instantiate the service provider. + * The constructor has its accessible flag set so that the access check + * is suppressed when instantiating the provider. This is necessary + * because newInstance is a caller sensitive method and ServiceLoader + * is instantiating the service provider on behalf of the service + * consumer. + */ + private static Constructor checkAndGetConstructor(Class c) + throws NoSuchMethodException, IllegalAccessException { + Constructor ctor = c.getConstructor(); - Class service; - ClassLoader loader; - Enumeration configs = null; - Iterator pending = null; - String nextName = null; - - private LazyIterator(Class service, ClassLoader loader) { - this.service = service; - this.loader = loader; + // check class and no-arg constructor are public + int modifiers = ctor.getModifiers(); + if (!Modifier.isPublic(Reflection.getClassAccessFlags(c) & modifiers)) { + String cn = c.getName(); + throw new IllegalAccessException(cn + " is not public"); } - private boolean hasNextService() { + // return Constructor to create the service implementation + PrivilegedAction action = new PrivilegedAction() { + public Void run() { ctor.setAccessible(true); return null; } + }; + AccessController.doPrivileged(action); + return ctor; + } + + /** + * Uses Class.forName to load a class in a module. + */ + private static Class loadClassInModule(Module module, String cn) { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return Class.forName(module, cn); + } else { + PrivilegedAction> pa = () -> Class.forName(module, cn); + return AccessController.doPrivileged(pa); + } + } + + /** + * An Iterator that runs the next and hasNext methods with permissions + * restricted by the {@code AccessControlContext} obtained when the + * ServiceLoader was created. + */ + private abstract class RestrictedIterator + implements Iterator + { + /** + * Returns {@code true} if the iteration has more elements. + */ + abstract boolean hasNextService(); + + /** + * Returns the next element in the iteration + */ + abstract S nextService(); + + public final boolean hasNext() { + if (acc == null) { + return hasNextService(); + } else { + PrivilegedAction action = new PrivilegedAction() { + public Boolean run() { return hasNextService(); } + }; + return AccessController.doPrivileged(action, acc); + } + } + + public final S next() { + if (acc == null) { + return nextService(); + } else { + PrivilegedAction action = new PrivilegedAction() { + public S run() { return nextService(); } + }; + return AccessController.doPrivileged(action, acc); + } + } + } + + /** + * Implements lazy service provider lookup of service providers that + * are provided by modules in a module Layer. + * + * For now, this iterator examines all modules in each Layer. This will + * be replaced once we decide on how the service-use graph is exposed + * in the module API. + */ + private class LayerLookupIterator + extends RestrictedIterator + { + final String serviceName; + Layer currentLayer; + Iterator descriptorIterator; + Iterator providersIterator; + + Module nextModule; + String nextProvider; + + LayerLookupIterator() { + serviceName = service.getName(); + currentLayer = layer; + + // need to get us started + descriptorIterator = descriptors(layer, serviceName); + } + + Iterator descriptors(Layer layer, String service) { + return layer.modules().stream() + .map(Module::getDescriptor) + .filter(d -> d.provides().get(service) != null) + .iterator(); + } + + @Override + boolean hasNextService() { + + // already have the next provider cached + if (nextProvider != null) + return true; + + while (true) { + + // next provider + if (providersIterator != null && providersIterator.hasNext()) { + nextProvider = providersIterator.next(); + return true; + } + + // next descriptor + if (descriptorIterator.hasNext()) { + ModuleDescriptor descriptor = descriptorIterator.next(); + + nextModule = currentLayer.findModule(descriptor.name()).get(); + + Provides provides = descriptor.provides().get(serviceName); + providersIterator = provides.providers().iterator(); + + continue; + } + + // next layer + Layer parent = currentLayer.parent().orElse(null); + if (parent == null) + return false; + + currentLayer = parent; + descriptorIterator = descriptors(currentLayer, serviceName); + } + } + + @Override + S nextService() { + if (!hasNextService()) + throw new NoSuchElementException(); + + assert nextModule != null && nextProvider != null; + + String cn = nextProvider; + nextProvider = null; + + // attempt to load the provider + Class c = loadClassInModule(nextModule, cn); + if (c == null) + fail(service, "Provider " + cn + " not found"); + if (!service.isAssignableFrom(c)) + fail(service, "Provider " + cn + " not a subtype"); + + // instantiate the provider + S p = null; + try { + Constructor ctor = checkAndGetConstructor(c); + p = service.cast(ctor.newInstance()); + } catch (Throwable x) { + if (x instanceof InvocationTargetException) + x = x.getCause(); + fail(service, + "Provider " + cn + " could not be instantiated", x); + } + + // add to cached provider list + providers.add(p); + + return p; + } + } + + /** + * Implements lazy service provider lookup of service providers that + * are provided by modules defined to a class loader. + */ + private class ModuleServicesIterator + extends RestrictedIterator + { + final JavaLangAccess langAccess = SharedSecrets.getJavaLangAccess(); + + ClassLoader currentLoader; + Iterator iterator; + ServiceProvider nextProvider; + + ModuleServicesIterator() { + this.currentLoader = loader; + this.iterator = iteratorFor(loader); + } + + /** + * Returns an iterator to iterate over the implementations of {@code + * service} in modules defined to the given class loader. + */ + private Iterator iteratorFor(ClassLoader loader) { + + // if the class loader is in a loader pool then return an Iterator + // that iterates over all service providers in the pool that provide + // an implementation of the service + if (currentLoader instanceof Loader) { + LoaderPool pool = ((Loader) loader).pool(); + if (pool != null) { + return pool.loaders() + .map(l -> langAccess.getServicesCatalog(l)) + .filter(sc -> sc != null) + .map(sc -> sc.findServices(service.getName())) + .flatMap(Set::stream) + .iterator(); + } + } + + ServicesCatalog catalog; + if (currentLoader == null) { + catalog = BootLoader.getServicesCatalog(); + } else { + catalog = langAccess.getServicesCatalog(currentLoader); + } + if (catalog == null) { + return Collections.emptyIterator(); + } else { + return catalog.findServices(service.getName()).iterator(); + } + } + + @Override + boolean hasNextService() { + // already have the next provider cached + if (nextProvider != null) + return true; + + while (true) { + if (iterator.hasNext()) { + nextProvider = iterator.next(); + return true; + } + + // move to the next class loader if possible + if (currentLoader == null) { + return false; + } else { + currentLoader = currentLoader.getParent(); + iterator = iteratorFor(currentLoader); + } + } + } + + @Override + S nextService() { + if (!hasNextService()) + throw new NoSuchElementException(); + + ServiceProvider provider = nextProvider; + nextProvider = null; + + // attempt to load the provider + Module module = provider.module(); + String cn = provider.providerName(); + + Class c = loadClassInModule(module, cn); + if (c == null) { + fail(service, + "Provider " + cn + " not found in " + module.getName()); + } + if (!service.isAssignableFrom(c)) { + fail(service, "Provider " + cn + " not a subtype"); + } + + // instantiate the provider + S p = null; + try { + Constructor ctor = checkAndGetConstructor(c); + p = service.cast(ctor.newInstance()); + } catch (Throwable x) { + if (x instanceof InvocationTargetException) + x = x.getCause(); + fail(service, + "Provider " + cn + " could not be instantiated", x); + } + + // add to provider list + providers.add(p); + + // record the class name of the service provider, this is + // needed for cases where there a module has both a "uses" + // and a services configuration file listing the same + // provider + providerNames.add(cn); + + return p; + } + } + + /** + * Implements lazy service provider lookup where the service providers + * are configured via service configuration files. + */ + private class LazyClassPathIterator + extends RestrictedIterator + { + Enumeration configs; + Iterator pending; + String nextName; + + @Override + boolean hasNextService() { if (nextName != null) { return true; } @@ -358,7 +811,8 @@ public final class ServiceLoader return true; } - private S nextService() { + @Override + S nextService() { if (!hasNextService()) throw new NoSuchElementException(); String cn = nextName; @@ -374,44 +828,18 @@ public final class ServiceLoader fail(service, "Provider " + cn + " not a subtype"); } + S p = null; try { - S p = service.cast(c.newInstance()); - providers.put(cn, p); - return p; + p = service.cast(c.newInstance()); } catch (Throwable x) { fail(service, "Provider " + cn + " could not be instantiated", x); } - throw new Error(); // This cannot happen + providers.add(p); + providerNames.add(cn); + return p; } - - public boolean hasNext() { - if (acc == null) { - return hasNextService(); - } else { - PrivilegedAction action = new PrivilegedAction() { - public Boolean run() { return hasNextService(); } - }; - return AccessController.doPrivileged(action, acc); - } - } - - public S next() { - if (acc == null) { - return nextService(); - } else { - PrivilegedAction action = new PrivilegedAction() { - public S run() { return nextService(); } - }; - return AccessController.doPrivileged(action, acc); - } - } - - public void remove() { - throw new UnsupportedOperationException(); - } - } /** @@ -422,16 +850,14 @@ public final class ServiceLoader * loads and instantiates any remaining providers, adding each one to the * cache in turn. * - *

    To achieve laziness the actual work of parsing the available - * provider-configuration files and instantiating providers must be done by - * the iterator itself. Its {@link java.util.Iterator#hasNext hasNext} and - * {@link java.util.Iterator#next next} methods can therefore throw a - * {@link ServiceConfigurationError} if a provider-configuration file - * violates the specified format, or if it names a provider class that - * cannot be found and instantiated, or if the result of instantiating the - * class is not assignable to the service type, or if any other kind of - * exception or error is thrown as the next provider is located and - * instantiated. To write robust code it is only necessary to catch {@link + *

    To achieve laziness the actual work of locating and instantiating + * providers must be done by the iterator itself. Its {@link + * java.util.Iterator#hasNext hasNext} and {@link java.util.Iterator#next + * next} methods can therefore throw a {@link ServiceConfigurationError} + * if a provider class cannot be loaded, doesn't have the appropriate + * constructor, can't be assigned to the service type or if any other kind + * of exception or error is thrown as the next provider is located and + * instantiated. To write robust code it is only necessary to catch {@link * ServiceConfigurationError} when using a service iterator. * *

    If such an error is thrown then subsequent invocations of the @@ -447,6 +873,14 @@ public final class ServiceLoader * preferable to throw an error rather than try to recover or, even worse, * fail silently. * + *

    If this loader's provider cache is cleared by invoking the {@link + * #reload() reload} method then existing iterators for this service + * loader should be discarded. + * The {@link java.util.Iterator#hasNext() hasNext} and {@link + * java.util.Iterator#next() next} methods of the iterator throw {@link + * java.util.ConcurrentModificationException ConcurrentModificationException} + * if used after the provider cache has been cleared. + * *

    The iterator returned by this method does not support removal. * Invoking its {@link java.util.Iterator#remove() remove} method will * cause an {@link UnsupportedOperationException} to be thrown. @@ -463,28 +897,84 @@ public final class ServiceLoader public Iterator iterator() { return new Iterator() { - Iterator> knownProviders - = providers.entrySet().iterator(); + // record reload count + final int expectedReloadCount = ServiceLoader.this.reloadCount; + + // index into the cached providers list + int index; + + /** + * Throws ConcurrentModificationException if the list of cached + * providers has been cleared by reload. + */ + private void checkReloadCount() { + if (ServiceLoader.this.reloadCount != expectedReloadCount) + throw new ConcurrentModificationException(); + } public boolean hasNext() { - if (knownProviders.hasNext()) + checkReloadCount(); + if (index < providers.size()) return true; - return lookupIterator.hasNext(); + + if (layerLookupIterator != null) { + return layerLookupIterator.hasNext(); + } else { + return moduleServicesIterator.hasNext() || + lazyClassPathIterator.hasNext(); + } } public S next() { - if (knownProviders.hasNext()) - return knownProviders.next().getValue(); - return lookupIterator.next(); - } - - public void remove() { - throw new UnsupportedOperationException(); + checkReloadCount(); + S next; + if (index < providers.size()) { + next = providers.get(index); + } else { + if (layerLookupIterator != null) { + next = layerLookupIterator.next(); + } else { + if (moduleServicesIterator.hasNext()) { + next = moduleServicesIterator.next(); + } else { + next = lazyClassPathIterator.next(); + } + } + } + index++; + return next; } }; } + /** + * Creates a new service loader for the given service type, class + * loader, and caller. + * + * @param the class of the service type + * + * @param service + * The interface or abstract class representing the service + * + * @param loader + * The class loader to be used to load provider-configuration files + * and provider classes, or null if the system class + * loader (or, failing that, the bootstrap class loader) is to be + * used + * + * @param callerModule + * The caller's module for which a new service loader is created + * + * @return A new service loader + */ + static ServiceLoader load(Class service, + ClassLoader loader, + Module callerModule) + { + return new ServiceLoader<>(callerModule, service, loader); + } + /** * Creates a new service loader for the given service type and class * loader. @@ -496,16 +986,22 @@ public final class ServiceLoader * * @param loader * The class loader to be used to load provider-configuration files - * and provider classes, or null if the system class + * and provider classes, or {@code null} if the system class * loader (or, failing that, the bootstrap class loader) is to be * used * * @return A new service loader + * + * @throws ServiceConfigurationError + * if the service type is not accessible to the caller or the + * caller is in a named module and its module descriptor does + * not declare that it uses {@code service} */ + @CallerSensitive public static ServiceLoader load(Class service, ClassLoader loader) { - return new ServiceLoader<>(service, loader); + return new ServiceLoader<>(Reflection.getCallerClass(), service, loader); } /** @@ -530,30 +1026,32 @@ public final class ServiceLoader * The interface or abstract class representing the service * * @return A new service loader + * + * @throws ServiceConfigurationError + * if the service type is not accessible to the caller or the + * caller is in a named module and its module descriptor does + * not declare that it uses {@code service} */ + @CallerSensitive public static ServiceLoader load(Class service) { ClassLoader cl = Thread.currentThread().getContextClassLoader(); - return ServiceLoader.load(service, cl); + return new ServiceLoader<>(Reflection.getCallerClass(), service, cl); } /** * Creates a new service loader for the given service type, using the - * extension class loader. + * {@linkplain ClassLoader#getPlatformClassLoader() platform class loader}. * - *

    This convenience method simply locates the extension class loader, - * call it extClassLoader, and then returns + *

    This convenience method is equivalent to:

    * *
    -     * ServiceLoader.load(service, extClassLoader)
    - * - *

    If the extension class loader cannot be found then the system class - * loader is used; if there is no system class loader then the bootstrap - * class loader is used. + * ServiceLoader.load(service, ClassLoader.getPlatformClassLoader()) + * * *

    This method is intended for use when only installed providers are * desired. The resulting service will only find and load providers that * have been installed into the current Java virtual machine; providers on - * the application's class path will be ignored. + * the application's module path or class path will be ignored. * * @param the class of the service type * @@ -561,7 +1059,13 @@ public final class ServiceLoader * The interface or abstract class representing the service * * @return A new service loader + * + * @throws ServiceConfigurationError + * if the service type is not accessible to the caller or the + * caller is in a named module and its module descriptor does + * not declare that it uses {@code service} */ + @CallerSensitive public static ServiceLoader loadInstalled(Class service) { ClassLoader cl = ClassLoader.getSystemClassLoader(); ClassLoader prev = null; @@ -569,7 +1073,40 @@ public final class ServiceLoader prev = cl; cl = cl.getParent(); } - return ServiceLoader.load(service, prev); + return new ServiceLoader<>(Reflection.getCallerClass(), service, prev); + } + + /** + * Creates a new service loader for the given service type that loads + * service providers from modules in the given {@code Layer} and its + * ancestors. + * + * @apiNote Unlike the other load methods defined here, the service type + * is the second parameter. The reason for this is to avoid source + * compatibility issues for code that uses {@code load(S, null)}. + * + * @param the class of the service type + * + * @param layer + * The module Layer + * + * @param service + * The interface or abstract class representing the service + * + * @return A new service loader + * + * @throws ServiceConfigurationError + * if the service type is not accessible to the caller or the + * caller is in a named module and its module descriptor does + * not declare that it uses {@code service} + * + * @since 9 + */ + @CallerSensitive + public static ServiceLoader load(Layer layer, Class service) { + return new ServiceLoader<>(Reflection.getCallerClass(), + Objects.requireNonNull(layer), + Objects.requireNonNull(service)); } /** 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 new file mode 100644 index 00000000000..1a6ee655be5 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util.spi; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.reflect.Module; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Locale; +import java.util.ResourceBundle; +import sun.util.locale.provider.ResourceBundleProviderSupport; +import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION; + + +/** + * {@code AbstractResourceBundleProvider} is an abstract class for helping + * implement the {@link ResourceBundleProvider} interface. + * + * @since 9 + */ +public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider { + private static final String FORMAT_CLASS = "java.class"; + private static final String FORMAT_PROPERTIES = "java.properties"; + + private final String[] formats; + + /** + * Constructs an {@code AbstractResourceBundleProvider} with the + * "java.properties" format. This constructor is equivalent to + * {@code AbstractResourceBundleProvider("java.properties")}. + */ + protected AbstractResourceBundleProvider() { + this(FORMAT_PROPERTIES); + } + + /** + * Constructs an {@code AbstractResourceBundleProvider} with the specified + * {@code formats}. The {@link #getBundle(String, Locale)} method looks up + * resource bundles for the given {@code formats}. {@code formats} must + * be "java.class" or "java.properties". + * + * @param formats the formats to be used for loading resource bundles + * @throws NullPointerException if the given {@code formats} is null + * @throws IllegalArgumentException if the given {@code formats} is not + * "java.class" or "java.properties". + */ + protected AbstractResourceBundleProvider(String... formats) { + this.formats = formats.clone(); // defensive copy + if (this.formats.length == 0) { + throw new IllegalArgumentException("empty formats"); + } + for (String f : this.formats) { + if (!FORMAT_CLASS.equals(f) && !FORMAT_PROPERTIES.equals(f)) { + throw new IllegalArgumentException(f); + } + } + } + + /** + * Returns the bundle name for the given {@code baseName} and {@code + * locale}. This method is called from the default implementation of the + * {@link #getBundle(String, Locale)} method. + * + * @implNote The default implementation of this method is the same as the + * implementation of + * {@link java.util.ResourceBundle.Control#toBundleName(String, Locale)}. + * + * @param baseName the base name of the resource bundle, a fully qualified + * class name + * @param locale the locale for which a resource bundle should be loaded + * @return the bundle name for the resource bundle + */ + protected String toBundleName(String baseName, Locale locale) { + return ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT) + .toBundleName(baseName, locale); + } + + /** + * Returns a {@code ResourceBundle} for the given {@code baseName} and + * {@code locale}. This method calls the + * {@link #toBundleName(String, Locale) toBundleName} method to get the + * bundle name for the {@code baseName} and {@code locale}. The formats + * specified by the constructor will be searched to find the resource + * bundle. + * + * @implNote + * The default implementation of this method will find the resource bundle + * local to the module of this provider. + * + * @param baseName the base bundle name of the resource bundle, a fully + * qualified class name. + * @param locale the locale for which the resource bundle should be instantiated + * @return {@code ResourceBundle} of the given {@code baseName} and {@code locale}, + * or null if no resource bundle is found + * @throws NullPointerException if {@code baseName} or {@code locale} is null + * @throws UncheckedIOException if any IO exception occurred during resource + * bundle loading + */ + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + Module module = this.getClass().getModule(); + String bundleName = toBundleName(baseName, locale); + ResourceBundle bundle = null; + for (String format : formats) { + try { + if (FORMAT_CLASS.equals(format)) { + PrivilegedAction pa = () -> + ResourceBundleProviderSupport + .loadResourceBundle(module, bundleName); + bundle = AccessController.doPrivileged(pa, null, GET_CLASSLOADER_PERMISSION); + } else if (FORMAT_PROPERTIES.equals(format)) { + bundle = ResourceBundleProviderSupport + .loadPropertyResourceBundle(module, bundleName); + } + if (bundle != null) { + break; + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + return bundle; + } +} 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 a215e867399..3005df43167 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 @@ -42,6 +42,8 @@ import java.util.ResourceBundle; * ResourceBundleControlProvider} implementations are loaded using {@link * java.util.ServiceLoader} at the {@code ResourceBundle} class loading time. * + *

    All {@code ResourceBundleControlProvider}s are ignored in named modules. + * * @author Masayoshi Okutsu * @since 1.8 * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control) 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 new file mode 100644 index 00000000000..714ae625f08 --- /dev/null +++ b/jdk/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util.spi; + +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * {@code ResourceBundleProvider} is a provider interface that is used for + * loading resource bundles. Implementation classes of this interface are loaded + * with {@link java.util.ServiceLoader ServiceLoader} during a call to the + * {@link ResourceBundle#getBundle(String, Locale, ClassLoader) + * ResourceBundle.getBundle} method. The provider service type is determined by + * {@code basename+"Provider"}. For example, if the base name is + * "com.example.app.MyResources", {@code com.example.app.MyResourcesProvider} + * will be the provider service type. + *

    + * This providers's {@link #getBundle(String, Locale) getBundle} method is called + * through the resource bundle loading process instead of {@link + * java.util.ResourceBundle.Control#newBundle(String, Locale, String, ClassLoader, boolean) + * ResourceBundle.Control.newBundle()}. Refer to {@link ResourceBundle} for + * details. + * + * @since 9 + */ +public interface ResourceBundleProvider { + /** + * Returns a {@code ResourceBundle} for the given bundle name and locale. + * This method returns null if there is no {@code ResourceBundle} found + * for the given parameters. + * + * + * @param baseName + * the base bundle name of the resource bundle, a fully + * qualified class name + * @param locale + * the locale for which the resource bundle should be loaded + * @return the ResourceBundle created for the given parameters, or null if no + * {@code ResourceBundle} for the given parameters is found + */ + public ResourceBundle getBundle(String baseName, Locale locale); +} diff --git a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java index 97e05c326ec..da80728f255 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/java.base/share/classes/java/util/stream/Collectors.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -656,8 +656,9 @@ public final class Collectors { */ return new CollectorImpl<>( () -> new double[3], - (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); - a[2] += mapper.applyAsDouble(t);}, + (a, t) -> { double val = mapper.applyAsDouble(t); + sumWithCompensation(a, val); + a[2] += val;}, (a, b) -> { sumWithCompensation(a, b[0]); a[2] += b[2]; return sumWithCompensation(a, b[1]); }, @@ -768,7 +769,7 @@ public final class Collectors { */ return new CollectorImpl<>( () -> new double[4], - (a, t) -> { sumWithCompensation(a, mapper.applyAsDouble(t)); a[2]++; a[3]+= mapper.applyAsDouble(t);}, + (a, t) -> { double val = mapper.applyAsDouble(t); sumWithCompensation(a, val); a[2]++; a[3]+= val;}, (a, b) -> { sumWithCompensation(a, b[0]); sumWithCompensation(a, b[1]); a[2] += b[2]; a[3] += b[3]; return a; }, a -> (a[2] == 0) ? 0.0d : (computeFinalSum(a) / a[2]), CH_NOID); diff --git a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java index 081f68d1a0e..8d989930386 100644 --- a/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java +++ b/jdk/src/java.base/share/classes/java/util/stream/PipelineHelper.java @@ -98,7 +98,7 @@ abstract class PipelineHelper { * @implSpec * The implementation behaves as if: *

    {@code
    -     *     intoWrapped(wrapSink(sink), spliterator);
    +     *     copyInto(wrapSink(sink), spliterator);
          * }
    * * @param sink the {@code Sink} to receive the results diff --git a/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java b/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java index 338aa12eafc..d4fffacf38f 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java +++ b/jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java @@ -251,11 +251,8 @@ final class JceSecurity { File exportJar = new File(pathToPolicyJar, "US_export_policy.jar"); File importJar = new File(pathToPolicyJar, "local_policy.jar"); - URL jceCipherURL = ClassLoader.getSystemResource - ("javax/crypto/Cipher.class"); - if ((jceCipherURL == null) || - !exportJar.exists() || !importJar.exists()) { + if (!exportJar.exists() || !importJar.exists()) { throw new SecurityException ("Cannot locate policy or framework files!"); } diff --git a/jdk/src/java.base/share/classes/javax/crypto/SealedObject.java b/jdk/src/java.base/share/classes/javax/crypto/SealedObject.java index 9cee4d070f1..743125bf0f7 100644 --- a/jdk/src/java.base/share/classes/javax/crypto/SealedObject.java +++ b/jdk/src/java.base/share/classes/javax/crypto/SealedObject.java @@ -453,9 +453,6 @@ public class SealedObject implements Serializable { } final class extObjectInputStream extends ObjectInputStream { - - private static ClassLoader systemClassLoader = null; - extObjectInputStream(InputStream in) throws IOException, StreamCorruptedException { super(in); @@ -478,10 +475,7 @@ final class extObjectInputStream extends ObjectInputStream { */ ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { - if (systemClassLoader == null) { - systemClassLoader = ClassLoader.getSystemClassLoader(); - } - loader = systemClassLoader; + loader = ClassLoader.getSystemClassLoader(); if (loader == null) { throw new ClassNotFoundException(v.getName()); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java index 731f36e786f..15c888daa83 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/BasicImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,183 +26,288 @@ package jdk.internal.jimage; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.File; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; -import java.util.Comparator; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Objects; import java.util.stream.IntStream; +import jdk.internal.jimage.decompressor.Decompressor; +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ public class BasicImageReader implements AutoCloseable { - private final String imagePath; - private final ImageSubstrate substrate; - private final ByteOrder byteOrder; - private final ImageStringsReader strings; - - protected BasicImageReader(String imagePath, ByteOrder byteOrder) - throws IOException { - this.imagePath = imagePath; - this.substrate = openImageSubstrate(imagePath, byteOrder); - this.byteOrder = byteOrder; - this.strings = new ImageStringsReader(this); + private static boolean isSystemProperty(String key, String value, String def) { + // No lambdas during bootstrap + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Boolean run() { + return value.equals(System.getProperty(key, def)); + } + }); } - protected BasicImageReader(String imagePath) throws IOException { + static private final boolean IS_64_BIT = + isSystemProperty("sun.arch.data.model", "64", "32"); + static private final boolean USE_JVM_MAP = + isSystemProperty("jdk.image.use.jvm.map", "true", "true"); + static private final boolean MAP_ALL = + isSystemProperty("jdk.image.map.all", "true", IS_64_BIT ? "true" : "false"); + + private final String name; + private final ByteOrder byteOrder; + private final Path imagePath; + private final ByteBuffer memoryMap; + private final FileChannel channel; + private final ImageHeader header; + private final long indexSize; + private final IntBuffer redirect; + private final IntBuffer offsets; + private final ByteBuffer locations; + private final ByteBuffer strings; + private final ImageStringsReader stringsReader; + private final Decompressor decompressor; + + protected BasicImageReader(Path path, ByteOrder byteOrder) + throws IOException { + Objects.requireNonNull(path); + Objects.requireNonNull(byteOrder); + this.name = path.toString(); + this.byteOrder = byteOrder; + imagePath = path; + + ByteBuffer map; + + if (USE_JVM_MAP && BasicImageReader.class.getClassLoader() == null) { + // Check to see if the jvm has opened the file using libjimage + // native entry when loading the image for this runtime + map = NativeImageBuffer.getNativeMap(name); + } else { + map = null; + } + + // Open the file only if no memory map yet or is 32 bit jvm + channel = map != null && MAP_ALL ? null : + FileChannel.open(imagePath, StandardOpenOption.READ); + + // If no memory map yet and 64 bit jvm then memory map entire file + if (MAP_ALL && map == null) { + map = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + } + + // Assume we have a memory map to read image file header + ByteBuffer headerBuffer = map; + int headerSize = ImageHeader.getHeaderSize(); + + // If no memory map then read header from image file + if (map == null) { + headerBuffer = ByteBuffer.allocateDirect(headerSize); + channel.read(headerBuffer, 0L); + headerBuffer.rewind(); + } + + // Interpret the image file header + header = readHeader(intBuffer(headerBuffer, 0, headerSize)); + indexSize = header.getIndexSize(); + + // If no memory map yet then must be 32 bit jvm not previously mapped + if (map == null) { + // Just map the image index + map = channel.map(FileChannel.MapMode.READ_ONLY, 0, indexSize); + } + + memoryMap = map.asReadOnlyBuffer(); + + // Interpret the image index + redirect = intBuffer(memoryMap, header.getRedirectOffset(), header.getRedirectSize()); + offsets = intBuffer(memoryMap, header.getOffsetsOffset(), header.getOffsetsSize()); + locations = slice(memoryMap, header.getLocationsOffset(), header.getLocationsSize()); + strings = slice(memoryMap, header.getStringsOffset(), header.getStringsSize()); + + stringsReader = new ImageStringsReader(this); + decompressor = new Decompressor(); + } + + protected BasicImageReader(Path imagePath) throws IOException { this(imagePath, ByteOrder.nativeOrder()); } - private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder) - throws IOException { - ImageSubstrate substrate; - - try { - substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder); - } catch (UnsatisfiedLinkError | NoClassDefFoundError ex) { - substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder); - } - - return substrate; + public static BasicImageReader open(Path imagePath) throws IOException { + return new BasicImageReader(imagePath, ByteOrder.nativeOrder()); } - public static BasicImageReader open(String imagePath) throws IOException { - return new BasicImageReader(imagePath, ByteOrder.nativeOrder()); + public ImageHeader getHeader() { + return header; + } + + private ImageHeader readHeader(IntBuffer buffer) throws IOException { + ImageHeader result = ImageHeader.readFrom(buffer); + + if (result.getMagic() != ImageHeader.MAGIC) { + throw new IOException("\"" + name + "\" is not an image file"); + } + + if (result.getMajorVersion() != ImageHeader.MAJOR_VERSION || + result.getMinorVersion() != ImageHeader.MINOR_VERSION) { + throw new IOException("The image file \"" + name + "\" is not the correct version"); + } + + return result; + } + + private static ByteBuffer slice(ByteBuffer buffer, int position, int capacity) { + // Note that this is the only limit and position manipulation of + // BasicImageReader private ByteBuffers. The synchronize could be avoided + // by cloning the buffer to make a local copy, but at the cost of creating + // a new object. + synchronized(buffer) { + buffer.limit(position + capacity); + buffer.position(position); + return buffer.slice(); + } + } + + private IntBuffer intBuffer(ByteBuffer buffer, int offset, int size) { + return slice(buffer, offset, size).order(byteOrder).asIntBuffer(); } public static void releaseByteBuffer(ByteBuffer buffer) { ImageBufferCache.releaseBuffer(buffer); } + public String getName() { + return name; + } + public ByteOrder getByteOrder() { return byteOrder; } - public String imagePath() { + public Path getImagePath() { return imagePath; } - public String imagePathName() { - int slash = imagePath().lastIndexOf(File.separator); - - if (slash != -1) { - return imagePath().substring(slash + 1); - } - - return imagePath(); - } - - public boolean isOpen() { - return true; - } - + @Override public void close() throws IOException { - substrate.close(); - } - - public ImageHeader getHeader() throws IOException { - return ImageHeader.readFrom( - getIndexIntBuffer(0, ImageHeader.getHeaderSize())); + if (channel != null) { + channel.close(); + } } public ImageStringsReader getStrings() { - return strings; + return stringsReader; } - public ImageLocation findLocation(String name) { - return findLocation(new UTF8String(name)); + public ImageLocation findLocation(String mn, String rn) { + return findLocation("/" + mn + "/" + rn); } - public ImageLocation findLocation(byte[] name) { - return findLocation(new UTF8String(name)); - } + public synchronized ImageLocation findLocation(String name) { + // Details of the algorithm used here can be found in + // jdk.tools.jlink.internal.PerfectHashBuilder. + byte[] bytes = ImageStringsReader.mutf8FromString(name); + int count = header.getTableLength(); + int index = redirect.get(ImageStringsReader.hashCode(bytes) % count); - public synchronized ImageLocation findLocation(UTF8String name) { - return substrate.findLocation(name, strings); + if (index < 0) { + // index is twos complement of location attributes index. + index = -index - 1; + } else if (index > 0) { + // index is hash seed needed to compute location attributes index. + index = ImageStringsReader.hashCode(bytes, index) % count; + } else { + // No entry. + return null; + } + + long[] attributes = getAttributes(offsets.get(index)); + + ImageLocation imageLocation = new ImageLocation(attributes, stringsReader); + + if (!imageLocation.verify(name)) { + return null; + } + + return imageLocation; } public String[] getEntryNames() { - return IntStream.of(substrate.attributeOffsets()) + int[] attributeOffsets = new int[offsets.capacity()]; + offsets.get(attributeOffsets); + return IntStream.of(attributeOffsets) .filter(o -> o != 0) - .mapToObj(o -> ImageLocation.readFrom(this, o).getFullNameString()) + .mapToObj(o -> ImageLocation.readFrom(this, o).getFullName()) .sorted() .toArray(String[]::new); } - protected ImageLocation[] getAllLocations(boolean sorted) { - return IntStream.of(substrate.attributeOffsets()) - .filter(o -> o != 0) - .mapToObj(o -> ImageLocation.readFrom(this, o)) - .sorted(Comparator.comparing(ImageLocation::getFullNameString)) - .toArray(ImageLocation[]::new); - } - - private IntBuffer getIndexIntBuffer(long offset, long size) - throws IOException { - ByteBuffer buffer = substrate.getIndexBuffer(offset, size); - buffer.order(byteOrder); - - return buffer.asIntBuffer(); - } - ImageLocation getLocation(int offset) { return ImageLocation.readFrom(this, offset); } public long[] getAttributes(int offset) { - return substrate.getAttributes(offset); + ByteBuffer buffer = slice(locations, offset, locations.limit() - offset); + return ImageLocation.decompress(buffer); } public String getString(int offset) { - return getUTF8String(offset).toString(); + ByteBuffer buffer = slice(strings, offset, strings.limit() - offset); + return ImageStringsReader.stringFromByteBuffer(buffer); } - public UTF8String getUTF8String(int offset) { - return new UTF8String(substrate.getStringBytes(offset)); - } - - private byte[] getBufferBytes(ByteBuffer buffer, long size) { - assert size < Integer.MAX_VALUE; - byte[] bytes = new byte[(int)size]; + private byte[] getBufferBytes(ByteBuffer buffer) { + byte[] bytes = new byte[buffer.limit()]; buffer.get(bytes); return bytes; } - private byte[] getBufferBytes(long offset, long size) { - ByteBuffer buffer = substrate.getDataBuffer(offset, size); - - return getBufferBytes(buffer, size); - } - - public byte[] getResource(ImageLocation loc) { - long offset = loc.getContentOffset(); - long compressedSize = loc.getCompressedSize(); - long uncompressedSize = loc.getUncompressedSize(); - assert compressedSize < Integer.MAX_VALUE; - assert uncompressedSize < Integer.MAX_VALUE; - - if (substrate.supportsDataBuffer() && compressedSize == 0) { - return getBufferBytes(offset, uncompressedSize); + private ByteBuffer readBuffer(long offset, long size) { + if (offset < 0 || Integer.MAX_VALUE <= offset) { + throw new IndexOutOfBoundsException("offset"); } - ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize); - boolean isRead; + if (size < 0 || Integer.MAX_VALUE <= size) { + throw new IndexOutOfBoundsException("size"); + } - if (compressedSize != 0) { - ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize); - isRead = substrate.read(offset, compressedBuffer, compressedSize, - uncompressedBuffer, uncompressedSize); - ImageBufferCache.releaseBuffer(compressedBuffer); + if (MAP_ALL) { + ByteBuffer buffer = slice(memoryMap, (int)offset, (int)size); + buffer.order(ByteOrder.BIG_ENDIAN); + + return buffer; } else { - isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize); + ByteBuffer buffer = ImageBufferCache.getBuffer(size); + int read = 0; + + try { + if (channel == null) { + throw new InternalError("Image file channel not open"); + } + + read = channel.read(buffer, offset); + buffer.rewind(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + if (read != size) { + ImageBufferCache.releaseBuffer(buffer); + } + + return buffer; } - - byte[] bytes = isRead ? getBufferBytes(uncompressedBuffer, - uncompressedSize) : null; - - ImageBufferCache.releaseBuffer(uncompressedBuffer); - - return bytes; } public byte[] getResource(String name) { @@ -211,42 +316,54 @@ public class BasicImageReader implements AutoCloseable { return location != null ? getResource(location) : null; } - public ByteBuffer getResourceBuffer(ImageLocation loc) { - long offset = loc.getContentOffset(); - long compressedSize = loc.getCompressedSize(); - long uncompressedSize = loc.getUncompressedSize(); - assert compressedSize < Integer.MAX_VALUE; - assert uncompressedSize < Integer.MAX_VALUE; + public byte[] getResource(ImageLocation loc) { + ByteBuffer buffer = getResourceBuffer(loc); - if (substrate.supportsDataBuffer() && compressedSize == 0) { - return substrate.getDataBuffer(offset, uncompressedSize); + if (buffer != null) { + byte[] bytes = getBufferBytes(buffer); + ImageBufferCache.releaseBuffer(buffer); + + return bytes; } - ByteBuffer uncompressedBuffer = ImageBufferCache.getBuffer(uncompressedSize); - boolean isRead; - - if (compressedSize != 0) { - ByteBuffer compressedBuffer = ImageBufferCache.getBuffer(compressedSize); - isRead = substrate.read(offset, compressedBuffer, compressedSize, - uncompressedBuffer, uncompressedSize); - ImageBufferCache.releaseBuffer(compressedBuffer); - } else { - isRead = substrate.read(offset, uncompressedBuffer, uncompressedSize); - } - - if (isRead) { - return uncompressedBuffer; - } else { - ImageBufferCache.releaseBuffer(uncompressedBuffer); - - return null; - } + return null; } - public ByteBuffer getResourceBuffer(String name) { - ImageLocation location = findLocation(name); + public ByteBuffer getResourceBuffer(ImageLocation loc) { + long offset = loc.getContentOffset() + indexSize; + long compressedSize = loc.getCompressedSize(); + long uncompressedSize = loc.getUncompressedSize(); - return location != null ? getResourceBuffer(location) : null; + if (compressedSize < 0 || Integer.MAX_VALUE < compressedSize) { + throw new IndexOutOfBoundsException("Compressed size"); + } + + if (uncompressedSize < 0 || Integer.MAX_VALUE < uncompressedSize) { + throw new IndexOutOfBoundsException("Uncompressed size"); + } + + if (compressedSize == 0) { + return readBuffer(offset, uncompressedSize); + } else { + ByteBuffer buffer = readBuffer(offset, compressedSize); + + if (buffer != null) { + byte[] bytesIn = getBufferBytes(buffer); + ImageBufferCache.releaseBuffer(buffer); + byte[] bytesOut; + + try { + bytesOut = decompressor.decompressResource(byteOrder, + (int strOffset) -> getString(strOffset), bytesIn); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + + return ByteBuffer.wrap(bytesOut); + } + } + + return null; } public InputStream getResourceStream(ImageLocation loc) { @@ -254,10 +371,4 @@ public class BasicImageReader implements AutoCloseable { return new ByteArrayInputStream(bytes); } - - public InputStream getResourceStream(String name) { - ImageLocation location = findLocation(name); - - return location != null ? getResourceStream(location) : null; - } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java deleted file mode 100644 index 228704309f2..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ExternalFilesWriter.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jimage; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.function.Consumer; -import jdk.internal.jimage.Archive.Entry; - -/** - * A Consumer suitable for processing non resources Archive Entry and writing it to the - * appropriate location. - */ -class ExternalFilesWriter implements Consumer { - private final Path root; - - ExternalFilesWriter(Path root) { - this.root = root; - } - - @Override - public void accept(Entry entry) { - String name = entry.path(); - try { - String filename = entry.path(); - try (InputStream in = entry.stream()) { - switch (entry.type()) { - case NATIVE_LIB: - writeEntry(in, destFile(nativeDir(filename), filename)); - break; - case NATIVE_CMD: - Path path = destFile("bin", filename); - writeEntry(in, path); - path.toFile().setExecutable(true, false); - break; - case CONFIG: - writeEntry(in, destFile("conf", filename)); - break; - case MODULE_NAME: - // skip - break; - case SERVICE: - //throw new UnsupportedOperationException(name + " in " + zipfile.toString()); //TODO - throw new UnsupportedOperationException(name + " in " + name); - default: - //throw new InternalError("unexpected entry: " + name + " " + zipfile.toString()); //TODO - throw new InternalError("unexpected entry: " + name + " " + name); - } - } - } catch (FileAlreadyExistsException x) { - System.err.println("File already exists (skipped) " + name); - } catch (IOException x) { - throw new UncheckedIOException(x); - } - } - - private Path destFile(String dir, String filename) { - return root.resolve(dir).resolve(filename); - } - - private void writeEntry(InputStream in, Path dstFile) throws IOException { - Files.createDirectories(dstFile.getParent()); - Files.copy(in, dstFile); - } - - private static String nativeDir(String filename) { - if (System.getProperty("os.name").startsWith("Windows")) { - if (filename.endsWith(".dll") || filename.endsWith(".diz") - || filename.endsWith(".pdb") || filename.endsWith(".map")) { - return "bin"; - } else { - return "lib"; - } - } else { - return "lib"; - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java index 6929f74e21d..c9efbe114eb 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageBufferCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,13 @@ package jdk.internal.jimage; import java.nio.ByteBuffer; import java.util.ArrayList; +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ class ImageBufferCache { private static final int MAX_FREE_BUFFERS = 3; private static final int LARGE_BUFFER = 0x10000; @@ -37,7 +44,10 @@ class ImageBufferCache { private boolean isUsed; static ByteBuffer getBuffer(long size) { - assert size < Integer.MAX_VALUE; + if (size < 0 || Integer.MAX_VALUE < size) { + throw new IndexOutOfBoundsException("size"); + } + ByteBuffer buffer = null; if (size > LARGE_BUFFER) { @@ -84,7 +94,7 @@ class ImageBufferCache { static void releaseBuffer(ByteBuffer buffer) { ArrayList buffers = threadLocal.get(); - if (buffers == null ) { + if (buffers == null) { return; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java deleted file mode 100644 index 78915e58c46..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageFileCreator.java +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.jimage; - -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import jdk.internal.jimage.Archive.Entry; -import jdk.internal.jimage.Archive.Entry.EntryType; -import static jdk.internal.jimage.BasicImageWriter.BOOT_NAME; -import static jdk.internal.jimage.BasicImageWriter.IMAGE_EXT; - -/** - * An image (native endian.) - *
    {@code
    - * {
    - *   u4 magic;
    - *   u2 major_version;
    - *   u2 minor_version;
    - *   u4 resource_count;
    - *   u4 table_length;
    - *   u4 location_attributes_size;
    - *   u4 strings_size;
    - *   u4 redirect[table_length];
    - *   u4 offsets[table_length];
    - *   u1 location_attributes[location_attributes_size];
    - *   u1 strings[strings_size];
    - *   u1 content[if !EOF];
    - * }
    - * }
    - */ -public final class ImageFileCreator { - private final Path root; - private final Path mdir; - private final Map> entriesForModule = new HashMap<>(); - private ImageFileCreator(Path path) { - this.root = path; - this.mdir = root.resolve(path.getFileSystem().getPath("lib", "modules")); - } - - public static ImageFileCreator create(Path output, - Set archives) - throws IOException { - return create(output, BOOT_NAME, archives, ByteOrder.nativeOrder()); - } - - public static ImageFileCreator create(Path output, - Set archives, - ByteOrder byteOrder) - throws IOException { - return create(output, BOOT_NAME, archives, byteOrder); - } - - public static ImageFileCreator create(Path output, - String fileName, - Set archives, - ByteOrder byteOrder) - throws IOException - { - ImageFileCreator image = new ImageFileCreator(output); - // get all entries - Map> modulePackagesMap = new HashMap<>(); - image.readAllEntries(modulePackagesMap, archives); - // write to modular image - image.writeImage(fileName, modulePackagesMap, archives, byteOrder); - return image; - } - - private void readAllEntries(Map> modulePackagesMap, - Set archives) { - archives.stream().forEach((archive) -> { - Map> es; - try(Stream entries = archive.entries()) { - es = entries.collect(Collectors.partitioningBy(n -> n.type() - == EntryType.CLASS_OR_RESOURCE)); - } - String mn = archive.moduleName(); - List all = new ArrayList<>(); - all.addAll(es.get(false)); - all.addAll(es.get(true)); - entriesForModule.put(mn, all); - // Extract package names - Set pkgs = es.get(true).stream().map(Entry::name) - .filter(n -> isClassPackage(n)) - .map(ImageFileCreator::toPackage) - .collect(Collectors.toSet()); - modulePackagesMap.put(mn, pkgs); - }); - } - - public static boolean isClassPackage(String path) { - return path.endsWith(".class"); - } - - public static boolean isResourcePackage(String path) { - path = path.substring(1); - path = path.substring(path.indexOf("/")+1); - return !path.startsWith("META-INF/"); - } - - public static void recreateJimage(Path jimageFile, - String jdataName, - Set archives, - Map> modulePackages) - throws IOException { - Map> entriesForModule - = archives.stream().collect(Collectors.toMap( - Archive::moduleName, - a -> { - try(Stream entries = a.entries()) { - return entries.collect(Collectors.toList()); - } - })); - Map nameToArchive - = archives.stream() - .collect(Collectors.toMap(Archive::moduleName, Function.identity())); - ByteOrder order = ByteOrder.nativeOrder(); - ResourcePoolImpl resources = createResources(modulePackages, nameToArchive, - (Entry t) -> { - throw new UnsupportedOperationException("Not supported, no external file " - + "in a jimage file"); - }, entriesForModule, order); - generateJImage(jimageFile, jdataName, resources, order); - } - - private void writeImage(String fileName, - Map> modulePackagesMap, - Set archives, - ByteOrder byteOrder) - throws IOException { - Files.createDirectories(mdir); - ExternalFilesWriter filesWriter = new ExternalFilesWriter(root); - // name to Archive file - Map nameToArchive - = archives.stream() - .collect(Collectors.toMap(Archive::moduleName, Function.identity())); - ResourcePoolImpl resources = createResources(modulePackagesMap, - nameToArchive, filesWriter, - entriesForModule, byteOrder); - generateJImage(mdir.resolve(fileName + IMAGE_EXT), fileName, resources, - byteOrder); - } - - private static void generateJImage(Path img, - String fileName, - ResourcePoolImpl resources, - ByteOrder byteOrder - ) throws IOException { - BasicImageWriter writer = new BasicImageWriter(byteOrder); - - Map> modulePackagesMap = resources.getModulePackages(); - - try (OutputStream fos = Files.newOutputStream(img); - BufferedOutputStream bos = new BufferedOutputStream(fos); - DataOutputStream out = new DataOutputStream(bos)) { - Set duplicates = new HashSet<>(); - ImageModuleDataWriter moduleData = - ImageModuleDataWriter.buildModuleData(writer, modulePackagesMap); - moduleData.addLocation(fileName, writer); - long offset = moduleData.size(); - - List content = new ArrayList<>(); - List paths = new ArrayList<>(); - // the order of traversing the resources and the order of - // the module content being written must be the same - for (ResourcePool.Resource res : resources.getResources()) { - String path = res.getPath(); - int index = path.indexOf("/META-INF/"); - if (index != -1) { - path = path.substring(index + 1); - } - - content.add(res); - long uncompressedSize = res.getLength(); - long compressedSize = 0; - if (res instanceof ResourcePool.CompressedResource) { - ResourcePool.CompressedResource comp = - (ResourcePool.CompressedResource) res; - compressedSize = res.getLength(); - uncompressedSize = comp.getUncompressedSize(); - } - long onFileSize = res.getLength(); - - if (duplicates.contains(path)) { - System.err.format("duplicate resource \"%s\", skipping%n", - path); - // TODO Need to hang bytes on resource and write - // from resource not zip. - // Skipping resource throws off writing from zip. - offset += onFileSize; - continue; - } - duplicates.add(path); - writer.addLocation(path, offset, compressedSize, uncompressedSize); - paths.add(path); - offset += onFileSize; - } - - ImageResourcesTree tree = new ImageResourcesTree(offset, writer, paths); - - // write header and indices - byte[] bytes = writer.getBytes(); - out.write(bytes, 0, bytes.length); - - // write module meta data - moduleData.writeTo(out); - - // write module content - for(ResourcePool.Resource res : content) { - byte[] buf = res.getByteArray(); - out.write(buf, 0, buf.length); - } - - tree.addContent(out); - } - } - - private static ResourcePoolImpl createResources(Map> modulePackagesMap, - Map nameToArchive, - Consumer externalFileHandler, - Map> entriesForModule, - ByteOrder byteOrder) throws IOException { - ResourcePoolImpl resources = new ResourcePoolImpl(byteOrder); - // Doesn't contain META-INF - Set mods = modulePackagesMap.keySet(); - for (String mn : mods) { - for (Entry entry : entriesForModule.get(mn)) { - String path = entry.name(); - if (entry.type() == EntryType.CLASS_OR_RESOURCE) { - if (!entry.path().endsWith(BOOT_NAME)) { - try (InputStream stream = entry.stream()) { - byte[] bytes = readAllBytes(stream); - path = "/" + mn + "/" + path; - try { - resources.addResource(new ResourcePool.Resource(path, - ByteBuffer.wrap(bytes))); - } catch (Exception ex) { - throw new IOException(ex); - } - } - } - } else { - externalFileHandler.accept(entry); - } - } - // Done with this archive, close it. - Archive archive = nameToArchive.get(mn); - archive.close(); - } - // Fix for 8136365. Do we have an archive with module name "META-INF"? - // If yes, we are recreating a jimage. - // This is a workaround for META-INF being at the top level of resource path - String mn = "META-INF"; - Archive archive = nameToArchive.get(mn); - if (archive != null) { - try { - for (Entry entry : entriesForModule.get(mn)) { - String path = entry.name(); - try (InputStream stream = entry.stream()) { - byte[] bytes = readAllBytes(stream); - path = mn + "/" + path; - try { - resources.addResource(new ResourcePool.Resource(path, - ByteBuffer.wrap(bytes))); - } catch (Exception ex) { - throw new IOException(ex); - } - } - } - } finally { - // Done with this archive, close it. - archive.close(); - } - } - return resources; - } - - private static final int BUF_SIZE = 8192; - - private static byte[] readAllBytes(InputStream is) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buf = new byte[BUF_SIZE]; - while (true) { - int n = is.read(buf); - if (n < 0) { - break; - } - baos.write(buf, 0, n); - } - return baos.toByteArray(); - } - - /** - * Helper method that splits a Resource path onto 3 items: module, parent - * and resource name. - * - * @param path - * @return An array containing module, parent and name. - */ - public static String[] splitPath(String path) { - Objects.requireNonNull(path); - String noRoot = path.substring(1); - int pkgStart = noRoot.indexOf("/"); - String module = noRoot.substring(0, pkgStart); - List result = new ArrayList<>(); - result.add(module); - String pkg = noRoot.substring(pkgStart + 1); - String resName; - int pkgEnd = pkg.lastIndexOf("/"); - if (pkgEnd == -1) { // No package. - resName = pkg; - } else { - resName = pkg.substring(pkgEnd + 1); - } - - pkg = toPackage(pkg, false); - result.add(pkg); - result.add(resName); - - String[] array = new String[result.size()]; - return result.toArray(array); - } - - private static String toPackage(String name) { - String pkg = toPackage(name, true); - return pkg; - } - - private static String toPackage(String name, boolean log) { - int index = name.lastIndexOf('/'); - if (index > 0) { - return name.substring(0, index).replace('/', '.'); - } else { - // ## unnamed package - if (log) { - System.err.format("Warning: %s in unnamed package%n", name); - } - return ""; - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java index f55ef349d92..094f8dd6929 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageHeader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,11 +28,18 @@ package jdk.internal.jimage; import java.nio.ByteBuffer; import java.nio.IntBuffer; +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ public final class ImageHeader { public static final int MAGIC = 0xCAFEDADA; - public static final int BADMAGIC = 0xDADAFECA; public static final int MAJOR_VERSION = 1; public static final int MINOR_VERSION = 0; + private static final int HEADER_SLOTS = 7; private final int magic; private final int majorVersion; @@ -64,10 +71,14 @@ public final class ImageHeader { } public static int getHeaderSize() { - return 7 * 4; + return HEADER_SLOTS * 4; } static ImageHeader readFrom(IntBuffer buffer) { + if (buffer.capacity() != HEADER_SLOTS) { + throw new InternalError("jimage header not the correct size"); + } + int magic = buffer.get(0); int version = buffer.get(1); int majorVersion = version >>> 16; @@ -82,7 +93,7 @@ public final class ImageHeader { resourceCount, tableLength, locationsSize, stringsSize); } - void writeTo(ImageStream stream) { + public void writeTo(ImageStream stream) { stream.ensure(getHeaderSize()); writeTo(stream.getBuffer()); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java deleted file mode 100644 index 96a7f23d216..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageJavaSubstrate.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.jimage; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; -import java.nio.channels.FileChannel; -import java.nio.file.Paths; -import static java.nio.file.StandardOpenOption.READ; -import jdk.internal.jimage.decompressor.Decompressor; - -final class ImageJavaSubstrate implements ImageSubstrate { - - private final String imagePath; - private final ByteOrder byteOrder; - private final FileChannel channel; - private final ImageHeader header; - private final long indexSize; - private final int[] redirect; - private final int[] offsets; - private final byte[] locations; - private final byte[] strings; - - private final Decompressor decompressor = new Decompressor(); - - private ImageJavaSubstrate(String imagePath, ByteOrder byteOrder) - throws IOException { - this.imagePath = imagePath; - this.byteOrder = byteOrder; - channel = FileChannel.open(Paths.get(imagePath), READ); - - int headerSize = ImageHeader.getHeaderSize(); - ByteBuffer buffer = getIndexBuffer(0, headerSize); - header = ImageHeader.readFrom(buffer.asIntBuffer()); - - if (header.getMagic() != ImageHeader.MAGIC || - header.getMajorVersion() != ImageHeader.MAJOR_VERSION || - header.getMinorVersion() != ImageHeader.MINOR_VERSION) { - throw new IOException("Image not found \"" + imagePath + "\""); - } - - indexSize = header.getIndexSize(); - - redirect = readIntegers(header.getRedirectOffset(), - header.getRedirectSize()); - offsets = readIntegers(header.getOffsetsOffset(), - header.getOffsetsSize()); - locations = readBytes(header.getLocationsOffset(), - header.getLocationsSize()); - strings = readBytes(header.getStringsOffset(), - header.getStringsSize()); - } - - static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder) - throws IOException { - return new ImageJavaSubstrate(imagePath, byteOrder); - } - - @Override - public void close() { - try { - channel.close(); - } catch (IOException ex) { - // Mostly harmless - } - } - - @Override - public boolean supportsDataBuffer() { - return false; - } - - private int[] readIntegers(long offset, long size) { - assert size < Integer.MAX_VALUE; - IntBuffer buffer = readBuffer(offset, size).asIntBuffer(); - int[] integers = new int[(int)size / 4]; - buffer.get(integers); - - return integers; - } - - private byte[] readBytes(long offset, long size) { - assert size < Integer.MAX_VALUE; - ByteBuffer buffer = readBuffer(offset, size); - byte[] bytes = new byte[(int)size]; - buffer.get(bytes); - - return bytes; - } - - private ByteBuffer readBuffer(long offset, long size) { - assert size < Integer.MAX_VALUE; - ByteBuffer buffer = ByteBuffer.allocate((int)size); - buffer.order(byteOrder); - - if (!readBuffer(buffer, offset, size)) { - return null; - } - - return buffer; - } - - private boolean readBuffer(ByteBuffer buffer, long offset, long size) { - assert size < Integer.MAX_VALUE; - assert buffer.limit() == size; - int read = 0; - - try { - read = channel.read(buffer, offset); - buffer.rewind(); - } catch (IOException ex) { - // fall thru - } - - return read == size; - } - - @Override - public ByteBuffer getIndexBuffer(long offset, long size) { - assert size < Integer.MAX_VALUE; - return readBuffer(offset, size); - } - - @Override - public ByteBuffer getDataBuffer(long offset, long size) { - assert size < Integer.MAX_VALUE; - return getIndexBuffer(indexSize + offset, size); - } - - @Override - public boolean read(long offset, - ByteBuffer compressedBuffer, long compressedSize, - ByteBuffer uncompressedBuffer, long uncompressedSize) { - assert compressedSize < Integer.MAX_VALUE; - assert uncompressedSize < Integer.MAX_VALUE; - boolean isRead = readBuffer(compressedBuffer, - indexSize + offset, compressedSize); - if (isRead) { - byte[] bytesIn = new byte[(int)compressedSize]; - compressedBuffer.get(bytesIn); - byte[] bytesOut; - try { - bytesOut = decompressor.decompressResource(byteOrder, (int strOffset) -> { - return new UTF8String(getStringBytes(strOffset)).toString(); - }, bytesIn); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - uncompressedBuffer.put(bytesOut); - uncompressedBuffer.rewind(); - } - - return isRead; - } - - @Override - public boolean read(long offset, - ByteBuffer uncompressedBuffer, long uncompressedSize) { - assert uncompressedSize < Integer.MAX_VALUE; - boolean isRead = readBuffer(uncompressedBuffer, - indexSize + offset, uncompressedSize); - - return isRead; - } - - @Override - public byte[] getStringBytes(int offset) { - if (offset == 0) { - return new byte[0]; - } - - int length = strings.length - offset; - - for (int i = offset; i < strings.length; i++) { - if (strings[i] == 0) { - length = i - offset; - break; - } - } - - byte[] bytes = new byte[length]; - System.arraycopy(strings, offset, bytes, 0, length); - - return bytes; - } - - @Override - public long[] getAttributes(int offset) { - return ImageLocationBase.decompress(locations, offset); - } - - @Override - public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) { - int count = header.getTableLength(); - int index = redirect[name.hashCode() % count]; - - if (index < 0) { - index = -index - 1; - } else { - index = name.hashCode(index) % count; - } - - long[] attributes = getAttributes(offsets[index]); - - ImageLocation imageLocation = new ImageLocation(attributes, strings); - - if (!imageLocation.verify(name)) { - return null; - } - - return imageLocation; - } - - @Override - public int[] attributeOffsets() { - return offsets; - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java index 148debdf4f0..a8147d2a53a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,228 @@ package jdk.internal.jimage; -public final class ImageLocation extends ImageLocationBase { - ImageLocation(long[] attributes, ImageStringsReader strings) { - super(attributes, strings); +import java.nio.ByteBuffer; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class ImageLocation { + public static final int ATTRIBUTE_END = 0; + public static final int ATTRIBUTE_MODULE = 1; + public static final int ATTRIBUTE_PARENT = 2; + public static final int ATTRIBUTE_BASE = 3; + public static final int ATTRIBUTE_EXTENSION = 4; + public static final int ATTRIBUTE_OFFSET = 5; + public static final int ATTRIBUTE_COMPRESSED = 6; + public static final int ATTRIBUTE_UNCOMPRESSED = 7; + public static final int ATTRIBUTE_COUNT = 8; + + protected final long[] attributes; + + protected final ImageStrings strings; + + public ImageLocation(long[] attributes, ImageStrings strings) { + this.attributes = attributes; + this.strings = strings; + } + + ImageStrings getStrings() { + return strings; + } + + private static int attributeLength(int data) { + return (data & 0x7) + 1; + } + + private static int attributeKind(int data) { + return data >>> 3; + } + + static long[] decompress(ByteBuffer bytes) { + long[] attributes = new long[ATTRIBUTE_COUNT]; + + if (bytes != null) { + while (bytes.hasRemaining()) { + int data = bytes.get() & 0xFF; + int kind = attributeKind(data); + + if (kind == ATTRIBUTE_END) { + break; + } + + if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) { + throw new InternalError("Invalid jimage attribute kind"); + } + + int length = attributeLength(data); + long value = 0; + + for (int j = 0; j < length; j++) { + value <<= 8; + + if (!bytes.hasRemaining()) { + throw new InternalError("\"Missing jimage attribute datad"); + } + + value |= bytes.get() & 0xFF; + } + + attributes[kind] = value; + } + } + + return attributes; + } + + public static byte[] compress(long[] attributes) { + ImageStream stream = new ImageStream(16); + + for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) { + long value = attributes[kind]; + + if (value != 0) { + int n = (63 - Long.numberOfLeadingZeros(value)) >> 3; + stream.put((kind << 3) | n); + + for (int i = n; i >= 0; i--) { + stream.put((int)(value >> (i << 3))); + } + } + } + + stream.put(ATTRIBUTE_END << 3); + + return stream.toArray(); + } + + public boolean verify(String name) { + return name.equals(getFullName()); + } + + long getAttribute(int kind) { + if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) { + throw new InternalError("Invalid jimage attribute kind"); + } + + return attributes[kind]; + } + + String getAttributeString(int kind) { + if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) { + throw new InternalError("Invalid jimage attribute kind"); + } + + return getStrings().get((int)attributes[kind]); + } + + public String getModule() { + return getAttributeString(ATTRIBUTE_MODULE); + } + + public int getModuleOffset() { + return (int)getAttribute(ATTRIBUTE_MODULE); + } + + public String getBase() { + return getAttributeString(ATTRIBUTE_BASE); + } + + public int getBaseOffset() { + return (int)getAttribute(ATTRIBUTE_BASE); + } + + public String getParent() { + return getAttributeString(ATTRIBUTE_PARENT); + } + + public int getParentOffset() { + return (int)getAttribute(ATTRIBUTE_PARENT); + } + + public String getExtension() { + return getAttributeString(ATTRIBUTE_EXTENSION); + } + + public int getExtensionOffset() { + return (int)getAttribute(ATTRIBUTE_EXTENSION); + } + + public String getFullName() { + return getFullName(false); + } + + public String getFullName(boolean modulesPrefix) { + StringBuilder builder = new StringBuilder(); + + if (getModuleOffset() != 0) { + if (modulesPrefix) { + builder.append("/modules"); + } + + builder.append('/'); + builder.append(getModule()); + builder.append('/'); + } + + if (getParentOffset() != 0) { + builder.append(getParent()); + builder.append('/'); + } + + builder.append(getBase()); + + if (getExtensionOffset() != 0) { + builder.append('.'); + builder.append(getExtension()); + } + + return builder.toString(); + } + + String buildName(boolean includeModule, boolean includeParent, + boolean includeName) { + StringBuilder builder = new StringBuilder(); + + if (includeModule && getModuleOffset() != 0) { + builder.append("/modules/"); + builder.append(getModule()); + } + + if (includeParent && getParentOffset() != 0) { + builder.append('/'); + builder.append(getParent()); + } + + if (includeName) { + if (includeModule || includeParent) { + builder.append('/'); + } + + builder.append(getBase()); + + if (getExtensionOffset() != 0) { + builder.append('.'); + builder.append(getExtension()); + } + } + + return builder.toString(); + } + + public long getContentOffset() { + return getAttribute(ATTRIBUTE_OFFSET); + } + + public long getCompressedSize() { + return getAttribute(ATTRIBUTE_COMPRESSED); + } + + public long getUncompressedSize() { + return getAttribute(ATTRIBUTE_UNCOMPRESSED); } static ImageLocation readFrom(BasicImageReader reader, int offset) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java deleted file mode 100644 index 461db371d90..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageLocationBase.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jimage; - -public class ImageLocationBase { - static final int ATTRIBUTE_END = 0; - static final int ATTRIBUTE_MODULE = 1; - static final int ATTRIBUTE_PARENT = 2; - static final int ATTRIBUTE_BASE = 3; - static final int ATTRIBUTE_EXTENSION = 4; - static final int ATTRIBUTE_OFFSET = 5; - static final int ATTRIBUTE_COMPRESSED = 6; - static final int ATTRIBUTE_UNCOMPRESSED = 7; - static final int ATTRIBUTE_COUNT = 8; - - protected final long[] attributes; - - protected final ImageStrings strings; - - protected ImageLocationBase(long[] attributes, ImageStrings strings) { - this.attributes = attributes; - this.strings = strings; - } - - ImageStrings getStrings() { - return strings; - } - - private static int attributeLength(int data) { - return (data & 0x7) + 1; - } - - private static int attributeKind(int data) { - return data >>> 3; - } - - static long[] decompress(byte[] bytes) { - return decompress(bytes, 0); - } - - static long[] decompress(byte[] bytes, int offset) { - long[] attributes = new long[ATTRIBUTE_COUNT]; - - if (bytes != null) { - for (int i = offset; i < bytes.length; ) { - int data = bytes[i++] & 0xFF; - int kind = attributeKind(data); - - if (kind == ATTRIBUTE_END) { - break; - } - - assert ATTRIBUTE_END < kind && - kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - int length = attributeLength(data); - long value = 0; - - for (int j = 0; j < length; j++) { - value <<= 8; - value |= bytes[i++] & 0xFF; - } - - attributes[kind] = value; - } - } - - return attributes; - } - - static byte[] compress(long[] attributes) { - ImageStream stream = new ImageStream(16); - - for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) { - long value = attributes[kind]; - - if (value != 0) { - int n = (63 - Long.numberOfLeadingZeros(value)) >> 3; - stream.put((kind << 3) | n); - - for (int i = n; i >= 0; i--) { - stream.put((int)(value >> (i << 3))); - } - } - } - - stream.put(ATTRIBUTE_END << 3); - - return stream.toArray(); - } - - public boolean verify(UTF8String name) { - return UTF8String.equals(getFullName(), name); - } - - protected long getAttribute(int kind) { - assert ATTRIBUTE_END < kind && - kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - - return attributes[kind]; - } - - protected UTF8String getAttributeUTF8String(int kind) { - assert ATTRIBUTE_END < kind && - kind < ATTRIBUTE_COUNT : "Invalid attribute kind"; - - return getStrings().get((int)attributes[kind]); - } - - protected String getAttributeString(int kind) { - return getAttributeUTF8String(kind).toString(); - } - - UTF8String getModule() { - return getAttributeUTF8String(ATTRIBUTE_MODULE); - } - - public String getModuleString() { - return getModule().toString(); - } - - int getModuleOffset() { - return (int)getAttribute(ATTRIBUTE_MODULE); - } - - UTF8String getBase() { - return getAttributeUTF8String(ATTRIBUTE_BASE); - } - - public String getBaseString() { - return getBase().toString(); - } - - int getBaseOffset() { - return (int)getAttribute(ATTRIBUTE_BASE); - } - - UTF8String getParent() { - return getAttributeUTF8String(ATTRIBUTE_PARENT); - } - - public String getParentString() { - return getParent().toString(); - } - - int getParentOffset() { - return (int)getAttribute(ATTRIBUTE_PARENT); - } - - UTF8String getExtension() { - return getAttributeUTF8String(ATTRIBUTE_EXTENSION); - } - - public String getExtensionString() { - return getExtension().toString(); - } - - int getExtensionOffset() { - return (int)getAttribute(ATTRIBUTE_EXTENSION); - } - - UTF8String getFullName() { - return getFullName(false); - } - - UTF8String getFullName(boolean modulesPrefix) { - // Note: Consider a UTF8StringBuilder. - UTF8String fullName = UTF8String.EMPTY_STRING; - - if (getModuleOffset() != 0) { - fullName = fullName.concat( - // TODO The use of UTF8String.MODULES_STRING does not belong here. - modulesPrefix? UTF8String.MODULES_STRING : - UTF8String.EMPTY_STRING, - UTF8String.SLASH_STRING, - getModule(), - UTF8String.SLASH_STRING); - } - - if (getParentOffset() != 0) { - fullName = fullName.concat(getParent(), - UTF8String.SLASH_STRING); - } - - fullName = fullName.concat(getBase()); - - if (getExtensionOffset() != 0) { - fullName = fullName.concat(UTF8String.DOT_STRING, - getExtension()); - } - - return fullName; - } - - UTF8String buildName(boolean includeModule, boolean includeParent, - boolean includeName) { - // Note: Consider a UTF8StringBuilder. - UTF8String name = UTF8String.EMPTY_STRING; - - if (includeModule && getModuleOffset() != 0) { - name = name.concat(UTF8String.MODULES_STRING, - UTF8String.SLASH_STRING, - getModule()); - } - - if (includeParent && getParentOffset() != 0) { - name = name.concat(UTF8String.SLASH_STRING, - getParent()); - } - - if (includeName) { - if (includeModule || includeParent) { - name = name.concat(UTF8String.SLASH_STRING); - } - - name = name.concat(getBase()); - - if (getExtensionOffset() != 0) { - name = name.concat(UTF8String.DOT_STRING, - getExtension()); - } - } - - return name; - } - - String getFullNameString() { - return getFullName().toString(); - } - - public long getContentOffset() { - return getAttribute(ATTRIBUTE_OFFSET); - } - - public long getCompressedSize() { - return getAttribute(ATTRIBUTE_COMPRESSED); - } - - public long getUncompressedSize() { - return getAttribute(ATTRIBUTE_UNCOMPRESSED); - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java deleted file mode 100644 index c15ce732c4b..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleData.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jimage; - -import java.nio.ByteBuffer; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -/* - * Manage module meta data. - * - * NOTE: needs revision. - * Each loader requires set of module meta data to identify which modules and - * packages are managed by that loader. Currently, there is one image file per - * loader, so only one module meta data resource per file. - * - * Each element in the module meta data is a native endian 4 byte integer. Note - * that entries with zero offsets for string table entries should be ignored ( - * padding for hash table lookup.) - * - * Format: - * Count of package to module entries - * Count of module to package entries - * Perfect Hash redirect table[Count of package to module entries] - * Package to module entries[Count of package to module entries] - * Offset to package name in string table - * Offset to module name in string table - * Perfect Hash redirect table[Count of module to package entries] - * Module to package entries[Count of module to package entries] - * Offset to module name in string table - * Count of packages in module - * Offset to first package in packages table - * Packages[] - * Offset to package name in string table - */ - -public final class ImageModuleData { - public static final String META_DATA_EXTENSION = ".jdata"; - public static final String SEPARATOR = "\t"; - public static final int NOT_FOUND = -1; - private static final int ptmCountOffset = 0; - private static final int mtpCountOffset = 1; - private static final int ptmRedirectOffset = 2; - private static final int dataNameOffset = 0; - private static final int ptmDataWidth = 2; - private static final int ptmDataModuleOffset = 1; - private static final int mtpDataWidth = 3; - private static final int mtpDataCountOffset = 1; - private static final int mtpDataOffsetOffset = 2; - - private final BasicImageReader reader; - private final IntBuffer intBuffer; - private final int ptmRedirectLength; - private final int mtpRedirectLength; - private final int ptmDataOffset; - private final int mtpRedirectOffset; - private final int mtpDataOffset; - private final int mtpPackagesOffset; - - public ImageModuleData(BasicImageReader reader) { - this(reader, getBytes(reader)); - } - - public ImageModuleData(BasicImageReader reader, byte[] bytes) { - this.reader = reader; - - ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(reader.getByteOrder()); - this.intBuffer = byteBuffer.asIntBuffer(); - - this.ptmRedirectLength = get(ptmCountOffset); - this.mtpRedirectLength = get(mtpCountOffset); - - this.ptmDataOffset = ptmRedirectOffset + ptmRedirectLength; - this.mtpRedirectOffset = ptmDataOffset + ptmRedirectLength * ptmDataWidth; - this.mtpDataOffset = mtpRedirectOffset + mtpRedirectLength; - this.mtpPackagesOffset = mtpDataOffset + mtpRedirectLength * mtpDataWidth; - } - - private static byte[] getBytes(BasicImageReader reader) { - String loaderName = reader.imagePathName(); - - if (loaderName.endsWith(BasicImageWriter.IMAGE_EXT)) { - loaderName = loaderName.substring(0, loaderName.length() - - BasicImageWriter.IMAGE_EXT.length()); - } - - byte[] bytes = reader.getResource(getModuleDataName(loaderName)); - - if (bytes == null) { - throw new InternalError("module data missing"); - } - - return bytes; - } - - public List fromModulePackages() { - List lines = new ArrayList<>(); - - for (int i = 0; i < mtpRedirectLength; i++) { - int index = mtpDataOffset + i * mtpDataWidth; - int offset = get(index + dataNameOffset); - - if (offset != 0) { - StringBuilder sb = new StringBuilder(); - - sb.append(getString(offset)); - - int count = get(index + mtpDataCountOffset); - int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset; - - for (int j = 0; j < count; j++) { - sb.append(SEPARATOR); - sb.append(stringAt(base + j)); - } - - lines.add(sb.toString()); - } - } - - return lines; - } - - public static String getModuleDataName(String loaderName) { - return loaderName + META_DATA_EXTENSION; - } - - private int get(int index) { - return intBuffer.get(index); - } - - private String getString(int offset) { - return reader.getString(offset); - } - - private String stringAt(int index) { - return reader.getString(get(index)); - } - - private UTF8String getUTF8String(int offset) { - return reader.getUTF8String(offset); - } - - private UTF8String utf8StringAt(int index) { - return reader.getUTF8String(get(index)); - } - - private int find(UTF8String name, int baseOffset, int length, int width) { - if (length == 0) { - return NOT_FOUND; - } - - int hashCode = name.hashCode(); - int index = hashCode % length; - int value = get(baseOffset + index); - - if (value > 0 ) { - hashCode = name.hashCode(value); - index = hashCode % length; - } else if (value < 0) { - index = -1 - value; - } else { - return NOT_FOUND; - } - - index = baseOffset + length + index * width; - - if (!utf8StringAt(index + dataNameOffset).equals(name)) { - return NOT_FOUND; - } - - return index; - } - - public String packageToModule(String packageName) { - UTF8String moduleName = packageToModule(new UTF8String(packageName)); - - return moduleName != null ? moduleName.toString() : null; - } - - public UTF8String packageToModule(UTF8String packageName) { - int index = find(packageName, ptmRedirectOffset, ptmRedirectLength, ptmDataWidth); - - if (index != NOT_FOUND) { - return utf8StringAt(index + ptmDataModuleOffset); - } - - return null; - } - - public List moduleToPackages(String moduleName) { - int index = find(new UTF8String(moduleName), mtpRedirectOffset, - mtpRedirectLength, mtpDataWidth); - - if (index != NOT_FOUND) { - int count = get(index + mtpDataCountOffset); - int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset; - List packages = new ArrayList<>(count); - - for (int i = 0; i < count; i++) { - packages.add(stringAt(base + i)); - } - - return packages; - } - - return null; - } - - public List allPackageNames() { - List packages = new ArrayList<>(); - - for (int i = 0; i < ptmRedirectLength; i++) { - int offset = get(ptmDataOffset + i * ptmDataWidth + dataNameOffset); - - if (offset != 0) { - packages.add(getString(offset)); - } - } - - return packages; - } - - public Set allModuleNames() { - Set modules = new HashSet<>(); - - for (int i = 0; i < mtpRedirectLength; i++) { - int index = mtpDataOffset + i * mtpDataWidth; - int offset = get(index + dataNameOffset); - - if (offset != 0) { - modules.add(getString(offset)); - } - } - - return modules; - } - - public Map packageModuleMap() { - Map map = new HashMap<>(); - - for (int i = 0; i < mtpRedirectLength; i++) { - int index = mtpDataOffset + i * mtpDataWidth; - int offset = get(index + dataNameOffset); - - if (offset != 0) { - String moduleName = getString(offset); - - int count = get(index + mtpDataCountOffset); - int base = get(index + mtpDataOffsetOffset) + mtpPackagesOffset; - - for (int j = 0; j < count; j++) { - map.put(stringAt(base + j), moduleName); - } - } - } - - return map; - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java deleted file mode 100644 index 65c0de0f9a5..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageModuleDataWriter.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jimage; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -public class ImageModuleDataWriter { - final byte[] bytes; - - public ImageModuleDataWriter(BasicImageWriter writer, - Map> modulePackages) { - PerfectHashBuilder packageToModule = new PerfectHashBuilder<>( - new PerfectHashBuilder.Entry().getClass(), - new PerfectHashBuilder.Bucket().getClass()); - PerfectHashBuilder> moduleToPackages = new PerfectHashBuilder<>( - new PerfectHashBuilder.Entry>().getClass(), - new PerfectHashBuilder.Bucket>().getClass()); - - modulePackages.entrySet().stream().forEach((entry) -> { - String moduleName = entry.getKey(); - List packages = entry.getValue(); - packages.stream().forEach((packageName) -> { - packageToModule.put(packageName, moduleName); - }); - - moduleToPackages.put(moduleName, packages); - }); - - packageToModule.generate(); - moduleToPackages.generate(); - - bytes = getBytes(writer, packageToModule, moduleToPackages); - } - - public static ImageModuleDataWriter buildModuleData(BasicImageWriter writer, - Map> modulePackagesMap) { - Set modules = modulePackagesMap.keySet(); - - Map> modulePackages = new LinkedHashMap<>(); - modules.stream().sorted().forEach((moduleName) -> { - List localPackages = modulePackagesMap.get(moduleName).stream() - .map(pn -> pn.replace('.', '/')) - .sorted() - .collect(Collectors.toList()); - modulePackages.put(moduleName, localPackages); - }); - - return new ImageModuleDataWriter(writer, modulePackages); - } - - public static Map> toModulePackages(List lines) { - Map> modulePackages = new LinkedHashMap<>(); - - for (String line : lines) { - String[] parts = line.split(ImageModuleData.SEPARATOR); - String moduleName = parts[0]; - List packages = Arrays.asList(Arrays.copyOfRange(parts, 1, parts.length)); - modulePackages.put(moduleName, packages); - } - - return modulePackages; - } - - public void addLocation(String name, BasicImageWriter writer) { - writer.addLocation(ImageModuleData.getModuleDataName(name), 0, 0, bytes.length); - } - - private byte[] getBytes(BasicImageWriter writer, - PerfectHashBuilder packageToModule, - PerfectHashBuilder> moduleToPackages) { - ImageStream stream = new ImageStream(writer.getByteOrder()); - - // Empty jimage - if (packageToModule.getCount() == 0) { - stream.putInt(0); - stream.putInt(0); - return stream.toArray(); - } - - int[] ptmRedirect = packageToModule.getRedirect(); - int[] mtpRedirect = moduleToPackages.getRedirect(); - PerfectHashBuilder.Entry[] ptmOrder = packageToModule.getOrder(); - PerfectHashBuilder.Entry>[] mtpOrder = moduleToPackages.getOrder(); - - stream.putInt(ptmRedirect.length); - stream.putInt(mtpRedirect.length); - - for (int value : ptmRedirect) { - stream.putInt(value); - } - - for (PerfectHashBuilder.Entry entry : ptmOrder) { - if (entry != null) { - stream.putInt(writer.addString(entry.getKey())); - stream.putInt(writer.addString(entry.getValue())); - } else { - stream.putInt(0); - stream.putInt(0); - } - } - - for (int value : mtpRedirect) { - stream.putInt(value); - } - - int index = 0; - - for (PerfectHashBuilder.Entry> entry : mtpOrder) { - if (entry != null) { - int count = entry.getValue().size(); - stream.putInt(writer.addString(entry.getKey())); - stream.putInt(count); - stream.putInt(index); - index += count; - } else { - stream.putInt(0); - stream.putInt(0); - stream.putInt(0); - } - } - - for (PerfectHashBuilder.Entry> entry : mtpOrder) { - if (entry != null) { - List value = entry.getValue(); - value.stream().forEach((packageName) -> { - stream.putInt(writer.addString(packageName)); - }); - } - } - - return stream.toArray(); - } - - public void writeTo(DataOutputStream out) throws IOException { - out.write(bytes, 0, bytes.length); - } - - public int size() { - return bytes.length; - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java deleted file mode 100644 index a839595085f..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageNativeSubstrate.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.jimage; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; - -public final class ImageNativeSubstrate implements ImageSubstrate { - static { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - @Override - public Void run() { - System.loadLibrary("jimage"); - return null; - } - }); - } - - // TODO: Reinstate when the class below, NIOACCESS, is removed. - //private static final JavaNioAccess NIOACCESS = - // SharedSecrets.getJavaNioAccess(); - - - private final long id; - private final long indexAddress; - private final long dataAddress; - - static native long openImage(String imagePath, boolean bigEndian); - static native void closeImage(long id); - static native long getIndexAddress(long id); - static native long getDataAddress(long id); - static native boolean readCompressed(long id, long offset, - ByteBuffer compressedBuffer, long compressedSize, - ByteBuffer uncompressedBuffer, long uncompressedSize); - static native boolean read(long id, long offset, - ByteBuffer uncompressedBuffer, long uncompressedSize); - static native byte[] getStringBytes(long id, int offset); - static native long[] getAttributes(long id, int offset); - static native long[] findAttributes(long id, byte[] path); - static native int[] attributeOffsets(long id); - - public static native long JIMAGE_Open(String path) throws IOException; - public static native void JIMAGE_Close(long jimageHandle); - public static native long JIMAGE_FindResource(long jimageHandle, - String moduleName, String Version, String path, - long[] size); - public static native long JIMAGE_GetResource(long jimageHandle, - long locationHandle, byte[] buffer, long size); - // Get an array of names that match; return the count found upto array size - public static native int JIMAGE_Resources(long jimageHandle, - String[] outputNames); - // Return the module name for the package - public static native String JIMAGE_PackageToModule(long imageHandle, - String packageName); - - static ByteBuffer newDirectByteBuffer(long address, long capacity) { - assert capacity < Integer.MAX_VALUE; - return NIOACCESS.newDirectByteBuffer(address, (int)capacity, null); - } - - private ImageNativeSubstrate(long id) { - this.id = id; - this.indexAddress = getIndexAddress(id); - this.dataAddress = getDataAddress(id); - } - - static ImageSubstrate openImage(String imagePath, ByteOrder byteOrder) - throws IOException { - long id = openImage(imagePath, byteOrder == ByteOrder.BIG_ENDIAN); - - if (id == 0) { - throw new IOException("Image not found \"" + imagePath + "\""); - } - - return new ImageNativeSubstrate(id); - } - - @Override - public void close() { - closeImage(id); - } - - @Override - public ByteBuffer getIndexBuffer(long offset, long size) { - return newDirectByteBuffer(indexAddress + offset, size); - } - - @Override - public ByteBuffer getDataBuffer(long offset, long size) { - return dataAddress != 0 ? - newDirectByteBuffer(dataAddress + offset, size) : null; - } - - @Override - public boolean supportsDataBuffer() { - return dataAddress != 0; - } - - @Override - public boolean read(long offset, - ByteBuffer compressedBuffer, long compressedSize, - ByteBuffer uncompressedBuffer, long uncompressedSize) { - return readCompressed(id, offset, - compressedBuffer, compressedSize, - uncompressedBuffer, uncompressedSize); - } - - @Override - public boolean read(long offset, - ByteBuffer uncompressedBuffer, long uncompressedSize) { - return read(id, offset, uncompressedBuffer, uncompressedSize); - } - - @Override - public byte[] getStringBytes(int offset) { - byte[] ret = getStringBytes(id, offset); - if (ret == null) { - throw new OutOfMemoryError("Error accessing array at offset " - + offset); - } - return ret; - } - - @Override - public long[] getAttributes(int offset) { - return getAttributes(id, offset); - } - - @Override - public ImageLocation findLocation(UTF8String name, ImageStringsReader strings) { - long[] attributes = findAttributes(id, name.getBytes()); - - return attributes != null ? new ImageLocation(attributes, strings) : null; - } - - @Override - public int[] attributeOffsets() { - return attributeOffsets(id); - } - - // TODO: Remove when JRT-FS no longer indirectly depends on ImageNativeSubstrate - /** - * Reflective wrapper around ShareSecrets JavaNioAccess. - * - * SharedSecrets and friend interfaces moved from 'sun.misc' to 'jdk.internal.misc' - * in 1.9. This class provides the runtime with access to the appropriate - * JavaNioAccess methods whether running on 1.9, or lower. - */ - static class NIOACCESS { - - private static final String PKG_PREFIX = "jdk.internal.misc"; - private static final String LEGACY_PKG_PREFIX = "sun.misc"; - - private static final Object javaNioAccess; - private static final java.lang.reflect.Method newDirectByteBufferMethod; - - static { - try { - Class c = getJDKClass("JavaNioAccess"); - - java.lang.reflect.Method m = - getJDKClass("SharedSecrets").getDeclaredMethod("getJavaNioAccess"); - javaNioAccess = m.invoke(null); - - newDirectByteBufferMethod = c.getDeclaredMethod("newDirectByteBuffer", - long.class, - int.class, - Object.class); - } catch (ReflectiveOperationException x) { - throw new InternalError(x); - } - } - - private static Class getJDKClass(String name) throws ClassNotFoundException { - try { - return Class.forName(PKG_PREFIX + "." + name); - } catch (ClassNotFoundException x) { - try { - return Class.forName(LEGACY_PKG_PREFIX + "." + name); - } catch (ClassNotFoundException ex) { - x.addSuppressed(ex); - throw x; - } - } - } - - static ByteBuffer newDirectByteBuffer(long addr, int cap, Object ob) { - try { - return (ByteBuffer) newDirectByteBufferMethod.invoke(javaNioAccess, addr, cap, ob); - } catch (ReflectiveOperationException x) { - throw new InternalError(x); - } - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java index d66621f04e0..cb64fb088c0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,19 +32,34 @@ import java.nio.IntBuffer; import java.nio.file.Files; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; -import java.nio.file.Paths; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; -import static jdk.internal.jimage.UTF8String.*; +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ public class ImageReader extends BasicImageReader { - // well-known strings needed for image file system. - static final UTF8String ROOT_STRING = UTF8String.SLASH_STRING; + + private static final int SIZE_OF_OFFSET = 4; + + // Map of files opened as LITTLE_ENDIAN + private static final HashMap OPEN_LE_FILES + = new HashMap<>(); + + // Map of files opened as BIG_ENDIAN + private static final HashMap OPEN_BE_FILES + = new HashMap<>(); + + private int openCount; // attributes of the .jimage file. jimage file does not contain // attributes for the individual resources (yet). We use attributes @@ -52,78 +67,60 @@ public class ImageReader extends BasicImageReader { // Iniitalized lazily, see {@link #imageFileAttributes()}. private BasicFileAttributes imageFileAttributes; - private final ImageModuleData moduleData; - // directory management implementation - private final Map nodes; + private final HashMap nodes; private volatile Directory rootDir; private Directory packagesDir; private Directory modulesDir; - ImageReader(String imagePath, ByteOrder byteOrder) throws IOException { + private ImageReader(Path imagePath, ByteOrder byteOrder) throws IOException { super(imagePath, byteOrder); - this.moduleData = new ImageModuleData(this); - this.nodes = Collections.synchronizedMap(new HashMap<>()); + this.nodes = new HashMap<>(); } - ImageReader(String imagePath) throws IOException { - this(imagePath, ByteOrder.nativeOrder()); + public static ImageReader open(Path imagePath, ByteOrder byteOrder) throws IOException { + HashMap openFiles = getOpenFilesMap(byteOrder); + ImageReader reader; + synchronized (openFiles) { + reader = openFiles.get(imagePath); + if (reader == null) { + reader = new ImageReader(imagePath, byteOrder); + ImageReader existingReader = openFiles.putIfAbsent(imagePath, reader); + assert (existingReader == null); + } + reader.openCount++; + } + return reader; } - public static ImageReader open(String imagePath, ByteOrder byteOrder) throws IOException { - return new ImageReader(imagePath, byteOrder); + private static HashMap getOpenFilesMap(ByteOrder byteOrder) { + return (byteOrder == ByteOrder.BIG_ENDIAN) ? OPEN_BE_FILES : OPEN_LE_FILES; } /** * Opens the given file path as an image file, returning an {@code ImageReader}. */ - public static ImageReader open(String imagePath) throws IOException { + public static ImageReader open(Path imagePath) throws IOException { return open(imagePath, ByteOrder.nativeOrder()); } - @Override - public synchronized void close() throws IOException { - super.close(); - clearNodes(); - } - - @Override - public ImageLocation findLocation(UTF8String name) { - ImageLocation location = super.findLocation(name); - - // NOTE: This should be removed when module system is up in full. - if (location == null) { - int index = name.lastIndexOf('/'); - - if (index != -1) { - UTF8String packageName = name.substring(0, index); - UTF8String moduleName = moduleData.packageToModule(packageName); - - if (moduleName != null) { - UTF8String fullName = UTF8String.SLASH_STRING.concat(moduleName, - UTF8String.SLASH_STRING, name); - location = super.findLocation(fullName); - } - } else { - // No package, try all modules. - for (String mod : moduleData.allModuleNames()) { - location = super.findLocation("/" + mod + "/" + name); - if (location != null) { - break; - } - } + private boolean canClose() { + HashMap openFiles = getOpenFilesMap(this.getByteOrder()); + synchronized (openFiles) { + if (--this.openCount == 0) { + return openFiles.remove(this.getName(), this); } } - - return location; + return false; } - /** - * Return the module name that contains the given package name. - */ - public String getModule(String packageName) { - return moduleData.packageToModule(packageName); + @Override + public void close() throws IOException { + if (canClose()) { + super.close(); + clearNodes(); + } } // jimage file does not store directory structure. We build nodes @@ -135,15 +132,13 @@ public class ImageReader extends BasicImageReader { private static final int MODULES_DIR = 0b0000_0000_0000_0100; private int flags; - private final UTF8String name; + private final String name; private final BasicFileAttributes fileAttrs; private boolean completed; - Node(UTF8String name, BasicFileAttributes fileAttrs) { - assert name != null; - assert fileAttrs != null; - this.name = name; - this.fileAttrs = fileAttrs; + Node(String name, BasicFileAttributes fileAttrs) { + this.name = Objects.requireNonNull(name); + this.fileAttrs = Objects.requireNonNull(fileAttrs); } /** @@ -183,7 +178,7 @@ public class ImageReader extends BasicImageReader { return (flags & MODULES_DIR) != 0; } - public final UTF8String getName() { + public final String getName() { return name; } @@ -250,7 +245,7 @@ public class ImageReader extends BasicImageReader { } public final String getNameString() { - return name.toString(); + return name; } @Override @@ -281,17 +276,17 @@ public class ImageReader extends BasicImageReader { static final class Directory extends Node { private final List children; - private Directory(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) { + private Directory(String name, BasicFileAttributes fileAttrs) { super(name, fileAttrs); children = new ArrayList<>(); } - static Directory create(Directory parent, UTF8String name, BasicFileAttributes fileAttrs) { - Directory dir = new Directory(parent, name, fileAttrs); + static Directory create(Directory parent, String name, BasicFileAttributes fileAttrs) { + Directory d = new Directory(name, fileAttrs); if (parent != null) { - parent.addChild(dir); + parent.addChild(d); } - return dir; + return d; } @Override @@ -325,25 +320,15 @@ public class ImageReader extends BasicImageReader { static class Resource extends Node { private final ImageLocation loc; - private Resource(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { - this(parent, loc.getFullName(true), loc, fileAttrs); - } - - private Resource(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) { - super(name, fileAttrs); + private Resource(ImageLocation loc, BasicFileAttributes fileAttrs) { + super(loc.getFullName(true), fileAttrs); this.loc = loc; - } + } static Resource create(Directory parent, ImageLocation loc, BasicFileAttributes fileAttrs) { - Resource resource = new Resource(parent, loc, fileAttrs); - parent.addChild(resource); - return resource; - } - - static Resource create(Directory parent, UTF8String name, ImageLocation loc, BasicFileAttributes fileAttrs) { - Resource resource = new Resource(parent, name, loc, fileAttrs); - parent.addChild(resource); - return resource; + Resource rs = new Resource(loc, fileAttrs); + parent.addChild(rs); + return rs; } @Override @@ -373,7 +358,7 @@ public class ImageReader extends BasicImageReader { @Override public String extension() { - return loc.getExtensionString(); + return loc.getExtension(); } @Override @@ -386,15 +371,15 @@ public class ImageReader extends BasicImageReader { static class LinkNode extends Node { private final Node link; - private LinkNode(Directory parent, UTF8String name, Node link) { + private LinkNode(String name, Node link) { super(name, link.getFileAttributes()); this.link = link; } - static LinkNode create(Directory parent, UTF8String name, Node link) { - LinkNode linkNode = new LinkNode(parent, name, link); - parent.addChild(linkNode); - return linkNode; + static LinkNode create(Directory parent, String name, Node link) { + LinkNode ln = new LinkNode(name, link); + parent.addChild(ln); + return ln; } @Override @@ -418,14 +403,6 @@ public class ImageReader extends BasicImageReader { return buildRootDirectory(); } - public Node findNode(String name) { - return findNode(new UTF8String(name)); - } - - public Node findNode(byte[] name) { - return findNode(new UTF8String(name)); - } - /** * To visit sub tree resources. */ @@ -436,142 +413,178 @@ public class ImageReader extends BasicImageReader { /** * Lazily build a node from a name. - */ - private final class NodeBuilder { + */ + private Node buildNode(String name) { + Node n; + boolean isPackages = name.startsWith("/packages"); + boolean isModules = !isPackages && name.startsWith("/modules"); - private static final int SIZE_OF_OFFSET = 4; - - private final UTF8String name; - - private NodeBuilder(UTF8String name) { - this.name = name; + if (!(isModules || isPackages)) { + return null; } - private Node buildNode() { - Node n = null; - boolean isPackages = false; - boolean isModules = false; - String strName = name.toString(); - if (strName.startsWith("" + PACKAGES_STRING)) { - isPackages = true; + ImageLocation loc = findLocation(name); + + if (loc != null) { // A sub tree node + if (isPackages) { + n = handlePackages(name, loc); + } else { // modules sub tree + n = handleModulesSubTree(name, loc); + } + } else { // Asking for a resource? /modules/java.base/java/lang/Object.class + if (isModules) { + n = handleResource(name); } else { - if (strName.startsWith("" + MODULES_STRING)) { - isModules = true; - } - } - if (!isModules && !isPackages) { - return null; - } - - ImageLocation loc = findLocation(name); - - if (loc != null) { // A sub tree node - if (isPackages) { - n = handlePackages(strName, loc); - } else { // modules sub tree - n = handleModulesSubTree(strName, loc); - } - } else { // Asking for a resource? /modules/java.base/java/lang/Object.class - if (isModules) { - n = handleResource(strName, loc); - } - } - return n; - } - - private void visitLocation(ImageLocation loc, LocationVisitor visitor) { - byte[] offsets = getResource(loc); - ByteBuffer buffer = ByteBuffer.wrap(offsets); - buffer.order(getByteOrder()); - IntBuffer intBuffer = buffer.asIntBuffer(); - for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { - int offset = intBuffer.get(i); - ImageLocation pkgLoc = getLocation(offset); - visitor.visit(pkgLoc); + // Possibly ask for /packages/java.lang/java.base + // although /packages/java.base not created + n = handleModuleLink(name); } } + return n; + } - private Node handlePackages(String name, ImageLocation loc) { - long size = loc.getUncompressedSize(); - Node n = null; - // Only possiblities are /packages, /packages/package/module - if (name.equals("" + PACKAGES_STRING)) { - visitLocation(loc, (childloc) -> { - findNode(childloc.getFullName()); - }); - packagesDir.setCompleted(true); - n = packagesDir; - } else { - if (size != 0) { // children are links to module - String pkgName = getBaseExt(loc); - Directory pkgDir = newDirectory(packagesDir, - packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName))); - visitLocation(loc, (childloc) -> { - findNode(childloc.getFullName()); - }); - pkgDir.setCompleted(true); - n = pkgDir; - } else { // Link to module - String pkgName = loc.getParentString(); - String modName = getBaseExt(loc); - Node targetNode = findNode(MODULES_STRING + "/" + modName); - if (targetNode != null) { - UTF8String pkgDirName = packagesDir.getName().concat(SLASH_STRING, new UTF8String(pkgName)); - Directory pkgDir = (Directory) nodes.get(pkgDirName); - Node linkNode = newLinkNode(pkgDir, - pkgDir.getName().concat(SLASH_STRING, new UTF8String(modName)), targetNode); - n = linkNode; - } - } - } - return n; - } - - private Node handleModulesSubTree(String name, ImageLocation loc) { - Node n; - Directory dir = makeDirectories(loc.getFullName()); - visitLocation(loc, (childloc) -> { - String path = childloc.getFullNameString(); - if (path.startsWith(MODULES_STRING.toString())) { // a package - makeDirectories(childloc.getFullName()); - } else { // a resource - makeDirectories(childloc.buildName(true, true, false)); - newResource(dir, childloc); - } - }); - dir.setCompleted(true); - n = dir; - return n; - } - - private Node handleResource(String name, ImageLocation loc) { - Node n = null; - String locationPath = name.substring((MODULES_STRING).length()); - ImageLocation resourceLoc = findLocation(locationPath); - if (resourceLoc != null) { - Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); - Resource res = newResource(dir, resourceLoc); - n = res; - } - return n; - } - - private String getBaseExt(ImageLocation loc) { - String base = loc.getBaseString(); - String ext = loc.getExtensionString(); - if (ext != null && !ext.isEmpty()) { - base = base + "." + ext; - } - return base; + private void visitLocation(ImageLocation loc, LocationVisitor visitor) { + byte[] offsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(offsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + for (int i = 0; i < offsets.length / SIZE_OF_OFFSET; i++) { + int offset = intBuffer.get(i); + ImageLocation pkgLoc = getLocation(offset); + visitor.visit(pkgLoc); } } - public synchronized Node findNode(UTF8String name) { + private void visitPackageLocation(ImageLocation loc) { + // Retrieve package name + String pkgName = getBaseExt(loc); + // Content is array of offsets in Strings table + byte[] stringsOffsets = getResource(loc); + ByteBuffer buffer = ByteBuffer.wrap(stringsOffsets); + buffer.order(getByteOrder()); + IntBuffer intBuffer = buffer.asIntBuffer(); + // For each module, create a link node. + for (int i = 0; i < stringsOffsets.length / SIZE_OF_OFFSET; i++) { + // skip empty state, useless. + intBuffer.get(i); + i++; + int offset = intBuffer.get(i); + String moduleName = getString(offset); + Node targetNode = findNode("/modules/" + moduleName); + if (targetNode != null) { + String pkgDirName = packagesDir.getName() + "/" + pkgName; + Directory pkgDir = (Directory) nodes.get(pkgDirName); + newLinkNode(pkgDir, pkgDir.getName() + "/" + moduleName, targetNode); + } + } + } + + private Node handlePackages(String name, ImageLocation loc) { + long size = loc.getUncompressedSize(); + Node n = null; + // Only possiblities are /packages, /packages/package/module + if (name.equals("/packages")) { + visitLocation(loc, (childloc) -> { + findNode(childloc.getFullName()); + }); + packagesDir.setCompleted(true); + n = packagesDir; + } else { + if (size != 0) { // children are offsets to module in StringsTable + String pkgName = getBaseExt(loc); + Directory pkgDir = newDirectory(packagesDir, packagesDir.getName() + "/" + pkgName); + visitPackageLocation(loc); + pkgDir.setCompleted(true); + n = pkgDir; + } else { // Link to module + String pkgName = loc.getParent(); + String modName = getBaseExt(loc); + Node targetNode = findNode("/modules/" + modName); + if (targetNode != null) { + String pkgDirName = packagesDir.getName() + "/" + pkgName; + Directory pkgDir = (Directory) nodes.get(pkgDirName); + Node linkNode = newLinkNode(pkgDir, pkgDir.getName() + "/" + modName, targetNode); + n = linkNode; + } + } + } + return n; + } + + // Asking for /packages/package/module although + // /packages// not yet created, need to create it + // prior to return the link to module node. + private Node handleModuleLink(String name) { + // eg: unresolved /packages/package/module + // Build /packages/package node + Node ret = null; + String radical = "/packages/"; + String path = name; + if (path.startsWith(radical)) { + int start = radical.length(); + int pkgEnd = path.indexOf('/', start); + if (pkgEnd != -1) { + String pkg = path.substring(start, pkgEnd); + String pkgPath = radical + pkg; + Node n = findNode(pkgPath); + // If not found means that this is a symbolic link such as: + // /packages/java.util/java.base/java/util/Vector.class + // and will be done by a retry of the filesystem + for (Node child : n.getChildren()) { + if (child.name.equals(name)) { + ret = child; + break; + } + } + } + } + return ret; + } + + private Node handleModulesSubTree(String name, ImageLocation loc) { + Node n; + assert (name.equals(loc.getFullName())); + Directory dir = makeDirectories(name); + visitLocation(loc, (childloc) -> { + String path = childloc.getFullName(); + if (path.startsWith("/modules")) { // a package + makeDirectories(path); + } else { // a resource + makeDirectories(childloc.buildName(true, true, false)); + newResource(dir, childloc); + } + }); + dir.setCompleted(true); + n = dir; + return n; + } + + private Node handleResource(String name) { + Node n = null; + String locationPath = name.substring("/modules".length()); + ImageLocation resourceLoc = findLocation(locationPath); + if (resourceLoc != null) { + Directory dir = makeDirectories(resourceLoc.buildName(true, true, false)); + Resource res = newResource(dir, resourceLoc); + n = res; + } + return n; + } + + private String getBaseExt(ImageLocation loc) { + String base = loc.getBase(); + String ext = loc.getExtension(); + if (ext != null && !ext.isEmpty()) { + base = base + "." + ext; + } + return base; + } + + public synchronized Node findNode(String name) { buildRootDirectory(); Node n = nodes.get(name); if (n == null || !n.isCompleted()) { - NodeBuilder builder = new NodeBuilder(name); - n = builder.buildNode(); + n = buildNode(name); } return n; } @@ -588,7 +601,7 @@ public class ImageReader extends BasicImageReader { BasicFileAttributes attrs = imageFileAttributes; if (attrs == null) { try { - Path file = Paths.get(imagePath()); + Path file = getImagePath(); attrs = Files.readAttributes(file, BasicFileAttributes.class); } catch (IOException ioe) { throw new UncheckedIOException(ioe); @@ -598,30 +611,38 @@ public class ImageReader extends BasicImageReader { return attrs; } - private synchronized Directory buildRootDirectory() { - if (rootDir != null) { - return rootDir; + private Directory buildRootDirectory() { + Directory root = rootDir; // volatile read + if (root != null) { + return root; } - // FIXME no time information per resource in jimage file (yet?) - // we use file attributes of jimage itself. - // root directory - rootDir = newDirectory(null, ROOT_STRING); - rootDir.setIsRootDir(); + synchronized (this) { + root = rootDir; + if (root != null) { + return root; + } - // /packages dir - packagesDir = newDirectory(rootDir, PACKAGES_STRING); - packagesDir.setIsPackagesDir(); + // FIXME no time information per resource in jimage file (yet?) + // we use file attributes of jimage itself. + // root directory + root = newDirectory(null, "/"); + root.setIsRootDir(); - // /modules dir - modulesDir = newDirectory(rootDir, MODULES_STRING); - modulesDir.setIsModulesDir(); + // /packages dir + packagesDir = newDirectory(root, "/packages"); + packagesDir.setIsPackagesDir(); - rootDir.setCompleted(true); - return rootDir; + // /modules dir + modulesDir = newDirectory(root, "/modules"); + modulesDir.setIsModulesDir(); + + root.setCompleted(true); + return rootDir = root; + } } - private Directory newDirectory(Directory parent, UTF8String name) { + private Directory newDirectory(Directory parent, String name) { Directory dir = Directory.create(parent, name, imageFileAttributes()); nodes.put(dir.getName(), dir); return dir; @@ -633,39 +654,30 @@ public class ImageReader extends BasicImageReader { return res; } - private LinkNode newLinkNode(Directory dir, UTF8String name, Node link) { + private LinkNode newLinkNode(Directory dir, String name, Node link) { LinkNode linkNode = LinkNode.create(dir, name, link); nodes.put(linkNode.getName(), linkNode); return linkNode; } - private List dirs(UTF8String parent) { - List splits = new ArrayList<>(); - - for (int i = 1; i < parent.length(); i++) { - if (parent.byteAt(i) == '/') { - splits.add(parent.substring(0, i)); - } + private Directory makeDirectories(String parent) { + Directory last = rootDir; + for (int offset = parent.indexOf('/', 1); + offset != -1; + offset = parent.indexOf('/', offset + 1)) { + String dir = parent.substring(0, offset); + last = makeDirectory(dir, last); } + return makeDirectory(parent, last); - splits.add(parent); - - return splits; } - private Directory makeDirectories(UTF8String parent) { - Directory last = rootDir; - List dirs = dirs(parent); - - for (UTF8String dir : dirs) { - Directory nextDir = (Directory) nodes.get(dir); - if (nextDir == null) { - nextDir = newDirectory(last, dir); - } - last = nextDir; + private Directory makeDirectory(String dir, Directory last) { + Directory nextDir = (Directory) nodes.get(dir); + if (nextDir == null) { + nextDir = newDirectory(last, dir); } - - return last; + return nextDir; } public byte[] getResource(Node node) throws IOException { diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java index 5f9a219a92f..23be8faaf19 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageReaderFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,13 +34,19 @@ import java.util.Map; /** * Factory to get ImageReader + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public class ImageReaderFactory { private ImageReaderFactory() {} private static final String JAVA_HOME = System.getProperty("java.home"); private static final Path BOOT_MODULES_JIMAGE = - Paths.get(JAVA_HOME, "lib", "modules", "bootmodules.jimage"); + Paths.get(JAVA_HOME, "lib", "modules"); private static final Map readers = new ConcurrentHashMap<>(); @@ -52,7 +58,7 @@ public class ImageReaderFactory { if (reader != null) { return reader; } - reader = ImageReader.open(jimage.toString()); + reader = ImageReader.open(jimage); // potential race with other threads opening the same URL ImageReader r = readers.putIfAbsent(jimage, reader); if (r == null) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java index dd7709c8ac7..6abe1e651aa 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,40 +29,47 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; -class ImageStream { +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class ImageStream { private ByteBuffer buffer; - ImageStream() { + public ImageStream() { this(1024, ByteOrder.nativeOrder()); } - ImageStream(int size) { + public ImageStream(int size) { this(size, ByteOrder.nativeOrder()); } - ImageStream(byte[] bytes) { + public ImageStream(byte[] bytes) { this(bytes, ByteOrder.nativeOrder()); } - ImageStream(ByteOrder byteOrder) { + public ImageStream(ByteOrder byteOrder) { this(1024, byteOrder); } - ImageStream(int size, ByteOrder byteOrder) { + public ImageStream(int size, ByteOrder byteOrder) { buffer = ByteBuffer.allocate(size); buffer.order(byteOrder); } - ImageStream(byte[] bytes, ByteOrder byteOrder) { + public ImageStream(byte[] bytes, ByteOrder byteOrder) { buffer = ByteBuffer.wrap(bytes); buffer.order(byteOrder); } - ImageStream(ByteBuffer buffer) { + public ImageStream(ByteBuffer buffer) { this.buffer = buffer; } - ImageStream align(int alignment) { + public ImageStream align(int alignment) { int padding = (getSize() - 1) & ((1 << alignment) - 1); for (int i = 0; i < padding; i++) { @@ -72,8 +79,10 @@ class ImageStream { return this; } - void ensure(int needs) { - assert 0 <= needs : "Negative needs"; + public void ensure(int needs) { + if (needs < 0) { + throw new IndexOutOfBoundsException("needs"); + } if (needs > buffer.remaining()) { byte[] bytes = buffer.array(); @@ -86,109 +95,112 @@ class ImageStream { } } - boolean hasByte() { + public boolean hasByte() { return buffer.remaining() != 0; } - boolean hasBytes(int needs) { + public boolean hasBytes(int needs) { return needs <= buffer.remaining(); } - void skip(int n) { - assert 0 <= n : "Negative offset"; + public void skip(int n) { + if (n < 0) { + throw new IndexOutOfBoundsException("n"); + } + buffer.position(buffer.position() + n); } - int get() { + public int get() { return buffer.get() & 0xFF; } - void get(byte bytes[], int offset, int size) { + public void get(byte bytes[], int offset, int size) { buffer.get(bytes, offset, size); } - int getShort() { + public int getShort() { return buffer.getShort(); } - int getInt() { + public int getInt() { return buffer.getInt(); } - long getLong() { + public long getLong() { return buffer.getLong(); } - ImageStream put(byte byt) { + public ImageStream put(byte byt) { ensure(1); buffer.put(byt); return this; } - ImageStream put(int byt) { + public ImageStream put(int byt) { return put((byte)byt); } - ImageStream put(byte bytes[], int offset, int size) { + public ImageStream put(byte bytes[], int offset, int size) { ensure(size); buffer.put(bytes, offset, size); return this; } - ImageStream put(ImageStream stream) { + public ImageStream put(ImageStream stream) { put(stream.buffer.array(), 0, stream.buffer.position()); return this; } - ImageStream putShort(short value) { + public ImageStream putShort(short value) { ensure(2); buffer.putShort(value); return this; } - ImageStream putShort(int value) { + public ImageStream putShort(int value) { return putShort((short)value); } - ImageStream putInt(int value) { + public ImageStream putInt(int value) { ensure(4); buffer.putInt(value); return this; } - ImageStream putLong(long value) { + public ImageStream putLong(long value) { ensure(8); buffer.putLong(value); return this; } - ByteBuffer getBuffer() { + public ByteBuffer getBuffer() { return buffer; } - int getPosition() { + public int getPosition() { return buffer.position(); } - int getSize() { + public int getSize() { return buffer.position(); } - byte[] getBytes() { + public byte[] getBytes() { return buffer.array(); } - void setPosition(int offset) { + public void setPosition(int offset) { buffer.position(offset); } - byte[] toArray() { + public byte[] toArray() { return Arrays.copyOf(buffer.array(), buffer.position()); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java index d4470d999a1..6e7d76a8ff9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStrings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,15 @@ package jdk.internal.jimage; -interface ImageStrings { - public UTF8String get(int offset); +/** + * @implNote This interface needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public interface ImageStrings { + public String get(int offset); - public int add(final UTF8String string); + public int add(final String string); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java index e4ee6c3d220..7a6ad7b75f4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageStringsReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,18 @@ package jdk.internal.jimage; -class ImageStringsReader implements ImageStrings { +import java.io.UTFDataFormatException; +import java.nio.ByteBuffer; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class ImageStringsReader implements ImageStrings { + public static final int HASH_MULTIPLIER = 0x01000193; private final BasicImageReader reader; ImageStringsReader(BasicImageReader reader) { @@ -33,12 +44,239 @@ class ImageStringsReader implements ImageStrings { } @Override - public UTF8String get(int offset) { - return reader.getUTF8String(offset); + public String get(int offset) { + return reader.getString(offset); } @Override - public int add(final UTF8String string) { + public int add(final String string) { throw new InternalError("Can not add strings at runtime"); } + + private static int hashCode(byte[] bytes, int offset, int count, int seed) { + for (int i = offset, limit = offset + count; i < limit; i++) { + seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF); + } + + return seed & 0x7FFFFFFF; + } + + public static int hashCode(byte[] bytes, int seed) { + return hashCode(bytes, 0, bytes.length, seed); + } + + public static int hashCode(byte[] bytes) { + return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER); + } + + public static int hashCode(String string, int seed) { + return hashCode(mutf8FromString(string), seed); + } + + public static int hashCode(String string) { + return hashCode(mutf8FromString(string), HASH_MULTIPLIER); + } + + static int charsFromMUTF8Length(byte[] bytes, int offset, int count) { + int length = 0; + + for (int i = offset; i < offset + count; i++) { + byte ch = bytes[i]; + + if (ch == 0) { + break; + } + + if ((ch & 0xC0) != 0x80) { + length++; + } + } + + return length; + } + + static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException { + int j = 0; + + for (int i = offset; i < offset + count; i++) { + byte ch = bytes[i]; + + if (ch == 0) { + break; + } + + boolean is_unicode = (ch & 0x80) != 0; + int uch = ch & 0x7F; + + if (is_unicode) { + int mask = 0x40; + + while ((uch & mask) != 0) { + ch = bytes[++i]; + + if ((ch & 0xC0) != 0x80) { + throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch)); + } + + uch = ((uch & ~mask) << 6) | (ch & 0x3F); + mask <<= 6 - 1; + } + + if ((uch & 0xFFFF) != uch) { + throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch)); + } + } + + chars[j++] = (char)uch; + } + } + + public static String stringFromMUTF8(byte[] bytes, int offset, int count) { + int length = charsFromMUTF8Length(bytes, offset, count); + char[] chars = new char[length]; + + try { + charsFromMUTF8(chars, bytes, offset, count); + } catch (UTFDataFormatException ex) { + throw new InternalError("Attempt to convert non modified UTF-8 byte sequence"); + } + + return new String(chars); + } + + public static String stringFromMUTF8(byte[] bytes) { + return stringFromMUTF8(bytes, 0, bytes.length); + } + + static int charsFromByteBufferLength(ByteBuffer buffer) { + int length = 0; + + while(buffer.hasRemaining()) { + byte ch = buffer.get(); + + if (ch == 0) { + return length; + } + + if ((ch & 0xC0) != 0x80) { + length++; + } + } + + throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); + } + + static void charsFromByteBuffer(char chars[], ByteBuffer buffer) { + int j = 0; + + while(buffer.hasRemaining()) { + byte ch = buffer.get(); + + if (ch == 0) { + return; + } + + boolean is_unicode = (ch & 0x80) != 0; + int uch = ch & 0x7F; + + if (is_unicode) { + int mask = 0x40; + + while ((uch & mask) != 0) { + ch = buffer.get(); + + if ((ch & 0xC0) != 0x80) { + throw new InternalError("Bad continuation in modified UTF-8 byte sequence"); + } + + uch = ((uch & ~mask) << 6) | (ch & 0x3F); + mask <<= 6 - 1; + } + } + + if ((uch & 0xFFFF) != uch) { + throw new InternalError("UTF-32 char in modified UTF-8 byte sequence"); + } + + chars[j++] = (char)uch; + } + + throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); + } + + public static String stringFromByteBuffer(ByteBuffer buffer) { + int length = charsFromByteBufferLength(buffer); + buffer.rewind(); + char[] chars = new char[length]; + charsFromByteBuffer(chars, buffer); + + return new String(chars); + } + + static int mutf8FromCharsLength(char chars[]) { + int length = 0; + + for (char ch : chars) { + int uch = ch & 0xFFFF; + + if ((uch & ~0x7F) != 0) { + int mask = ~0x3F; + int n = 0; + + do { + n++; + uch >>= 6; + mask >>= 1; + } while ((uch & mask) != 0); + + length += n + 1; + } else if (uch == 0) { + length += 2; + } else { + length++; + } + } + + return length; + } + + static void mutf8FromChars(byte[] bytes, int offset, char chars[]) { + int j = offset; + byte[] buffer = new byte[8]; + + for (char ch : chars) { + int uch = ch & 0xFFFF; + + if ((uch & ~0x7F) != 0) { + int mask = ~0x3F; + int n = 0; + + do { + buffer[n++] = (byte)(0x80 | (uch & 0x3F)); + uch >>= 6; + mask >>= 1; + } while ((uch & mask) != 0); + + buffer[n] = (byte)((mask << 1) | uch); + + do { + bytes[j++] = buffer[n--]; + } while (0 <= n); + } else if (uch == 0) { + bytes[j++] = (byte)0xC0; + bytes[j++] = (byte)0x80; + } else { + bytes[j++] = (byte)uch; + } + } + } + + public static byte[] mutf8FromString(String string) { + char[] chars = string.toCharArray(); + int length = mutf8FromCharsLength(chars); + byte[] bytes = new byte[length]; + mutf8FromChars(bytes, 0, chars); + + return bytes; + } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java new file mode 100644 index 00000000000..b37907845a2 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage; + +import java.nio.ByteBuffer; + +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +class NativeImageBuffer { + static { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("jimage"); + return null; + } + }); + } + + native static ByteBuffer getNativeMap(String imagePath); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java deleted file mode 100644 index 89c1012f65c..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePool.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.jimage; - -import jdk.internal.jimage.decompressor.CompressedResourceHeader; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Collection; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * Pool of resources. This class contain the content of a jimage file in the - * matter of Resource. - */ -public interface ResourcePool { - - /** - * Resources visitor - */ - public interface Visitor { - - /** - * Called for each visited Resource. - * - * @param resource The resource to deal with. - * @param order Byte order - * @param strings - * @return A resource or null if the passed resource is to be removed - * from the jimage. - * @throws Exception - */ - public Resource visit(Resource resource, ByteOrder order, - StringTable strings) throws Exception; - } - - /** - * A JImage Resource. Fully identified by its path. - */ - public static class Resource { - - private final String path; - private final ByteBuffer content; - - private final String module; - - public Resource(String path, ByteBuffer content) { - Objects.requireNonNull(path); - Objects.requireNonNull(content); - this.path = path; - this.content = content.asReadOnlyBuffer(); - String[] split = ImageFileCreator.splitPath(path); - module = split[0]; - } - - public String getPath() { - return path; - } - - public String getModule() { - return module; - } - - /** - * The resource content. - * - * @return A read only buffer. - */ - public ByteBuffer getContent() { - return content; - } - - public int getLength() { - return content.limit(); - } - - public byte[] getByteArray() { - content.rewind(); - byte[] array = new byte[content.remaining()]; - content.get(array); - return array; - } - - @Override - public String toString() { - return getPath(); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Resource)) { - return false; - } - Resource res = (Resource) obj; - return res.path.equals(path); - } - - @Override - public int hashCode() { - int hash = 7; - hash = 53 * hash + Objects.hashCode(this.path); - return hash; - } - } - - /** - * A resource that has been compressed. - */ - public static final class CompressedResource extends Resource { - - private final long uncompressed_size; - - private CompressedResource(String path, ByteBuffer content, - long uncompressed_size) { - super(path, content); - this.uncompressed_size = uncompressed_size; - } - - public long getUncompressedSize() { - return uncompressed_size; - } - - public static CompressedResource newCompressedResource(Resource original, - ByteBuffer compressed, - String plugin, String pluginConfig, StringTable strings, - ByteOrder order) throws Exception { - Objects.requireNonNull(original); - Objects.requireNonNull(compressed); - Objects.requireNonNull(plugin); - - boolean isTerminal = !(original instanceof CompressedResource); - long uncompressed_size = original.getLength(); - if (original instanceof CompressedResource) { - CompressedResource comp = (CompressedResource) original; - uncompressed_size = comp.getUncompressedSize(); - } - int nameOffset = strings.addString(plugin); - int configOffset = -1; - if (pluginConfig != null) { - configOffset = strings.addString(plugin); - } - CompressedResourceHeader rh = - new CompressedResourceHeader(compressed.limit(), original.getLength(), - nameOffset, configOffset, isTerminal); - // Merge header with content; - byte[] h = rh.getBytes(order); - ByteBuffer bb = ByteBuffer.allocate(compressed.limit() + h.length); - bb.order(order); - bb.put(h); - bb.put(compressed); - ByteBuffer contentWithHeader = ByteBuffer.wrap(bb.array()); - - CompressedResource compressedResource = - new CompressedResource(original.getPath(), - contentWithHeader, uncompressed_size); - return compressedResource; - } - } - - /** - * Read only state. - * - * @return true if readonly false otherwise. - */ - public boolean isReadOnly(); - - /** - * The byte order - * - * @return - */ - public ByteOrder getByteOrder(); - - /** - * Add a resource. - * - * @param resource The Resource to add. - * @throws java.lang.Exception If the pool is read only. - */ - public void addResource(Resource resource) throws Exception; - - /** - * Check if a resource is contained in the pool. - * - * @param res The resource to check. - * @return true if res is contained, false otherwise. - */ - public boolean contains(Resource res); - - /** - * Get all resources contained in this pool instance. - * - * @return The collection of resources; - */ - public Collection getResources(); - - /** - * Get the resource for the passed path. - * - * @param path A resource path - * @return A Resource instance or null if the resource is not found - */ - public Resource getResource(String path); - - /** - * The Image modules. It is computed based on the resources contained by - * this ResourcePool instance. - * - * @return The Image Modules. - */ - public Map> getModulePackages(); - - /** - * Check if this pool contains some resources. - * - * @return True if contains some resources. - */ - public boolean isEmpty(); - - /** - * Visit the resources contained in this ResourcePool. - * - * @param visitor The visitor - * @param output The pool to store resources. - * @param strings - * @throws Exception - */ - public void visit(Visitor visitor, ResourcePool output, StringTable strings) - throws Exception; - - public void addTransformedResource(Resource original, ByteBuffer transformed) - throws Exception; -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java deleted file mode 100644 index b54ff09411a..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ResourcePoolImpl.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package jdk.internal.jimage; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -/** - * Pool of resources. This class contain the content of a jimage file in the - * matter of Resource. - */ -public class ResourcePoolImpl implements ResourcePool { - - private final Map resources = new LinkedHashMap<>(); - - private final ByteOrder order; - private boolean isReadOnly; - - public ResourcePoolImpl(ByteOrder order) { - Objects.requireNonNull(order); - this.order = order; - } - - /** - * Make this Resources instance read-only. No resource can be added. - */ - public void setReadOnly() { - isReadOnly = true; - } - - /** - * Read only state. - * - * @return true if readonly false otherwise. - */ - @Override - public boolean isReadOnly() { - return isReadOnly; - } - - /** - * The byte order - * - * @return - */ - @Override - public ByteOrder getByteOrder() { - return order; - } - - /** - * Add a resource. - * - * @param resource The Resource to add. - * @throws java.lang.Exception If the pool is read only. - */ - @Override - public void addResource(Resource resource) throws Exception { - if (isReadOnly()) { - throw new Exception("pool is readonly"); - } - Objects.requireNonNull(resource); - if (resources.get(resource.getPath()) != null) { - throw new Exception("Resource" + resource.getPath() + - " already present"); - } - resources.put(resource.getPath(), resource); - } - - /** - * Check if a resource is contained in the pool. - * - * @param res The resource to check. - * @return true if res is contained, false otherwise. - */ - @Override - public boolean contains(Resource res) { - Objects.requireNonNull(res); - try { - getResource(res.getPath()); - return true; - } catch (Exception ex) { - return false; - } - } - - /** - * Get all resources contained in this pool instance. - * - * @return The collection of resources; - */ - @Override - public Collection getResources() { - return Collections.unmodifiableCollection(resources.values()); - } - -/** - * Get the resource for the passed path. - * - * @param path A resource path - * @return A Resource instance or null if the resource is not found - */ - @Override - public Resource getResource(String path) { - Objects.requireNonNull(path); - return resources.get(path); - } - - /** - * The Image modules. It is computed based on the resources contained by - * this ResourcePool instance. - * - * @return The Image Modules. - */ - @Override - public Map> getModulePackages() { - Map> moduleToPackage = new LinkedHashMap<>(); - retrieveModulesPackages(moduleToPackage); - return moduleToPackage; - } - - /** - * Check if this pool contains some resources. - * - * @return True if contains some resources. - */ - @Override - public boolean isEmpty() { - return resources.isEmpty(); - } - - /** - * Visit the resources contained in this ResourcePool. - * - * @param visitor The visitor - * @param strings - * @throws Exception - */ - @Override - public void visit(Visitor visitor, ResourcePool output, StringTable strings) - throws Exception { - for (Resource resource : getResources()) { - Resource res = visitor.visit(resource, order, strings); - if (res != null) { - output.addResource(res); - } - } - } - - @Override - public void addTransformedResource(Resource original, ByteBuffer transformed) - throws Exception { - if (isReadOnly()) { - throw new Exception("Pool is readonly"); - } - Objects.requireNonNull(original); - Objects.requireNonNull(transformed); - if (resources.get(original.getPath()) != null) { - throw new Exception("Resource already present"); - } - Resource res = new Resource(original.getPath(), transformed); - addResource(res); - } - - private void retrieveModulesPackages(Map> moduleToPackage) { - for (Resource res : resources.values()) { - Set pkgs = moduleToPackage.get(res.getModule()); - if (pkgs == null) { - pkgs = new HashSet<>(); - moduleToPackage.put(res.getModule(), pkgs); - } - // Module metadata only contains packages with resource files - if (ImageFileCreator.isResourcePackage(res.getPath())) { - String[] split = ImageFileCreator.splitPath(res.getPath()); - String pkg = split[1]; - if (pkg != null && !pkg.isEmpty()) { - pkgs.add(pkg); - } - } - } - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java deleted file mode 100644 index 531c0ba3de3..00000000000 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/UTF8String.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.jimage; - -import java.nio.charset.Charset; -import java.util.Arrays; - -public final class UTF8String implements CharSequence { - // Same as StandardCharsets.UTF_8 without loading all of the standard charsets - static final Charset UTF_8 = Charset.forName("UTF-8"); - - static final int NOT_FOUND = -1; - static final int HASH_MULTIPLIER = 0x01000193; - static final UTF8String EMPTY_STRING = new UTF8String(""); - static final UTF8String SLASH_STRING = new UTF8String("/"); - static final UTF8String DOT_STRING = new UTF8String("."); - - // TODO This strings are implementation specific and should be defined elsewhere. - static final UTF8String MODULES_STRING = new UTF8String("/modules"); - static final UTF8String PACKAGES_STRING = new UTF8String("/packages"); - - final byte[] bytes; - final int offset; - final int count; - int hashcode; - - public UTF8String(byte[] bytes, int offset, int count) { - if (offset < 0 || count < 0 || (offset + count) > bytes.length) { - throw new IndexOutOfBoundsException("offset/count out of range"); - } - this.bytes = bytes; - this.offset = offset; - this.count = count; - this.hashcode = -1; - } - - public UTF8String(byte[] bytes, int offset) { - this(bytes, offset, bytes.length - offset); - } - - public UTF8String(byte[] bytes) { - this(bytes, 0, bytes.length); - } - - public UTF8String(String string) { - this(stringToBytes(string)); - } - - @Override - public int length() { - return count; - } - - public boolean isEmpty() { - return count == 0; - } - - public int byteAt(int index) { - return bytes[offset + index] & 0xFF; - } - - public UTF8String concat(UTF8String s) { - int total = count + s.count; - byte[] combined = new byte[total]; - System.arraycopy(bytes, offset, combined, 0, count); - System.arraycopy(s.bytes, s.offset, combined, count, s.count); - - return new UTF8String(combined, 0, total); - } - - public UTF8String concat(UTF8String... s) { - int total = count; - - for (UTF8String i : s) { - total += i.count; - } - - byte[] combined = new byte[total]; - System.arraycopy(bytes, offset, combined, 0, count); - int next = count; - - for (UTF8String i : s) { - System.arraycopy(i.bytes, i.offset, combined, next, i.count); - next += i.count; - } - - return new UTF8String(combined, 0, total); - } - - public UTF8String substring(int offset) { - return substring(offset, this.count - offset); - } - - public UTF8String substring(int offset, int count) { - int newOffset = this.offset + offset; - return new UTF8String(bytes, newOffset, count); - } - - public UTF8String trimToSize() { - return offset == 0 && bytes.length == count ? this : - new UTF8String(Arrays.copyOfRange(bytes, offset, offset + count)); - } - - public int indexOf(int ch) { - return indexOf(ch, 0); - } - - public int indexOf(int ch, int start) { - for (int i = Math.max(start, 0); i < count; i++) { - if (byteAt(i) == ch) { - return i; - } - } - - return NOT_FOUND; - } - - public int lastIndexOf(int ch) { - return lastIndexOf(ch, count - 1); - } - - public int lastIndexOf(int ch, int start) { - for (int i = Math.min(start, count); i > 0; i--) { - if (byteAt(i) == ch) { - return i; - } - } - - return NOT_FOUND; - } - - void writeTo(ImageStream buffer) { - buffer.put(bytes, offset, count); - } - - static int hashCode(int seed, byte[] bytes, int offset, int count) { - for (int i = offset, limit = offset + count; i < limit; i++) { - seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF); - } - - return seed & 0x7FFFFFFF; - } - - int hashCode(int seed) { - return hashCode(seed, bytes, offset, count); - } - - @Override - public int hashCode() { - if (hashcode < 0) { - hashcode = hashCode(HASH_MULTIPLIER, bytes, offset, count); - } - - return hashcode; - } - - @Override - public boolean equals(Object obj) { - if (obj == null) { - return false; - } - - if (getClass() != obj.getClass()) { - return false; - } - - return equals(this, (UTF8String)obj); - } - - public static boolean equals(UTF8String a, UTF8String b) { - if (a == b) { - return true; - } - - int count = a.count; - - if (count != b.count) { - return false; - } - - byte[] aBytes = a.bytes; - byte[] bBytes = b.bytes; - int aOffset = a.offset; - int bOffset = b.offset; - - for (int i = 0; i < count; i++) { - if (aBytes[aOffset + i] != bBytes[bOffset + i]) { - return false; - } - } - - return true; - } - - public byte[] getBytesCopy() { - return Arrays.copyOfRange(bytes, offset, offset + count); - } - - byte[] getBytes() { - if (offset != 0 || bytes.length != count) { - return Arrays.copyOfRange(bytes, offset, offset + count); - } - - return bytes; - } - - private static byte[] stringToBytes(String string) { - return string.getBytes(UTF_8); - } - - @Override - public String toString() { - return new String(bytes, offset, count, UTF_8); - } - - @Override - public char charAt(int index) { - int ch = byteAt(index); - - return (ch & 0x80) == 0 ? (char)ch : '\0'; - } - - @Override - public CharSequence subSequence(int start, int end) { - return (CharSequence)substring(start, end - start); - } -} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java new file mode 100644 index 00000000000..bcc9513bd6f --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressIndexes.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.DataInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +/** + * + * Index compressor. Use the minimal amount of bytes required to store + * an integer. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class CompressIndexes { + private static final int INTEGER_SIZE = 4; + + public static List decompressFlow(byte[] values) { + List lst = new ArrayList<>(); + for (int i = 0; i < values.length;) { + byte b = values[i]; + int length = isCompressed(b) ? getLength(b) : INTEGER_SIZE; + int decompressed = decompress(values, i); + lst.add(decompressed); + i += length; + } + return lst; + } + + public static int readInt(DataInputStream cr) throws IOException { + byte[] b = new byte[1]; + cr.readFully(b); + byte firstByte = b[0]; + boolean compressed = CompressIndexes.isCompressed(firstByte); + int toRead = 4; + if(compressed) { + toRead = CompressIndexes.getLength(firstByte); + } + byte[] content = new byte[toRead-1]; + cr.readFully(content); + ByteBuffer bb = ByteBuffer.allocate(content.length+1); + bb.put(firstByte); + bb.put(content); + int index = CompressIndexes.decompress(bb.array(), 0); + return index; + } + + public static int getLength(byte b) { + return ((byte) (b & 0x60) >> 5); + } + + public static boolean isCompressed(byte b) { + return b < 0; + } + + public static int decompress(byte[] value, int offset) { + byte b1 = value[offset]; + ByteBuffer buffer = ByteBuffer.allocate(INTEGER_SIZE); + if (isCompressed(b1)) { // compressed + int length = getLength(b1); + byte clearedValue = (byte) (b1 & 0x1F); + + int start = INTEGER_SIZE - length; + buffer.put(start, clearedValue); + for (int i = offset + 1; i < offset + length; i++) { + buffer.put(++start, value[i]); + } + } else { + buffer.put(value, offset, INTEGER_SIZE); + } + return buffer.getInt(0); + } + + public static byte[] compress(int val) { + ByteBuffer result = ByteBuffer.allocate(4).putInt(val); + byte[] array = result.array(); + + if ((val & 0xFF000000) == 0) { // nothing on 4th + if ((val & 0x00FF0000) == 0) { // nothing on 3rd + if ((val & 0x0000FF00) == 0) { // nothing on 2nd + if ((val & 0x000000E0) == 0) { // only in 1st, encode length in the byte. + //sign bit and size 1 ==> 101X + result = ByteBuffer.allocate(1); + result.put((byte) (0xA0 | array[3])); + } else { // add a byte for size + //sign bit and size 2 ==> 110X + result = ByteBuffer.allocate(2); + result.put((byte) 0xC0); + result.put(array[3]); + } + } else { // content in 2nd + if ((val & 0x0000E000) == 0) {// encode length in the byte. + //sign bit and size 2 ==> 110X + result = ByteBuffer.allocate(2); + result.put((byte) (0xC0 | array[2])); + result.put(array[3]); + } else { // add a byte for size + //sign bit and size 3 ==> 111X + result = ByteBuffer.allocate(3); + result.put((byte) 0xE0); + result.put(array[2]); + result.put(array[3]); + } + } + } else {// content in 3rd + if ((val & 0x00E00000) == 0) {// encode length in the byte. + //sign bit and size 3 ==> 111X + result = ByteBuffer.allocate(3); + result.put((byte) (0xE0 | array[1])); + result.put(array[2]); + result.put(array[3]); + } else { // add a byte, useless + // + } + } + } + return result.array(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java index 66afd336b66..006e754651c 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/CompressedResourceHeader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,19 +34,25 @@ import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider; * A resource header for compressed resource. This class is handled internally, * you don't have to add header to the resource, headers are added automatically * for compressed resources. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public final class CompressedResourceHeader { - private static final int SIZE = 21; + private static final int SIZE = 29; public static final int MAGIC = 0xCAFEFAFA; - private final int uncompressedSize; - private final int compressedSize; + private final long uncompressedSize; + private final long compressedSize; private final int decompressorNameOffset; private final int contentOffset; private final boolean isTerminal; - public CompressedResourceHeader(int compressedSize, - int uncompressedSize, int decompressorNameOffset, int contentOffset, + public CompressedResourceHeader(long compressedSize, + long uncompressedSize, int decompressorNameOffset, int contentOffset, boolean isTerminal) { this.compressedSize = compressedSize; this.uncompressedSize = uncompressedSize; @@ -68,18 +74,18 @@ public final class CompressedResourceHeader { } public String getStoredContent(StringsProvider provider) { - Objects.nonNull(provider); + Objects.requireNonNull(provider); if(contentOffset == -1) { return null; } return provider.getString(contentOffset); } - public int getUncompressedSize() { + public long getUncompressedSize() { return uncompressedSize; } - public int getResourceSize() { + public long getResourceSize() { return compressedSize; } @@ -88,8 +94,8 @@ public final class CompressedResourceHeader { ByteBuffer buffer = ByteBuffer.allocate(SIZE); buffer.order(order); buffer.putInt(MAGIC); - buffer.putInt(compressedSize); - buffer.putInt(uncompressedSize); + buffer.putLong(compressedSize); + buffer.putLong(uncompressedSize); buffer.putInt(decompressorNameOffset); buffer.putInt(contentOffset); buffer.put(isTerminal ? (byte)1 : (byte)0); @@ -113,8 +119,8 @@ public final class CompressedResourceHeader { if(magic != MAGIC) { return null; } - int size = buffer.getInt(); - int uncompressedSize = buffer.getInt(); + long size = buffer.getLong(); + long uncompressedSize = buffer.getLong(); int decompressorNameOffset = buffer.getInt(); int contentIndex = buffer.getInt(); byte isTerminal = buffer.get(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java index 0c640e0e0da..3fb934c85fb 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/Decompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ package jdk.internal.jimage.decompressor; import java.io.ByteArrayInputStream; import java.io.IOException; import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -35,6 +36,12 @@ import jdk.internal.jimage.decompressor.ResourceDecompressor.StringsProvider; /** * Entry point to decompress resources. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public final class Decompressor { @@ -71,8 +78,9 @@ public final class Decompressor { String storedContent = header.getStoredContent(provider); Properties props = new Properties(); if (storedContent != null) { - try (ByteArrayInputStream stream = - new ByteArrayInputStream(storedContent.getBytes());) { + try (ByteArrayInputStream stream + = new ByteArrayInputStream(storedContent. + getBytes(StandardCharsets.UTF_8));) { props.loadFromXML(stream); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java index 1e1e99e3247..3e4e32d2d89 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,13 @@ package jdk.internal.jimage.decompressor; /** * - * JImage Decompressor. + * JLink Image Decompressor. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public interface ResourceDecompressor { @@ -49,5 +55,5 @@ public interface ResourceDecompressor { * @throws Exception */ public byte[] decompress(StringsProvider strings, byte[] content, int offset, - int originalSize) throws Exception; + long originalSize) throws Exception; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java index 4a517a06546..77b0cd4a6d8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,18 +29,19 @@ import java.util.Properties; /** * - * JImage Resource Decompressor factory + * JLink Resource Decompressor factory + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public abstract class ResourceDecompressorFactory { private final String name; - private final String description; - private final String arguments; - protected ResourceDecompressorFactory(String name, String description, - String arguments) { + protected ResourceDecompressorFactory(String name) { this.name = name; - this.description = description; - this.arguments = arguments; } /** @@ -51,22 +52,6 @@ public abstract class ResourceDecompressorFactory { return name; } - /** - * The Factory description. - * @return The description. - */ - public String getDescription() { - return description; - } - - /** - * The Factory arguments description. - * @return The arguments description. - */ - public String getArgumentsDescription() { - return arguments; - } - /** * To build a new decompressor. * @param properties Contains configuration. diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java index 90800351c9f..a07c7fd1b14 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ResourceDecompressorRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,8 +31,14 @@ import java.util.Properties; /** * - * JImage Decompressors. All decompressors must be registered in the static + * JLink Decompressors. All decompressors must be registered in the static * initializer of this class. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public final class ResourceDecompressorRepository { @@ -43,6 +49,7 @@ public final class ResourceDecompressorRepository { static { registerReaderProvider(new ZipDecompressorFactory()); + registerReaderProvider(new StringSharingDecompressorFactory()); } /** diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/SignatureParser.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/SignatureParser.java new file mode 100644 index 00000000000..a9a1df29c33 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/SignatureParser.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * A descriptor parser used to extract java type strings from + * UTF_8 descriptors. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class SignatureParser { + + public static class ParseResult { + + public final List types = new ArrayList<>(); + public String formatted; + private ParseResult() {} + } + + private SignatureParser() {} + + public static String reconstruct(String formatted, List arguments) { + int arg_index = 0; + char[] chars = formatted.toCharArray(); + StringBuilder out = new StringBuilder(); + + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + out.append(c); + switch (c) { + case 'L': { + String pkg = arguments.get(arg_index); + if(pkg.length() > 0) { + out.append(pkg).append("/"); + } + arg_index+=1; + out.append(arguments.get(arg_index)); + arg_index+=1; + break; + } + default: { + break; + } + } + } + return out.toString(); + } + + public static ParseResult parseSignatureDescriptor(String str) { + ParseResult res = new ParseResult(); + char[] chars = str.toCharArray(); + StringBuilder type = null; + StringBuilder formatted = new StringBuilder(); + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + switch (c) { + case ';': + case ':': + case '<': { + if(type != null) { + String fullName = type.toString(); + int endIndex = fullName.lastIndexOf("/"); + String clazz = fullName; + String pkg = ""; + if(endIndex != -1) { + pkg = fullName.substring(0, endIndex); + clazz = fullName.substring(endIndex+1); + } + res.types.add(pkg); + res.types.add(clazz); + } + formatted.append(c); + + type = null; + break; + } + case 'L': { + if(type == null) { + type = new StringBuilder(); + formatted.append(c); + } else { + type.append(c); + } + break; + } + default: { + if(type == null) { + formatted.append(c); + } else { + type.append(c); + } + break; + } + } + } + res.formatted = formatted.toString(); + return res; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java new file mode 100644 index 00000000000..d979f984da3 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressor.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +/** + * + * A Decompressor that reconstructs the constant pool of classes. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class StringSharingDecompressor implements ResourceDecompressor { + + public static final int EXTERNALIZED_STRING = 23; + public static final int EXTERNALIZED_STRING_DESCRIPTOR = 25; + + private static final int CONSTANT_Utf8 = 1; + private static final int CONSTANT_Integer = 3; + private static final int CONSTANT_Float = 4; + private static final int CONSTANT_Long = 5; + private static final int CONSTANT_Double = 6; + private static final int CONSTANT_Class = 7; + private static final int CONSTANT_String = 8; + private static final int CONSTANT_Fieldref = 9; + private static final int CONSTANT_Methodref = 10; + private static final int CONSTANT_InterfaceMethodref = 11; + private static final int CONSTANT_NameAndType = 12; + private static final int CONSTANT_MethodHandle = 15; + private static final int CONSTANT_MethodType = 16; + private static final int CONSTANT_InvokeDynamic = 18; + + private static final int[] SIZES = new int[20]; + + static { + + //SIZES[CONSTANT_Utf8] = XXX; + SIZES[CONSTANT_Integer] = 4; + SIZES[CONSTANT_Float] = 4; + SIZES[CONSTANT_Long] = 8; + SIZES[CONSTANT_Double] = 8; + SIZES[CONSTANT_Class] = 2; + SIZES[CONSTANT_String] = 2; + SIZES[CONSTANT_Fieldref] = 4; + SIZES[CONSTANT_Methodref] = 4; + SIZES[CONSTANT_InterfaceMethodref] = 4; + SIZES[CONSTANT_NameAndType] = 4; + SIZES[CONSTANT_MethodHandle] = 3; + SIZES[CONSTANT_MethodType] = 2; + SIZES[CONSTANT_InvokeDynamic] = 4; + } + + public static int[] getSizes() { + return SIZES.clone(); + } + + @SuppressWarnings("fallthrough") + public static byte[] normalize(StringsProvider provider, byte[] transformed, + int offset) throws IOException { + DataInputStream stream = new DataInputStream(new ByteArrayInputStream(transformed, + offset, transformed.length - offset)); + ByteArrayOutputStream outStream = new ByteArrayOutputStream(transformed.length); + DataOutputStream out = new DataOutputStream(outStream); + byte[] header = new byte[8]; //maginc/4, minor/2, major/2 + stream.readFully(header); + out.write(header); + int count = stream.readUnsignedShort(); + out.writeShort(count); + for (int i = 1; i < count; i++) { + int tag = stream.readUnsignedByte(); + byte[] arr; + switch (tag) { + case CONSTANT_Utf8: { + out.write(tag); + String utf = stream.readUTF(); + out.writeUTF(utf); + break; + } + + case EXTERNALIZED_STRING: { + int index = CompressIndexes.readInt(stream); + String orig = provider.getString(index); + out.write(CONSTANT_Utf8); + out.writeUTF(orig); + break; + } + + case EXTERNALIZED_STRING_DESCRIPTOR: { + String orig = reconstruct(provider, stream); + out.write(CONSTANT_Utf8); + out.writeUTF(orig); + break; + } + case CONSTANT_Long: + case CONSTANT_Double: { + i++; + } + default: { + out.write(tag); + int size = SIZES[tag]; + arr = new byte[size]; + stream.readFully(arr); + out.write(arr); + } + } + } + out.write(transformed, transformed.length - stream.available(), + stream.available()); + out.flush(); + + return outStream.toByteArray(); + } + + private static String reconstruct(StringsProvider reader, DataInputStream cr) + throws IOException { + int descIndex = CompressIndexes.readInt(cr); + String desc = reader.getString(descIndex); + byte[] encodedDesc = getEncoded(desc); + int indexes_length = CompressIndexes.readInt(cr); + byte[] bytes = new byte[indexes_length]; + cr.readFully(bytes); + List indices = CompressIndexes.decompressFlow(bytes); + ByteBuffer buffer = ByteBuffer.allocate(encodedDesc.length * 2); + buffer.order(ByteOrder.BIG_ENDIAN); + int argIndex = 0; + for (byte c : encodedDesc) { + if (c == 'L') { + buffer = safeAdd(buffer, c); + int index = indices.get(argIndex); + argIndex += 1; + String pkg = reader.getString(index); + if (pkg.length() > 0) { + pkg = pkg + "/"; + byte[] encoded = getEncoded(pkg); + buffer = safeAdd(buffer, encoded); + } + int classIndex = indices.get(argIndex); + argIndex += 1; + String clazz = reader.getString(classIndex); + byte[] encoded = getEncoded(clazz); + buffer = safeAdd(buffer, encoded); + } else { + buffer = safeAdd(buffer, c); + } + } + + byte[] encoded = buffer.array(); + ByteBuffer result = ByteBuffer.allocate(encoded.length + 2); + result.order(ByteOrder.BIG_ENDIAN); + result.putShort((short) buffer.position()); + result.put(encoded, 0, buffer.position()); + ByteArrayInputStream stream = new ByteArrayInputStream(result.array()); + DataInputStream inStream = new DataInputStream(stream); + String str = inStream.readUTF(); + return str; + } + + public static byte[] getEncoded(String pre) throws IOException { + ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); + DataOutputStream resultOut = new DataOutputStream(resultStream); + resultOut.writeUTF(pre); + byte[] content = resultStream.toByteArray(); + // first 2 items are length; + if (content.length <= 2) { + return new byte[0]; + } + return Arrays.copyOfRange(content, 2, content.length); + } + + private static ByteBuffer safeAdd(ByteBuffer current, byte b) { + byte[] bytes = {b}; + return safeAdd(current, bytes); + } + + private static ByteBuffer safeAdd(ByteBuffer current, byte[] bytes) { + if (current.remaining() < bytes.length) { + ByteBuffer newBuffer = ByteBuffer.allocate((current.capacity() + + bytes.length) * 2); + newBuffer.order(ByteOrder.BIG_ENDIAN); + newBuffer.put(current.array(), 0, current.position()); + current = newBuffer; + } + current.put(bytes); + return current; + } + + @Override + public String getName() { + return StringSharingDecompressorFactory.NAME; + } + + public StringSharingDecompressor(Properties properties) { + + } + + @Override + public byte[] decompress(StringsProvider reader, byte[] content, + int offset, long originalSize) throws Exception { + return normalize(reader, content, offset); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java new file mode 100644 index 00000000000..654a8d68ed2 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/StringSharingDecompressorFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jimage.decompressor; + +import java.io.IOException; +import java.util.Properties; + +/** + * + * Constant Pool strings sharing Decompressor factory. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public class StringSharingDecompressorFactory extends ResourceDecompressorFactory { + + public static final String NAME = "compact-cp"; + public StringSharingDecompressorFactory() { + super(NAME); + } + + @Override + public ResourceDecompressor newDecompressor(Properties properties) + throws IOException { + return new StringSharingDecompressor(properties); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java index 18aeb9ef7a0..7f8f3fcc8ec 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,17 @@ package jdk.internal.jimage.decompressor; import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.zip.DataFormatException; import java.util.zip.Inflater; /** * * ZIP Decompressor + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ final class ZipDecompressor implements ResourceDecompressor { @@ -40,29 +44,18 @@ final class ZipDecompressor implements ResourceDecompressor { return ZipDecompressorFactory.NAME; } - static byte[] decompress(byte[] bytesIn, int offset) { + static byte[] decompress(byte[] bytesIn, int offset) throws Exception { Inflater inflater = new Inflater(); inflater.setInput(bytesIn, offset, bytesIn.length - offset); ByteArrayOutputStream stream = new ByteArrayOutputStream(bytesIn.length - offset); byte[] buffer = new byte[1024]; while (!inflater.finished()) { - int count; - - try { - count = inflater.inflate(buffer); - } catch (DataFormatException ex) { - return null; - } - + int count = inflater.inflate(buffer); stream.write(buffer, 0, count); } - try { - stream.close(); - } catch (IOException ex) { - return null; - } + stream.close(); byte[] bytesOut = stream.toByteArray(); inflater.end(); @@ -72,7 +65,7 @@ final class ZipDecompressor implements ResourceDecompressor { @Override public byte[] decompress(StringsProvider reader, byte[] content, int offset, - int originalSize) throws Exception { + long originalSize) throws Exception { byte[] decompressed = decompress(content, offset); return decompressed; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java index cbdbcc67e79..eb822e037d5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jimage/decompressor/ZipDecompressorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,11 +30,17 @@ import java.util.Properties; /** * * ZIP decompressor factory + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ public final class ZipDecompressorFactory extends ResourceDecompressorFactory { public static final String NAME = "zip"; public ZipDecompressorFactory() { - super(NAME, "ZIP Decompression", null); + super(NAME); } @Override diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java new file mode 100644 index 00000000000..ab7bd29ac06 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileAttributes.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Formatter; + +/** + * Base class for file attributes supported by jrt file systems. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +public abstract class AbstractJrtFileAttributes implements BasicFileAttributes { + + // jrt fs specific attributes + /** + * Compressed resource file. If not available or not applicable, 0L is + * returned. + * + * @return the compressed resource size for compressed resources. + */ + public abstract long compressedSize(); + + /** + * "file" extension of a file resource. + * + * @return extension string for the file resource + */ + public abstract String extension(); + + @Override + public final String toString() { + StringBuilder sb = new StringBuilder(1024); + try (Formatter fm = new Formatter(sb)) { + if (creationTime() != null) { + fm.format(" creationTime : %tc%n", creationTime().toMillis()); + } else { + fm.format(" creationTime : null%n"); + } + + if (lastAccessTime() != null) { + fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); + } else { + fm.format(" lastAccessTime : null%n"); + } + fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); + fm.format(" isRegularFile : %b%n", isRegularFile()); + fm.format(" isDirectory : %b%n", isDirectory()); + fm.format(" isSymbolicLink : %b%n", isSymbolicLink()); + fm.format(" isOther : %b%n", isOther()); + fm.format(" fileKey : %s%n", fileKey()); + fm.format(" size : %d%n", size()); + fm.format(" compressedSize : %d%n", compressedSize()); + fm.format(" extension : %s%n", extension()); + } + return sb.toString(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java new file mode 100644 index 00000000000..42004e6e9c9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtFileSystem.java @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.charset.Charset; +import java.nio.file.ClosedFileSystemException; +import java.nio.file.CopyOption; +import java.nio.file.FileStore; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.ReadOnlyFileSystemException; +import java.nio.file.StandardOpenOption; +import java.nio.file.WatchService; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * Base class for jrt file systems. jrt filesystem implementations are currently + * available on top of .jimage file and on top "exploded" build directories. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +abstract class AbstractJrtFileSystem extends FileSystem { + + private final JrtFileSystemProvider provider; + + AbstractJrtFileSystem(JrtFileSystemProvider provider, Map options) { + this.provider = provider; + } + + private static final Charset UTF_8 = Charset.forName("UTF-8"); + + // static utility methods + static ReadOnlyFileSystemException readOnly() { + return new ReadOnlyFileSystemException(); + } + + // if a Path does not exist, throw exception + static void checkExists(Path path) { + if (Files.notExists(path)) { + throw new FileSystemNotFoundException(path.toString()); + } + } + + static byte[] getBytes(String name) { + return name.getBytes(UTF_8); + } + + static String getString(byte[] name) { + return new String(name, UTF_8); + } + + // do the supplied options imply that we have to chase symlinks? + static boolean followLinks(LinkOption... options) { + if (options != null) { + for (LinkOption lo : options) { + if (lo == LinkOption.NOFOLLOW_LINKS) { + return false; + } else if (lo == null) { + throw new NullPointerException(); + } else { + throw new AssertionError("should not reach here"); + } + } + } + return true; + } + + // check that the options passed are supported by (read-only) jrt file system + static void checkOptions(Set options) { + // check for options of null type and option is an intance of StandardOpenOption + for (OpenOption option : options) { + if (option == null) { + throw new NullPointerException(); + } + if (!(option instanceof StandardOpenOption)) { + throw new IllegalArgumentException(); + } + } + + if (options.contains(StandardOpenOption.WRITE) + || options.contains(StandardOpenOption.APPEND)) { + throw readOnly(); + } + } + + // FileSystem method implementations + @Override + public FileSystemProvider provider() { + return provider; + } + + @Override + public Iterable getRootDirectories() { + ArrayList pathArr = new ArrayList<>(); + pathArr.add(getRootPath()); + return pathArr; + } + + @Override + public AbstractJrtPath getPath(String first, String... more) { + String path; + if (more.length == 0) { + path = first; + } else { + StringBuilder sb = new StringBuilder(); + sb.append(first); + for (String segment : more) { + if (segment.length() > 0) { + if (sb.length() > 0) { + sb.append('/'); + } + sb.append(segment); + } + } + path = sb.toString(); + } + return getRootPath().newJrtPath(getBytes(path)); + } + + @Override + public final boolean isReadOnly() { + return true; + } + + @Override + public final UserPrincipalLookupService getUserPrincipalLookupService() { + throw new UnsupportedOperationException(); + } + + @Override + public final WatchService newWatchService() { + throw new UnsupportedOperationException(); + } + + @Override + public final Iterable getFileStores() { + ArrayList list = new ArrayList<>(1); + list.add(getFileStore(getRootPath())); + return list; + } + + private static final Set supportedFileAttributeViews + = Collections.unmodifiableSet( + new HashSet(Arrays.asList("basic", "jrt"))); + + @Override + public final Set supportedFileAttributeViews() { + return supportedFileAttributeViews; + } + + @Override + public final String toString() { + return "jrt:/"; + } + + @Override + public final String getSeparator() { + return "/"; + } + + private static final String GLOB_SYNTAX = "glob"; + private static final String REGEX_SYNTAX = "regex"; + + @Override + public PathMatcher getPathMatcher(String syntaxAndInput) { + int pos = syntaxAndInput.indexOf(':'); + if (pos <= 0 || pos == syntaxAndInput.length()) { + throw new IllegalArgumentException(); + } + String syntax = syntaxAndInput.substring(0, pos); + String input = syntaxAndInput.substring(pos + 1); + String expr; + if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) { + expr = JrtUtils.toRegexPattern(input); + } else { + if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) { + expr = input; + } else { + throw new UnsupportedOperationException("Syntax '" + syntax + + "' not recognized"); + } + } + // return matcher + final Pattern pattern = Pattern.compile(expr); + return (Path path) -> pattern.matcher(path.toString()).matches(); + } + + // These methods throw read only file system exception + final void setTimes(AbstractJrtPath jrtPath, FileTime mtime, FileTime atime, FileTime ctime) + throws IOException { + throw readOnly(); + } + + final void createDirectory(AbstractJrtPath jrtPath, FileAttribute... attrs) throws IOException { + throw readOnly(); + } + + final void deleteFile(AbstractJrtPath jrtPath, boolean failIfNotExists) + throws IOException { + throw readOnly(); + } + + final OutputStream newOutputStream(AbstractJrtPath jrtPath, OpenOption... options) + throws IOException { + throw readOnly(); + } + + final void copyFile(boolean deletesrc, AbstractJrtPath srcPath, AbstractJrtPath dstPath, CopyOption... options) + throws IOException { + throw readOnly(); + } + + final FileChannel newFileChannel(AbstractJrtPath jrtPath, + Set options, + FileAttribute... attrs) + throws IOException { + throw new UnsupportedOperationException("newFileChannel"); + } + + final InputStream newInputStream(AbstractJrtPath jrtPath) throws IOException { + return new ByteArrayInputStream(getFileContent(jrtPath)); + } + + final SeekableByteChannel newByteChannel(AbstractJrtPath jrtPath, + Set options, + FileAttribute... attrs) + throws IOException { + checkOptions(options); + + byte[] buf = getFileContent(jrtPath); + final ReadableByteChannel rbc + = Channels.newChannel(new ByteArrayInputStream(buf)); + final long size = buf.length; + return new SeekableByteChannel() { + long read = 0; + + @Override + public boolean isOpen() { + return rbc.isOpen(); + } + + @Override + public long position() throws IOException { + return read; + } + + @Override + public SeekableByteChannel position(long pos) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public int read(ByteBuffer dst) throws IOException { + int n = rbc.read(dst); + if (n > 0) { + read += n; + } + return n; + } + + @Override + public SeekableByteChannel truncate(long size) + throws IOException { + throw new NonWritableChannelException(); + } + + @Override + public int write(ByteBuffer src) throws IOException { + throw new NonWritableChannelException(); + } + + @Override + public long size() throws IOException { + return size; + } + + @Override + public void close() throws IOException { + rbc.close(); + } + }; + } + + final JrtFileStore getFileStore(AbstractJrtPath jrtPath) { + return new JrtFileStore(jrtPath); + } + + final void ensureOpen() throws IOException { + if (!isOpen()) { + throw new ClosedFileSystemException(); + } + } + + // abstract methods to be implemented by a particular jrt file system + abstract AbstractJrtPath getRootPath(); + + abstract boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException; + + abstract boolean isLink(AbstractJrtPath jrtPath) throws IOException; + + abstract AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException; + + abstract AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException; + + abstract boolean exists(AbstractJrtPath jrtPath) throws IOException; + + abstract boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException; + + /** + * returns the list of child paths of the given directory "path" + * + * @param path name of the directory whose content is listed + * @return iterator for child paths of the given directory path + */ + abstract Iterator iteratorOf(AbstractJrtPath jrtPath) throws IOException; + + // returns the content of the file resource specified by the path + abstract byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException; +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java new file mode 100644 index 00000000000..8e939a0c5d0 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/AbstractJrtPath.java @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.channels.*; +import java.nio.file.*; +import java.nio.file.DirectoryStream.Filter; +import java.nio.file.attribute.*; +import java.util.*; +import static java.nio.file.StandardOpenOption.*; +import static java.nio.file.StandardCopyOption.*; + +/** + * Base class for Path implementation of jrt file systems. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +abstract class AbstractJrtPath implements Path { + + protected final AbstractJrtFileSystem jrtfs; + private final byte[] path; + private volatile int[] offsets; + private int hashcode = 0; // cached hashcode (created lazily) + + AbstractJrtPath(AbstractJrtFileSystem jrtfs, byte[] path) { + this(jrtfs, path, false); + this.resolved = null; + } + + AbstractJrtPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) { + this.resolved = null; + this.jrtfs = jrtfs; + if (normalized) { + this.path = path; + } else { + this.path = normalize(path); + } + } + + // factory methods to create subtypes of AbstractJrtPath + protected abstract AbstractJrtPath newJrtPath(byte[] path); + + protected abstract AbstractJrtPath newJrtPath(byte[] path, boolean normalized); + + final byte[] getName() { + return path; + } + + @Override + public final AbstractJrtPath getRoot() { + if (this.isAbsolute()) { + return jrtfs.getRootPath(); + } else { + return null; + } + } + + @Override + public final AbstractJrtPath getFileName() { + initOffsets(); + int count = offsets.length; + if (count == 0) { + return null; // no elements so no name + } + if (count == 1 && path[0] != '/') { + return this; + } + int lastOffset = offsets[count - 1]; + int len = path.length - lastOffset; + byte[] result = new byte[len]; + System.arraycopy(path, lastOffset, result, 0, len); + return newJrtPath(result); + } + + @Override + public final AbstractJrtPath getParent() { + initOffsets(); + int count = offsets.length; + if (count == 0) // no elements so no parent + { + return null; + } + int len = offsets[count - 1] - 1; + if (len <= 0) // parent is root only (may be null) + { + return getRoot(); + } + byte[] result = new byte[len]; + System.arraycopy(path, 0, result, 0, len); + return newJrtPath(result); + } + + @Override + public final int getNameCount() { + initOffsets(); + return offsets.length; + } + + @Override + public final AbstractJrtPath getName(int index) { + initOffsets(); + if (index < 0 || index >= offsets.length) { + throw new IllegalArgumentException(); + } + int begin = offsets[index]; + int len; + if (index == (offsets.length - 1)) { + len = path.length - begin; + } else { + len = offsets[index + 1] - begin - 1; + } + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return newJrtPath(result); + } + + @Override + public final AbstractJrtPath subpath(int beginIndex, int endIndex) { + initOffsets(); + if (beginIndex < 0 + || beginIndex >= offsets.length + || endIndex > offsets.length + || beginIndex >= endIndex) { + throw new IllegalArgumentException(); + } + + // starting offset and length + int begin = offsets[beginIndex]; + int len; + if (endIndex == offsets.length) { + len = path.length - begin; + } else { + len = offsets[endIndex] - begin - 1; + } + // construct result + byte[] result = new byte[len]; + System.arraycopy(path, begin, result, 0, len); + return newJrtPath(result); + } + + @Override + public final AbstractJrtPath toRealPath(LinkOption... options) throws IOException { + AbstractJrtPath realPath = newJrtPath(getResolvedPath()).toAbsolutePath(); + realPath = JrtFileSystem.followLinks(options) ? jrtfs.resolveLink(this) : realPath; + realPath.checkAccess(); + return realPath; + } + + final AbstractJrtPath readSymbolicLink() throws IOException { + if (!jrtfs.isLink(this)) { + throw new IOException("not a symbolic link"); + } + + return jrtfs.resolveLink(this); + } + + final boolean isHidden() { + return false; + } + + @Override + public final AbstractJrtPath toAbsolutePath() { + if (isAbsolute()) { + return this; + } else { + //add / bofore the existing path + byte[] tmp = new byte[path.length + 1]; + tmp[0] = '/'; + System.arraycopy(path, 0, tmp, 1, path.length); + return newJrtPath(tmp).normalize(); + } + } + + @Override + public final URI toUri() { + try { + return new URI("jrt", + JrtFileSystem.getString(toAbsolutePath().path), + null); + } catch (URISyntaxException ex) { + throw new AssertionError(ex); + } + } + + private boolean equalsNameAt(AbstractJrtPath other, int index) { + int mbegin = offsets[index]; + int mlen; + if (index == (offsets.length - 1)) { + mlen = path.length - mbegin; + } else { + mlen = offsets[index + 1] - mbegin - 1; + } + int obegin = other.offsets[index]; + int olen; + if (index == (other.offsets.length - 1)) { + olen = other.path.length - obegin; + } else { + olen = other.offsets[index + 1] - obegin - 1; + } + if (mlen != olen) { + return false; + } + int n = 0; + while (n < mlen) { + if (path[mbegin + n] != other.path[obegin + n]) { + return false; + } + n++; + } + return true; + } + + @Override + public final AbstractJrtPath relativize(Path other) { + final AbstractJrtPath o = checkPath(other); + if (o.equals(this)) { + return newJrtPath(new byte[0], true); + } + if (/* this.getFileSystem() != o.getFileSystem() || */this.isAbsolute() != o.isAbsolute()) { + throw new IllegalArgumentException(); + } + int mc = this.getNameCount(); + int oc = o.getNameCount(); + int n = Math.min(mc, oc); + int i = 0; + while (i < n) { + if (!equalsNameAt(o, i)) { + break; + } + i++; + } + int dotdots = mc - i; + int len = dotdots * 3 - 1; + if (i < oc) { + len += (o.path.length - o.offsets[i] + 1); + } + byte[] result = new byte[len]; + + int pos = 0; + while (dotdots > 0) { + result[pos++] = (byte) '.'; + result[pos++] = (byte) '.'; + if (pos < len) // no tailing slash at the end + { + result[pos++] = (byte) '/'; + } + dotdots--; + } + if (i < oc) { + System.arraycopy(o.path, o.offsets[i], + result, pos, + o.path.length - o.offsets[i]); + } + return newJrtPath(result); + } + + @Override + public AbstractJrtFileSystem getFileSystem() { + return jrtfs; + } + + @Override + public final boolean isAbsolute() { + return (this.path.length > 0 && path[0] == '/'); + } + + @Override + public final AbstractJrtPath resolve(Path other) { + final AbstractJrtPath o = checkPath(other); + if (o.isAbsolute()) { + return o; + } + byte[] res; + if (this.path[path.length - 1] == '/') { + res = new byte[path.length + o.path.length]; + System.arraycopy(path, 0, res, 0, path.length); + System.arraycopy(o.path, 0, res, path.length, o.path.length); + } else { + res = new byte[path.length + 1 + o.path.length]; + System.arraycopy(path, 0, res, 0, path.length); + res[path.length] = '/'; + System.arraycopy(o.path, 0, res, path.length + 1, o.path.length); + } + return newJrtPath(res); + } + + @Override + public final Path resolveSibling(Path other) { + if (other == null) { + throw new NullPointerException(); + } + Path parent = getParent(); + return (parent == null) ? other : parent.resolve(other); + } + + @Override + public final boolean startsWith(Path other) { + final AbstractJrtPath o = checkPath(other); + if (o.isAbsolute() != this.isAbsolute() + || o.path.length > this.path.length) { + return false; + } + int olast = o.path.length; + for (int i = 0; i < olast; i++) { + if (o.path[i] != this.path[i]) { + return false; + } + } + olast--; + return o.path.length == this.path.length + || o.path[olast] == '/' + || this.path[olast + 1] == '/'; + } + + @Override + public final boolean endsWith(Path other) { + final AbstractJrtPath o = checkPath(other); + int olast = o.path.length - 1; + if (olast > 0 && o.path[olast] == '/') { + olast--; + } + int last = this.path.length - 1; + if (last > 0 && this.path[last] == '/') { + last--; + } + if (olast == -1) // o.path.length == 0 + { + return last == -1; + } + if ((o.isAbsolute() && (!this.isAbsolute() || olast != last)) + || (last < olast)) { + return false; + } + for (; olast >= 0; olast--, last--) { + if (o.path[olast] != this.path[last]) { + return false; + } + } + return o.path[olast + 1] == '/' + || last == -1 || this.path[last] == '/'; + } + + @Override + public final AbstractJrtPath resolve(String other) { + return resolve(getFileSystem().getPath(other)); + } + + @Override + public final Path resolveSibling(String other) { + return resolveSibling(getFileSystem().getPath(other)); + } + + @Override + public final boolean startsWith(String other) { + return startsWith(getFileSystem().getPath(other)); + } + + @Override + public final boolean endsWith(String other) { + return endsWith(getFileSystem().getPath(other)); + } + + @Override + public final AbstractJrtPath normalize() { + byte[] res = getResolved(); + if (res == path) // no change + { + return this; + } + return newJrtPath(res, true); + } + + private AbstractJrtPath checkPath(Path path) { + if (path == null) { + throw new NullPointerException(); + } + if (!(path instanceof AbstractJrtPath)) { + throw new ProviderMismatchException(); + } + return (AbstractJrtPath) path; + } + + // create offset list if not already created + private void initOffsets() { + if (offsets == null) { + int count, index; + // count names + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index++]; + if (c != '/') { + count++; + while (index < path.length && path[index] != '/') { + index++; + } + } + } + // populate offsets + int[] result = new int[count]; + count = 0; + index = 0; + while (index < path.length) { + byte c = path[index]; + if (c == '/') { + index++; + } else { + result[count++] = index++; + while (index < path.length && path[index] != '/') { + index++; + } + } + } + synchronized (this) { + if (offsets == null) { + offsets = result; + } + } + } + } + + private volatile byte[] resolved; + + final byte[] getResolvedPath() { + byte[] r = resolved; + if (r == null) { + if (isAbsolute()) { + r = getResolved(); + } else { + r = toAbsolutePath().getResolvedPath(); + } + resolved = r; + } + return resolved; + } + + // removes redundant slashs, replace "\" to separator "/" + // and check for invalid characters + private static byte[] normalize(byte[] path) { + if (path.length == 0) { + return path; + } + byte prevC = 0; + for (int i = 0; i < path.length; i++) { + byte c = path[i]; + if (c == '\\') { + return normalize(path, i); + } + if (c == (byte) '/' && prevC == '/') { + return normalize(path, i - 1); + } + if (c == '\u0000') { + throw new InvalidPathException(JrtFileSystem.getString(path), + "Path: nul character not allowed"); + } + prevC = c; + } + + if (path.length > 1 && path[path.length - 1] == '/') { + return Arrays.copyOf(path, path.length - 1); + } + + return path; + } + + private static byte[] normalize(byte[] path, int off) { + byte[] to = new byte[path.length]; + int n = 0; + while (n < off) { + to[n] = path[n]; + n++; + } + int m = n; + byte prevC = 0; + while (n < path.length) { + byte c = path[n++]; + if (c == (byte) '\\') { + c = (byte) '/'; + } + if (c == (byte) '/' && prevC == (byte) '/') { + continue; + } + if (c == '\u0000') { + throw new InvalidPathException(JrtFileSystem.getString(path), + "Path: nul character not allowed"); + } + to[m++] = c; + prevC = c; + } + if (m > 1 && to[m - 1] == '/') { + m--; + } + return (m == to.length) ? to : Arrays.copyOf(to, m); + } + + // Remove DotSlash(./) and resolve DotDot (..) components + private byte[] getResolved() { + if (path.length == 0) { + return path; + } + for (int i = 0; i < path.length; i++) { + byte c = path[i]; + if (c == (byte) '.') { + return resolve0(); + } + } + + return path; + } + + // TBD: performance, avoid initOffsets + private byte[] resolve0() { + byte[] to = new byte[path.length]; + int nc = getNameCount(); + int[] lastM = new int[nc]; + int lastMOff = -1; + int m = 0; + for (int i = 0; i < nc; i++) { + int n = offsets[i]; + int len = (i == offsets.length - 1) + ? (path.length - n) : (offsets[i + 1] - n - 1); + if (len == 1 && path[n] == (byte) '.') { + if (m == 0 && path[0] == '/') // absolute path + { + to[m++] = '/'; + } + continue; + } + if (len == 2 && path[n] == '.' && path[n + 1] == '.') { + if (lastMOff >= 0) { + m = lastM[lastMOff--]; // retreat + continue; + } + if (path[0] == '/') { // "/../xyz" skip + if (m == 0) { + to[m++] = '/'; + } + } else { // "../xyz" -> "../xyz" + if (m != 0 && to[m - 1] != '/') { + to[m++] = '/'; + } + while (len-- > 0) { + to[m++] = path[n++]; + } + } + continue; + } + if (m == 0 && path[0] == '/' || // absolute path + m != 0 && to[m - 1] != '/') { // not the first name + to[m++] = '/'; + } + lastM[++lastMOff] = m; + while (len-- > 0) { + to[m++] = path[n++]; + } + } + if (m > 1 && to[m - 1] == '/') { + m--; + } + return (m == to.length) ? to : Arrays.copyOf(to, m); + } + + @Override + public final String toString() { + return JrtFileSystem.getString(path); + } + + @Override + public final int hashCode() { + int h = hashcode; + if (h == 0) { + hashcode = h = Arrays.hashCode(path); + } + return h; + } + + @Override + public final boolean equals(Object obj) { + return obj != null + && obj instanceof AbstractJrtPath + && this.jrtfs == ((AbstractJrtPath) obj).jrtfs + && compareTo((Path) obj) == 0; + } + + @Override + public final int compareTo(Path other) { + final AbstractJrtPath o = checkPath(other); + int len1 = this.path.length; + int len2 = o.path.length; + + int n = Math.min(len1, len2); + byte v1[] = this.path; + byte v2[] = o.path; + + int k = 0; + while (k < n) { + int c1 = v1[k] & 0xff; + int c2 = v2[k] & 0xff; + if (c1 != c2) { + return c1 - c2; + } + k++; + } + return len1 - len2; + } + + @Override + public final WatchKey register( + WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) { + if (watcher == null || events == null || modifiers == null) { + throw new NullPointerException(); + } + throw new UnsupportedOperationException(); + } + + @Override + public final WatchKey register(WatchService watcher, WatchEvent.Kind... events) { + return register(watcher, events, new WatchEvent.Modifier[0]); + } + + @Override + public final File toFile() { + throw new UnsupportedOperationException(); + } + + @Override + public final Iterator iterator() { + return new Iterator() { + private int i = 0; + + @Override + public boolean hasNext() { + return (i < getNameCount()); + } + + @Override + public Path next() { + if (i < getNameCount()) { + Path result = getName(i); + i++; + return result; + } else { + throw new NoSuchElementException(); + } + } + + @Override + public void remove() { + throw new ReadOnlyFileSystemException(); + } + }; + } + + ///////////////////////////////////////////////////////////////////// + // Helpers for JrtFileSystemProvider and JrtFileSystem + final int getPathLength() { + return path.length; + } + + final void createDirectory(FileAttribute... attrs) + throws IOException { + jrtfs.createDirectory(this, attrs); + } + + final InputStream newInputStream(OpenOption... options) throws IOException { + if (options.length > 0) { + for (OpenOption opt : options) { + if (opt != READ) { + throw new UnsupportedOperationException("'" + opt + "' not allowed"); + } + } + } + return jrtfs.newInputStream(this); + } + + final DirectoryStream newDirectoryStream(Filter filter) + throws IOException { + return new JrtDirectoryStream(this, filter); + } + + final void delete() throws IOException { + jrtfs.deleteFile(this, true); + } + + final void deleteIfExists() throws IOException { + jrtfs.deleteFile(this, false); + } + + final AbstractJrtFileAttributes getAttributes(LinkOption... options) throws IOException { + AbstractJrtFileAttributes zfas = jrtfs.getFileAttributes(this, options); + if (zfas == null) { + throw new NoSuchFileException(toString()); + } + return zfas; + } + + final void setAttribute(String attribute, Object value, LinkOption... options) + throws IOException { + String type; + String attr; + int colonPos = attribute.indexOf(':'); + if (colonPos == -1) { + type = "basic"; + attr = attribute; + } else { + type = attribute.substring(0, colonPos++); + attr = attribute.substring(colonPos); + } + JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options); + if (view == null) { + throw new UnsupportedOperationException("view <" + view + "> is not supported"); + } + view.setAttribute(attr, value); + } + + final void setTimes(FileTime mtime, FileTime atime, FileTime ctime) + throws IOException { + jrtfs.setTimes(this, mtime, atime, ctime); + } + + final Map readAttributes(String attributes, LinkOption... options) + throws IOException { + String view; + String attrs; + int colonPos = attributes.indexOf(':'); + if (colonPos == -1) { + view = "basic"; + attrs = attributes; + } else { + view = attributes.substring(0, colonPos++); + attrs = attributes.substring(colonPos); + } + JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options); + if (jrtfv == null) { + throw new UnsupportedOperationException("view not supported"); + } + return jrtfv.readAttributes(attrs); + } + + final FileStore getFileStore() throws IOException { + // each JrtFileSystem only has one root (as requested for now) + if (exists()) { + return jrtfs.getFileStore(this); + } + throw new NoSuchFileException(JrtFileSystem.getString(path)); + } + + final boolean isSameFile(Path other) throws IOException { + if (this.equals(other)) { + return true; + } + if (other == null + || this.getFileSystem() != other.getFileSystem()) { + return false; + } + this.checkAccess(); + AbstractJrtPath target = (AbstractJrtPath) other; + target.checkAccess(); + return Arrays.equals(this.getResolvedPath(), target.getResolvedPath()) + || jrtfs.isSameFile(this, target); + } + + final SeekableByteChannel newByteChannel(Set options, + FileAttribute... attrs) + throws IOException { + return jrtfs.newByteChannel(this, options, attrs); + } + + final FileChannel newFileChannel(Set options, + FileAttribute... attrs) + throws IOException { + return jrtfs.newFileChannel(this, options, attrs); + } + + final void checkAccess(AccessMode... modes) throws IOException { + boolean w = false; + boolean x = false; + for (AccessMode mode : modes) { + switch (mode) { + case READ: + break; + case WRITE: + w = true; + break; + case EXECUTE: + x = true; + break; + default: + throw new UnsupportedOperationException(); + } + } + + BasicFileAttributes attrs = jrtfs.getFileAttributes(this); + if (attrs == null && (path.length != 1 || path[0] != '/')) { + throw new NoSuchFileException(toString()); + } + if (w) { +// if (jrtfs.isReadOnly()) + throw new AccessDeniedException(toString()); + } + if (x) { + throw new AccessDeniedException(toString()); + } + } + + final boolean exists() { + try { + return jrtfs.exists(this); + } catch (IOException x) { + } + return false; + } + + final OutputStream newOutputStream(OpenOption... options) throws IOException { + if (options.length == 0) { + return jrtfs.newOutputStream(this, + CREATE_NEW, WRITE); + } + return jrtfs.newOutputStream(this, options); + } + + final void move(AbstractJrtPath target, CopyOption... options) + throws IOException { + if (this.jrtfs == target.jrtfs) { + jrtfs.copyFile(true, + this, target, + options); + } else { + copyToTarget(target, options); + delete(); + } + } + + final void copy(AbstractJrtPath target, CopyOption... options) + throws IOException { + if (this.jrtfs == target.jrtfs) { + jrtfs.copyFile(false, + this, target, + options); + } else { + copyToTarget(target, options); + } + } + + private void copyToTarget(AbstractJrtPath target, CopyOption... options) + throws IOException { + boolean replaceExisting = false; + boolean copyAttrs = false; + for (CopyOption opt : options) { + if (opt == REPLACE_EXISTING) { + replaceExisting = true; + } else if (opt == COPY_ATTRIBUTES) { + copyAttrs = true; + } + } + // attributes of source file + BasicFileAttributes jrtfas = getAttributes(); + // check if target exists + boolean exists; + if (replaceExisting) { + try { + target.deleteIfExists(); + exists = false; + } catch (DirectoryNotEmptyException x) { + exists = true; + } + } else { + exists = target.exists(); + } + if (exists) { + throw new FileAlreadyExistsException(target.toString()); + } + + if (jrtfas.isDirectory()) { + // create directory or file + target.createDirectory(); + } else { + try (InputStream is = jrtfs.newInputStream(this); OutputStream os = target.newOutputStream()) { + byte[] buf = new byte[8192]; + int n; + while ((n = is.read(buf)) != -1) { + os.write(buf, 0, n); + } + } + } + if (copyAttrs) { + BasicFileAttributeView view + = JrtFileAttributeView.get(target, BasicFileAttributeView.class); + try { + view.setTimes(jrtfas.lastModifiedTime(), + jrtfas.lastAccessTime(), + jrtfas.creationTime()); + } catch (IOException x) { + // rollback? + try { + target.delete(); + } catch (IOException ignore) { + } + throw x; + } + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java index 1a870fa6d95..ed7702c237b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtDirectoryStream.java @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; import java.nio.file.DirectoryStream; @@ -34,48 +33,47 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.io.IOException; +/** + * DirectoryStream implementation for jrt file system implementations. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ final class JrtDirectoryStream implements DirectoryStream { - private final JrtFileSystem jrtfs; - private final byte[] path; - // prefix to be used for children of this directory - // so that child path are reported relatively (if needed) - private final String childPrefix; + + private final AbstractJrtFileSystem jrtfs; + private final AbstractJrtPath dir; private final DirectoryStream.Filter filter; private volatile boolean isClosed; private volatile Iterator itr; - JrtDirectoryStream(JrtPath jrtPath, - DirectoryStream.Filter filter) - throws IOException - { + JrtDirectoryStream(AbstractJrtPath jrtPath, + DirectoryStream.Filter filter) + throws IOException { this.jrtfs = jrtPath.getFileSystem(); - this.path = jrtPath.getResolvedPath(); + this.dir = jrtPath; // sanity check - if (!jrtfs.isDirectory(path, true)) + if (!jrtfs.isDirectory(dir, true)) { throw new NotDirectoryException(jrtPath.toString()); - - // absolute path and does not have funky chars in front like /./java.base - if (jrtPath.isAbsolute() && (path.length == jrtPath.getPathLength())) { - childPrefix = null; - } else { - // cases where directory content needs to modified with prefix - // like ./java.base, /./java.base, java.base and so on. - String dirName = jrtPath.toString(); - int idx = dirName.indexOf(JrtFileSystem.getString(path).substring(1)); - childPrefix = dirName.substring(0, idx); } + this.filter = filter; } @Override public synchronized Iterator iterator() { - if (isClosed) + if (isClosed) { throw new ClosedDirectoryStreamException(); - if (itr != null) + } + if (itr != null) { throw new IllegalStateException("Iterator has already been returned"); + } try { - itr = jrtfs.iteratorOf(path, childPrefix); + itr = jrtfs.iteratorOf(dir); } catch (IOException e) { throw new IllegalStateException(e); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java new file mode 100644 index 00000000000..161bbaab487 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileAttributes.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.IOException; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import jdk.internal.jrtfs.JrtExplodedFileSystem.Node; + +/** + * jrt file system attributes implementation on top of 'exploded file system' + * Node. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtExplodedFileAttributes extends AbstractJrtFileAttributes { + + private final Node node; + private final BasicFileAttributes attrs; + + JrtExplodedFileAttributes(Node node) throws IOException { + this.node = node; + this.attrs = node.getBasicAttrs(); + } + + @Override + public FileTime creationTime() { + return attrs.creationTime(); + } + + @Override + public boolean isDirectory() { + return node.isDirectory(); + } + + @Override + public boolean isOther() { + return false; + } + + @Override + public boolean isRegularFile() { + return node.isFile(); + } + + @Override + public FileTime lastAccessTime() { + return attrs.lastAccessTime(); + } + + @Override + public FileTime lastModifiedTime() { + return attrs.lastModifiedTime(); + } + + @Override + public long size() { + return isRegularFile() ? attrs.size() : 0L; + } + + @Override + public boolean isSymbolicLink() { + return node.isLink(); + } + + @Override + public Object fileKey() { + return node.resolveLink(true); + } + + @Override + public long compressedSize() { + return 0L; + } + + @Override + public String extension() { + return node.getExtension(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java new file mode 100644 index 00000000000..3a077b199db --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedFileSystem.java @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.NoSuchFileException; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import static java.util.stream.Collectors.toList; +import static jdk.internal.jrtfs.AbstractJrtFileSystem.getString; + +/** + * A jrt file system built on $JAVA_HOME/modules directory ('exploded modules + * build') + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +class JrtExplodedFileSystem extends AbstractJrtFileSystem { + + private static final String MODULES = "/modules/"; + private static final String PACKAGES = "/packages/"; + private static final int PACKAGES_LEN = PACKAGES.length(); + + // root path + private final JrtExplodedPath rootPath; + private volatile boolean isOpen; + private final FileSystem defaultFS; + private final String separator; + private final Map nodes = Collections.synchronizedMap(new HashMap<>()); + private final BasicFileAttributes modulesDirAttrs; + + JrtExplodedFileSystem(JrtFileSystemProvider provider, + Map env) + throws IOException { + + super(provider, env); + checkExists(SystemImages.explodedModulesDir()); + byte[] root = new byte[]{'/'}; + rootPath = new JrtExplodedPath(this, root); + isOpen = true; + defaultFS = FileSystems.getDefault(); + String str = defaultFS.getSeparator(); + separator = str.equals(getSeparator()) ? null : str; + modulesDirAttrs = Files.readAttributes(SystemImages.explodedModulesDir(), BasicFileAttributes.class); + initNodes(); + } + + @Override + public void close() throws IOException { + cleanup(); + } + + @Override + public boolean isOpen() { + return isOpen; + } + + @Override + protected void finalize() throws Throwable { + cleanup(); + super.finalize(); + } + + private synchronized void cleanup() { + isOpen = false; + nodes.clear(); + } + + @Override + JrtExplodedPath getRootPath() { + return rootPath; + } + + // Base class for Nodes of this file system + abstract class Node { + + private final String name; + + Node(String name) { + this.name = name; + } + + final String getName() { + return name; + } + + final String getExtension() { + if (isFile()) { + final int index = name.lastIndexOf("."); + if (index != -1) { + return name.substring(index + 1); + } + } + + return null; + } + + BasicFileAttributes getBasicAttrs() throws IOException { + return modulesDirAttrs; + } + + boolean isLink() { + return false; + } + + boolean isDirectory() { + return false; + } + + boolean isFile() { + return false; + } + + byte[] getContent() throws IOException { + if (!isFile()) { + throw new FileSystemException(name + " is not file"); + } + + throw new AssertionError("ShouldNotReachHere"); + } + + List getChildren() throws IOException { + if (!isDirectory()) { + throw new NotDirectoryException(name); + } + + throw new AssertionError("ShouldNotReachHere"); + } + + final Node resolveLink() { + return resolveLink(false); + } + + Node resolveLink(boolean recursive) { + return this; + } + } + + // A Node that is backed by actual default file system Path + private final class PathNode extends Node { + + // Path in underlying default file system + private final Path path; + private final boolean file; + // lazily initialized, don't read attributes unless required! + private BasicFileAttributes attrs; + + PathNode(String name, Path path) { + super(name); + this.path = path; + this.file = Files.isRegularFile(path); + } + + @Override + synchronized BasicFileAttributes getBasicAttrs() throws IOException { + if (attrs == null) { + attrs = Files.readAttributes(path, BasicFileAttributes.class); + } + return attrs; + } + + @Override + boolean isDirectory() { + return !file; + } + + @Override + boolean isFile() { + return file; + } + + @Override + byte[] getContent() throws IOException { + if (!isFile()) { + throw new FileSystemException(getName() + " is not file"); + } + + return Files.readAllBytes(path); + } + + @Override + List getChildren() throws IOException { + if (!isDirectory()) { + throw new NotDirectoryException(getName()); + } + + List children = new ArrayList<>(); + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path cp : stream) { + cp = SystemImages.explodedModulesDir().relativize(cp); + String cpName = MODULES + nativeSlashToFrontSlash(cp.toString()); + try { + children.add(findNode(cpName)); + } catch (NoSuchFileException nsfe) { + // findNode may choose to hide certain files! + } + } + } + + return children; + } + } + + // A Node that links to another Node + private final class LinkNode extends Node { + + // underlying linked Node + private final Node link; + + LinkNode(String name, Node link) { + super(name); + this.link = link; + } + + @Override + BasicFileAttributes getBasicAttrs() throws IOException { + return link.getBasicAttrs(); + } + + @Override + public boolean isLink() { + return true; + } + + @Override + Node resolveLink(boolean recursive) { + return recursive && (link instanceof LinkNode) ? ((LinkNode) link).resolveLink(true) : link; + } + } + + // A directory Node with it's children Nodes + private final class DirNode extends Node { + + // children Nodes of this Node. + private final List children; + + DirNode(String name, List children) { + super(name); + this.children = children; + } + + @Override + boolean isDirectory() { + return true; + } + + @Override + List getChildren() throws IOException { + return children; + } + } + + private JrtExplodedPath toJrtExplodedPath(String path) { + return toJrtExplodedPath(getBytes(path)); + } + + private JrtExplodedPath toJrtExplodedPath(byte[] path) { + return new JrtExplodedPath(this, path); + } + + @Override + boolean isSameFile(AbstractJrtPath jrtPath1, AbstractJrtPath jrtPath2) throws IOException { + Node n1 = checkNode(jrtPath1); + Node n2 = checkNode(jrtPath2); + return n1 == n2; + } + + @Override + boolean isLink(AbstractJrtPath jrtPath) throws IOException { + return checkNode(jrtPath).isLink(); + } + + @Override + AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException { + String name = checkNode(jrtPath).resolveLink().getName(); + return toJrtExplodedPath(name); + } + + @Override + AbstractJrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) throws IOException { + Node node = checkNode(jrtPath); + if (node.isLink() && followLinks(options)) { + node = node.resolveLink(true); + } + return new JrtExplodedFileAttributes(node); + } + + @Override + boolean exists(AbstractJrtPath jrtPath) throws IOException { + try { + checkNode(jrtPath); + return true; + } catch (NoSuchFileException nsfe) { + return false; + } + } + + @Override + boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) throws IOException { + Node node = checkNode(jrtPath); + return resolveLinks && node.isLink() + ? node.resolveLink(true).isDirectory() + : node.isDirectory(); + } + + @Override + Iterator iteratorOf(AbstractJrtPath dir) throws IOException { + Node node = checkNode(dir).resolveLink(true); + if (!node.isDirectory()) { + throw new NotDirectoryException(getString(dir.getName())); + } + + Function nodeToPath = + child -> dir.resolve( + toJrtExplodedPath(child.getName()). + getFileName()); + + return node.getChildren().stream(). + map(nodeToPath).collect(toList()). + iterator(); + } + + @Override + byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException { + return checkNode(jrtPath).getContent(); + } + + private Node checkNode(AbstractJrtPath jrtPath) throws IOException { + return checkNode(jrtPath.getResolvedPath()); + } + + private Node checkNode(byte[] path) throws IOException { + ensureOpen(); + return findNode(path); + } + + synchronized Node findNode(byte[] path) throws IOException { + return findNode(getString(path)); + } + + // find Node for the given Path + synchronized Node findNode(String str) throws IOException { + Node node = findModulesNode(str); + if (node != null) { + return node; + } + + // lazily created for paths like /packages///xyz + // For example /packages/java.lang/java.base/java/lang/ + if (str.startsWith(PACKAGES)) { + // pkgEndIdx marks end of part + int pkgEndIdx = str.indexOf('/', PACKAGES_LEN); + if (pkgEndIdx != -1) { + // modEndIdx marks end of part + int modEndIdx = str.indexOf('/', pkgEndIdx + 1); + if (modEndIdx != -1) { + // make sure we have such module link! + // ie., /packages// is valid + Node linkNode = nodes.get(str.substring(0, modEndIdx)); + if (linkNode == null || !linkNode.isLink()) { + throw new NoSuchFileException(str); + } + + // map to "/modules/zyz" path and return that node + // For example, "/modules/java.base/java/lang" for + // "/packages/java.lang/java.base/java/lang". + String mod = MODULES + str.substring(pkgEndIdx + 1); + return findNode(mod); + } + } + } + + throw new NoSuchFileException(str); + } + + // find a Node for a path that starts like "/modules/..." + synchronized Node findModulesNode(String str) throws IOException { + Node node = nodes.get(str); + if (node != null) { + return node; + } + + // lazily created "/modules/xyz/abc/" Node + // This is mapped to default file system path "/xyz/abc" + Path p = underlyingPath(str); + if (p != null) { + if (Files.isRegularFile(p)) { + Path file = p.getFileName(); + if (file.toString().startsWith("_the.")) { + return null; + } + } + node = new PathNode(str, p); + nodes.put(str, node); + return node; + } + + return null; + } + + Path underlyingPath(String str) { + if (str.startsWith(MODULES)) { + str = frontSlashToNativeSlash(str.substring("/modules".length())); + return defaultFS.getPath(SystemImages.explodedModulesDir().toString(), str); + } + return null; + } + + // convert "/" to platform path separator + private String frontSlashToNativeSlash(String str) { + return separator == null ? str : str.replace("/", separator); + } + + // convert platform path separator to "/" + private String nativeSlashToFrontSlash(String str) { + return separator == null ? str : str.replace(separator, "/"); + } + + // convert "/"s to "."s + private String slashesToDots(String str) { + return str.replace(separator != null ? separator : "/", "."); + } + + // initialize file system Nodes + private void initNodes() throws IOException { + // same package prefix may exist in mutliple modules. This Map + // is filled by walking "jdk modules" directory recursively! + Map> packageToModules = new HashMap<>(); + + try (DirectoryStream stream = Files.newDirectoryStream(SystemImages.explodedModulesDir())) { + for (Path module : stream) { + if (Files.isDirectory(module)) { + String moduleName = module.getFileName().toString(); + // make sure "/modules/" is created + findModulesNode(MODULES + moduleName); + + Files.walk(module).filter(Files::isDirectory).forEach((p) -> { + p = module.relativize(p); + String pkgName = slashesToDots(p.toString()); + // skip META-INFO and empty strings + if (!pkgName.isEmpty() && !pkgName.startsWith("META-INF")) { + List moduleNames = packageToModules.get(pkgName); + if (moduleNames == null) { + moduleNames = new ArrayList<>(); + packageToModules.put(pkgName, moduleNames); + } + moduleNames.add(moduleName); + } + }); + } + } + } + + // create "/modules" directory + // "nodes" map contains only /modules/ nodes only so far and so add all as children of /modules + DirNode modulesDir = new DirNode("/modules", new ArrayList<>(nodes.values())); + nodes.put(modulesDir.getName(), modulesDir); + + // create children under "/packages" + List packagesChildren = new ArrayList<>(packageToModules.size()); + for (Map.Entry> entry : packageToModules.entrySet()) { + String pkgName = entry.getKey(); + List moduleNameList = entry.getValue(); + List moduleLinkNodes = new ArrayList<>(moduleNameList.size()); + for (String moduleName : moduleNameList) { + Node moduleNode = findModulesNode(MODULES + moduleName); + LinkNode linkNode = new LinkNode(PACKAGES + pkgName + "/" + moduleName, moduleNode); + nodes.put(linkNode.getName(), linkNode); + moduleLinkNodes.add(linkNode); + } + + DirNode pkgDir = new DirNode(PACKAGES + pkgName, moduleLinkNodes); + nodes.put(pkgDir.getName(), pkgDir); + packagesChildren.add(pkgDir); + } + + // "/packages" dir + DirNode packagesDir = new DirNode("/packages", packagesChildren); + nodes.put(packagesDir.getName(), packagesDir); + + // finally "/" dir! + List rootChildren = new ArrayList<>(); + rootChildren.add(modulesDir); + rootChildren.add(packagesDir); + DirNode root = new DirNode("/", rootChildren); + nodes.put(root.getName(), root); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java new file mode 100644 index 00000000000..8746ee0a161 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtExplodedPath.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.jrtfs; + +/** + * Path implementation for jrt file system on JDK exploded modules build. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtExplodedPath extends AbstractJrtPath { + + JrtExplodedPath(AbstractJrtFileSystem jrtfs, byte[] path) { + super(jrtfs, path); + } + + JrtExplodedPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) { + super(jrtfs, path, normalized); + } + + @Override + protected AbstractJrtPath newJrtPath(byte[] path) { + return new JrtExplodedPath(jrtfs, path); + } + + @Override + protected AbstractJrtPath newJrtPath(byte[] path, boolean normalized) { + return new JrtExplodedPath(jrtfs, path, normalized); + } + + @Override + public JrtExplodedFileSystem getFileSystem() { + return (JrtExplodedFileSystem) jrtfs; + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java index 93b88f7fea8..e6e80657bab 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributeView.java @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; import java.nio.file.LinkOption; @@ -31,9 +30,19 @@ import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; -final class JrtFileAttributeView implements BasicFileAttributeView -{ +/** + * File attribute view for jrt file system. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtFileAttributeView implements BasicFileAttributeView { + private static enum AttrID { + size, creationTime, lastAccessTime, @@ -47,124 +56,133 @@ final class JrtFileAttributeView implements BasicFileAttributeView extension }; - private final JrtPath path; + private final AbstractJrtPath path; private final boolean isJrtView; private final LinkOption[] options; - private JrtFileAttributeView(JrtPath path, boolean isJrtView, LinkOption... options) { + private JrtFileAttributeView(AbstractJrtPath path, boolean isJrtView, LinkOption... options) { this.path = path; this.isJrtView = isJrtView; this.options = options; } @SuppressWarnings("unchecked") // Cast to V - static V get(JrtPath path, Class type, LinkOption... options) { - if (type == null) + static V get(AbstractJrtPath path, Class type, LinkOption... options) { + if (type == null) { throw new NullPointerException(); - if (type == BasicFileAttributeView.class) - return (V)new JrtFileAttributeView(path, false, options); - if (type == JrtFileAttributeView.class) - return (V)new JrtFileAttributeView(path, true, options); + } + if (type == BasicFileAttributeView.class) { + return (V) new JrtFileAttributeView(path, false, options); + } + if (type == JrtFileAttributeView.class) { + return (V) new JrtFileAttributeView(path, true, options); + } return null; } - static JrtFileAttributeView get(JrtPath path, String type, LinkOption... options) { - if (type == null) + static JrtFileAttributeView get(AbstractJrtPath path, String type, LinkOption... options) { + if (type == null) { throw new NullPointerException(); - if (type.equals("basic")) + } + if (type.equals("basic")) { return new JrtFileAttributeView(path, false, options); - if (type.equals("jjrt")) + } + if (type.equals("jrt")) { return new JrtFileAttributeView(path, true, options); + } return null; } @Override public String name() { - return isJrtView ? "jjrt" : "basic"; + return isJrtView ? "jrt" : "basic"; } @Override - public JrtFileAttributes readAttributes() throws IOException - { + public AbstractJrtFileAttributes readAttributes() throws IOException { return path.getAttributes(options); } @Override public void setTimes(FileTime lastModifiedTime, - FileTime lastAccessTime, - FileTime createTime) - throws IOException - { + FileTime lastAccessTime, + FileTime createTime) + throws IOException { path.setTimes(lastModifiedTime, lastAccessTime, createTime); } void setAttribute(String attribute, Object value) - throws IOException - { + throws IOException { try { - if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) - setTimes ((FileTime)value, null, null); - if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) - setTimes (null, (FileTime)value, null); - if (AttrID.valueOf(attribute) == AttrID.creationTime) - setTimes (null, null, (FileTime)value); + if (AttrID.valueOf(attribute) == AttrID.lastModifiedTime) { + setTimes((FileTime) value, null, null); + } + if (AttrID.valueOf(attribute) == AttrID.lastAccessTime) { + setTimes(null, (FileTime) value, null); + } + if (AttrID.valueOf(attribute) == AttrID.creationTime) { + setTimes(null, null, (FileTime) value); + } return; - } catch (IllegalArgumentException x) {} - throw new UnsupportedOperationException("'" + attribute + - "' is unknown or read-only attribute"); + } catch (IllegalArgumentException x) { + } + throw new UnsupportedOperationException("'" + attribute + + "' is unknown or read-only attribute"); } Map readAttributes(String attributes) - throws IOException - { - JrtFileAttributes jrtfas = readAttributes(); + throws IOException { + AbstractJrtFileAttributes jrtfas = readAttributes(); LinkedHashMap map = new LinkedHashMap<>(); if ("*".equals(attributes)) { for (AttrID id : AttrID.values()) { try { map.put(id.name(), attribute(id, jrtfas)); - } catch (IllegalArgumentException x) {} + } catch (IllegalArgumentException x) { + } } } else { String[] as = attributes.split(","); for (String a : as) { try { map.put(a, attribute(AttrID.valueOf(a), jrtfas)); - } catch (IllegalArgumentException x) {} + } catch (IllegalArgumentException x) { + } } } return map; } - Object attribute(AttrID id, JrtFileAttributes jrtfas) { + Object attribute(AttrID id, AbstractJrtFileAttributes jrtfas) { switch (id) { - case size: - return jrtfas.size(); - case creationTime: - return jrtfas.creationTime(); - case lastAccessTime: - return jrtfas.lastAccessTime(); - case lastModifiedTime: - return jrtfas.lastModifiedTime(); - case isDirectory: - return jrtfas.isDirectory(); - case isRegularFile: - return jrtfas.isRegularFile(); - case isSymbolicLink: - return jrtfas.isSymbolicLink(); - case isOther: - return jrtfas.isOther(); - case fileKey: - return jrtfas.fileKey(); - case compressedSize: - if (isJrtView) - return jrtfas.compressedSize(); - break; - case extension: - if (isJrtView) { - return jrtfas.extension(); - } - break; + case size: + return jrtfas.size(); + case creationTime: + return jrtfas.creationTime(); + case lastAccessTime: + return jrtfas.lastAccessTime(); + case lastModifiedTime: + return jrtfas.lastModifiedTime(); + case isDirectory: + return jrtfas.isDirectory(); + case isRegularFile: + return jrtfas.isRegularFile(); + case isSymbolicLink: + return jrtfas.isSymbolicLink(); + case isOther: + return jrtfas.isOther(); + case fileKey: + return jrtfas.fileKey(); + case compressedSize: + if (isJrtView) { + return jrtfas.compressedSize(); + } + break; + case extension: + if (isJrtView) { + return jrtfas.extension(); + } + break; } return null; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java index f09dec55059..9293b1f4e4b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileAttributes.java @@ -22,16 +22,22 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; -import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; -import java.util.Formatter; import jdk.internal.jimage.ImageReader.Node; -final class JrtFileAttributes implements BasicFileAttributes -{ +/** + * File attributes implementation for jrt image file system. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtFileAttributes extends AbstractJrtFileAttributes { + private final Node node; JrtFileAttributes(Node node) { @@ -85,37 +91,13 @@ final class JrtFileAttributes implements BasicFileAttributes } ///////// jrt entry attributes /////////// + @Override public long compressedSize() { return node.compressedSize(); } + @Override public String extension() { return node.extension(); } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(1024); - try (Formatter fm = new Formatter(sb)) { - if (creationTime() != null) - fm.format(" creationTime : %tc%n", creationTime().toMillis()); - else - fm.format(" creationTime : null%n"); - - if (lastAccessTime() != null) - fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis()); - else - fm.format(" lastAccessTime : null%n"); - fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis()); - fm.format(" isRegularFile : %b%n", isRegularFile()); - fm.format(" isDirectory : %b%n", isDirectory()); - fm.format(" isSymbolicLink : %b%n", isSymbolicLink()); - fm.format(" isOther : %b%n", isOther()); - fm.format(" fileKey : %s%n", fileKey()); - fm.format(" size : %d%n", size()); - fm.format(" compressedSize : %d%n", compressedSize()); - fm.format(" extension : %s%n", extension()); - } - return sb.toString(); - } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java index d0a57736652..09a1f091482 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileStore.java @@ -22,23 +22,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; import java.io.IOException; -import java.nio.file.Files; import java.nio.file.FileStore; -import java.nio.file.FileSystems; -import java.nio.file.Path; +import java.nio.file.FileSystem; import java.nio.file.attribute.FileAttributeView; -import java.nio.file.attribute.FileStoreAttributeView; import java.nio.file.attribute.BasicFileAttributeView; +import java.nio.file.attribute.FileStoreAttributeView; +/** + * File store implementation for jrt file systems. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ final class JrtFileStore extends FileStore { - private final JrtFileSystem jrtfs; + protected final FileSystem jrtfs; - JrtFileStore(JrtPath jrtPath) { + JrtFileStore(AbstractJrtPath jrtPath) { this.jrtfs = jrtPath.getFileSystem(); } @@ -57,12 +63,6 @@ final class JrtFileStore extends FileStore { return jrtfs.isReadOnly(); } - @Override - public boolean supportsFileAttributeView(Class type) { - return (type == BasicFileAttributeView.class || - type == JrtFileAttributeView.class); - } - @Override public boolean supportsFileAttributeView(String name) { return name.equals("basic") || name.equals("jrt"); @@ -71,28 +71,35 @@ final class JrtFileStore extends FileStore { @Override @SuppressWarnings("unchecked") public V getFileStoreAttributeView(Class type) { - if (type == null) + if (type == null) { throw new NullPointerException(); - return (V)null; + } + return (V) null; } @Override public long getTotalSpace() throws IOException { - throw new UnsupportedOperationException("getTotalSpace"); + throw new UnsupportedOperationException("getTotalSpace"); } @Override public long getUsableSpace() throws IOException { - throw new UnsupportedOperationException("getUsableSpace"); + throw new UnsupportedOperationException("getUsableSpace"); } @Override public long getUnallocatedSpace() throws IOException { - throw new UnsupportedOperationException("getUnallocatedSpace"); + throw new UnsupportedOperationException("getUnallocatedSpace"); } @Override public Object getAttribute(String attribute) throws IOException { - throw new UnsupportedOperationException("does not support " + attribute); + throw new UnsupportedOperationException("does not support " + attribute); + } + + @Override + public boolean supportsFileAttributeView(Class type) { + return (type == BasicFileAttributeView.class + || type == JrtFileAttributeView.class); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java index 641428be03d..84a7a34daae 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystem.java @@ -24,73 +24,44 @@ */ package jdk.internal.jrtfs; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.nio.charset.Charset; -import java.nio.file.ClosedFileSystemException; -import java.nio.file.CopyOption; import java.nio.file.LinkOption; -import java.nio.file.FileStore; -import java.nio.file.FileSystem; import java.nio.file.FileSystemException; -import java.nio.file.FileSystemNotFoundException; -import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.NoSuchFileException; import java.nio.file.NotDirectoryException; -import java.nio.file.OpenOption; import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.nio.file.ReadOnlyFileSystemException; -import java.nio.file.StandardOpenOption; -import java.nio.file.WatchService; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.attribute.FileTime; -import java.nio.file.attribute.UserPrincipalLookupService; -import java.nio.file.spi.FileSystemProvider; -import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Function; -import java.util.regex.Pattern; import static java.util.stream.Collectors.toList; import jdk.internal.jimage.ImageReader; import jdk.internal.jimage.ImageReader.Node; -import jdk.internal.jimage.UTF8String; + /** - * A FileSystem built on System jimage files. + * jrt file system implementation built on System jimage files. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. */ -class JrtFileSystem extends FileSystem { - private static final Charset UTF_8 = Charset.forName("UTF-8"); +class JrtFileSystem extends AbstractJrtFileSystem { - private final JrtFileSystemProvider provider; - // System image readers + // System image reader private ImageReader bootImage; - private ImageReader extImage; - private ImageReader appImage; // root path private final JrtPath rootPath; private volatile boolean isOpen; - private static void checkExists(Path path) { - if (Files.notExists(path)) { - throw new FileSystemNotFoundException(path.toString()); - } - } - // open a .jimage and build directory structure private static ImageReader openImage(Path path) throws IOException { - ImageReader image = ImageReader.open(path.toString()); + ImageReader image = ImageReader.open(path); image.getRootDirectory(); return image; } @@ -98,31 +69,18 @@ class JrtFileSystem extends FileSystem { JrtFileSystem(JrtFileSystemProvider provider, Map env) throws IOException { - this.provider = provider; - checkExists(SystemImages.bootImagePath); - checkExists(SystemImages.extImagePath); - checkExists(SystemImages.appImagePath); + super(provider, env); + checkExists(SystemImages.moduleImageFile()); - // open image files - this.bootImage = openImage(SystemImages.bootImagePath); - this.extImage = openImage(SystemImages.extImagePath); - this.appImage = openImage(SystemImages.appImagePath); + // open image file + this.bootImage = openImage(SystemImages.moduleImageFile()); - byte[] root = new byte[] { '/' }; + byte[] root = new byte[]{'/'}; rootPath = new JrtPath(this, root); isOpen = true; } - @Override - public FileSystemProvider provider() { - return provider; - } - - @Override - public String getSeparator() { - return "/"; - } - + // FileSystem method implementations @Override public boolean isOpen() { return isOpen; @@ -134,191 +92,139 @@ class JrtFileSystem extends FileSystem { } @Override - protected void finalize() { + protected void finalize() throws Throwable { try { cleanup(); - } catch (IOException ignored) {} + } catch (IOException ignored) { + } + super.finalize(); } + // AbstractJrtFileSystem method implementations + @Override + JrtPath getRootPath() { + return rootPath; + } + + @Override + boolean isSameFile(AbstractJrtPath p1, AbstractJrtPath p2) throws IOException { + ensureOpen(); + Node node1 = findNode(p1); + Node node2 = findNode(p2); + return node1.equals(node2); + } + + @Override + boolean isLink(AbstractJrtPath jrtPath) throws IOException { + return checkNode(jrtPath).isLink(); + } + + @Override + AbstractJrtPath resolveLink(AbstractJrtPath jrtPath) throws IOException { + Node node = checkNode(jrtPath); + if (node.isLink()) { + node = node.resolveLink(); + return toJrtPath(getBytes(node.getName())); + } + + return jrtPath; + } + + @Override + JrtFileAttributes getFileAttributes(AbstractJrtPath jrtPath, LinkOption... options) + throws IOException { + Node node = checkNode(jrtPath); + if (node.isLink() && followLinks(options)) { + return new JrtFileAttributes(node.resolveLink(true)); + } + return new JrtFileAttributes(node); + } + + @Override + boolean exists(AbstractJrtPath jrtPath) throws IOException { + try { + checkNode(jrtPath); + } catch (NoSuchFileException exp) { + return false; + } + return true; + } + + @Override + boolean isDirectory(AbstractJrtPath jrtPath, boolean resolveLinks) + throws IOException { + Node node = checkNode(jrtPath); + return resolveLinks && node.isLink() + ? node.resolveLink(true).isDirectory() + : node.isDirectory(); + } + + @Override + Iterator iteratorOf(AbstractJrtPath jrtPath) throws IOException { + Node node = checkNode(jrtPath).resolveLink(true); + if (!node.isDirectory()) { + throw new NotDirectoryException(getString(jrtPath.getName())); + } + + if (node.isRootDir()) { + return rootDirIterator(jrtPath); + } else if (node.isModulesDir()) { + return modulesDirIterator(jrtPath); + } else if (node.isPackagesDir()) { + return packagesDirIterator(jrtPath); + } + + return nodesToIterator(jrtPath, node.getChildren()); + } + + @Override + byte[] getFileContent(AbstractJrtPath jrtPath) throws IOException { + final Node node = checkResource(jrtPath); + return bootImage.getResource(node); + } + + // Implementation details below this point // clean up this file system - called from finalize and close private void cleanup() throws IOException { if (!isOpen) { return; } - synchronized(this) { + synchronized (this) { isOpen = false; // close all image reader and null out bootImage.close(); bootImage = null; - extImage.close(); - extImage = null; - appImage.close(); - appImage = null; } } - private void ensureOpen() throws IOException { - if (!isOpen) { - throw new ClosedFileSystemException(); + private Node lookup(byte[] path) { + Node node = null; + try { + node = bootImage.findNode(getString(path)); + } catch (RuntimeException re) { + throw new InvalidPathException(getString(path), re.toString()); } + return node; } - @Override - public boolean isReadOnly() { - return true; - } - - private ReadOnlyFileSystemException readOnly() { - return new ReadOnlyFileSystemException(); - } - - @Override - public Iterable getRootDirectories() { - ArrayList pathArr = new ArrayList<>(); - pathArr.add(rootPath); - return pathArr; - } - - JrtPath getRootPath() { - return rootPath; - } - - @Override - public JrtPath getPath(String first, String... more) { - String path; - if (more.length == 0) { - path = first; - } else { - StringBuilder sb = new StringBuilder(); - sb.append(first); - for (String segment : more) { - if (segment.length() > 0) { - if (sb.length() > 0) { - sb.append('/'); - } - sb.append(segment); - } - } - path = sb.toString(); - } - return new JrtPath(this, getBytes(path)); - } - - @Override - public UserPrincipalLookupService getUserPrincipalLookupService() { - throw new UnsupportedOperationException(); - } - - @Override - public WatchService newWatchService() { - throw new UnsupportedOperationException(); - } - - FileStore getFileStore(JrtPath path) { - return new JrtFileStore(path); - } - - @Override - public Iterable getFileStores() { - ArrayList list = new ArrayList<>(1); - list.add(new JrtFileStore(new JrtPath(this, new byte[]{'/'}))); - return list; - } - - private static final Set supportedFileAttributeViews - = Collections.unmodifiableSet( - new HashSet(Arrays.asList("basic", "jrt"))); - - @Override - public Set supportedFileAttributeViews() { - return supportedFileAttributeViews; - } - - @Override - public String toString() { - return "jrt:/"; - } - - private static final String GLOB_SYNTAX = "glob"; - private static final String REGEX_SYNTAX = "regex"; - - @Override - public PathMatcher getPathMatcher(String syntaxAndInput) { - int pos = syntaxAndInput.indexOf(':'); - if (pos <= 0 || pos == syntaxAndInput.length()) { - throw new IllegalArgumentException(); - } - String syntax = syntaxAndInput.substring(0, pos); - String input = syntaxAndInput.substring(pos + 1); - String expr; - if (syntax.equalsIgnoreCase(GLOB_SYNTAX)) { - expr = JrtUtils.toRegexPattern(input); - } else { - if (syntax.equalsIgnoreCase(REGEX_SYNTAX)) { - expr = input; - } else { - throw new UnsupportedOperationException("Syntax '" + syntax - + "' not recognized"); - } - } - // return matcher - final Pattern pattern = Pattern.compile(expr); - return (Path path) -> pattern.matcher(path.toString()).matches(); - } - - static byte[] getBytes(String name) { - return name.getBytes(UTF_8); - } - - static String getString(byte[] name) { - return new String(name, UTF_8); - } - - private static class NodeAndImage { - final Node node; - final ImageReader image; - - NodeAndImage(Node node, ImageReader image) { - this.node = node; this.image = image; - } - - byte[] getResource() throws IOException { - return image.getResource(node); - } - } - - private NodeAndImage lookup(byte[] path) { - Node node = bootImage.findNode(path); - ImageReader image = bootImage; - if (node == null) { - node = extImage.findNode(path); - image = extImage; - } - if (node == null) { - node = appImage.findNode(path); - image = appImage; - } - return node != null? new NodeAndImage(node, image) : null; - } - - private NodeAndImage lookupSymbolic(byte[] path) { + private Node lookupSymbolic(byte[] path) { for (int i = 1; i < path.length; i++) { - if (path[i] == (byte)'/') { + if (path[i] == (byte) '/') { byte[] prefix = Arrays.copyOfRange(path, 0, i); - NodeAndImage ni = lookup(prefix); - if (ni == null) { + Node node = lookup(prefix); + if (node == null) { break; } - if (ni.node.isLink()) { - Node link = ni.node.resolveLink(true); + if (node.isLink()) { + Node link = node.resolveLink(true); // resolved symbolic path concatenated to the rest of the path - UTF8String resPath = link.getName().concat(new UTF8String(path, i)); - byte[] resPathBytes = resPath.getBytesCopy(); - ni = lookup(resPathBytes); - return ni != null? ni : lookupSymbolic(resPathBytes); + String resPath = link.getName() + getString(path).substring(i); + byte[] resPathBytes = getBytes(resPath); + node = lookup(resPathBytes); + return node != null ? node : lookupSymbolic(resPathBytes); } } } @@ -326,336 +232,100 @@ class JrtFileSystem extends FileSystem { return null; } - private NodeAndImage findNode(byte[] path) throws IOException { - NodeAndImage ni = lookup(path); - if (ni == null) { - ni = lookupSymbolic(path); - if (ni == null) { + private Node findNode(AbstractJrtPath jrtPath) throws IOException { + return findNode(jrtPath.getResolvedPath()); + } + + private Node findNode(byte[] path) throws IOException { + Node node = lookup(path); + if (node == null) { + node = lookupSymbolic(path); + if (node == null) { throw new NoSuchFileException(getString(path)); } } - return ni; + return node; } - private NodeAndImage checkNode(byte[] path) throws IOException { + private Node checkNode(AbstractJrtPath jrtPath) throws IOException { + return checkNode(jrtPath.getResolvedPath()); + } + + private Node checkNode(byte[] path) throws IOException { ensureOpen(); return findNode(path); } - private NodeAndImage checkResource(byte[] path) throws IOException { - NodeAndImage ni = checkNode(path); - if (ni.node.isDirectory()) { + private Node checkResource(AbstractJrtPath jrtPath) throws IOException { + return checkResource(jrtPath.getResolvedPath()); + } + + private Node checkResource(byte[] path) throws IOException { + Node node = checkNode(path); + if (node.isDirectory()) { throw new FileSystemException(getString(path) + " is a directory"); } - assert ni.node.isResource() : "resource node expected here"; - return ni; + assert node.isResource() : "resource node expected here"; + return node; } - static boolean followLinks(LinkOption... options) { - if (options != null) { - for (LinkOption lo : options) { - if (lo == LinkOption.NOFOLLOW_LINKS) { - return false; - } else if (lo == null) { - throw new NullPointerException(); - } else { - throw new AssertionError("should not reach here"); - } - } - } - return true; - } - - // package private helpers - JrtFileAttributes getFileAttributes(byte[] path, LinkOption... options) - throws IOException { - NodeAndImage ni = checkNode(path); - if (ni.node.isLink() && followLinks(options)) { - return new JrtFileAttributes(ni.node.resolveLink(true)); - } - return new JrtFileAttributes(ni.node); - } - - void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime) - throws IOException { - throw readOnly(); - } - - boolean exists(byte[] path) throws IOException { - ensureOpen(); - try { - findNode(path); - } catch (NoSuchFileException exp) { - return false; - } - return true; - } - - boolean isDirectory(byte[] path, boolean resolveLinks) - throws IOException { - ensureOpen(); - NodeAndImage ni = checkNode(path); - return resolveLinks && ni.node.isLink()? - ni.node.resolveLink(true).isDirectory() : - ni.node.isDirectory(); - } - - JrtPath toJrtPath(String path) { + private JrtPath toJrtPath(String path) { return toJrtPath(getBytes(path)); } - JrtPath toJrtPath(byte[] path) { + private JrtPath toJrtPath(byte[] path) { return new JrtPath(this, path); } - boolean isSameFile(JrtPath p1, JrtPath p2) throws IOException { - NodeAndImage n1 = findNode(p1.getName()); - NodeAndImage n2 = findNode(p2.getName()); - return n1.node.equals(n2.node); - } - - boolean isLink(JrtPath jrtPath) throws IOException { - return findNode(jrtPath.getName()).node.isLink(); - } - - JrtPath resolveLink(JrtPath jrtPath) throws IOException { - NodeAndImage ni = findNode(jrtPath.getName()); - if (ni.node.isLink()) { - Node node = ni.node.resolveLink(); - return toJrtPath(node.getName().getBytesCopy()); - } - - return jrtPath; - } - - private Map> packagesTreeChildren = new ConcurrentHashMap<>(); - - /** - * returns the list of child paths of the given directory "path" - * - * @param path name of the directory whose content is listed - * @param childPrefix prefix added to returned children names - may be null - in which case absolute child paths are returned - * @return iterator for child paths of the given directory path - */ - Iterator iteratorOf(byte[] path, String childPrefix) - throws IOException { - NodeAndImage ni = checkNode(path); - Node node = ni.node.resolveLink(true); - - if (!node.isDirectory()) { - throw new NotDirectoryException(getString(path)); - } - - if (node.isRootDir()) { - return rootDirIterator(path, childPrefix); - } else if (node.isModulesDir()) { - return modulesDirIterator(path, childPrefix); - } else if (node.isPackagesDir()) { - return packagesDirIterator(path, childPrefix); - } else if (node.getNameString().startsWith("/packages/")) { - if (ni.image != appImage) { - UTF8String name = node.getName(); - List children = packagesTreeChildren.get(name); - if (children != null) { - return nodesToIterator(toJrtPath(path), childPrefix, children); - } - - children = new ArrayList<>(); - children.addAll(node.getChildren()); - Node tmpNode = null; - // found in boot - if (ni.image == bootImage) { - tmpNode = extImage.findNode(name); - if (tmpNode != null) { - children.addAll(tmpNode.getChildren()); - } - } - - // found in ext - tmpNode = appImage.findNode(name); - if (tmpNode != null) { - children.addAll(tmpNode.getChildren()); - } - - packagesTreeChildren.put(name, children); - return nodesToIterator(toJrtPath(path), childPrefix, children); - } - } - - return nodesToIterator(toJrtPath(path), childPrefix, node.getChildren()); - } - - private Iterator nodesToIterator(Path path, String childPrefix, List childNodes) { - Function f = childPrefix == null - ? child -> toJrtPath(child.getNameString()) - : child -> toJrtPath(childPrefix + child.getNameString().substring(1)); - return childNodes.stream().map(f).collect(toList()).iterator(); - } - - private void addRootDirContent(List children) { - for (Node child : children) { - if (!(child.isModulesDir() || child.isPackagesDir())) { - rootChildren.add(child); - } - } + private Iterator nodesToIterator(AbstractJrtPath dir, List childNodes) { + Function nodeToPath = + child -> dir.resolve( + toJrtPath(child.getNameString()).getFileName()); + return childNodes.stream(). + map(nodeToPath).collect(toList()). + iterator(); } private List rootChildren; - private synchronized void initRootChildren(byte[] path) { + + private synchronized void initRootChildren(AbstractJrtPath jrtPath) throws IOException { if (rootChildren == null) { rootChildren = new ArrayList<>(); - rootChildren.addAll(bootImage.findNode(path).getChildren()); - addRootDirContent(extImage.findNode(path).getChildren()); - addRootDirContent(appImage.findNode(path).getChildren()); + rootChildren.addAll(findNode(jrtPath).getChildren()); } } - private Iterator rootDirIterator(byte[] path, String childPrefix) throws IOException { - initRootChildren(path); - return nodesToIterator(rootPath, childPrefix, rootChildren); + private Iterator rootDirIterator(AbstractJrtPath jrtPath) throws IOException { + initRootChildren(jrtPath); + return nodesToIterator(jrtPath, rootChildren); } private List modulesChildren; - private synchronized void initModulesChildren(byte[] path) { + + private synchronized void initModulesChildren(AbstractJrtPath jrtPath) throws IOException { if (modulesChildren == null) { modulesChildren = new ArrayList<>(); - modulesChildren.addAll(bootImage.findNode(path).getChildren()); - modulesChildren.addAll(appImage.findNode(path).getChildren()); - modulesChildren.addAll(extImage.findNode(path).getChildren()); + modulesChildren.addAll(findNode(jrtPath).getChildren()); } } - private Iterator modulesDirIterator(byte[] path, String childPrefix) throws IOException { - initModulesChildren(path); - return nodesToIterator(new JrtPath(this, path), childPrefix, modulesChildren); + private Iterator modulesDirIterator(AbstractJrtPath jrtPath) throws IOException { + initModulesChildren(jrtPath); + return nodesToIterator(jrtPath, modulesChildren); } private List packagesChildren; - private synchronized void initPackagesChildren(byte[] path) { + + private synchronized void initPackagesChildren(AbstractJrtPath jrtPath) throws IOException { if (packagesChildren == null) { packagesChildren = new ArrayList<>(); - packagesChildren.addAll(bootImage.findNode(path).getChildren()); - packagesChildren.addAll(extImage.findNode(path).getChildren()); - packagesChildren.addAll(appImage.findNode(path).getChildren()); - } - } - private Iterator packagesDirIterator(byte[] path, String childPrefix) throws IOException { - initPackagesChildren(path); - return nodesToIterator(new JrtPath(this, path), childPrefix, packagesChildren); - } - - void createDirectory(byte[] dir, FileAttribute... attrs) - throws IOException { - throw readOnly(); - } - - void copyFile(boolean deletesrc, byte[] src, byte[] dst, CopyOption... options) - throws IOException { - throw readOnly(); - } - - public void deleteFile(byte[] path, boolean failIfNotExists) - throws IOException { - throw readOnly(); - } - - OutputStream newOutputStream(byte[] path, OpenOption... options) - throws IOException { - throw readOnly(); - } - - private void checkOptions(Set options) { - // check for options of null type and option is an intance of StandardOpenOption - for (OpenOption option : options) { - if (option == null) { - throw new NullPointerException(); - } - if (!(option instanceof StandardOpenOption)) { - throw new IllegalArgumentException(); - } + packagesChildren.addAll(findNode(jrtPath).getChildren()); } } - // Returns an input stream for reading the contents of the specified - // file entry. - InputStream newInputStream(byte[] path) throws IOException { - final NodeAndImage ni = checkResource(path); - return new ByteArrayInputStream(ni.getResource()); - } - - SeekableByteChannel newByteChannel(byte[] path, - Set options, - FileAttribute... attrs) - throws IOException { - checkOptions(options); - if (options.contains(StandardOpenOption.WRITE) - || options.contains(StandardOpenOption.APPEND)) { - throw readOnly(); - } - - NodeAndImage ni = checkResource(path); - byte[] buf = ni.getResource(); - final ReadableByteChannel rbc - = Channels.newChannel(new ByteArrayInputStream(buf)); - final long size = buf.length; - return new SeekableByteChannel() { - long read = 0; - - @Override - public boolean isOpen() { - return rbc.isOpen(); - } - - @Override - public long position() throws IOException { - return read; - } - - @Override - public SeekableByteChannel position(long pos) - throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public int read(ByteBuffer dst) throws IOException { - int n = rbc.read(dst); - if (n > 0) { - read += n; - } - return n; - } - - @Override - public SeekableByteChannel truncate(long size) - throws IOException { - throw new NonWritableChannelException(); - } - - @Override - public int write(ByteBuffer src) throws IOException { - throw new NonWritableChannelException(); - } - - @Override - public long size() throws IOException { - return size; - } - - @Override - public void close() throws IOException { - rbc.close(); - } - }; - } - - // Returns a FileChannel of the specified path. - FileChannel newFileChannel(byte[] path, - Set options, - FileAttribute... attrs) - throws IOException { - throw new UnsupportedOperationException("newFileChannel"); + private Iterator packagesDirIterator(AbstractJrtPath jrtPath) throws IOException { + initPackagesChildren(jrtPath); + return nodesToIterator(jrtPath, packagesChildren); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java index 54beafda0c9..1cae4a5d173 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java @@ -22,26 +22,42 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.channels.*; import java.nio.file.*; import java.nio.file.DirectoryStream.Filter; import java.nio.file.attribute.*; import java.nio.file.spi.FileSystemProvider; import java.net.URI; -import java.net.URISyntaxException; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ExecutorService; +/** + * File system provider for jrt file systems. Conditionally creates jrt fs on + * .jimage file or exploded modules directory of underlying JDK. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ public final class JrtFileSystemProvider extends FileSystemProvider { + private volatile FileSystem theFileSystem; - public JrtFileSystemProvider() { } + public JrtFileSystemProvider() { + } @Override public String getScheme() { @@ -55,50 +71,132 @@ public final class JrtFileSystemProvider extends FileSystemProvider { SecurityManager sm = System.getSecurityManager(); if (sm != null) { String home = SystemImages.RUNTIME_HOME; - FilePermission perm = - new FilePermission(home + File.separator + "-", "read"); + FilePermission perm + = new FilePermission(home + File.separator + "-", "read"); sm.checkPermission(perm); } } private void checkUri(URI uri) { - if (!uri.getScheme().equalsIgnoreCase(getScheme())) + if (!uri.getScheme().equalsIgnoreCase(getScheme())) { throw new IllegalArgumentException("URI does not match this provider"); - if (uri.getAuthority() != null) + } + if (uri.getAuthority() != null) { throw new IllegalArgumentException("Authority component present"); - if (uri.getPath() == null) + } + if (uri.getPath() == null) { throw new IllegalArgumentException("Path component is undefined"); - if (!uri.getPath().equals("/")) + } + if (!uri.getPath().equals("/")) { throw new IllegalArgumentException("Path component should be '/'"); - if (uri.getQuery() != null) + } + if (uri.getQuery() != null) { throw new IllegalArgumentException("Query component present"); - if (uri.getFragment() != null) + } + if (uri.getFragment() != null) { throw new IllegalArgumentException("Fragment component present"); + } } @Override public FileSystem newFileSystem(URI uri, Map env) - throws IOException - { + throws IOException { checkPermission(); checkUri(uri); - return new JrtFileSystem(this, env); + + if (env != null && env.containsKey("java.home")) { + return newFileSystem((String)env.get("java.home"), uri, env); + } else { + return SystemImages.hasModulesImage() + ? new JrtFileSystem(this, env) + : new JrtExplodedFileSystem(this, env); + } + } + + private static final String JRT_FS_JAR = "jrt-fs.jar"; + private FileSystem newFileSystem(String targetHome, URI uri, Map env) + throws IOException { + Objects.requireNonNull(targetHome); + Path jrtfs = FileSystems.getDefault().getPath(targetHome, JRT_FS_JAR); + if (Files.notExists(jrtfs)) { + throw new IOException(jrtfs.toString() + " not exist"); + } + + Map newEnv = new HashMap<>(env); + newEnv.remove("java.home"); + ClassLoader cl = newJrtFsLoader(jrtfs); + try { + Class c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl); + return ((FileSystemProvider)c.newInstance()).newFileSystem(uri, newEnv); + } catch (ClassNotFoundException | + IllegalAccessException | + InstantiationException e) { + throw new IOException(e); + } + } + + private static class JrtFsLoader extends URLClassLoader { + JrtFsLoader(URL[] urls) { + super(urls); + } + + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + Class c = findLoadedClass(cn); + if (c == null) { + URL u = findResource(cn.replace('.', '/') + ".class"); + if (u != null) { + c = findClass(cn); + } else { + return super.loadClass(cn, resolve); + } + } + if (resolve) + resolveClass(c); + return c; + } + } + + private static URLClassLoader newJrtFsLoader(Path jrtfs) { + final URL url; + try { + url = jrtfs.toUri().toURL(); + } catch (MalformedURLException mue) { + throw new IllegalArgumentException(mue); + } + + final URL[] urls = new URL[] { url }; + return AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public URLClassLoader run() { + return new JrtFsLoader(urls); + } + } + ); } @Override public Path getPath(URI uri) { checkPermission(); - if (!uri.getScheme().equalsIgnoreCase(getScheme())) + if (!uri.getScheme().equalsIgnoreCase(getScheme())) { throw new IllegalArgumentException("URI does not match this provider"); - if (uri.getAuthority() != null) + } + if (uri.getAuthority() != null) { throw new IllegalArgumentException("Authority component present"); - if (uri.getQuery() != null) + } + if (uri.getQuery() != null) { throw new IllegalArgumentException("Query component present"); - if (uri.getFragment() != null) + } + if (uri.getFragment() != null) { throw new IllegalArgumentException("Fragment component present"); + } String path = uri.getPath(); - if (path == null || path.charAt(0) != '/') + if (path == null || path.charAt(0) != '/') { throw new IllegalArgumentException("Invalid path component"); + } return getTheFileSystem().getPath(path); } @@ -110,11 +208,21 @@ public final class JrtFileSystemProvider extends FileSystemProvider { fs = this.theFileSystem; if (fs == null) { try { - this.theFileSystem = fs = new JrtFileSystem(this, null) { - @Override public void close() { - throw new UnsupportedOperationException(); - } - }; + if (SystemImages.hasModulesImage()) { + this.theFileSystem = fs = new JrtFileSystem(this, null) { + @Override + public void close() { + throw new UnsupportedOperationException(); + } + }; + } else { + this.theFileSystem = fs = new JrtExplodedFileSystem(this, null) { + @Override + public void close() { + throw new UnsupportedOperationException(); + } + }; + } } catch (IOException ioe) { throw new InternalError(ioe); } @@ -132,71 +240,69 @@ public final class JrtFileSystemProvider extends FileSystemProvider { } // Checks that the given file is a JrtPath - static final JrtPath toJrtPath(Path path) { - if (path == null) + static final AbstractJrtPath toAbstractJrtPath(Path path) { + if (path == null) { throw new NullPointerException(); - if (!(path instanceof JrtPath)) + } + if (!(path instanceof AbstractJrtPath)) { throw new ProviderMismatchException(); - return (JrtPath)path; + } + return (AbstractJrtPath) path; } @Override public void checkAccess(Path path, AccessMode... modes) throws IOException { - toJrtPath(path).checkAccess(modes); + toAbstractJrtPath(path).checkAccess(modes); } @Override public Path readSymbolicLink(Path link) throws IOException { - return toJrtPath(link).readSymbolicLink(); + return toAbstractJrtPath(link).readSymbolicLink(); } @Override public void copy(Path src, Path target, CopyOption... options) - throws IOException - { - toJrtPath(src).copy(toJrtPath(target), options); + throws IOException { + toAbstractJrtPath(src).copy(toAbstractJrtPath(target), options); } @Override public void createDirectory(Path path, FileAttribute... attrs) - throws IOException - { - toJrtPath(path).createDirectory(attrs); + throws IOException { + toAbstractJrtPath(path).createDirectory(attrs); } @Override public final void delete(Path path) throws IOException { - toJrtPath(path).delete(); + toAbstractJrtPath(path).delete(); } @Override @SuppressWarnings("unchecked") public V - getFileAttributeView(Path path, Class type, LinkOption... options) - { - return JrtFileAttributeView.get(toJrtPath(path), type, options); + getFileAttributeView(Path path, Class type, LinkOption... options) { + return JrtFileAttributeView.get(toAbstractJrtPath(path), type, options); } @Override public FileStore getFileStore(Path path) throws IOException { - return toJrtPath(path).getFileStore(); + return toAbstractJrtPath(path).getFileStore(); } @Override public boolean isHidden(Path path) { - return toJrtPath(path).isHidden(); + return toAbstractJrtPath(path).isHidden(); } @Override public boolean isSameFile(Path path, Path other) throws IOException { - return toJrtPath(path).isSameFile(other); + return toAbstractJrtPath(path).isSameFile(other); } @Override public void move(Path src, Path target, CopyOption... options) - throws IOException - { - toJrtPath(src).move(toJrtPath(target), options); + throws IOException { + toAbstractJrtPath(src).move(toAbstractJrtPath(target), options); } @Override @@ -204,74 +310,66 @@ public final class JrtFileSystemProvider extends FileSystemProvider { Set options, ExecutorService exec, FileAttribute... attrs) - throws IOException - { + throws IOException { throw new UnsupportedOperationException(); } @Override public SeekableByteChannel newByteChannel(Path path, - Set options, - FileAttribute... attrs) - throws IOException - { - return toJrtPath(path).newByteChannel(options, attrs); + Set options, + FileAttribute... attrs) + throws IOException { + return toAbstractJrtPath(path).newByteChannel(options, attrs); } @Override public DirectoryStream newDirectoryStream( - Path path, Filter filter) throws IOException - { - return toJrtPath(path).newDirectoryStream(filter); + Path path, Filter filter) throws IOException { + return toAbstractJrtPath(path).newDirectoryStream(filter); } @Override public FileChannel newFileChannel(Path path, - Set options, - FileAttribute... attrs) - throws IOException - { - return toJrtPath(path).newFileChannel(options, attrs); + Set options, + FileAttribute... attrs) + throws IOException { + return toAbstractJrtPath(path).newFileChannel(options, attrs); } @Override public InputStream newInputStream(Path path, OpenOption... options) - throws IOException - { - return toJrtPath(path).newInputStream(options); + throws IOException { + return toAbstractJrtPath(path).newInputStream(options); } @Override public OutputStream newOutputStream(Path path, OpenOption... options) - throws IOException - { - return toJrtPath(path).newOutputStream(options); + throws IOException { + return toAbstractJrtPath(path).newOutputStream(options); } @Override @SuppressWarnings("unchecked") // Cast to A public A - readAttributes(Path path, Class type, LinkOption... options) - throws IOException - { - if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) - return (A)toJrtPath(path).getAttributes(options); + readAttributes(Path path, Class type, LinkOption... options) + throws IOException { + if (type == BasicFileAttributes.class || type == JrtFileAttributes.class) { + return (A) toAbstractJrtPath(path).getAttributes(options); + } return null; } @Override public Map - readAttributes(Path path, String attribute, LinkOption... options) - throws IOException - { - return toJrtPath(path).readAttributes(attribute, options); + readAttributes(Path path, String attribute, LinkOption... options) + throws IOException { + return toAbstractJrtPath(path).readAttributes(attribute, options); } @Override public void setAttribute(Path path, String attribute, - Object value, LinkOption... options) - throws IOException - { - toJrtPath(path).setAttribute(attribute, value, options); + Object value, LinkOption... options) + throws IOException { + toAbstractJrtPath(path).setAttribute(attribute, value, options); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java index 175ceaa1b04..3bd0f6c1fbd 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java @@ -22,848 +22,34 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; -import java.io.*; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.channels.*; -import java.nio.file.*; -import java.nio.file.DirectoryStream.Filter; -import java.nio.file.attribute.*; -import java.util.*; -import static java.nio.file.StandardOpenOption.*; -import static java.nio.file.StandardCopyOption.*; +/** + * jrt Path implementation for jrt on .jimage files. + * + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ +final class JrtPath extends AbstractJrtPath { -final class JrtPath implements Path { - - private final JrtFileSystem jrtfs; - private final byte[] path; - private volatile int[] offsets; - private int hashcode = 0; // cached hashcode (created lazily) - - JrtPath(JrtFileSystem jrtfs, byte[] path) { + JrtPath(AbstractJrtFileSystem jrtfs, byte[] path) { this(jrtfs, path, false); } - JrtPath(JrtFileSystem jrtfs, byte[] path, boolean normalized) { - this.jrtfs = jrtfs; - if (normalized) - this.path = path; - else - this.path = normalize(path); - } - - byte[] getName() { - return path; + JrtPath(AbstractJrtFileSystem jrtfs, byte[] path, boolean normalized) { + super(jrtfs, path, normalized); } @Override - public JrtPath getRoot() { - if (this.isAbsolute()) - return jrtfs.getRootPath(); - else - return null; + protected JrtPath newJrtPath(byte[] path) { + return new JrtPath(jrtfs, path); } @Override - public Path getFileName() { - initOffsets(); - int count = offsets.length; - if (count == 0) - return null; // no elements so no name - if (count == 1 && path[0] != '/') - return this; - int lastOffset = offsets[count-1]; - int len = path.length - lastOffset; - byte[] result = new byte[len]; - System.arraycopy(path, lastOffset, result, 0, len); - return new JrtPath(jrtfs, result); - } - - @Override - public JrtPath getParent() { - initOffsets(); - int count = offsets.length; - if (count == 0) // no elements so no parent - return null; - int len = offsets[count-1] - 1; - if (len <= 0) // parent is root only (may be null) - return getRoot(); - byte[] result = new byte[len]; - System.arraycopy(path, 0, result, 0, len); - return new JrtPath(jrtfs, result); - } - - @Override - public int getNameCount() { - initOffsets(); - return offsets.length; - } - - @Override - public JrtPath getName(int index) { - initOffsets(); - if (index < 0 || index >= offsets.length) - throw new IllegalArgumentException(); - int begin = offsets[index]; - int len; - if (index == (offsets.length-1)) - len = path.length - begin; - else - len = offsets[index+1] - begin - 1; - // construct result - byte[] result = new byte[len]; - System.arraycopy(path, begin, result, 0, len); - return new JrtPath(jrtfs, result); - } - - @Override - public JrtPath subpath(int beginIndex, int endIndex) { - initOffsets(); - if (beginIndex < 0 || - beginIndex >= offsets.length || - endIndex > offsets.length || - beginIndex >= endIndex) - throw new IllegalArgumentException(); - - // starting offset and length - int begin = offsets[beginIndex]; - int len; - if (endIndex == offsets.length) - len = path.length - begin; - else - len = offsets[endIndex] - begin - 1; - // construct result - byte[] result = new byte[len]; - System.arraycopy(path, begin, result, 0, len); - return new JrtPath(jrtfs, result); - } - - @Override - public JrtPath toRealPath(LinkOption... options) throws IOException { - JrtPath realPath = new JrtPath(jrtfs, getResolvedPath()).toAbsolutePath(); - realPath = JrtFileSystem.followLinks(options)? jrtfs.resolveLink(this) : realPath; - realPath.checkAccess(); - return realPath; - } - - JrtPath readSymbolicLink() throws IOException { - if (! jrtfs.isLink(this)) { - throw new IOException("not a symbolic link"); - } - - return jrtfs.resolveLink(this); - } - - boolean isHidden() { - return false; - } - - @Override - public JrtPath toAbsolutePath() { - if (isAbsolute()) { - return this; - } else { - //add / bofore the existing path - byte[] tmp = new byte[path.length + 1]; - tmp[0] = '/'; - System.arraycopy(path, 0, tmp, 1, path.length); - return (JrtPath) new JrtPath(jrtfs, tmp).normalize(); - } - } - - @Override - public URI toUri() { - try { - return new URI("jrt", - JrtFileSystem.getString(toAbsolutePath().path), - null); - } catch (URISyntaxException ex) { - throw new AssertionError(ex); - } - } - - private boolean equalsNameAt(JrtPath other, int index) { - int mbegin = offsets[index]; - int mlen; - if (index == (offsets.length-1)) - mlen = path.length - mbegin; - else - mlen = offsets[index + 1] - mbegin - 1; - int obegin = other.offsets[index]; - int olen; - if (index == (other.offsets.length - 1)) - olen = other.path.length - obegin; - else - olen = other.offsets[index + 1] - obegin - 1; - if (mlen != olen) - return false; - int n = 0; - while(n < mlen) { - if (path[mbegin + n] != other.path[obegin + n]) - return false; - n++; - } - return true; - } - - @Override - public Path relativize(Path other) { - final JrtPath o = checkPath(other); - if (o.equals(this)) - return new JrtPath(getFileSystem(), new byte[0], true); - if (/* this.getFileSystem() != o.getFileSystem() || */ - this.isAbsolute() != o.isAbsolute()) { - throw new IllegalArgumentException(); - } - int mc = this.getNameCount(); - int oc = o.getNameCount(); - int n = Math.min(mc, oc); - int i = 0; - while (i < n) { - if (!equalsNameAt(o, i)) - break; - i++; - } - int dotdots = mc - i; - int len = dotdots * 3 - 1; - if (i < oc) - len += (o.path.length - o.offsets[i] + 1); - byte[] result = new byte[len]; - - int pos = 0; - while (dotdots > 0) { - result[pos++] = (byte)'.'; - result[pos++] = (byte)'.'; - if (pos < len) // no tailing slash at the end - result[pos++] = (byte)'/'; - dotdots--; - } - if (i < oc) - System.arraycopy(o.path, o.offsets[i], - result, pos, - o.path.length - o.offsets[i]); - return new JrtPath(getFileSystem(), result); - } - - @Override - public JrtFileSystem getFileSystem() { - return jrtfs; - } - - @Override - public boolean isAbsolute() { - return (this.path.length > 0 && path[0] == '/'); - } - - @Override - public JrtPath resolve(Path other) { - final JrtPath o = checkPath(other); - if (o.isAbsolute()) - return o; - byte[] res; - if (this.path[path.length - 1] == '/') { - res = new byte[path.length + o.path.length]; - System.arraycopy(path, 0, res, 0, path.length); - System.arraycopy(o.path, 0, res, path.length, o.path.length); - } else { - res = new byte[path.length + 1 + o.path.length]; - System.arraycopy(path, 0, res, 0, path.length); - res[path.length] = '/'; - System.arraycopy(o.path, 0, res, path.length + 1, o.path.length); - } - return new JrtPath(jrtfs, res); - } - - @Override - public Path resolveSibling(Path other) { - if (other == null) - throw new NullPointerException(); - Path parent = getParent(); - return (parent == null) ? other : parent.resolve(other); - } - - @Override - public boolean startsWith(Path other) { - final JrtPath o = checkPath(other); - if (o.isAbsolute() != this.isAbsolute() || - o.path.length > this.path.length) - return false; - int olast = o.path.length; - for (int i = 0; i < olast; i++) { - if (o.path[i] != this.path[i]) - return false; - } - olast--; - return o.path.length == this.path.length || - o.path[olast] == '/' || - this.path[olast + 1] == '/'; - } - - @Override - public boolean endsWith(Path other) { - final JrtPath o = checkPath(other); - int olast = o.path.length - 1; - if (olast > 0 && o.path[olast] == '/') - olast--; - int last = this.path.length - 1; - if (last > 0 && this.path[last] == '/') - last--; - if (olast == -1) // o.path.length == 0 - return last == -1; - if ((o.isAbsolute() &&(!this.isAbsolute() || olast != last)) || - (last < olast)) - return false; - for (; olast >= 0; olast--, last--) { - if (o.path[olast] != this.path[last]) - return false; - } - return o.path[olast + 1] == '/' || - last == -1 || this.path[last] == '/'; - } - - @Override - public JrtPath resolve(String other) { - return resolve(getFileSystem().getPath(other)); - } - - @Override - public final Path resolveSibling(String other) { - return resolveSibling(getFileSystem().getPath(other)); - } - - @Override - public final boolean startsWith(String other) { - return startsWith(getFileSystem().getPath(other)); - } - - @Override - public final boolean endsWith(String other) { - return endsWith(getFileSystem().getPath(other)); - } - - @Override - public Path normalize() { - byte[] res = getResolved(); - if (res == path) // no change - return this; - return new JrtPath(jrtfs, res, true); - } - - private JrtPath checkPath(Path path) { - if (path == null) - throw new NullPointerException(); - if (!(path instanceof JrtPath)) - throw new ProviderMismatchException(); - return (JrtPath) path; - } - - // create offset list if not already created - private void initOffsets() { - if (offsets == null) { - int count, index; - // count names - count = 0; - index = 0; - while (index < path.length) { - byte c = path[index++]; - if (c != '/') { - count++; - while (index < path.length && path[index] != '/') - index++; - } - } - // populate offsets - int[] result = new int[count]; - count = 0; - index = 0; - while (index < path.length) { - byte c = path[index]; - if (c == '/') { - index++; - } else { - result[count++] = index++; - while (index < path.length && path[index] != '/') - index++; - } - } - synchronized (this) { - if (offsets == null) - offsets = result; - } - } - } - - // resolved path for locating jrt entry inside the jrt file, - // the result path does not contain ./ and .. components - // resolved bytes will always start with '/' - private volatile byte[] resolved = null; - byte[] getResolvedPath() { - byte[] r = resolved; - if (r == null) { - if (isAbsolute()) - r = getResolved(); - else - r = toAbsolutePath().getResolvedPath(); - resolved = r; - } - return resolved; - } - - // removes redundant slashs, replace "\" to separator "/" - // and check for invalid characters - private static byte[] normalize(byte[] path) { - if (path.length == 0) - return path; - byte prevC = 0; - for (int i = 0; i < path.length; i++) { - byte c = path[i]; - if (c == '\\') - return normalize(path, i); - if (c == (byte)'/' && prevC == '/') - return normalize(path, i - 1); - if (c == '\u0000') - throw new InvalidPathException(JrtFileSystem.getString(path), - "Path: nul character not allowed"); - prevC = c; - } - - if (path.length > 1 && path[path.length - 1] == '/') { - return Arrays.copyOf(path, path.length - 1); - } - - return path; - } - - private static byte[] normalize(byte[] path, int off) { - byte[] to = new byte[path.length]; - int n = 0; - while (n < off) { - to[n] = path[n]; - n++; - } - int m = n; - byte prevC = 0; - while (n < path.length) { - byte c = path[n++]; - if (c == (byte)'\\') - c = (byte)'/'; - if (c == (byte)'/' && prevC == (byte)'/') - continue; - if (c == '\u0000') - throw new InvalidPathException(JrtFileSystem.getString(path), - "Path: nul character not allowed"); - to[m++] = c; - prevC = c; - } - if (m > 1 && to[m - 1] == '/') - m--; - return (m == to.length)? to : Arrays.copyOf(to, m); - } - - // Remove DotSlash(./) and resolve DotDot (..) components - private byte[] getResolved() { - if (path.length == 0) - return path; - for (int i = 0; i < path.length; i++) { - byte c = path[i]; - if (c == (byte)'.') - return resolve0(); - } - - return path; - } - - // TBD: performance, avoid initOffsets - private byte[] resolve0() { - byte[] to = new byte[path.length]; - int nc = getNameCount(); - int[] lastM = new int[nc]; - int lastMOff = -1; - int m = 0; - for (int i = 0; i < nc; i++) { - int n = offsets[i]; - int len = (i == offsets.length - 1)? - (path.length - n):(offsets[i + 1] - n - 1); - if (len == 1 && path[n] == (byte)'.') { - if (m == 0 && path[0] == '/') // absolute path - to[m++] = '/'; - continue; - } - if (len == 2 && path[n] == '.' && path[n + 1] == '.') { - if (lastMOff >= 0) { - m = lastM[lastMOff--]; // retreat - continue; - } - if (path[0] == '/') { // "/../xyz" skip - if (m == 0) - to[m++] = '/'; - } else { // "../xyz" -> "../xyz" - if (m != 0 && to[m-1] != '/') - to[m++] = '/'; - while (len-- > 0) - to[m++] = path[n++]; - } - continue; - } - if (m == 0 && path[0] == '/' || // absolute path - m != 0 && to[m-1] != '/') { // not the first name - to[m++] = '/'; - } - lastM[++lastMOff] = m; - while (len-- > 0) - to[m++] = path[n++]; - } - if (m > 1 && to[m - 1] == '/') - m--; - return (m == to.length)? to : Arrays.copyOf(to, m); - } - - @Override - public String toString() { - return JrtFileSystem.getString(path); - } - - @Override - public int hashCode() { - int h = hashcode; - if (h == 0) - hashcode = h = Arrays.hashCode(path); - return h; - } - - @Override - public boolean equals(Object obj) { - return obj != null && - obj instanceof JrtPath && - this.jrtfs == ((JrtPath)obj).jrtfs && - compareTo((Path) obj) == 0; - } - - @Override - public int compareTo(Path other) { - final JrtPath o = checkPath(other); - int len1 = this.path.length; - int len2 = o.path.length; - - int n = Math.min(len1, len2); - byte v1[] = this.path; - byte v2[] = o.path; - - int k = 0; - while (k < n) { - int c1 = v1[k] & 0xff; - int c2 = v2[k] & 0xff; - if (c1 != c2) - return c1 - c2; - k++; - } - return len1 - len2; - } - - @Override - public WatchKey register( - WatchService watcher, - WatchEvent.Kind[] events, - WatchEvent.Modifier... modifiers) { - if (watcher == null || events == null || modifiers == null) { - throw new NullPointerException(); - } - throw new UnsupportedOperationException(); - } - - @Override - public WatchKey register(WatchService watcher, WatchEvent.Kind... events) { - return register(watcher, events, new WatchEvent.Modifier[0]); - } - - @Override - public final File toFile() { - throw new UnsupportedOperationException(); - } - - @Override - public Iterator iterator() { - return new Iterator() { - private int i = 0; - - @Override - public boolean hasNext() { - return (i < getNameCount()); - } - - @Override - public Path next() { - if (i < getNameCount()) { - Path result = getName(i); - i++; - return result; - } else { - throw new NoSuchElementException(); - } - } - - @Override - public void remove() { - throw new ReadOnlyFileSystemException(); - } - }; - } - - ///////////////////////////////////////////////////////////////////// - // Helpers for JrtFileSystemProvider and JrtFileSystem - - int getPathLength() { - return path.length; - } - - - void createDirectory(FileAttribute... attrs) - throws IOException - { - jrtfs.createDirectory(getResolvedPath(), attrs); - } - - InputStream newInputStream(OpenOption... options) throws IOException - { - if (options.length > 0) { - for (OpenOption opt : options) { - if (opt != READ) - throw new UnsupportedOperationException("'" + opt + "' not allowed"); - } - } - return jrtfs.newInputStream(getResolvedPath()); - } - - DirectoryStream newDirectoryStream(Filter filter) - throws IOException - { - return new JrtDirectoryStream(this, filter); - } - - void delete() throws IOException { - jrtfs.deleteFile(getResolvedPath(), true); - } - - void deleteIfExists() throws IOException { - jrtfs.deleteFile(getResolvedPath(), false); - } - - JrtFileAttributes getAttributes(LinkOption... options) throws IOException - { - JrtFileAttributes zfas = jrtfs.getFileAttributes(getResolvedPath(), options); - if (zfas == null) - throw new NoSuchFileException(toString()); - return zfas; - } - - void setAttribute(String attribute, Object value, LinkOption... options) - throws IOException - { - String type; - String attr; - int colonPos = attribute.indexOf(':'); - if (colonPos == -1) { - type = "basic"; - attr = attribute; - } else { - type = attribute.substring(0, colonPos++); - attr = attribute.substring(colonPos); - } - JrtFileAttributeView view = JrtFileAttributeView.get(this, type, options); - if (view == null) - throw new UnsupportedOperationException("view <" + view + "> is not supported"); - view.setAttribute(attr, value); - } - - void setTimes(FileTime mtime, FileTime atime, FileTime ctime) - throws IOException - { - jrtfs.setTimes(getResolvedPath(), mtime, atime, ctime); - } - - Map readAttributes(String attributes, LinkOption... options) - throws IOException - - { - String view; - String attrs; - int colonPos = attributes.indexOf(':'); - if (colonPos == -1) { - view = "basic"; - attrs = attributes; - } else { - view = attributes.substring(0, colonPos++); - attrs = attributes.substring(colonPos); - } - JrtFileAttributeView jrtfv = JrtFileAttributeView.get(this, view, options); - if (jrtfv == null) { - throw new UnsupportedOperationException("view not supported"); - } - return jrtfv.readAttributes(attrs); - } - - FileStore getFileStore() throws IOException { - // each JrtFileSystem only has one root (as requested for now) - if (exists()) - return jrtfs.getFileStore(this); - throw new NoSuchFileException(JrtFileSystem.getString(path)); - } - - boolean isSameFile(Path other) throws IOException { - if (this.equals(other)) - return true; - if (other == null || - this.getFileSystem() != other.getFileSystem()) - return false; - this.checkAccess(); - JrtPath path = (JrtPath)other; - path.checkAccess(); - return Arrays.equals(this.getResolvedPath(), path.getResolvedPath()) || - jrtfs.isSameFile(this, (JrtPath)other); - } - - SeekableByteChannel newByteChannel(Set options, - FileAttribute... attrs) - throws IOException - { - return jrtfs.newByteChannel(getResolvedPath(), options, attrs); - } - - - FileChannel newFileChannel(Set options, - FileAttribute... attrs) - throws IOException - { - return jrtfs.newFileChannel(getResolvedPath(), options, attrs); - } - - void checkAccess(AccessMode... modes) throws IOException { - boolean w = false; - boolean x = false; - for (AccessMode mode : modes) { - switch (mode) { - case READ: - break; - case WRITE: - w = true; - break; - case EXECUTE: - x = true; - break; - default: - throw new UnsupportedOperationException(); - } - } - JrtFileAttributes attrs = jrtfs.getFileAttributes(getResolvedPath()); - if (attrs == null && (path.length != 1 || path[0] != '/')) - throw new NoSuchFileException(toString()); - if (w) { - if (jrtfs.isReadOnly()) - throw new AccessDeniedException(toString()); - } - if (x) - throw new AccessDeniedException(toString()); - } - - boolean exists() { - if (isAbsolute()) - return true; - try { - return jrtfs.exists(getResolvedPath()); - } catch (IOException x) {} - return false; - } - - OutputStream newOutputStream(OpenOption... options) throws IOException - { - if (options.length == 0) - return jrtfs.newOutputStream(getResolvedPath(), - CREATE_NEW, WRITE); - return jrtfs.newOutputStream(getResolvedPath(), options); - } - - void move(JrtPath target, CopyOption... options) - throws IOException - { - if (this.jrtfs == target.jrtfs) - { - jrtfs.copyFile(true, - getResolvedPath(), target.getResolvedPath(), - options); - } else { - copyToTarget(target, options); - delete(); - } - } - - void copy(JrtPath target, CopyOption... options) - throws IOException - { - if (this.jrtfs == target.jrtfs) - jrtfs.copyFile(false, - getResolvedPath(), target.getResolvedPath(), - options); - else - copyToTarget(target, options); - } - - private void copyToTarget(JrtPath target, CopyOption... options) - throws IOException - { - boolean replaceExisting = false; - boolean copyAttrs = false; - for (CopyOption opt : options) { - if (opt == REPLACE_EXISTING) - replaceExisting = true; - else if (opt == COPY_ATTRIBUTES) - copyAttrs = true; - } - // attributes of source file - JrtFileAttributes jrtfas = getAttributes(); - // check if target exists - boolean exists; - if (replaceExisting) { - try { - target.deleteIfExists(); - exists = false; - } catch (DirectoryNotEmptyException x) { - exists = true; - } - } else { - exists = target.exists(); - } - if (exists) - throw new FileAlreadyExistsException(target.toString()); - - if (jrtfas.isDirectory()) { - // create directory or file - target.createDirectory(); - } else { - try (InputStream is = jrtfs.newInputStream(getResolvedPath()); OutputStream os = target.newOutputStream()) { - byte[] buf = new byte[8192]; - int n; - while ((n = is.read(buf)) != -1) { - os.write(buf, 0, n); - } - } - } - if (copyAttrs) { - BasicFileAttributeView view = - JrtFileAttributeView.get(target, BasicFileAttributeView.class); - try { - view.setTimes(jrtfas.lastModifiedTime(), - jrtfas.lastAccessTime(), - jrtfas.creationTime()); - } catch (IOException x) { - // rollback? - try { - target.delete(); - } catch (IOException ignore) { } - throw x; - } - } + protected JrtPath newJrtPath(byte[] path, boolean normalized) { + return new JrtPath(jrtfs, path, normalized); } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java index 9014bf094fd..f1cd81051ff 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtUtils.java @@ -27,6 +27,13 @@ package jdk.internal.jrtfs; import java.util.regex.PatternSyntaxException; +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ final class JrtUtils { private JrtUtils() {} diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java index c209ad2755e..249479ed445 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/SystemImages.java @@ -22,11 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.internal.jrtfs; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Files; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -35,22 +35,52 @@ import java.security.AccessController; import java.security.CodeSource; import java.security.PrivilegedAction; +/** + * @implNote This class needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ final class SystemImages { private SystemImages() {} + static final String RUNTIME_HOME; - static final Path bootImagePath; - static final Path extImagePath; - static final Path appImagePath; + // "modules" jimage file Path + private static final Path moduleImageFile; + // "modules" jimage exists or not? + private static final boolean modulesImageExists; + // /modules directory Path + private static final Path explodedModulesDir; static { PrivilegedAction pa = SystemImages::findHome; RUNTIME_HOME = AccessController.doPrivileged(pa); FileSystem fs = FileSystems.getDefault(); - bootImagePath = fs.getPath(RUNTIME_HOME, "lib", "modules", "bootmodules.jimage"); - extImagePath = fs.getPath(RUNTIME_HOME, "lib", "modules", "extmodules.jimage"); - appImagePath = fs.getPath(RUNTIME_HOME, "lib", "modules", "appmodules.jimage"); + moduleImageFile = fs.getPath(RUNTIME_HOME, "lib", "modules"); + explodedModulesDir = fs.getPath(RUNTIME_HOME, "modules"); + + modulesImageExists = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public Boolean run() { + return Files.isRegularFile(moduleImageFile); + } + }); + } + + static boolean hasModulesImage() { + return modulesImageExists; + } + + static Path moduleImageFile() { + return moduleImageFile; + } + + static Path explodedModulesDir() { + return explodedModulesDir; } /** diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js index 968d1c785ce..c86514a7166 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtfsviewer.js @@ -25,6 +25,13 @@ * questions. */ +/* + * @implNote This script needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ function usage() { print("Usage:"); print("jdk9+: jjs -fx jrtfsviewer.js"); diff --git a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js index e4b3c81fd85..ed96f89b30b 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js +++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/jrtls.js @@ -27,6 +27,13 @@ * Usage: jjs jrtls.js * * Recursively list the content of / directory of the jrt fs. + * + * @implNote This script needs to maintain JDK 8 source compatibility. + * + * It is used internally in the JDK to implement jimage/jrtfs access, + * but also compiled and delivered as part of the jrtfs.jar to support access + * to the jimage file provided by the shipped JDK by tools running on JDK 8. + */ */ // classes used diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java new file mode 100644 index 00000000000..13c3eeda5d6 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.loader; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleReference; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Optional; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; +import java.util.stream.Stream; + +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.module.ServicesCatalog; + +/** + * Find resources and packages in modules defined to the boot class loader or + * resources and packages on the "boot class path" specified via -Xbootclasspath/a. + */ + +public class BootLoader { + private BootLoader() { } + + // The unnamed module for the boot loader + private static final Module UNNAMED_MODULE; + private static final String JAVA_HOME = System.getProperty("java.home"); + + static { + UNNAMED_MODULE + = SharedSecrets.getJavaLangReflectModuleAccess().defineUnnamedModule(null); + setBootLoaderUnnamedModule0(UNNAMED_MODULE); + } + + // ServiceCatalog for the boot class loader + private static final ServicesCatalog SERVICES_CATALOG = new ServicesCatalog(); + + /** + * Returns the unnamed module for the boot loader. + */ + public static Module getUnnamedModule() { + return UNNAMED_MODULE; + } + + /** + * Returns the ServiceCatalog for modules defined to the boot class loader. + */ + public static ServicesCatalog getServicesCatalog() { + return SERVICES_CATALOG; + } + + /** + * Register a module with this class loader so that its classes (and + * resources) become visible via this class loader. + */ + public static void loadModule(ModuleReference mref) { + ClassLoaders.bootLoader().loadModule(mref); + } + + /** + * Loads the Class object with the given name defined to the boot loader. + */ + public static Class loadClassOrNull(String name) { + return ClassLoaders.bootLoader().loadClassOrNull(name); + } + + /** + * Returns a URL to a resource in a named module defined to the boot loader. + */ + public static URL findResource(String mn, String name) throws IOException { + return ClassLoaders.bootLoader().findResource(mn, name); + } + + /** + * Returns an input stream to a resource in a named module defined to the + * boot loader. + */ + public static InputStream findResourceAsStream(String mn, String name) + throws IOException + { + return ClassLoaders.bootLoader().findResourceAsStream(mn, name); + } + + /** + * Returns the URL to the given resource if the resource can be located + * on the boot class path. This method does not locate a resource in any + * of the named modules defined to the boot loader. + */ + public static URL findResource(String name) { + return ClassLoaders.bootLoader().findResource(name); + } + + /** + * Returns an Iterator to iterate over the resources of the given name + * on the boot class path. This method does not locate resources in any + * of the named modules defined to the boot loader. + */ + public static Enumeration findResources(String name) throws IOException { + return ClassLoaders.bootLoader().findResources(name); + } + + /** + * Define a package for the given class to the boot loader, if not already + * defined. + */ + public static Package definePackage(Class c) { + return getDefinedPackage(c.getPackageName()); + } + + /** + * Returns the Package of the given name defined to the boot loader or null + * if the package has not been defined. + */ + public static Package getDefinedPackage(String pn) { + Package pkg = ClassLoaders.bootLoader().getDefinedPackage(pn); + if (pkg == null) { + String location = getSystemPackageLocation(pn.replace('.', '/')); + if (location != null) { + pkg = PackageHelper.definePackage(pn.intern(), location); + } + } + return pkg; + } + + /** + * Returns a stream of the packages defined to the boot loader. + */ + public static Stream packages() { + return Arrays.stream(getSystemPackageNames()) + .map(name -> getDefinedPackage(name.replace('/', '.'))); + } + + /** + * Helper class to define {@code Package} objects for packages in modules + * defined to the boot loader. + */ + static class PackageHelper { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + /** + * Define the {@code Package} with the given name. The specified + * location is a jrt URL to a named module in the run-time image, a + * file path to a module in an exploded run-time image, or the file + * path to an enty on the boot class path (java agent Boot-Class-Path + * or -Xbootclasspath/a. + * + *

    If the given location is a JAR file containing a manifest, + * the defined Package contains the versioning information from + * the manifest, if present. + * + * @param name package name + * @param location location where the package is (jrt URL or file path) + */ + static Package definePackage(String name, String location) { + Module module = findModule(location); + if (module != null) { + // named module from runtime image or exploded module + if (name.isEmpty()) + throw new InternalError("empty package in " + location); + return JLA.definePackage(ClassLoaders.bootLoader(), name, module); + } + + // package in unnamed module (-Xbootclasspath/a) + URL url = toFileURL(location); + Manifest man = url != null ? getManifest(location) : null; + + return ClassLoaders.bootLoader().defineOrCheckPackage(name, man, url); + } + + /** + * Finds the module at the given location defined to the boot loader. + * The module is either in runtime image or exploded image. + * Otherwise this method returns null. + */ + private static Module findModule(String location) { + String mn = null; + if (location.startsWith("jrt:/")) { + // named module in runtime image ("jrt:/".length() == 5) + mn = location.substring(5, location.length()); + } else { + // named module in exploded image + Path path = Paths.get(location); + Path modulesDir = Paths.get(JAVA_HOME, "modules"); + if (path.startsWith(modulesDir)) { + mn = path.getFileName().toString(); + } + } + + if (mn != null) { + // named module from runtime image or exploded module + Optional om = Layer.boot().findModule(mn); + if (!om.isPresent()) + throw new InternalError(mn + " not in boot layer"); + return om.get(); + } + + return null; + } + + /** + * Returns URL if the given location is a regular file path. + */ + private static URL toFileURL(String location) { + return AccessController.doPrivileged(new PrivilegedAction<>() { + public URL run() { + Path path = Paths.get(location); + if (Files.isRegularFile(path)) { + try { + return path.toUri().toURL(); + } catch (MalformedURLException e) {} + } + return null; + } + }); + } + + /** + * Returns the Manifest if the given location is a JAR file + * containing a manifest. + */ + private static Manifest getManifest(String location) { + return AccessController.doPrivileged(new PrivilegedAction<>() { + public Manifest run() { + Path jar = Paths.get(location); + try (InputStream in = Files.newInputStream(jar); + JarInputStream jis = new JarInputStream(in, false)) { + return jis.getManifest(); + } catch (IOException e) { + return null; + } + } + }); + } + } + + /** + * Returns an array of the binary name of the packages defined by + * the boot loader, in VM internal form (forward slashes instead of dot). + */ + private static native String[] getSystemPackageNames(); + + /** + * Returns the location of the package of the given name, if + * defined by the boot loader; otherwise {@code null} is returned. + * + * The location may be a module from the runtime image or exploded image, + * or from the boot class append path (i.e. -Xbootclasspath/a or + * BOOT-CLASS-PATH attribute specified in java agent). + */ + private static native String getSystemPackageLocation(String name); + private static native void setBootLoaderUnnamedModule0(Module module); +} 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 new file mode 100644 index 00000000000..055cba276b9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java @@ -0,0 +1,766 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.File; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleReader; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.CodeSigner; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.SecureClassLoader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import jdk.internal.module.ModulePatcher.PatchedModuleReader; +import jdk.internal.misc.VM; +import sun.misc.URLClassPath; +import sun.misc.Resource; + + +/** + * The platform or application class loader. Resources loaded from modules + * defined to the boot class loader are also loaded via an instance of this + * ClassLoader type. + * + *

    This ClassLoader supports loading of classes and resources from modules. + * Modules are defined to the ClassLoader by invoking the {@link #loadModule} + * method. Defining a module to this ClassLoader has the effect of making the + * types in the module visible.

    + * + *

    This ClassLoader also supports loading of classes and resources from a + * class path of URLs that are specified to the ClassLoader at construction + * time. The class path may expand at runtime (the Class-Path attribute in JAR + * files or via instrumentation agents).

    + * + *

    The delegation model used by this ClassLoader differs to the regular + * delegation model. When requested to load a class then this ClassLoader first + * maps the class name to its package name. If there is a module defined to a + * BuiltinClassLoader containing this package then the class loader delegates + * directly to that class loader. If there isn't a module containing the + * package then it delegates the search to the parent class loader and if not + * found in the parent then it searches the class path. The main difference + * between this and the usual delegation model is that it allows the platform + * class loader to delegate to the application class loader, important with + * upgraded modules defined to the platform class loader. + */ + +public class BuiltinClassLoader + extends SecureClassLoader +{ + static { + if (!ClassLoader.registerAsParallelCapable()) + throw new InternalError(); + } + + // parent ClassLoader + private final BuiltinClassLoader parent; + + // the URL class path or null if there is no class path + private final URLClassPath ucp; + + + /** + * A module defined/loaded by a built-in class loader. + * + * A LoadedModule encapsulates a ModuleReference along with its CodeSource + * URL to avoid needing to create this URL when define classes. + */ + private static class LoadedModule { + private final BuiltinClassLoader loader; + private final ModuleReference mref; + private final URL codeSourceURL; // may be null + + LoadedModule(BuiltinClassLoader loader, ModuleReference mref) { + URL url = null; + if (mref.location().isPresent()) { + try { + url = mref.location().get().toURL(); + } catch (MalformedURLException e) { } + } + this.loader = loader; + this.mref = mref; + this.codeSourceURL = url; + } + + BuiltinClassLoader loader() { return loader; } + ModuleReference mref() { return mref; } + String name() { return mref.descriptor().name(); } + URL codeSourceURL() { return codeSourceURL; } + } + + + // maps package name to loaded module for modules in the boot layer + private static final Map packageToModule + = new ConcurrentHashMap<>(1024); + + // maps a module name to a module reference + private final Map nameToModule; + + // maps a module reference to a module reader + private final Map moduleToReader; + + + /** + * Create a new instance. + */ + BuiltinClassLoader(BuiltinClassLoader parent, URLClassPath ucp) { + // ensure getParent() returns null when the parent is the boot loader + super(parent == null || parent == ClassLoaders.bootLoader() ? null : parent); + + this.parent = parent; + this.ucp = ucp; + + this.nameToModule = new ConcurrentHashMap<>(); + this.moduleToReader = new ConcurrentHashMap<>(); + } + + /** + * Register a module this this class loader. This has the effect of making + * the types in the module visible. + */ + public void loadModule(ModuleReference mref) { + String mn = mref.descriptor().name(); + if (nameToModule.putIfAbsent(mn, mref) != null) { + throw new InternalError(mn + " already defined to this loader"); + } + + LoadedModule loadedModule = new LoadedModule(this, mref); + for (String pn : mref.descriptor().packages()) { + LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule); + if (other != null) { + throw new InternalError(pn + " in modules " + mn + " and " + + other.mref().descriptor().name()); + } + } + } + + /** + * Returns the {@code ModuleReference} for the named module defined to + * this class loader; or {@code null} if not defined. + * + * @param name The name of the module to find + */ + protected ModuleReference findModule(String name) { + return nameToModule.get(name); + } + + + // -- finding resources + + /** + * Returns a URL to a resource of the given name in a module defined to + * this class loader. + */ + @Override + public URL findResource(String mn, String name) throws IOException { + ModuleReference mref = nameToModule.get(mn); + if (mref == null) + return null; // not defined to this class loader + + URL url; + + try { + url = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public URL run() throws IOException { + URI u = moduleReaderFor(mref).find(name).orElse(null); + if (u != null) { + try { + return u.toURL(); + } catch (MalformedURLException e) { } + } + return null; + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + + // check access to the URL + return checkURL(url); + } + + /** + * Returns an input stream to a resource of the given name in a module + * defined to this class loader. + */ + public InputStream findResourceAsStream(String mn, String name) + throws IOException + { + // Need URL to resource when running with a security manager so that + // the right permission check is done. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + + URL url = findResource(mn, name); + return (url != null) ? url.openStream() : null; + + } else { + + ModuleReference mref = nameToModule.get(mn); + if (mref == null) + return null; // not defined to this class loader + + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public InputStream run() throws IOException { + return moduleReaderFor(mref).open(name).orElse(null); + } + }); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + } + } + + /** + * Finds the resource with the given name on the class path of this class + * loader. + */ + @Override + public URL findResource(String name) { + if (ucp != null) { + PrivilegedAction pa = () -> ucp.findResource(name, false); + URL url = AccessController.doPrivileged(pa); + return checkURL(url); + } else { + return null; + } + } + + /** + * Returns an enumeration of URL objects to all the resources with the + * given name on the class path of this class loader. + */ + @Override + public Enumeration findResources(String name) throws IOException { + if (ucp != null) { + List result = new ArrayList<>(); + PrivilegedAction> pa = () -> ucp.findResources(name, false); + Enumeration e = AccessController.doPrivileged(pa); + while (e.hasMoreElements()) { + URL url = checkURL(e.nextElement()); + if (url != null) { + result.add(url); + } + } + return Collections.enumeration(result); // checked URLs + } else { + return Collections.emptyEnumeration(); + } + } + + + // -- finding/loading classes + + /** + * Finds the class with the specified binary name. + */ + @Override + protected Class findClass(String cn) throws ClassNotFoundException { + // no class loading until VM is fully initialized + if (!VM.isModuleSystemInited()) + throw new ClassNotFoundException(cn); + + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(cn); + + Class c = null; + if (loadedModule != null) { + + // attempt to load class in module defined to this loader + if (loadedModule.loader() == this) { + c = findClassInModuleOrNull(loadedModule, cn); + } + + } else { + + // search class path + if (ucp != null) { + c = findClassOnClassPathOrNull(cn); + } + + } + + // not found + if (c == null) + throw new ClassNotFoundException(cn); + + return c; + } + + /** + * Finds the class with the specified binary name in a given module. + * This method returns {@code null} if the class cannot be found. + */ + @Override + protected Class findClass(String mn, String cn) { + ModuleReference mref = nameToModule.get(mn); + if (mref == null) + return null; // not defined to this class loader + + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule == null || !loadedModule.name().equals(mn)) { + return null; // module name does not match + } + + // attempt to load class in module defined to this loader + assert loadedModule.loader() == this; + return findClassInModuleOrNull(loadedModule, cn); + } + + /** + * Loads the class with the specified binary name. + */ + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + Class c = loadClassOrNull(cn, resolve); + if (c == null) + throw new ClassNotFoundException(cn); + return c; + } + + /** + * A variation of {@code loadCass} to load a class with the specified + * binary name. This method returns {@code null} when the class is not + * found. + */ + protected Class loadClassOrNull(String cn, boolean resolve) { + synchronized (getClassLoadingLock(cn)) { + // check if already loaded + Class c = findLoadedClass(cn); + + if (c == null) { + + // find the candidate module for this class + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null) { + + // package is in a module + BuiltinClassLoader loader = loadedModule.loader(); + if (loader == this) { + if (VM.isModuleSystemInited()) { + c = findClassInModuleOrNull(loadedModule, cn); + } + } else { + // delegate to the other loader + c = loader.loadClassOrNull(cn); + } + + } else { + + // check parent + if (parent != null) { + c = parent.loadClassOrNull(cn); + } + + // check class path + if (c == null && ucp != null && VM.isModuleSystemInited()) { + c = findClassOnClassPathOrNull(cn); + } + } + + } + + if (resolve && c != null) + resolveClass(c); + + return c; + } + } + + /** + * A variation of {@code loadCass} to load a class with the specified + * binary name. This method returns {@code null} when the class is not + * found. + */ + protected Class loadClassOrNull(String cn) { + return loadClassOrNull(cn, false); + } + + /** + * Find the candidate loaded module for the given class name. + * Returns {@code null} if none of the modules defined to this + * class loader contain the API package for the class. + */ + private LoadedModule findLoadedModule(String cn) { + int pos = cn.lastIndexOf('.'); + if (pos < 0) + return null; // unnamed package + + String pn = cn.substring(0, pos); + return packageToModule.get(pn); + } + + /** + * Finds the class with the specified binary name if in a module + * defined to this ClassLoader. + * + * @return the resulting Class or {@code null} if not found + */ + private Class findClassInModuleOrNull(LoadedModule loadedModule, String cn) { + PrivilegedAction> pa = () -> defineClass(cn, loadedModule); + return AccessController.doPrivileged(pa); + } + + /** + * Finds the class with the specified binary name on the class path. + * + * @return the resulting Class or {@code null} if not found + */ + private Class findClassOnClassPathOrNull(String cn) { + return AccessController.doPrivileged( + new PrivilegedAction>() { + public Class run() { + String path = cn.replace('.', '/').concat(".class"); + Resource res = ucp.getResource(path, false); + if (res != null) { + try { + return defineClass(cn, res); + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + } + } + return null; + } + }); + } + + /** + * Defines the given binary class name to the VM, loading the class + * bytes from the given module. + * + * @return the resulting Class or {@code null} if an I/O error occurs + */ + private Class defineClass(String cn, LoadedModule loadedModule) { + ModuleReference mref = loadedModule.mref(); + ModuleReader reader = moduleReaderFor(mref); + + try { + ByteBuffer bb = null; + URL csURL = null; + + // locate class file, special handling for patched modules to + // avoid locating the resource twice + String rn = cn.replace('.', '/').concat(".class"); + if (reader instanceof PatchedModuleReader) { + Resource r = ((PatchedModuleReader)reader).findResource(rn); + if (r != null) { + bb = r.getByteBuffer(); + csURL = r.getCodeSourceURL(); + } + } else { + bb = reader.read(rn).orElse(null); + csURL = loadedModule.codeSourceURL(); + } + + if (bb == null) { + // class not found + return null; + } + + CodeSource cs = new CodeSource(csURL, (CodeSigner[]) null); + try { + // define class to VM + return defineClass(cn, bb, cs); + + } finally { + reader.release(bb); + } + + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + return null; + } + } + + /** + * Defines the given binary class name to the VM, loading the class + * bytes via the given Resource object. + * + * @return the resulting Class + * @throws IOException if reading the resource fails + * @throws SecurityException if there is a sealing violation (JAR spec) + */ + private Class defineClass(String cn, Resource res) throws IOException { + URL url = res.getCodeSourceURL(); + + // if class is in a named package then ensure that the package is defined + int pos = cn.lastIndexOf('.'); + if (pos != -1) { + String pn = cn.substring(0, pos); + Manifest man = res.getManifest(); + defineOrCheckPackage(pn, man, url); + } + + // defines the class to the runtime + ByteBuffer bb = res.getByteBuffer(); + if (bb != null) { + CodeSigner[] signers = res.getCodeSigners(); + CodeSource cs = new CodeSource(url, signers); + return defineClass(cn, bb, cs); + } else { + byte[] b = res.getBytes(); + CodeSigner[] signers = res.getCodeSigners(); + CodeSource cs = new CodeSource(url, signers); + return defineClass(cn, b, 0, b.length, cs); + } + } + + + // -- packages + + /** + * Defines a package in this ClassLoader. If the package is already defined + * then its sealing needs to be checked if sealed by the legacy sealing + * mechanism. + * + * @throws SecurityException if there is a sealing violation (JAR spec) + */ + protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { + Package pkg = getAndVerifyPackage(pn, man, url); + if (pkg == null) { + try { + if (man != null) { + pkg = definePackage(pn, man, url); + } else { + pkg = definePackage(pn, null, null, null, null, null, null, null); + } + } catch (IllegalArgumentException iae) { + // defined by another thread so need to re-verify + pkg = getAndVerifyPackage(pn, man, url); + if (pkg == null) + throw new InternalError("Cannot find package: " + pn); + } + } + return pkg; + } + + /** + * Get the Package with the specified package name. If defined + * then verify that it against the manifest and code source. + * + * @throws SecurityException if there is a sealing violation (JAR spec) + */ + private Package getAndVerifyPackage(String pn, Manifest man, URL url) { + Package pkg = getDefinedPackage(pn); + if (pkg != null) { + if (pkg.isSealed()) { + if (!pkg.isSealed(url)) { + throw new SecurityException( + "sealing violation: package " + pn + " is sealed"); + } + } else { + // can't seal package if already defined without sealing + if ((man != null) && isSealed(pn, man)) { + throw new SecurityException( + "sealing violation: can't seal package " + pn + + ": already defined"); + } + } + } + return pkg; + } + + /** + * Defines a new package in this ClassLoader. The attributes in the specified + * Manifest are use to get the package version and sealing information. + * + * @throws IllegalArgumentException if the package name duplicates an + * existing package either in this class loader or one of its ancestors + */ + private Package definePackage(String pn, Manifest man, URL url) { + String specTitle = null; + String specVersion = null; + String specVendor = null; + String implTitle = null; + String implVersion = null; + String implVendor = null; + String sealed = null; + URL sealBase = null; + + if (man != null) { + Attributes attr = man.getAttributes(pn.replace('.', '/').concat("/")); + if (attr != null) { + specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); + specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); + specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); + implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + sealed = attr.getValue(Attributes.Name.SEALED); + } + + attr = man.getMainAttributes(); + if (attr != null) { + if (specTitle == null) + specTitle = attr.getValue(Attributes.Name.SPECIFICATION_TITLE); + if (specVersion == null) + specVersion = attr.getValue(Attributes.Name.SPECIFICATION_VERSION); + if (specVendor == null) + specVendor = attr.getValue(Attributes.Name.SPECIFICATION_VENDOR); + if (implTitle == null) + implTitle = attr.getValue(Attributes.Name.IMPLEMENTATION_TITLE); + if (implVersion == null) + implVersion = attr.getValue(Attributes.Name.IMPLEMENTATION_VERSION); + if (implVendor == null) + implVendor = attr.getValue(Attributes.Name.IMPLEMENTATION_VENDOR); + if (sealed == null) + sealed = attr.getValue(Attributes.Name.SEALED); + } + + // package is sealed + if ("true".equalsIgnoreCase(sealed)) + sealBase = url; + } + return definePackage(pn, + specTitle, + specVersion, + specVendor, + implTitle, + implVersion, + implVendor, + sealBase); + } + + /** + * Returns {@code true} if the specified package name is sealed according to + * the given manifest. + */ + private boolean isSealed(String pn, Manifest man) { + String path = pn.replace('.', '/').concat("/"); + Attributes attr = man.getAttributes(path); + String sealed = null; + if (attr != null) + sealed = attr.getValue(Attributes.Name.SEALED); + if (sealed == null && (attr = man.getMainAttributes()) != null) + sealed = attr.getValue(Attributes.Name.SEALED); + return "true".equalsIgnoreCase(sealed); + } + + // -- permissions + + /** + * Returns the permissions for the given CodeSource. + */ + @Override + protected PermissionCollection getPermissions(CodeSource cs) { + PermissionCollection perms = super.getPermissions(cs); + + // add the permission to access the resource + URL url = cs.getLocation(); + if (url == null) + return perms; + Permission p = null; + try { + p = url.openConnection().getPermission(); + if (p != null) { + // for directories then need recursive access + if (p instanceof FilePermission) { + String path = p.getName(); + if (path.endsWith(File.separator)) { + path += "-"; + p = new FilePermission(path, "read"); + } + } + perms.add(p); + } + } catch (IOException ioe) { } + + return perms; + } + + + // -- miscellaneous supporting methods + + /** + * Returns the ModuleReader for the given module. + */ + private ModuleReader moduleReaderFor(ModuleReference mref) { + return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref)); + } + + /** + * Creates a ModuleReader for the given module. + */ + private ModuleReader createModuleReader(ModuleReference mref) { + try { + return mref.open(); + } catch (IOException e) { + // Return a null module reader to avoid a future class load + // attempting to open the module again. + return new NullModuleReader(); + } + } + + /** + * A ModuleReader that doesn't read any resources. + */ + private static class NullModuleReader implements ModuleReader { + @Override + public Optional find(String name) { + return Optional.empty(); + } + @Override + public void close() { + throw new InternalError("Should not get here"); + } + }; + + /** + * Checks access to the given URL. We use URLClassPath for consistent + * checking with java.net.URLClassLoader. + */ + private static URL checkURL(URL url) { + return URLClassPath.checkURL(url); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java new file mode 100644 index 00000000000..f21146f9998 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/ClassLoaders.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Module; +import java.net.URL; +import java.nio.file.InvalidPathException; +import java.nio.file.Paths; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.util.jar.Manifest; + +import jdk.internal.misc.JavaLangAccess; +import jdk.internal.misc.SharedSecrets; +import jdk.internal.misc.VM; +import sun.misc.URLClassPath; + + +/** + * Creates and provides access to the built-in platform and application class + * loaders. It also creates the class loader that is used to locate resources + * in modules defined to the boot class loader. + */ + +public class ClassLoaders { + + private ClassLoaders() { } + + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + + // the built-in class loaders + private static final BootClassLoader BOOT_LOADER; + private static final PlatformClassLoader PLATFORM_LOADER; + private static final AppClassLoader APP_LOADER; + + /** + * Creates the built-in class loaders + */ + static { + + // -Xbootclasspth/a or -javaagent Boot-Class-Path + URLClassPath bcp = null; + String s = VM.getSavedProperty("jdk.boot.class.path.append"); + if (s != null && s.length() > 0) + bcp = toURLClassPath(s); + + // we have a class path if -cp is specified or -m is not specified + URLClassPath ucp = null; + String mainMid = System.getProperty("jdk.module.main"); + String cp = System.getProperty("java.class.path"); + if (mainMid == null && (cp == null || cp.length() == 0)) + cp = "."; + if (cp != null && cp.length() > 0) + ucp = toURLClassPath(cp); + + + // create the class loaders + BOOT_LOADER = new BootClassLoader(bcp); + PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER); + APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp); + } + + /** + * Returns the class loader that is used to find resources in modules + * defined to the boot class loader. + * + * @apiNote This method is not public, it should instead be used via + * the BootLoader class that provides a restricted API to this class + * loader. + */ + static BuiltinClassLoader bootLoader() { + return BOOT_LOADER; + } + + /** + * Returns the platform class loader. + */ + public static ClassLoader platformClassLoader() { + return PLATFORM_LOADER; + } + + /** + * Returns the application class loader. + */ + public static ClassLoader appClassLoader() { + return APP_LOADER; + } + + /** + * The class loader that is used to find resources in modules defined to + * the boot class loader. It is not used for class loading. + */ + private static class BootClassLoader extends BuiltinClassLoader { + BootClassLoader(URLClassPath bcp) { + super(null, bcp); + } + + @Override + protected Class loadClassOrNull(String cn) { + return JLA.findBootstrapClassOrNull(this, cn); + } + }; + + /** + * The platform class loader, a unique type to make it easier to distinguish + * from the application class loader. + */ + private static class PlatformClassLoader extends BuiltinClassLoader { + static { + if (!ClassLoader.registerAsParallelCapable()) + throw new InternalError(); + } + + PlatformClassLoader(BootClassLoader parent) { + super(parent, null); + } + + /** + * Called by the VM to support define package for AppCDS. + * + * Shared classes are returned in ClassLoader::findLoadedClass + * that bypass the defineClass call. + */ + private Package definePackage(String pn, Module module) { + return JLA.definePackage(this, pn, module); + } + } + + /** + * The application class loader that is a {@code BuiltinClassLoader} with + * customizations to be compatible with long standing behavior. + */ + private static class AppClassLoader extends BuiltinClassLoader { + static { + if (!ClassLoader.registerAsParallelCapable()) + throw new InternalError(); + } + + final URLClassPath ucp; + + AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) { + super(parent, ucp); + this.ucp = ucp; + } + + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + // for compatibility reasons, say where restricted package list has + // been updated to list API packages in the unnamed module. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + int i = cn.lastIndexOf('.'); + if (i != -1) { + sm.checkPackageAccess(cn.substring(0, i)); + } + } + + return super.loadClass(cn, resolve); + } + + @Override + protected PermissionCollection getPermissions(CodeSource cs) { + PermissionCollection perms = super.getPermissions(cs); + perms.add(new RuntimePermission("exitVM")); + return perms; + } + + /** + * Called by the VM to support dynamic additions to the class path + * + * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch + */ + void appendToClassPathForInstrumentation(String path) { + appendToUCP(path, ucp); + } + + /** + * Called by the VM to support define package for AppCDS + * + * Shared classes are returned in ClassLoader::findLoadedClass + * that bypass the defineClass call. + */ + private Package definePackage(String pn, Module module) { + return JLA.definePackage(this, pn, module); + } + + /** + * Called by the VM to support define package for AppCDS + */ + protected Package defineOrCheckPackage(String pn, Manifest man, URL url) { + return super.defineOrCheckPackage(pn, man, url); + } + } + + /** + * Returns a {@code URLClassPath} of file URLs to each of the elements in + * the given class path. + */ + private static URLClassPath toURLClassPath(String cp) { + URLClassPath ucp = new URLClassPath(new URL[0]); + appendToUCP(cp, ucp); + return ucp; + } + + /** + * Converts the elements in the given class path to file URLs and adds + * them to the given URLClassPath. + */ + private static void appendToUCP(String cp, URLClassPath ucp) { + String[] elements = cp.split(File.pathSeparator); + if (elements.length == 0) { + // contains path separator(s) only, default to current directory + // to be compatible with long standing behavior + elements = new String[] { "" }; + } + for (String s: elements) { + try { + URL url = Paths.get(s).toRealPath().toUri().toURL(); + ucp.addURL(url); + } catch (InvalidPathException | IOException ignore) { + // malformed path string or class path element does not exist + } + } + } + +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java new file mode 100644 index 00000000000..91604ecbee5 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/Loader.java @@ -0,0 +1,540 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.io.File; +import java.io.FilePermission; +import java.io.IOException; +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSigner; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.SecureClassLoader; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * A class loader that loads classes and resources from a collection of + * modules, or from a single module where the class loader is a member + * of a pool of class loaders. + * + *

    The delegation model used by this ClassLoader differs to the regular + * delegation model. When requested to load a class then this ClassLoader first + * maps the class name to its package name. If there a module defined to the + * Loader containing the package then the class loader attempts to load from + * that module. If the package is instead defined to a module in a "remote" + * ClassLoader then this class loader delegates directly to that class loader. + * The map of package name to remote class loader is created based on the + * modules read by modules defined to this class loader. If the package is not + * local or remote then this class loader will delegate to the parent class + * loader. This allows automatic modules (for example) to link to types in the + * unnamed module of the parent class loader. + * + * @see Layer#createWithOneLoader + * @see Layer#createWithManyLoaders + */ + +public final class Loader extends SecureClassLoader { + + static { + ClassLoader.registerAsParallelCapable(); + } + + // the loader pool is in a pool, can be null + private final LoaderPool pool; + + // parent ClassLoader, can be null + private final ClassLoader parent; + + // maps a module name to a module reference + private final Map nameToModule; + + // maps package name to a module loaded by this class loader + private final Map localPackageToModule; + + // maps package name to a remote class loader, populated post initialization + private final Map remotePackageToLoader + = new ConcurrentHashMap<>(); + + // maps a module reference to a module reader, populated lazily + private final Map moduleToReader + = new ConcurrentHashMap<>(); + + // ACC used when loading classes and resources */ + private final AccessControlContext acc; + + /** + * A module defined/loaded to a {@code Loader}. + */ + private static class LoadedModule { + private final ModuleReference mref; + private final URL url; // may be null + private final CodeSource cs; + + LoadedModule(ModuleReference mref) { + URL url = null; + if (mref.location().isPresent()) { + try { + url = mref.location().get().toURL(); + } catch (MalformedURLException e) { } + } + this.mref = mref; + this.url = url; + this.cs = new CodeSource(url, (CodeSigner[]) null); + } + + ModuleReference mref() { return mref; } + String name() { return mref.descriptor().name(); } + URL location() { return url; } + CodeSource codeSource() { return cs; } + } + + + /** + * Creates a {@code Loader} in a loader pool that loads classes/resources + * from one module. + */ + public Loader(ResolvedModule resolvedModule, + LoaderPool pool, + ClassLoader parent) + { + super(parent); + + this.pool = pool; + this.parent = parent; + + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + String mn = descriptor.name(); + this.nameToModule = Map.of(mn, mref); + + Map localPackageToModule = new HashMap<>(); + LoadedModule lm = new LoadedModule(mref); + descriptor.packages().forEach(pn -> localPackageToModule.put(pn, lm)); + this.localPackageToModule = localPackageToModule; + + this.acc = AccessController.getContext(); + } + + /** + * Creates a {@code Loader} that loads classes/resources from a collection + * of modules. + * + * @throws IllegalArgumentException + * If two or more modules have the same package + */ + public Loader(Collection modules, ClassLoader parent) { + super(parent); + + this.pool = null; + this.parent = parent; + + Map nameToModule = new HashMap<>(); + Map localPackageToModule = new HashMap<>(); + for (ResolvedModule resolvedModule : modules) { + ModuleReference mref = resolvedModule.reference(); + ModuleDescriptor descriptor = mref.descriptor(); + nameToModule.put(descriptor.name(), mref); + descriptor.packages().forEach(pn -> { + LoadedModule lm = new LoadedModule(mref); + if (localPackageToModule.put(pn, lm) != null) + throw new IllegalArgumentException("Package " + + pn + " in more than one module"); + }); + } + this.nameToModule = nameToModule; + this.localPackageToModule = localPackageToModule; + + this.acc = AccessController.getContext(); + } + + + /** + * Completes initialization of this Loader. This method populates + * remotePackageToLoader with the packages of the remote modules, where + * "remote modules" are the modules read by modules defined to this loader. + * + * @param cf the Configuration containing at least modules to be defined to + * this class loader + * + * @param parentLayer the parent Layer + */ + public Loader initRemotePackageMap(Configuration cf, Layer parentLayer) { + + for (String name : nameToModule.keySet()) { + + ResolvedModule resolvedModule = cf.findModule(name).get(); + assert resolvedModule.configuration() == cf; + + for (ResolvedModule other : resolvedModule.reads()) { + String mn = other.name(); + ClassLoader loader; + + if (other.configuration() == cf) { + + // The module reads another module in the newly created + // layer. If all modules are defined to the same class + // loader then the packages are local. + if (pool == null) { + assert nameToModule.containsKey(mn); + continue; + } + + loader = pool.loaderFor(mn); + assert loader != null; + + } else { + + // find the layer contains the module that is read + Layer layer = parentLayer; + while (layer != null) { + if (layer.configuration() == other.configuration()) { + break; + } + layer = layer.parent().orElse(null); + } + assert layer != null; + + // find the class loader for the module in the layer + // For now we use the platform loader for modules defined to the + // boot loader + assert layer.findModule(mn).isPresent(); + loader = layer.findLoader(mn); + if (loader == null) + loader = ClassLoaders.platformClassLoader(); + } + + // find the packages that are exported to the target module + String target = resolvedModule.name(); + ModuleDescriptor descriptor = other.reference().descriptor(); + for (ModuleDescriptor.Exports e : descriptor.exports()) { + boolean delegate; + if (e.isQualified()) { + // qualified export in same configuration + delegate = (other.configuration() == cf) + && e.targets().contains(target); + } else { + // unqualified + delegate = true; + } + + if (delegate) { + String pn = e.source(); + ClassLoader l = remotePackageToLoader.putIfAbsent(pn, loader); + if (l != null && l != loader) { + throw new IllegalArgumentException("Package " + + pn + " cannot be imported from multiple loaders"); + } + + } + } + } + + } + + return this; + } + + /** + * Returns the loader pool that this loader is in or {@code null} if this + * loader is not in a loader pool. + */ + public LoaderPool pool() { + return pool; + } + + + // -- resources -- + + + /** + * Returns a URL to a resource of the given name in a module defined to + * this class loader. + */ + @Override + protected URL findResource(String mn, String name) throws IOException { + ModuleReference mref = nameToModule.get(mn); + if (mref == null) + return null; // not defined to this class loader + + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction() { + @Override + public URL run() throws IOException { + Optional ouri = moduleReaderFor(mref).find(name); + if (ouri.isPresent()) { + try { + return ouri.get().toURL(); + } catch (MalformedURLException e) { } + } + return null; + } + }, acc); + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); + } + } + + + // -- finding/loading classes + + /** + * Finds the class with the specified binary name. + */ + @Override + protected Class findClass(String cn) throws ClassNotFoundException { + Class c = null; + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null) + c = findClassInModuleOrNull(loadedModule, cn); + if (c == null) + throw new ClassNotFoundException(cn); + return c; + } + + /** + * Finds the class with the specified binary name in a given module. + * This method returns {@code null} if the class cannot be found. + */ + @Override + protected Class findClass(String mn, String cn) { + Class c = null; + LoadedModule loadedModule = findLoadedModule(cn); + if (loadedModule != null && loadedModule.name().equals(mn)) + c = findClassInModuleOrNull(loadedModule, cn); + return c; + } + + /** + * Loads the class with the specified binary name. + */ + @Override + protected Class loadClass(String cn, boolean resolve) + throws ClassNotFoundException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + String pn = packageName(cn); + if (!pn.isEmpty()) { + sm.checkPackageAccess(pn); + } + } + + synchronized (getClassLoadingLock(cn)) { + // check if already loaded + Class c = findLoadedClass(cn); + + if (c == null) { + + LoadedModule loadedModule = findLoadedModule(cn); + + if (loadedModule != null) { + + // class is in module defined to this class loader + c = findClassInModuleOrNull(loadedModule, cn); + + } else { + + // type in another module or visible via the parent loader + String pn = packageName(cn); + ClassLoader loader = remotePackageToLoader.get(pn); + if (loader == null) { + // type not in a module read by any of the modules + // defined to this loader, so delegate to parent + // class loader + loader = parent; + } + if (loader == null) { + c = BootLoader.loadClassOrNull(cn); + } else { + c = loader.loadClass(cn); + } + + } + } + + if (c == null) + throw new ClassNotFoundException(cn); + + if (resolve) + resolveClass(c); + + return c; + } + } + + + /** + * Finds the class with the specified binary name if in a module + * defined to this ClassLoader. + * + * @return the resulting Class or {@code null} if not found + */ + private Class findClassInModuleOrNull(LoadedModule loadedModule, String cn) { + PrivilegedAction> pa = () -> defineClass(cn, loadedModule); + return AccessController.doPrivileged(pa, acc); + } + + /** + * Defines the given binary class name to the VM, loading the class + * bytes from the given module. + * + * @return the resulting Class or {@code null} if an I/O error occurs + */ + private Class defineClass(String cn, LoadedModule loadedModule) { + ModuleReader reader = moduleReaderFor(loadedModule.mref()); + + try { + // read class file + String rn = cn.replace('.', '/').concat(".class"); + ByteBuffer bb = reader.read(rn).orElse(null); + if (bb == null) { + // class not found + return null; + } + + try { + return defineClass(cn, bb, loadedModule.codeSource()); + } finally { + reader.release(bb); + } + + } catch (IOException ioe) { + // TBD on how I/O errors should be propagated + return null; + } + } + + + // -- permissions + + /** + * Returns the permissions for the given CodeSource. + */ + @Override + protected PermissionCollection getPermissions(CodeSource cs) { + PermissionCollection perms = super.getPermissions(cs); + + URL url = cs.getLocation(); + if (url == null) + return perms; + + // add the permission to access the resource + try { + Permission p = url.openConnection().getPermission(); + if (p != null) { + // for directories then need recursive access + if (p instanceof FilePermission) { + String path = p.getName(); + if (path.endsWith(File.separator)) { + path += "-"; + p = new FilePermission(path, "read"); + } + } + perms.add(p); + } + } catch (IOException ioe) { } + + return perms; + } + + + // -- miscellaneous supporting methods + + /** + * Find the candidate module for the given class name. + * Returns {@code null} if none of the modules defined to this + * class loader contain the API package for the class. + */ + private LoadedModule findLoadedModule(String cn) { + String pn = packageName(cn); + return pn.isEmpty() ? null : localPackageToModule.get(pn); + } + + /** + * Returns the package name for the given class name + */ + private String packageName(String cn) { + int pos = cn.lastIndexOf('.'); + return (pos < 0) ? "" : cn.substring(0, pos); + } + + + /** + * Returns the ModuleReader for the given module. + */ + private ModuleReader moduleReaderFor(ModuleReference mref) { + return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref)); + } + + /** + * Creates a ModuleReader for the given module. + */ + private ModuleReader createModuleReader(ModuleReference mref) { + try { + return mref.open(); + } catch (IOException e) { + // Return a null module reader to avoid a future class load + // attempting to open the module again. + return new NullModuleReader(); + } + } + + /** + * A ModuleReader that doesn't read any resources. + */ + private static class NullModuleReader implements ModuleReader { + @Override + public Optional find(String name) { + return Optional.empty(); + } + @Override + public void close() { + throw new InternalError("Should not get here"); + } + } + +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java new file mode 100644 index 00000000000..a9bbc26a54b --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/loader/LoaderPool.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.loader; + +import java.lang.module.Configuration; +import java.lang.module.ModuleReference; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +/** + * A pool of class loaders. + * + * @see Layer#defineModulesWithManyLoaders + */ + +public final class LoaderPool { + + // maps module names to class loaders + private final Map loaders; + + + /** + * Creates a pool of class loaders. Each module in the given configuration + * will be loaded its own class loader in the pool. The class loader is + * created with the given parent class loader as its parent. + */ + public LoaderPool(Configuration cf, + Layer parentLayer, + ClassLoader parentLoader) + { + Map loaders = new HashMap<>(); + for (ResolvedModule resolvedModule : cf.modules()) { + Loader loader = new Loader(resolvedModule, this, parentLoader); + String mn = resolvedModule.name(); + loaders.put(mn, loader); + } + this.loaders = loaders; + + // complete the initialization + loaders.values().forEach(l -> l.initRemotePackageMap(cf, parentLayer)); + } + + + /** + * Returns the class loader for the named module + */ + public Loader loaderFor(String name) { + Loader loader = loaders.get(name); + assert loader != null; + return loader; + } + + /** + * Returns a stream of the loaders in this pool. + */ + public Stream loaders() { + return loaders.values().stream(); + } + +} + diff --git a/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java b/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java index 0a560dc11e5..88cd1feaf8f 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java +++ b/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java @@ -106,10 +106,28 @@ public class FormattedFloatingDecimal{ return decExponentRounded - 1; } + /** + * Returns the mantissa as a {@code char[]}. Note that the returned value + * is a reference to the internal {@code char[]} containing the mantissa, + * therefore code invoking this method should not pass the return value to + * external code but should in that case make a copy. + * + * @return a reference to the internal {@code char[]} representing the + * mantissa. + */ public char[] getMantissa(){ return mantissa; } + /** + * Returns the exponent as a {@code char[]}. Note that the returned value + * is a reference to the internal {@code char[]} containing the exponent, + * therefore code invoking this method should not pass the return value to + * external code but should in that case make a copy. + * + * @return a reference to the internal {@code char[]} representing the + * exponent. + */ public char[] getExponent(){ return exponent; } 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 75ba73da5b2..158d3c49abc 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 @@ -25,11 +25,17 @@ package jdk.internal.misc; +import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Executable; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.net.URL; import java.security.AccessControlContext; import java.util.Map; +import java.util.stream.Stream; +import jdk.internal.module.ServicesCatalog; import sun.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; import sun.nio.ch.Interruptible; @@ -123,6 +129,43 @@ public interface JavaLangAccess { */ void invokeFinalize(Object o) throws Throwable; + /** + * Returns the boot Layer + */ + Layer getBootLayer(); + + /** + * Returns the ServicesCatalog for the given class loader. + */ + ServicesCatalog getServicesCatalog(ClassLoader cl); + + /** + * Returns the ServicesCatalog for the given class loader, creating it + * if doesn't already exist. + */ + ServicesCatalog createOrGetServicesCatalog(ClassLoader cl); + + /** + * Returns a class loaded by the bootstrap class loader. + */ + Class findBootstrapClassOrNull(ClassLoader cl, String name); + + /** + * Returns a URL to a resource with the given name in a module that is + * defined to the given class loader. + */ + URL findResource(ClassLoader cl, String moduleName, String name) throws IOException; + + /** + * Returns the Packages for the given class loader. + */ + Stream packages(ClassLoader cl); + + /** + * Define a Package of the given name and module by the given class loader. + */ + Package definePackage(ClassLoader cl, String name, Module module); + /** * Invokes Long.fastUUID */ 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 new file mode 100644 index 00000000000..e0c7e66cf51 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Version; +import java.util.Map; +import java.util.Set; + +/** + * Provides access to non-public methods in java.lang.module. + */ + +public interface JavaLangModuleAccess { + + /** + * Returns {@code ModuleDescriptor.Requires} of the given modifier + * and module name. + */ + Requires newRequires(Set ms, String mn); + + /** + * Returns an unqualified {@code ModuleDescriptor.Exports} + * of the given package name. + */ + Exports newExports(String source); + + /** + * Returns a qualified {@code ModuleDescriptor.Exports} + * of the given package name and targets. + */ + Exports newExports(String source, Set targets); + + /** + * Returns a {@code ModuleDescriptor.Provides} + * of the given service name and providers. + */ + Provides newProvides(String service, Set 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, + boolean automatic, + boolean synthetic, + Set requires, + Set uses, + Set exports, + Map provides, + Version version, + String mainClass, + String osName, + String osArch, + String osVersion, + Set conceals, + Set packages); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java new file mode 100644 index 00000000000..91aa495528c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Module; +import java.net.URI; + +/** + * Provides access to non-public methods in java.lang.reflect.Module + */ + +public interface JavaLangReflectModuleAccess { + + /** + * Defines the unnamed module for the given class loader. + */ + Module defineUnnamedModule(ClassLoader loader); + + /** + * Defines a new module to the Java virtual machine. The module + * is defined to the given class loader. + * + * The URI is for information purposes only, it can be {@code null}. + */ + Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri); + + /** + * Updates the readability so that module m1 reads m2. The new read edge + * does not result in a strong reference to m2 (m2 can be GC'ed). + * + * This method is the same as m1.addReads(m2) but without a permission check. + */ + void addReads(Module m1, Module m2); + + /** + * Updates module m1 to export a package to module m2. The export does + * not result in a strong reference to m2 (m2 can be GC'ed). + */ + void addExports(Module m1, String pkg, Module m2); + + /** + * Updates a module m to export a package to all modules. + */ + void addExportsToAll(Module m, String pkg); + + /** + * Updates a module m to export a package to all unnamed modules. + */ + void addExportsToAllUnnamed(Module m, String pkg); + + /** + * Add a package to the given module. + */ + void addPackage(Module m, String pkg); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java new file mode 100644 index 00000000000..ab76a58e663 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaUtilResourceBundleAccess.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.misc; + +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * Provides access to non-public methods in java.util.ResourceBundle. + */ +public interface JavaUtilResourceBundleAccess { + /** + * Sets the bundle's parent to the given parent. + */ + void setParent(ResourceBundle bundle, ResourceBundle parent); + + /** + * Returns the parent of the given bundle or null if the bundle has no parent. + */ + ResourceBundle getParent(ResourceBundle bundle); + + /** + * Sets the bundle's locale to the given locale. + */ + void setLocale(ResourceBundle bundle, Locale locale); + + /** + * Sets the bundle's base name to the given name. + */ + void setName(ResourceBundle bundle, String name); +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java index 307989eed96..3246bde5be1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java @@ -25,6 +25,7 @@ package jdk.internal.misc; +import java.lang.module.ModuleDescriptor; import java.util.jar.JarFile; import java.io.Console; import java.io.FileDescriptor; @@ -45,6 +46,8 @@ public class SharedSecrets { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; + private static JavaLangModuleAccess javaLangModuleAccess; + private static JavaLangReflectModuleAccess javaLangReflectModuleAccess; private static JavaLangInvokeAccess javaLangInvokeAccess; private static JavaLangRefAccess javaLangRefAccess; private static JavaIOAccess javaIOAccess; @@ -56,6 +59,7 @@ public class SharedSecrets { private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess; private static JavaSecurityAccess javaSecurityAccess; private static JavaUtilZipFileAccess javaUtilZipFileAccess; + private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess; private static JavaAWTAccess javaAWTAccess; private static JavaAWTFontAccess javaAWTFontAccess; private static JavaBeansAccess javaBeansAccess; @@ -95,6 +99,27 @@ public class SharedSecrets { return javaLangInvokeAccess; } + public static void setJavaLangModuleAccess(JavaLangModuleAccess jlrma) { + javaLangModuleAccess = jlrma; + } + + public static JavaLangModuleAccess getJavaLangModuleAccess() { + if (javaLangModuleAccess == null) { + unsafe.ensureClassInitialized(ModuleDescriptor.class); + } + return javaLangModuleAccess; + } + + public static void setJavaLangReflectModuleAccess(JavaLangReflectModuleAccess jlrma) { + javaLangReflectModuleAccess = jlrma; + } + + public static JavaLangReflectModuleAccess getJavaLangReflectModuleAccess() { + if (javaLangReflectModuleAccess == null) + unsafe.ensureClassInitialized(java.lang.reflect.Module.class); + return javaLangReflectModuleAccess; + } + public static void setJavaLangRefAccess(JavaLangRefAccess jlra) { javaLangRefAccess = jlra; } @@ -229,4 +254,12 @@ public class SharedSecrets { public static void setJavaBeansAccess(JavaBeansAccess access) { javaBeansAccess = access; } + + public static JavaUtilResourceBundleAccess getJavaUtilResourceBundleAccess() { + return javaUtilResourceBundleAccess; + } + + public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) { + javaUtilResourceBundleAccess = access; + } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java b/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java index 04af46a49f9..e49d17b0830 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/VM.java @@ -144,36 +144,67 @@ public class VM { // public native static void writeJavaProfilerReport(); - private static volatile boolean booted = false; + // the init level when the VM is fully initialized + private static final int JAVA_LANG_SYSTEM_INITED = 1; + private static final int MODULE_SYSTEM_INITED = 2; + private static final int SYSTEM_LOADER_INITIALIZING = 3; + private static final int SYSTEM_BOOTED = 4; + + // 0, 1, 2, ... + private static volatile int initLevel; private static final Object lock = new Object(); - // Invoked by System.initializeSystemClass just before returning. - // Subsystems that are invoked during initialization can check this - // property in order to avoid doing things that should wait until the - // application class loader has been set up. - // - public static void booted() { + /** + * Sets the init level. + * + * @see java.lang.System#initPhase1 + * @see java.lang.System#initPhase2 + * @see java.lang.System#initPhase3 + */ + public static void initLevel(int value) { synchronized (lock) { - booted = true; + if (value <= initLevel || value > SYSTEM_BOOTED) + throw new InternalError(); + initLevel = value; lock.notifyAll(); } } - public static boolean isBooted() { - return booted; + /** + * Returns the current init level. + */ + public static int initLevel() { + return initLevel; } - // Waits until VM completes initialization - // - // This method is invoked by the Finalizer thread - public static void awaitBooted() throws InterruptedException { + /** + * Waits for the init level to get the given value. + * + * @see java.lang.ref.Finalizer + */ + public static void awaitInitLevel(int value) throws InterruptedException { synchronized (lock) { - while (!booted) { + while (initLevel < value) { lock.wait(); } } } + /** + * Returns {@code true} if the module system has been initialized. + * @see java.lang.System#initPhase2 + */ + public static boolean isModuleSystemInited() { + return VM.initLevel() >= MODULE_SYSTEM_INITED; + } + + /** + * Returns {@code true} if the VM is fully initialized. + */ + public static boolean isBooted() { + return initLevel >= SYSTEM_BOOTED; + } + // A user-settable upper limit on the maximum amount of allocatable direct // buffer memory. This value may be changed during VM initialization if // "java" is launched with "-XX:MaxDirectMemorySize=". @@ -240,8 +271,8 @@ public class VM { // // This method can only be invoked during system initialization. public static void saveAndRemoveProperties(Properties props) { - if (booted) - throw new IllegalStateException("System initialization has completed"); + if (initLevel() != 0) + throw new IllegalStateException("Wrong init level"); savedProps.putAll(props); @@ -273,13 +304,16 @@ public class VM { // used by sun.launcher.LauncherHelper props.remove("sun.java.launcher.diag"); + + // used by jdk.internal.loader.ClassLoaders + props.remove("jdk.boot.class.path.append"); } - // Initialize any miscellenous operating system settings that need to be + // Initialize any miscellaneous operating system settings that need to be // set for the class libraries. // public static void initializeOSEnvironment() { - if (!booted) { + if (initLevel() == 0) { OSEnvironment.initialize(); } } 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 new file mode 100644 index 00000000000..8d51a5c6419 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Version; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import jdk.internal.misc.JavaLangModuleAccess; +import jdk.internal.misc.SharedSecrets; + +/** + * This builder is optimized for reconstituting ModuleDescriptor + * for installed modules. The validation should be done at jlink time. + * + * 1. skip name validation + * 2. ignores dependency hashes. + * 3. ModuleDescriptor skips the defensive copy and directly uses the + * sets/maps created in this Builder. + * + * SystemModules should contain modules for the boot layer. + */ +final class Builder { + private static final JavaLangModuleAccess jlma = + SharedSecrets.getJavaLangModuleAccess(); + + private static final Set MANDATED = + Collections.singleton(Requires.Modifier.MANDATED); + private static final Set PUBLIC = + Collections.singleton(Requires.Modifier.PUBLIC); + + // Static cache of the most recently seen Version to cheaply deduplicate + // most Version objects. JDK modules have the same version. + static Version cachedVersion; + + final String name; + final Set requires; + final Set exports; + final Map provides; + final Set conceals; + final int numPackages; + Set uses; + Version version; + String mainClass; + String osName; + String osArch; + String osVersion; + + Builder(String name, int reqs, int exports, + int provides, int conceals, int packages) { + this.name = name; + this.requires = reqs > 0 ? new HashSet<>(reqs) : Collections.emptySet(); + this.exports = exports > 0 ? new HashSet<>(exports) : Collections.emptySet(); + this.provides = provides > 0 ? new HashMap<>(provides) : Collections.emptyMap(); + this.conceals = conceals > 0 ? new HashSet<>(conceals) : Collections.emptySet(); + this.uses = Collections.emptySet(); + this.numPackages = packages; + } + + /** + * Adds a module dependence with the given (and possibly empty) set + * of modifiers. + */ + public Builder requires(Set mods, String mn) { + requires.add(jlma.newRequires(Collections.unmodifiableSet(mods), mn)); + return this; + } + + /** + * Adds a module dependence with an empty set of modifiers. + */ + public Builder requires(String mn) { + requires.add(jlma.newRequires(Collections.emptySet(), mn)); + return this; + } + + /** + * Adds a module dependence with the given modifier. + */ + public Builder requires(Requires.Modifier mod, String mn) { + if (mod == Requires.Modifier.MANDATED) { + requires.add(jlma.newRequires(MANDATED, mn)); + } else if (mod == Requires.Modifier.PUBLIC) { + requires.add(jlma.newRequires(PUBLIC, mn)); + } else { + requires.add(jlma.newRequires(Collections.singleton(mod), mn)); + } + return this; + } + + /** + * Sets the set of service dependences. + */ + public Builder uses(Set uses) { + this.uses = uses; + return this; + } + + /** + * Adds an export to a set of target modules. + */ + public Builder exports(String pn, Set targets) { + exports.add(jlma.newExports(pn, targets)); + return this; + } + + /** + * Adds an export to a target module. + */ + public Builder exports(String pn, String target) { + return exports(pn, Collections.singleton(target)); + } + + /** + * Adds an export. + */ + public Builder exports(String pn) { + exports.add(jlma.newExports(pn)); + return this; + } + + /** + * Provides service {@code st} with implementations {@code pcs}. + */ + public Builder provides(String st, Set pcs) { + if (provides.containsKey(st)) + throw new IllegalStateException("Providers of service " + + st + " already declared"); + provides.put(st, jlma.newProvides(st, pcs)); + return this; + } + + /** + * Provides service {@code st} with implementation {@code pc}. + */ + public Builder provides(String st, String pc) { + return provides(st, Collections.singleton(pc)); + } + + /** + * Adds a set of (possible empty) concealed packages. + */ + public Builder conceals(Set packages) { + conceals.addAll(packages); + return this; + } + + /** + * Adds a concealed package. + */ + public Builder conceals(String pn) { + conceals.add(pn); + return this; + } + + /** + * Sets the module version. + * + * @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; + } else { + cachedVersion = version = Version.parse(v); + } + return this; + } + + /** + * 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 the set of packages that is the union of the exported and + * concealed packages. + */ + private Set computePackages(Set exports, Set conceals) { + if (exports.isEmpty()) + return conceals; + + Set pkgs = new HashSet<>(numPackages); + pkgs.addAll(conceals); + for (Exports e : exports) { + pkgs.add(e.source()); + } + return pkgs; + } + + /** + * Builds a {@code ModuleDescriptor} from the components. + */ + public ModuleDescriptor build() { + assert name != null; + + return jlma.newModuleDescriptor(name, + false, // automatic + false, // assume not synthetic for now + requires, + uses, + exports, + provides, + version, + mainClass, + osName, + osArch, + osVersion, + conceals, + computePackages(exports, conceals)); + } +} 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 new file mode 100644 index 00000000000..1738bfeba8e --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Checks.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + + +public final class Checks { + + private Checks() { } + + private static void fail(String what, String id, int i) { + throw new IllegalArgumentException(id + + ": Invalid " + what + ": " + + " Illegal character" + + " at index " + i); + } + + /** + * Returns {@code true} if the given identifier is a legal Java identifier. + */ + public static boolean isJavaIdentifier(String id) { + int n = id.length(); + if (n == 0) + return false; + if (!Character.isJavaIdentifierStart(id.codePointAt(0))) + return false; + int cp = id.codePointAt(0); + int i = Character.charCount(cp); + for (; i < n; i += Character.charCount(cp)) { + cp = id.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.') + return false; + } + if (cp == '.') + return false; + + return true; + } + + /** + * Checks if a given identifier is a legal Java identifier. + */ + public static String requireJavaIdentifier(String what, String id) { + if (id == null) + throw new IllegalArgumentException("Null " + what); + int n = id.length(); + if (n == 0) + throw new IllegalArgumentException("Empty " + what); + if (!Character.isJavaIdentifierStart(id.codePointAt(0))) + fail(what, id, 0); + int cp = id.codePointAt(0); + int i = Character.charCount(cp); + int last = 0; + for (; i < n; i += Character.charCount(cp)) { + cp = id.codePointAt(i); + if (!Character.isJavaIdentifierPart(cp) && id.charAt(i) != '.') + fail(what, id, i); + last = i; + } + if (cp == '.') + fail(what, id, last); + + return id; + } + + public static String requireModuleName(String id) { + return requireJavaIdentifier("module name", id); + } + + public static String requirePackageName(String id) { + return requireJavaIdentifier("package name", id); + } + + public static String requireServiceTypeName(String id) { + return requireJavaIdentifier("service type name", id); + } + + public static String requireServiceProviderName(String id) { + return requireJavaIdentifier("service provider name", id); + } + +} 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 new file mode 100644 index 00000000000..66b48915159 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java @@ -0,0 +1,647 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.module.ModuleDescriptor.Version; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ByteVector; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.module.Hasher.DependencyHashes; +import static jdk.internal.module.ClassFileConstants.*; + + +/** + * Provides ASM implementations of {@code Attribute} to read and write the + * class file attributes in a module-info class file. + */ + +class ClassFileAttributes { + + private ClassFileAttributes() { } + + /** + * Module_attribute { + * // See lang-vm.html for details. + * } + */ + static class ModuleAttribute extends Attribute { + + private ModuleDescriptor descriptor; + + ModuleAttribute(ModuleDescriptor descriptor) { + super(MODULE); + this.descriptor = descriptor; + } + + ModuleAttribute() { + super(MODULE); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + ModuleDescriptor.Builder builder + = new ModuleDescriptor.Builder("xyzzy"); // Name never used + ModuleAttribute attr = new ModuleAttribute(); + + // requires_count and requires[requires_count] + int requires_count = cr.readUnsignedShort(off); + off += 2; + for (int i=0; i mods; + if (flags == 0) { + mods = Collections.emptySet(); + } else { + mods = new HashSet<>(); + if ((flags & ACC_PUBLIC) != 0) + mods.add(Modifier.PUBLIC); + if ((flags & ACC_SYNTHETIC) != 0) + mods.add(Modifier.SYNTHETIC); + if ((flags & ACC_MANDATED) != 0) + mods.add(Modifier.MANDATED); + } + builder.requires(mods, dn); + off += 4; + } + + // exports_count and exports[exports_count] + int exports_count = cr.readUnsignedShort(off); + off += 2; + if (exports_count > 0) { + for (int i=0; i 0) { + Set targets = new HashSet<>(); + for (int j=0; j 0) { + for (int i=0; i 0) { + Map> provides = new HashMap<>(); + for (int i=0; i new HashSet<>()).add(cn); + off += 4; + } + provides.entrySet().forEach(e -> builder.provides(e.getKey(), + e.getValue())); + } + + attr.descriptor = builder.build(); + return attr; + } + + @Override + protected ByteVector write(ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + assert descriptor != null; + ByteVector attr = new ByteVector(); + + // requires_count + attr.putShort(descriptor.requires().size()); + + // requires[requires_count] + for (Requires md : descriptor.requires()) { + String dn = md.name(); + int flags = 0; + if (md.modifiers().contains(Modifier.PUBLIC)) + flags |= ACC_PUBLIC; + if (md.modifiers().contains(Modifier.SYNTHETIC)) + flags |= ACC_SYNTHETIC; + if (md.modifiers().contains(Modifier.MANDATED)) + flags |= ACC_MANDATED; + int index = cw.newUTF8(dn); + attr.putShort(index); + attr.putShort(flags); + } + + // exports_count and exports[exports_count]; + if (descriptor.exports().isEmpty()) { + attr.putShort(0); + } else { + attr.putShort(descriptor.exports().size()); + for (Exports e : descriptor.exports()) { + String pkg = e.source().replace('.', '/'); + attr.putShort(cw.newUTF8(pkg)); + if (e.isQualified()) { + Set ts = e.targets(); + attr.putShort(ts.size()); + ts.forEach(t -> attr.putShort(cw.newUTF8(t))); + } else { + attr.putShort(0); + } + } + } + + // uses_count and uses_index[uses_count] + if (descriptor.uses().isEmpty()) { + attr.putShort(0); + } else { + attr.putShort(descriptor.uses().size()); + for (String s : descriptor.uses()) { + String service = s.replace('.', '/'); + int index = cw.newClass(service); + attr.putShort(index); + } + } + + // provides_count and provides[provides_count] + if (descriptor.provides().isEmpty()) { + attr.putShort(0); + } else { + int count = descriptor.provides().values() + .stream().mapToInt(ps -> ps.providers().size()).sum(); + attr.putShort(count); + for (Provides p : descriptor.provides().values()) { + String service = p.service().replace('.', '/'); + int index = cw.newClass(service); + for (String provider : p.providers()) { + attr.putShort(index); + attr.putShort(cw.newClass(provider.replace('.', '/'))); + } + } + } + + return attr; + } + } + + /** + * Synthetic attribute. + */ + static class SyntheticAttribute extends Attribute { + SyntheticAttribute() { + super(SYNTHETIC); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + return new SyntheticAttribute(); + } + + @Override + protected ByteVector write(ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector attr = new ByteVector(); + return attr; + } + } + + /** + * ConcealedPackages attribute. + * + *

     {@code
    +     *
    +     * ConcealedPackages_attribute {
    +     *   // index to CONSTANT_utf8_info structure in constant pool representing
    +     *   // the string "ConcealedPackages"
    +     *   u2 attribute_name_index;
    +     *   u4 attribute_length;
    +     *
    +     *   // the number of entries in the packages table
    +     *   u2 package_count;
    +     *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
    +     *     u2 package_index
    +     *   } package[package_count];
    +     *
    +     * }
    + */ + static class ConcealedPackagesAttribute extends Attribute { + private final Set packages; + + ConcealedPackagesAttribute(Set packages) { + super(CONCEALED_PACKAGES); + this.packages = packages; + } + + ConcealedPackagesAttribute() { + this(null); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + // package count + int package_count = cr.readUnsignedShort(off); + off += 2; + + // packages + Set packages = new HashSet<>(); + for (int i=0; i p.replace('.', '/')) + .forEach(p -> attr.putShort(cw.newUTF8(p))); + + return attr; + } + + } + + /** + * Version attribute. + * + *
     {@code
    +     *
    +     * Version_attribute {
    +     *   // index to CONSTANT_utf8_info structure in constant pool representing
    +     *   // the string "Version"
    +     *   u2 attribute_name_index;
    +     *   u4 attribute_length;
    +     *
    +     *   // index to CONSTANT_CONSTANT_utf8_info structure with the version
    +     *   u2 version_index;
    +     * }
    +     *
    +     * } 
    + */ + static class VersionAttribute extends Attribute { + private final Version version; + + VersionAttribute(Version version) { + super(VERSION); + this.version = version; + } + + VersionAttribute() { + this(null); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + String value = cr.readUTF8(off, buf); + return new VersionAttribute(Version.parse(value)); + } + + @Override + protected ByteVector write(ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector attr = new ByteVector(); + int index = cw.newUTF8(version.toString()); + attr.putShort(index); + return attr; + } + } + + /** + * MainClass attribute. + * + *
     {@code
    +     *
    +     * MainClass_attribute {
    +     *   // index to CONSTANT_utf8_info structure in constant pool representing
    +     *   // the string "MainClass"
    +     *   u2 attribute_name_index;
    +     *   u4 attribute_length;
    +     *
    +     *   // index to CONSTANT_Class_info structure with the main class name
    +     *   u2 main_class_index;
    +     * }
    +     *
    +     * } 
    + */ + static class MainClassAttribute extends Attribute { + private final String mainClass; + + MainClassAttribute(String mainClass) { + super(MAIN_CLASS); + this.mainClass = mainClass; + } + + MainClassAttribute() { + this(null); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + String value = cr.readClass(off, buf); + return new MainClassAttribute(value); + } + + @Override + protected ByteVector write(ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector attr = new ByteVector(); + int index = cw.newClass(mainClass); + attr.putShort(index); + return attr; + } + } + + /** + * TargetPlatform attribute. + * + *
     {@code
    +     *
    +     * TargetPlatform_attribute {
    +     *   // index to CONSTANT_utf8_info structure in constant pool representing
    +     *   // the string "TargetPlatform"
    +     *   u2 attribute_name_index;
    +     *   u4 attribute_length;
    +     *
    +     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS name
    +     *   u2 os_name_index;
    +     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS arch
    +     *   u2 os_arch_index
    +     *   // index to CONSTANT_CONSTANT_utf8_info structure with the OS version
    +     *   u2 os_version_index;
    +     * }
    +     *
    +     * } 
    + */ + static class TargetPlatformAttribute extends Attribute { + private final String osName; + private final String osArch; + private final String osVersion; + + TargetPlatformAttribute(String osName, String osArch, String osVersion) { + super(TARGET_PLATFORM); + this.osName = osName; + this.osArch = osArch; + this.osVersion = osVersion; + } + + TargetPlatformAttribute() { + this(null, null, null); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + + String osName = null; + String osArch = null; + String osVersion = null; + + int name_index = cr.readUnsignedShort(off); + if (name_index != 0) + osName = cr.readUTF8(off, buf); + off += 2; + + int arch_index = cr.readUnsignedShort(off); + if (arch_index != 0) + osArch = cr.readUTF8(off, buf); + off += 2; + + int version_index = cr.readUnsignedShort(off); + if (version_index != 0) + osVersion = cr.readUTF8(off, buf); + off += 2; + + return new TargetPlatformAttribute(osName, osArch, osVersion); + } + + @Override + protected ByteVector write(ClassWriter cw, + byte[] code, + int len, + int maxStack, + int maxLocals) + { + ByteVector attr = new ByteVector(); + + int name_index = 0; + if (osName != null && osName.length() > 0) + name_index = cw.newUTF8(osName); + attr.putShort(name_index); + + int arch_index = 0; + if (osArch != null && osArch.length() > 0) + arch_index = cw.newUTF8(osArch); + attr.putShort(arch_index); + + int version_index = 0; + if (osVersion != null && osVersion.length() > 0) + version_index = cw.newUTF8(osVersion); + attr.putShort(version_index); + + return attr; + } + } + + /** + * Hashes attribute. + * + *
     {@code
    +     *
    +     * Hashes_attribute {
    +     *   // index to CONSTANT_utf8_info structure in constant pool representing
    +     *   // the string "Hashes"
    +     *   u2 attribute_name_index;
    +     *   u4 attribute_length;
    +     *
    +     *   // index to CONSTANT_CONSTANT_utf8_info structure with algorithm name
    +     *   u2 algorithm_index;
    +     *
    +     *   // the number of entries in the hashes table
    +     *   u2 hash_count;
    +     *   {   u2 requires_index
    +     *       u2 hash_index;
    +     *   } hashes[hash_count];
    +     *
    +     * } 
    + * + * @apiNote For now the hash is stored in base64 as a UTF-8 string, an + * alternative is to store it as an array of u1. + */ + static class HashesAttribute extends Attribute { + private final DependencyHashes hashes; + + HashesAttribute(DependencyHashes hashes) { + super(HASHES); + this.hashes = hashes; + } + + HashesAttribute() { + this(null); + } + + @Override + protected Attribute read(ClassReader cr, + int off, + int len, + char[] buf, + int codeOff, + Label[] labels) + { + String algorithm = cr.readUTF8(off, buf); + off += 2; + + int hash_count = cr.readUnsignedShort(off); + off += 2; + + Map map = new HashMap<>(); + for (int i=0; i names = hashes.names(); + attr.putShort(names.size()); + + for (String dn : names) { + String hash = hashes.hashFor(dn); + assert hash != null; + attr.putShort(cw.newUTF8(dn)); + attr.putShort(cw.newUTF8(hash)); + } + + return attr; + } + } + +} 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 new file mode 100644 index 00000000000..6a61f090e30 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + + +// Constants in module-info.class files + +public class ClassFileConstants { + + private ClassFileConstants() { } + + // Attribute names + public static final String MODULE = "Module"; + public static final String SOURCE_FILE = "SourceFile"; + public static final String SYNTHETIC = "Synthetic"; + public static final String SDE = "SourceDebugExtension"; + + public static final String CONCEALED_PACKAGES = "ConcealedPackages"; + public static final String VERSION = "Version"; + public static final String MAIN_CLASS = "MainClass"; + public static final String TARGET_PLATFORM = "TargetPlatform"; + public static final String HASHES = "Hashes"; + + // access and requires flags + public static final int ACC_MODULE = 0x8000; + public static final int ACC_PUBLIC = 0x0020; + 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/ConfigurableModuleFinder.java b/jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java new file mode 100644 index 00000000000..914f870044e --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ConfigurableModuleFinder.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.lang.module.ModuleFinder; + +/** + * A ModuleFinder that may be configured to work at either run-time + * or link-time. + */ + +public interface ConfigurableModuleFinder extends ModuleFinder { + + public static enum Phase { + RUN_TIME, + LINK_TIME + } + + /** + * Configures this finder to work in the given phase. + */ + void configurePhase(Phase phase); + +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/Hasher.java b/jdk/src/java.base/share/classes/jdk/internal/module/Hasher.java new file mode 100644 index 00000000000..947900f63dd --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Hasher.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Supporting class for computing, encoding and decoding hashes (message + * digests). + */ + +public class Hasher { + private Hasher() { } + + /** + * A supplier of an encoded message digest. + */ + public static interface HashSupplier { + String generate(String algorithm); + } + + /** + * Encapsulates the result of hashing the contents of a number of module + * artifacts. + */ + public static class DependencyHashes { + private final String algorithm; + private final Map nameToHash; + + public DependencyHashes(String algorithm, Map nameToHash) { + this.algorithm = algorithm; + this.nameToHash = nameToHash; + } + + /** + * Returns the algorithm used to hash the dependences ("SHA-256" or + * "MD5" for example). + */ + public String algorithm() { + return algorithm; + } + + /** + * Returns the set of module names for which hashes are recorded. + */ + public Set names() { + return nameToHash.keySet(); + } + + /** + * Retruns the hash string for the given module name, {@code null} + * if there is no hash recorded for the module. + */ + public String hashFor(String dn) { + return nameToHash.get(dn); + } + } + + + /** + * Computes the hash for the given file with the given message digest + * algorithm. Returns the results a base64-encoded String. + * + * @throws UncheckedIOException if an I/O error occurs + * @throws RuntimeException if the algorithm is not available + */ + public static String generate(Path file, String algorithm) { + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + + // Ideally we would just mmap the file but this consumes too much + // memory when jlink is running concurrently on very large jmods + try (FileChannel fc = FileChannel.open(file)) { + ByteBuffer bb = ByteBuffer.allocate(32*1024); + int nread; + while ((nread = fc.read(bb)) > 0) { + bb.flip(); + md.update(bb); + assert bb.remaining() == 0; + bb.clear(); + } + } + + byte[] bytes = md.digest(); + return Base64.getEncoder().encodeToString(bytes); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + /** + * Computes the hash for every entry in the given map, returning a + * {@code DependencyHashes} to encapsulate the result. The map key is + * the entry name, typically the module name. The map value is the file + * path to the entry (module artifact). + * + * @return DependencyHashes encapsulate the hashes + */ + public static DependencyHashes generate(Map map, String algorithm) { + Map nameToHash = new HashMap<>(); + for (Map.Entry entry: map.entrySet()) { + String name = entry.getKey(); + Path path = entry.getValue(); + nameToHash.put(name, generate(path, algorithm)); + } + return new DependencyHashes(algorithm, nameToHash); + } +} 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 new file mode 100644 index 00000000000..5b6c3c4372c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.File; +import java.lang.module.Configuration; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleFinder; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.BuiltinClassLoader; +import jdk.internal.perf.PerfCounter; + +/** + * Initializes/boots the module system. + * + * The {@link #boot() boot} method is called early in the startup to initialize + * the module system. In summary, the boot method creates a Configuration by + * resolving a set of module names specified via the launcher (or equivalent) + * -m and -addmods options. The modules are located on a module path that is + * constructed from the upgrade, system and application module paths. The + * Configuration is reified by creating the boot Layer with each module in the + * the configuration defined to one of the built-in class loaders. The mapping + * of modules to class loaders is statically mapped in a helper class. + */ + +public final class ModuleBootstrap { + private ModuleBootstrap() { } + + private static final String JAVA_BASE = "java.base"; + + // the token for "all unnamed modules" + private static final String ALL_UNNAMED = "ALL-UNNAMED"; + + // the token for "all system modules" + private static final String ALL_SYSTEM = "ALL-SYSTEM"; + + // the token for "all modules on the module path" + private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; + + // ModuleFinder for the initial configuration + private static ModuleFinder initialFinder; + + /** + * Returns the ModuleFinder for the initial configuration + */ + public static ModuleFinder finder() { + assert initialFinder != null; + return initialFinder; + } + + /** + * Initialize the module system, returning the boot Layer. + * + * @see java.lang.System#initPhase2() + */ + public static Layer boot() { + + long t0 = System.nanoTime(); + + // system module path + ModuleFinder systemModulePath = ModuleFinder.ofSystem(); + + // Once we have the system module path then we define the base module. + // We do this here so that java.base is defined to the VM as early as + // possible and also that resources in the base module can be located + // for error messages that may happen from here on. + Optional obase = systemModulePath.find(JAVA_BASE); + if (!obase.isPresent()) + throw new InternalError(JAVA_BASE + " not found"); + ModuleReference base = obase.get(); + BootLoader.loadModule(base); + Modules.defineModule(null, base.descriptor(), base.location().orElse(null)); + + + // -upgrademodulepath option specified to launcher + ModuleFinder upgradeModulePath + = createModulePathFinder("jdk.upgrade.module.path"); + + // -modulepath option specified to the launcher + ModuleFinder appModulePath = createModulePathFinder("jdk.module.path"); + + // The module finder: [-upgrademodulepath] system-module-path [-modulepath] + ModuleFinder finder = systemModulePath; + if (upgradeModulePath != null) + finder = ModuleFinder.compose(upgradeModulePath, finder); + if (appModulePath != null) + finder = ModuleFinder.compose(finder, appModulePath); + + // launcher -m option to specify the initial module + String mainModule = System.getProperty("jdk.module.main"); + + // additional module(s) specified by -addmods + boolean addAllSystemModules = false; + boolean addAllApplicationModules = false; + Set addModules = null; + String propValue = System.getProperty("jdk.launcher.addmods"); + if (propValue != null) { + addModules = new HashSet<>(); + for (String mod: propValue.split(",")) { + switch (mod) { + case ALL_SYSTEM: + addAllSystemModules = true; + break; + case ALL_MODULE_PATH: + addAllApplicationModules = true; + break; + default : + addModules.add(mod); + } + } + } + + // The root modules to resolve + Set roots = new HashSet<>(); + + // main/initial module + if (mainModule != null) { + roots.add(mainModule); + if (addAllApplicationModules) + fail(ALL_MODULE_PATH + " not allowed with initial module"); + } + + // If -addmods is specified then those modules need to be resolved + if (addModules != null) + roots.addAll(addModules); + + + // -limitmods + boolean limitmods = false; + propValue = System.getProperty("jdk.launcher.limitmods"); + if (propValue != null) { + Set mods = new HashSet<>(); + for (String mod: propValue.split(",")) { + mods.add(mod); + } + finder = limitFinder(finder, mods, roots); + limitmods = true; + } + + + // If there is no initial module specified then assume that the + // initial module is the unnamed module of the application class + // loader. By convention, and for compatibility, this is + // implemented by putting the names of all modules on the system + // module path into the set of modules to resolve. + // + // If `-addmods ALL-SYSTEM` is used then all modules on the system + // module path will be resolved, irrespective of whether an initial + // module is specified. + // + // If `-addmods ALL-MODULE-PATH` is used, and no initial module is + // specified, then all modules on the application module path will + // be resolved. + // + if (mainModule == null || addAllSystemModules) { + Set mrefs; + if (addAllApplicationModules) { + assert mainModule == null; + mrefs = finder.findAll(); + } else { + mrefs = systemModulePath.findAll(); + if (limitmods) { + ModuleFinder f = finder; + mrefs = mrefs.stream() + .filter(m -> f.find(m.descriptor().name()).isPresent()) + .collect(Collectors.toSet()); + } + } + // map to module names + for (ModuleReference mref : mrefs) { + roots.add(mref.descriptor().name()); + } + } + + long t1 = System.nanoTime(); + + // run the resolver to create the configuration + + Configuration cf = Configuration.empty() + .resolveRequiresAndUses(finder, + ModuleFinder.empty(), + roots); + + // time to create configuration + PerfCounters.resolveTime.addElapsedTimeFrom(t1); + + // mapping of modules to class loaders + Function clf = ModuleLoaderMap.mappingFunction(cf); + + // check that all modules to be mapped to the boot loader will be + // loaded from the system module path + if (finder != systemModulePath) { + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + String name = mref.descriptor().name(); + ClassLoader cl = clf.apply(name); + if (cl == null) { + + if (upgradeModulePath != null + && upgradeModulePath.find(name).isPresent()) + fail(name + ": cannot be loaded from upgrade module path"); + + if (!systemModulePath.find(name).isPresent()) + fail(name + ": cannot be loaded from application module path"); + } + } + } + + long t2 = System.nanoTime(); + + // define modules to VM/runtime + Layer bootLayer = Layer.empty().defineModules(cf, clf); + + PerfCounters.layerCreateTime.addElapsedTimeFrom(t2); + + long t3 = System.nanoTime(); + + // define the module to its class loader, except java.base + for (ResolvedModule resolvedModule : cf.modules()) { + ModuleReference mref = resolvedModule.reference(); + String name = mref.descriptor().name(); + ClassLoader cl = clf.apply(name); + if (cl == null) { + if (!name.equals(JAVA_BASE)) BootLoader.loadModule(mref); + } else { + ((BuiltinClassLoader)cl).loadModule(mref); + } + } + + PerfCounters.loadModulesTime.addElapsedTimeFrom(t3); + + // -XaddReads and -XaddExports + addExtraReads(bootLayer); + addExtraExports(bootLayer); + + // total time to initialize + PerfCounters.bootstrapTime.addElapsedTimeFrom(t0); + + // remember the ModuleFinder + initialFinder = finder; + + return bootLayer; + } + + /** + * Returns a ModuleFinder that limits observability to the given root + * modules, their transitive dependences, plus a set of other modules. + */ + private static ModuleFinder limitFinder(ModuleFinder finder, + Set roots, + Set otherMods) + { + // resolve all root modules + Configuration cf = Configuration.empty() + .resolveRequires(finder, + ModuleFinder.empty(), + roots); + + // module name -> reference + Map map = new HashMap<>(); + cf.modules().stream() + .map(ResolvedModule::reference) + .forEach(mref -> map.put(mref.descriptor().name(), mref)); + + // set of modules that are observable + Set mrefs = new HashSet<>(map.values()); + + // add the other modules + for (String mod : otherMods) { + Optional omref = finder.find(mod); + if (omref.isPresent()) { + ModuleReference mref = omref.get(); + map.putIfAbsent(mod, mref); + mrefs.add(mref); + } else { + // no need to fail + } + } + + return new ModuleFinder() { + @Override + public Optional find(String name) { + return Optional.ofNullable(map.get(name)); + } + @Override + public Set findAll() { + return mrefs; + } + }; + } + + /** + * Creates a finder from the module path that is the value of the given + * system property. + */ + private static ModuleFinder createModulePathFinder(String prop) { + String s = System.getProperty(prop); + if (s == null) { + return null; + } else { + String[] dirs = s.split(File.pathSeparator); + Path[] paths = new Path[dirs.length]; + int i = 0; + for (String dir: dirs) { + paths[i++] = Paths.get(dir); + } + return ModuleFinder.of(paths); + } + } + + + /** + * Process the -XaddReads options to add any additional read edges that + * are specified on the command-line. + */ + private static void addExtraReads(Layer bootLayer) { + + // decode the command line options + Map> map = decode("jdk.launcher.addreads."); + + for (Map.Entry> e : map.entrySet()) { + + // the key is $MODULE + String mn = e.getKey(); + Optional om = bootLayer.findModule(mn); + if (!om.isPresent()) + fail("Unknown module: " + mn); + Module m = om.get(); + + // the value is the set of other modules (by name) + for (String name : e.getValue()) { + + Module other; + if (ALL_UNNAMED.equals(name)) { + other = null; // loose + } else { + om = bootLayer.findModule(name); + if (!om.isPresent()) + fail("Unknown module: " + name); + other = om.get(); + } + + Modules.addReads(m, other); + } + } + } + + + /** + * Process the -XaddExports options to add any additional read edges that + * are specified on the command-line. + */ + private static void addExtraExports(Layer bootLayer) { + + // decode the command line options + Map> map = decode("jdk.launcher.addexports."); + + for (Map.Entry> e : map.entrySet()) { + + // the key is $MODULE/$PACKAGE + String key = e.getKey(); + String[] s = key.split("/"); + if (s.length != 2) + fail("Unable to parse: " + key); + + String mn = s[0]; + String pn = s[1]; + + // The exporting module is in the boot layer + Module m; + Optional om = bootLayer.findModule(mn); + if (!om.isPresent()) + fail("Unknown module: " + mn); + m = om.get(); + + // the value is the set of modules to export to (by name) + for (String name : e.getValue()) { + boolean allUnnamed = false; + Module other = null; + if (ALL_UNNAMED.equals(name)) { + allUnnamed = true; + } else { + om = bootLayer.findModule(name); + if (om.isPresent()) { + other = om.get(); + } else { + fail("Unknown module: " + name); + } + } + + if (allUnnamed) { + Modules.addExportsToAllUnnamed(m, pn); + } else { + Modules.addExports(m, pn, other); + } + } + } + } + + + /** + * Decodes the values of -XaddReads or -XaddExports options + * + * The format of the options is: $KEY=$MODULE(,$MODULE)* + * + * For transition purposes, this method allows the first usage to be + * $KEY=$MODULE(,$KEY=$MODULE) + * This format will eventually be removed. + */ + private static Map> decode(String prefix) { + int index = 0; + String value = System.getProperty(prefix + index); + if (value == null) + return Collections.emptyMap(); + + Map> map = new HashMap<>(); + + while (value != null) { + + int pos = value.indexOf('='); + if (pos == -1) + fail("Unable to parse: " + value); + if (pos == 0) + fail("Missing module name in: " + value); + + // key is or / + String key = value.substring(0, pos); + + String rhs = value.substring(pos+1); + if (rhs.isEmpty()) + fail("Unable to parse: " + value); + + // new format $MODULE(,$MODULE)* or old format $(MODULE)=... + pos = rhs.indexOf('='); + + // old format only allowed in first -X option + if (pos >= 0 && index > 0) + fail("Unable to parse: " + value); + + if (pos == -1) { + + // new format: $KEY=$MODULE(,$MODULE)* + + Set values = map.get(key); + if (values != null) + fail(key + " specified more than once"); + + values = new HashSet<>(); + map.put(key, values); + for (String s : rhs.split(",")) { + if (s.length() > 0) values.add(s); + } + + } else { + + // old format: $KEY=$MODULE(,$KEY=$MODULE)* + + assert index == 0; // old format only allowed in first usage + + for (String expr : value.split(",")) { + if (expr.length() > 0) { + String[] s = expr.split("="); + if (s.length != 2) + fail("Unable to parse: " + expr); + + map.computeIfAbsent(s[0], k -> new HashSet<>()).add(s[1]); + } + } + } + + index++; + value = System.getProperty(prefix + index); + } + + return map; + } + + + /** + * Throws a RuntimeException with the given message + */ + static void fail(String m) { + throw new RuntimeException(m); + } + + static class PerfCounters { + static PerfCounter resolveTime + = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime"); + static PerfCounter layerCreateTime + = PerfCounter.newPerfCounter("jdk.module.bootstrap.layerCreateTime"); + static PerfCounter loadModulesTime + = PerfCounter.newPerfCounter("jdk.module.bootstrap.loadModulesTime"); + static PerfCounter bootstrapTime + = PerfCounter.newPerfCounter("jdk.module.bootstrap.totalTime"); + } +} 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 new file mode 100644 index 00000000000..91d1f8ebae3 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.module.ModuleDescriptor.Version; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jdk.internal.org.objectweb.asm.Attribute; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.module.Hasher.DependencyHashes; + +import static jdk.internal.module.ClassFileAttributes.*; + +/** + * Utility class to extend a module-info.class with additional attributes. + */ + +public final class ModuleInfoExtender { + + // the input stream to read the original module-info.class + private final InputStream in; + + // the packages in the ConcealedPackages attribute + private Set conceals; + + // the value of the Version attribute + private Version version; + + // the value of the MainClass attribute + private String mainClass; + + // the values for the TargetPlatform attribute + private String osName; + private String osArch; + private String osVersion; + + // the hashes for the Hashes attribute + private DependencyHashes hashes; + + private ModuleInfoExtender(InputStream in) { + this.in = in; + } + + /** + * Sets the set of packages for the ConcealedPackages attribute + */ + public ModuleInfoExtender conceals(Set packages) { + this.conceals = Collections.unmodifiableSet(packages); + return this; + } + + /** + * Sets the value of the Version attribute. + */ + public ModuleInfoExtender version(Version version) { + this.version = version; + return this; + } + + /** + * Sets the value of the MainClass attribute. + */ + public ModuleInfoExtender mainClass(String mainClass) { + this.mainClass = mainClass; + return this; + } + + /** + * Sets the values for the TargetPlatform attribute. + */ + public ModuleInfoExtender targetPlatform(String osName, + String osArch, + String osVersion) { + this.osName = osName; + this.osArch = osArch; + this.osVersion = osVersion; + return this; + } + + /** + * The Hashes attribute will be emitted to the module-info with + * the hashes encapsulated in the given {@code DependencyHashes} + * object. + */ + public ModuleInfoExtender hashes(DependencyHashes hashes) { + this.hashes = hashes; + return this; + } + + /** + * A ClassVisitor that supports adding class file attributes. If an + * attribute already exists then the first occurence of the attribute + * is replaced. + */ + private static class AttributeAddingClassVisitor extends ClassVisitor { + private Map attrs = new HashMap<>(); + + AttributeAddingClassVisitor(int api, ClassVisitor cv) { + super(api, cv); + } + + void addAttribute(Attribute attr) { + attrs.put(attr.type, attr); + } + + @Override + public void visitAttribute(Attribute attr) { + String name = attr.type; + Attribute replacement = attrs.get(name); + if (replacement != null) { + attr = replacement; + attrs.remove(name); + } + super.visitAttribute(attr); + } + + /** + * Adds any remaining attributes that weren't replaced to the + * class file. + */ + void finish() { + attrs.values().forEach(a -> super.visitAttribute(a)); + attrs.clear(); + } + } + + /** + * Outputs the modified module-info.class to the given output stream. + * Once this method has been called then the Extender object should + * be discarded. + */ + public void write(OutputStream out) throws IOException { + ClassWriter cw + = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES); + + AttributeAddingClassVisitor cv + = new AttributeAddingClassVisitor(Opcodes.ASM5, cw); + + ClassReader cr = new ClassReader(in); + + if (conceals != null) + cv.addAttribute(new ConcealedPackagesAttribute(conceals)); + if (version != null) + cv.addAttribute(new VersionAttribute(version)); + if (mainClass != null) + cv.addAttribute(new MainClassAttribute(mainClass)); + if (osName != null || osArch != null || osVersion != null) + cv.addAttribute(new TargetPlatformAttribute(osName, osArch, osVersion)); + if (hashes != null) + cv.addAttribute(new HashesAttribute(hashes)); + + List attrs = new ArrayList<>(); + + // prototypes of attributes that should be parsed + attrs.add(new ModuleAttribute()); + attrs.add(new ConcealedPackagesAttribute()); + attrs.add(new VersionAttribute()); + attrs.add(new MainClassAttribute()); + attrs.add(new TargetPlatformAttribute()); + attrs.add(new HashesAttribute()); + + cr.accept(cv, attrs.toArray(new Attribute[0]), 0); + + // add any attributes that didn't replace previous attributes + cv.finish(); + + // emit to the output stream + out.write(cw.toByteArray()); + } + + /** + * Returns an {@code Extender} that may be used to add additional + * attributes to the module-info.class read from the given input + * stream. + */ + public static ModuleInfoExtender newExtender(InputStream in) { + return new ModuleInfoExtender(in); + } + +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java new file mode 100644 index 00000000000..f418b666a6d --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Version; +import java.nio.ByteBuffer; +import java.util.Optional; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; + +import static jdk.internal.module.ClassFileAttributes.*; +import static jdk.internal.module.ClassFileConstants.ACC_MODULE; + +/** + * Utility class to write a ModuleDescriptor as a module-info.class. + */ + +public final class ModuleInfoWriter { + + private ModuleInfoWriter() { } + + /** + * Writes the given module descriptor to a module-info.class file, + * returning it in a byte array. + */ + private static byte[] toModuleInfo(ModuleDescriptor descriptor) { + + ClassWriter cw = new ClassWriter(0); + + String name = descriptor.name().replace('.', '/') + "/module-info"; + cw.visit(Opcodes.V1_8, ACC_MODULE, name, null, null, null); + + cw.visitAttribute(new ModuleAttribute(descriptor)); + cw.visitAttribute(new ConcealedPackagesAttribute(descriptor.conceals())); + + Optional oversion = descriptor.version(); + if (oversion.isPresent()) + cw.visitAttribute(new VersionAttribute(oversion.get())); + + Optional omain = descriptor.mainClass(); + if (omain.isPresent()) + cw.visitAttribute(new MainClassAttribute(omain.get())); + + // write the TargetPlatform attribute if have any of OS name/arch/version + 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) { + cw.visitAttribute(new TargetPlatformAttribute(osName, + osArch, + osVersion)); + } + + cw.visitEnd(); + + return cw.toByteArray(); + } + + /** + * Writes a module descriptor to the given output stream as a + * module-info.class. + */ + public static void write(ModuleDescriptor descriptor, OutputStream out) + throws IOException + { + byte[] bytes = toModuleInfo(descriptor); + out.write(bytes); + } + + /** + * Returns a {@code ByteBuffer} containing the given module descriptor + * in module-info.class format. + */ + public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) { + byte[] bytes = toModuleInfo(descriptor); + return ByteBuffer.wrap(bytes); + } + +} 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 new file mode 100644 index 00000000000..9c3308f97a0 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; + +import jdk.internal.loader.ClassLoaders; + + +/** + * The module to class loader map. The list of boot modules and platform modules + * 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 + * built-in class loaders. + */ + static Function mappingFunction(Configuration cf) { + + Set bootModules = new HashSet<>(BOOT_MODULES.length); + for (String mn : BOOT_MODULES) { + bootModules.add(mn); + } + + Set platformModules = new HashSet<>(PLATFORM_MODULES.length); + for (String mn : PLATFORM_MODULES) { + platformModules.add(mn); + } + + ClassLoader platformClassLoader = ClassLoaders.platformClassLoader(); + ClassLoader appClassLoader = ClassLoaders.appClassLoader(); + + Map map = new HashMap<>(); + + for (ResolvedModule resolvedModule : cf.modules()) { + String mn = resolvedModule.name(); + if (!bootModules.contains(mn)) { + if (platformModules.contains(mn)) { + map.put(mn, platformClassLoader); + } else { + map.put(mn, appClassLoader); + } + } + } + + return new Function () { + @Override + public ClassLoader apply(String mn) { + return map.get(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 new file mode 100644 index 00000000000..d2224a599e1 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.module; + +import java.io.Closeable; +import java.io.File; +import java.io.IOError; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import jdk.internal.misc.JavaLangModuleAccess; +import jdk.internal.misc.SharedSecrets; +import sun.misc.Resource; +import sun.net.www.ParseUtil; + + +/** + * Provides support for patching modules in the boot layer with -Xpatch. + */ + +public final class ModulePatcher { + + private static final JavaLangModuleAccess JLMA + = SharedSecrets.getJavaLangModuleAccess(); + + // the prefix of the system properties that encode the value of -Xpatch + private static final String PATCH_PROPERTY_PREFIX = "jdk.launcher.patch."; + + // module name -> sequence of patches (directories or JAR files) + private static final Map> PATCH_MAP = decodeProperties(); + + private ModulePatcher() { } + + + /** + * Decodes the values of -Xpatch options, returning a Map of module name to + * list of file paths. + * + * @throws IllegalArgumentException if the the module name is missing or + * -Xpatch is used more than once to patch the same module + */ + private static Map> decodeProperties() { + + int index = 0; + String value = System.getProperty(PATCH_PROPERTY_PREFIX + index); + if (value == null) + return Collections.emptyMap(); // -Xpatch not specified + + Map> map = new HashMap<>(); + while (value != null) { + int pos = value.indexOf('='); + + if (pos == -1 && index > 0) + throwIAE("Unable to parse: " + value); + + if (pos == 0) + throwIAE("Missing module name: " + value); + + if (pos > 0) { + + // new format: =(:)* + + String mn = value.substring(0, pos); + List list = map.get(mn); + if (list != null) + throwIAE("Module " + mn + " specified more than once"); + list = new ArrayList<>(); + map.put(mn, list); + + String paths = value.substring(pos+1); + for (String path : paths.split(File.pathSeparator)) { + if (!path.isEmpty()) { + list.add(Paths.get(path)); + } + } + + } else { + + // old format: (:)* + + assert index == 0; // old format only allowed in first -Xpatch + + String[] dirs = value.split(File.pathSeparator); + for (String d : dirs) { + if (d.length() > 0) { + Path top = Paths.get(d); + try { + Files.list(top).forEach(e -> { + String mn = e.getFileName().toString(); + Path dir = top.resolve(mn); + map.computeIfAbsent(mn, k -> new ArrayList<>()) + .add(dir); + }); + } catch (IOException ignore) { } + } + } + + } + + + index++; + value = System.getProperty(PATCH_PROPERTY_PREFIX + index); + } + + return map; + } + + + /** + * Returns a module reference that interposes on the given module if + * needed. If there are no patches for the given module then the module + * reference is simply returned. Otherwise the patches for the module + * are scanned (to find any new concealed packages) and a new module + * reference is returned. + * + * @throws UncheckedIOException if an I/O error is detected + */ + public static ModuleReference interposeIfNeeded(ModuleReference mref) { + + ModuleDescriptor descriptor = mref.descriptor(); + String mn = descriptor.name(); + + // if there are no patches for the module then nothing to do + List paths = PATCH_MAP.get(mn); + if (paths == null) + return mref; + + + // scan the JAR file or directory tree to get the set of packages + Set packages = new HashSet<>(); + try { + for (Path file : paths) { + if (Files.isRegularFile(file)) { + + // JAR file + try (JarFile jf = new JarFile(file.toFile())) { + jf.stream() + .filter(e -> e.getName().endsWith(".class")) + .map(e -> toPackageName(file, e)) + .filter(pn -> pn.length() > 0) + .forEach(packages::add); + } + + } else if (Files.isDirectory(file)) { + + // exploded directory + Path top = file; + Files.find(top, Integer.MAX_VALUE, + ((path, attrs) -> attrs.isRegularFile() && + path.toString().endsWith(".class"))) + .map(path -> toPackageName(top, path)) + .filter(pn -> pn.length() > 0) + .forEach(packages::add); + + } + } + + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + + // 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); + } + + // return a new module reference + URI location = mref.location().orElse(null); + return new ModuleReference(descriptor, location, + () -> new PatchedModuleReader(paths, mref)); + + } + + + /** + * A ModuleReader that reads resources from a patched module. + * + * This class is public so as to expose the findResource method to the + * built-in class loaders and avoid locating the resource twice during + * class loading (once to locate the resource, the second to gets the + * URL for the CodeSource). + */ + public static class PatchedModuleReader implements ModuleReader { + private final List finders; + private final ModuleReference mref; + private final URL delegateCodeSourceURL; + private volatile ModuleReader delegate; + + /** + * Creates the ModuleReader to reads resources a patched module. + */ + PatchedModuleReader(List patches, ModuleReference mref) { + List finders = new ArrayList<>(); + boolean initialized = false; + try { + for (Path file : patches) { + if (Files.isRegularFile(file)) { + finders.add(new JarResourceFinder(file)); + } else { + finders.add(new ExplodedResourceFinder(file)); + } + } + initialized = true; + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } finally { + // close all ResourceFinder in the event of an error + if (!initialized) closeAll(finders); + } + + this.finders = finders; + this.mref = mref; + this.delegateCodeSourceURL = codeSourceURL(mref); + } + + /** + * Closes all resource finders. + */ + private static void closeAll(List finders) { + for (ResourceFinder finder : finders) { + try { finder.close(); } catch (IOException ioe) { } + } + } + + /** + * Returns the code source URL for the given module. + */ + private static URL codeSourceURL(ModuleReference mref) { + try { + Optional ouri = mref.location(); + if (ouri.isPresent()) + return ouri.get().toURL(); + } catch (MalformedURLException e) { } + return null; + } + + /** + * Returns the ModuleReader to delegate to when the resource is not + * found in a patch location. + */ + private ModuleReader delegate() throws IOException { + ModuleReader r = delegate; + if (r == null) { + synchronized (this) { + r = delegate; + if (r == null) { + delegate = r = mref.open(); + } + } + } + return r; + } + + /** + * Finds a resources in the patch locations. Returns null if not found. + */ + private Resource findResourceInPatch(String name) throws IOException { + for (ResourceFinder finder : finders) { + Resource r = finder.find(name); + if (r != null) + return r; + } + return null; + } + + /** + * Finds a resource of the given name in the patched module. + */ + public Resource findResource(String name) throws IOException { + + // patch locations + Resource r = findResourceInPatch(name); + if (r != null) + return r; + + // original module + ByteBuffer bb = delegate().read(name).orElse(null); + if (bb == null) + return null; + + return new Resource() { + private T shouldNotGetHere(Class type) { + throw new InternalError("should not get here"); + } + @Override + public String getName() { + return shouldNotGetHere(String.class); + } + @Override + public URL getURL() { + return shouldNotGetHere(URL.class); + } + @Override + public URL getCodeSourceURL() { + return delegateCodeSourceURL; + } + @Override + public ByteBuffer getByteBuffer() throws IOException { + return bb; + } + @Override + public InputStream getInputStream() throws IOException { + return shouldNotGetHere(InputStream.class); + } + @Override + public int getContentLength() throws IOException { + return shouldNotGetHere(int.class); + } + }; + } + + @Override + public Optional find(String name) throws IOException { + Resource r = findResourceInPatch(name); + if (r != null) { + URI uri = URI.create(r.getURL().toString()); + return Optional.of(uri); + } else { + return delegate().find(name); + } + } + + @Override + public Optional open(String name) throws IOException { + Resource r = findResourceInPatch(name); + if (r != null) { + return Optional.of(r.getInputStream()); + } else { + return delegate().open(name); + } + } + + @Override + public Optional read(String name) throws IOException { + Resource r = findResourceInPatch(name); + if (r != null) { + ByteBuffer bb = r.getByteBuffer(); + assert !bb.isDirect(); + return Optional.of(bb); + } else { + return delegate().read(name); + } + } + + @Override + public void release(ByteBuffer bb) { + if (bb.isDirect()) { + try { + delegate().release(bb); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + } + } + + @Override + public void close() throws IOException { + closeAll(finders); + delegate().close(); + } + } + + + /** + * A resource finder that find resources in a patch location. + */ + private static interface ResourceFinder extends Closeable { + Resource find(String name) throws IOException; + } + + + /** + * A ResourceFinder that finds resources in a JAR file. + */ + private static class JarResourceFinder implements ResourceFinder { + private final JarFile jf; + private final URL csURL; + + JarResourceFinder(Path path) throws IOException { + this.jf = new JarFile(path.toFile()); + this.csURL = path.toUri().toURL(); + } + + @Override + public void close() throws IOException { + jf.close(); + } + + @Override + public Resource find(String name) throws IOException { + JarEntry entry = jf.getJarEntry(name); + if (entry == null) + return null; + + return new Resource() { + @Override + public String getName() { + return name; + } + @Override + public URL getURL() { + String encodedPath = ParseUtil.encodePath(name, false); + try { + return new URL("jar:" + csURL + "!/" + encodedPath); + } catch (MalformedURLException e) { + return null; + } + } + @Override + public URL getCodeSourceURL() { + return csURL; + } + @Override + public ByteBuffer getByteBuffer() throws IOException { + byte[] bytes = getInputStream().readAllBytes(); + return ByteBuffer.wrap(bytes); + } + @Override + public InputStream getInputStream() throws IOException { + return jf.getInputStream(entry); + } + @Override + public int getContentLength() throws IOException { + long size = entry.getSize(); + return (size > Integer.MAX_VALUE) ? -1 : (int) size; + } + }; + } + } + + + /** + * A ResourceFinder that finds resources on the file system. + */ + private static class ExplodedResourceFinder implements ResourceFinder { + private final Path dir; + + ExplodedResourceFinder(Path dir) { + this.dir = dir; + } + + @Override + public void close() { } + + @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; + } + } + + private Resource newResource(String name, Path top, Path file) { + return new Resource() { + @Override + public String getName() { + return name; + } + @Override + public URL getURL() { + try { + return file.toUri().toURL(); + } catch (IOException | IOError e) { + return null; + } + } + @Override + public URL getCodeSourceURL() { + try { + return top.toUri().toURL(); + } catch (IOException | IOError e) { + return null; + } + } + @Override + public ByteBuffer getByteBuffer() throws IOException { + return ByteBuffer.wrap(Files.readAllBytes(file)); + } + @Override + public InputStream getInputStream() throws IOException { + return Files.newInputStream(file); + } + @Override + public int getContentLength() throws IOException { + long size = Files.size(file); + return (size > Integer.MAX_VALUE) ? -1 : (int)size; + } + }; + } + } + + + /** + * Derives a package name from a file path to a .class file. + */ + private static String toPackageName(Path top, Path file) { + Path entry = top.relativize(file); + Path parent = entry.getParent(); + if (parent == null) { + return warnUnnamedPackage(top, entry.toString()); + } else { + return parent.toString().replace(File.separatorChar, '.'); + } + } + + /** + * Derives a package name from the name of an entry in a JAR file. + */ + private static String toPackageName(Path file, JarEntry entry) { + String name = entry.getName(); + int index = name.lastIndexOf("/"); + if (index == -1) { + return warnUnnamedPackage(file, name); + } else { + return name.substring(0, index).replace('/', '.'); + } + } + + private static String warnUnnamedPackage(Path file, String e) { + System.err.println("WARNING: " + e + " not allowed in patch: " + file); + return ""; + } + + private static void throwIAE(String msg) { + throw new IllegalArgumentException(msg); + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000000..b33b1a8e416 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Module; +import java.net.URI; +import java.util.Set; + +import jdk.internal.loader.BootLoader; +import jdk.internal.loader.ClassLoaders; +import jdk.internal.misc.JavaLangReflectModuleAccess; +import jdk.internal.misc.SharedSecrets; + + +/** + * A helper class to allow JDK classes create dynamic modules and to update + * modules, exports and the readability graph. It is also invoked by the VM + * to add read edges when agents are instrumenting code that need to link + * to supporting classes. + * + * The parameters that are package names in this API are the fully-qualified + * names of the packages as defined in section 6.5.3 of The Java™ + * Language Specification , for example, {@code "java.lang"}. + */ + +public class Modules { + private Modules() { } + + private static final JavaLangReflectModuleAccess JLRMA + = SharedSecrets.getJavaLangReflectModuleAccess(); + + + /** + * Creates a new Module. The module has the given ModuleDescriptor and + * is defined to the given class loader. + * + * The resulting Module is in a larva state in that it does not not read + * any other module and does not have any exports. + * + * The URI is for information purposes only. + */ + public static Module defineModule(ClassLoader loader, + ModuleDescriptor descriptor, + URI uri) + { + return JLRMA.defineModule(loader, descriptor, uri); + } + + /** + * Define a new module to the VM. The module has the given set of + * concealed packages and is defined to the given class loader. + * + * The resulting Module is in a larva state in that it does not not read + * any other module and does not have any exports. + */ + public static Module defineModule(ClassLoader loader, + String name, + Set packages) + { + ModuleDescriptor descriptor + = new ModuleDescriptor.Builder(name).conceals(packages).build(); + + return JLRMA.defineModule(loader, descriptor, null); + } + + /** + * Adds a read-edge so that module {@code m1} reads module {@code m1}. + * Same as m1.addReads(m2) but without a caller check. + */ + public static void addReads(Module m1, Module m2) { + JLRMA.addReads(m1, m2); + } + + /** + * Updates module m1 to export a package to module m2. + * Same as m1.addExports(pkg, m2) but without a caller check. + */ + public static void addExports(Module m1, String pn, Module m2) { + JLRMA.addExports(m1, pn, m2); + } + + /** + * Updates a module m to export a package to all modules. + */ + public static void addExportsToAll(Module m, String pn) { + JLRMA.addExportsToAll(m, pn); + } + + /** + * Updates module m to export a package to all unnamed modules. + */ + public static void addExportsToAllUnnamed(Module m, String pn) { + JLRMA.addExportsToAllUnnamed(m, pn); + } + + /** + * Adds a package to a module's content. + * + * This method is a no-op if the module already contains the package. + */ + public static void addPackage(Module m, String pn) { + JLRMA.addPackage(m, pn); + } + + /** + * Called by the VM when code in the given Module has been transformed by + * an agent and so may have been instrumented to call into supporting + * classes on the boot class path or application class path. + */ + public static void transformedByAgent(Module m) { + addReads(m, BootLoader.getUnnamedModule()); + addReads(m, ClassLoaders.appClassLoader().getUnnamedModule()); + } + +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java new file mode 100644 index 00000000000..5d597f9ce55 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.reflect.Module; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Provides; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * A services catalog. Each {@code ClassLoader} has an optional {@code + * ServicesCatalog} for modules that provide services. This is to support + * ClassLoader centric ServiceLoader.load methods. + */ +public class ServicesCatalog { + + // use RW locks as register is rare + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + private final Lock readLock = lock.readLock(); + private final Lock writeLock = lock.writeLock(); + + /** + * Represents a service provider in the services catalog. + */ + public class ServiceProvider { + private final Module module; + private final String providerName; + ServiceProvider(Module module, String providerName) { + this.module = module; + this.providerName = providerName; + } + public Module module() { + return module; + } + public String providerName() { + return providerName; + } + } + + // service providers + private final Map> loaderServices = new HashMap<>(); + + /** + * Creates a new module catalog. + */ + public ServicesCatalog() { } + + /** + * Registers the module in this module catalog. + */ + public void register(Module m) { + ModuleDescriptor descriptor = m.getDescriptor(); + + writeLock.lock(); + try { + // extend the services map + for (Provides ps : descriptor.provides().values()) { + String service = ps.service(); + Set providerNames = ps.providers(); + + // create a new set to replace the existing + Set result = new HashSet<>(); + Set providers = loaderServices.get(service); + if (providers != null) { + result.addAll(providers); + } + for (String pn : providerNames) { + result.add(new ServiceProvider(m, pn)); + } + loaderServices.put(service, Collections.unmodifiableSet(result)); + } + + } finally { + writeLock.unlock(); + } + } + + /** + * Returns the (possibly empty) set of service providers that implement the + * given service type. + * + * @see java.util.ServiceLoader + */ + public Set findServices(String service) { + readLock.lock(); + try { + return loaderServices.getOrDefault(service, Collections.emptySet()); + } finally { + readLock.unlock(); + } + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java new file mode 100644 index 00000000000..3bd1371ee7d --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.module; + +import java.lang.module.ModuleDescriptor; + +/* + * SystemModules class will be generated at link time to create + * ModuleDescriptor for the installed modules directly to improve + * the module descriptor reconstitution time. + * + * This will skip parsing of module-info.class file and validating + * names such as module name, package name, service and provider type names. + * It also avoids taking a defensive copy of any collection. + * + * @see jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin + */ +public final class SystemModules { + /** + * Name of the installed modules. + * + * This array provides a way for InstalledModuleFinder to fallback + * and read module-info.class from the run-time image instead of + * the fastpath. + */ + public static final String[] MODULE_NAMES = new String[1]; + + /** + * Number of packages in the boot layer from the installed modules. + * + * Don't make it final to avoid inlining during compile time as + * the value will be changed at jlink time. + */ + public static final int PACKAGES_IN_BOOT_LAYER = 1024; + + /** + * Returns a non-empty array of ModuleDescriptors in the run-time image. + * + * When running an exploded image it returns an empty array. + */ + public static ModuleDescriptor[] modules() { + return new ModuleDescriptor[0]; + } +} \ No newline at end of file diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java index c9bf9d30225..90593f58fc3 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java @@ -195,7 +195,7 @@ public class ClassReader { public ClassReader(final byte[] b, final int off, final int len) { this.b = b; // checks the class version - if (readShort(off + 6) > Opcodes.V1_8) { + if (readShort(off + 6) > Opcodes.V1_9) { throw new IllegalArgumentException(); } // parses the constant pool @@ -1199,7 +1199,14 @@ public class ClassReader { if (labels[label] == null) { readLabel(label, labels).status |= Label.DEBUG; } - labels[label].line = readUnsignedShort(v + 12); + Label l = labels[label]; + while (l.line > 0) { + if (l.next == null) { + l.next = new Label(); + } + l = l.next; + } + l.line = readUnsignedShort(v + 12); v += 4; } } @@ -1314,9 +1321,15 @@ public class ClassReader { // visits the label and line number for this offset, if any Label l = labels[offset]; if (l != null) { + Label next = l.next; + l.next = null; mv.visitLabel(l); if ((context.flags & SKIP_DEBUG) == 0 && l.line > 0) { mv.visitLineNumber(l.line, l); + while (next != null) { + mv.visitLineNumber(next.line, l); + next = next.next; + } } } @@ -1857,8 +1870,7 @@ public class ClassReader { v += 2; break; case 'B': // pointer to CONSTANT_Byte - av.visit(name, - (byte) readInt(items[readUnsignedShort(v)])); + av.visit(name, (byte) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'Z': // pointer to CONSTANT_Boolean @@ -1868,13 +1880,11 @@ public class ClassReader { v += 2; break; case 'S': // pointer to CONSTANT_Short - av.visit(name, - (short) readInt(items[readUnsignedShort(v)])); + av.visit(name, (short) readInt(items[readUnsignedShort(v)])); v += 2; break; case 'C': // pointer to CONSTANT_Char - av.visit(name, - (char) readInt(items[readUnsignedShort(v)])); + av.visit(name, (char) readInt(items[readUnsignedShort(v)])); v += 2; break; case 's': // pointer to CONSTANT_Utf8 @@ -2515,11 +2525,12 @@ public class ClassReader { int tag = readByte(index); int[] items = this.items; int cpIndex = items[readUnsignedShort(index + 1)]; + boolean itf = b[cpIndex - 1] == ClassWriter.IMETH; String owner = readClass(cpIndex, buf); cpIndex = items[readUnsignedShort(cpIndex + 2)]; String name = readUTF8(cpIndex, buf); String desc = readUTF8(cpIndex + 2, buf); - return new Handle(tag, owner, name, desc); + return new Handle(tag, owner, name, desc, itf); } } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java index f5b24254ece..2e3d62b0369 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassWriter.java @@ -1081,7 +1081,7 @@ public class ClassWriter extends ClassVisitor { } } else if (cst instanceof Handle) { Handle h = (Handle) cst; - return newHandleItem(h.tag, h.owner, h.name, h.desc); + return newHandleItem(h.tag, h.owner, h.name, h.desc, h.itf); } else { throw new IllegalArgumentException("value " + cst); } @@ -1216,10 +1216,12 @@ public class ClassWriter extends ClassVisitor { * the name of the field or method. * @param desc * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. * @return a new or an already existing method type reference item. */ Item newHandleItem(final int tag, final String owner, final String name, - final String desc) { + final String desc, final boolean itf) { key4.set(HANDLE_BASE + tag, owner, name, desc); Item result = get(key4); if (result == null) { @@ -1228,8 +1230,7 @@ public class ClassWriter extends ClassVisitor { } else { put112(HANDLE, tag, - newMethod(owner, name, desc, - tag == Opcodes.H_INVOKEINTERFACE)); + newMethod(owner, name, desc, itf)); } result = new Item(index++, key4); put(result); @@ -1259,10 +1260,44 @@ public class ClassWriter extends ClassVisitor { * the descriptor of the field or method. * @return the index of a new or already existing method type reference * item. + * + * @deprecated this method is superseded by + * {@link #newHandle(int, String, String, String, boolean)}. */ + @Deprecated public int newHandle(final int tag, final String owner, final String name, final String desc) { - return newHandleItem(tag, owner, name, desc).index; + return newHandle(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Adds a handle to the constant pool of the class being build. Does nothing + * if the constant pool already contains a similar item. This method is + * intended for {@link Attribute} sub classes, and is normally not needed by + * class generators or adapters. + * + * @param tag + * the kind of this handle. Must be {@link Opcodes#H_GETFIELD}, + * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, + * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the field or method owner class. + * @param name + * the name of the field or method. + * @param desc + * the descriptor of the field or method. + * @param itf + * true if the owner is an interface. + * @return the index of a new or already existing method type reference + * item. + */ + public int newHandle(final int tag, final String owner, final String name, + final String desc, final boolean itf) { + return newHandleItem(tag, owner, name, desc, itf).index; } /** @@ -1294,7 +1329,7 @@ public class ClassWriter extends ClassVisitor { int hashCode = bsm.hashCode(); bootstrapMethods.putShort(newHandle(bsm.tag, bsm.owner, bsm.name, - bsm.desc)); + bsm.desc, bsm.isInterface())); int argsLength = bsmArgs.length; bootstrapMethods.putShort(argsLength); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java index bb7ff8f5147..811b74c7242 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Frame.java @@ -192,7 +192,7 @@ final class Frame { private static final int LOCAL = 0x2000000; /** - * Kind of the types that are relative to the stack of an input stack + * Kind of the the types that are relative to the stack of an input stack * map frame. The value of such types is a position relatively to the top of * this stack. */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java index e8b2859b05d..407c1d99774 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Handle.java @@ -93,6 +93,12 @@ public final class Handle { */ final String desc; + + /** + * Indicate if the owner is an interface or not. + */ + final boolean itf; + /** * Constructs a new field or method handle. * @@ -113,12 +119,44 @@ public final class Handle { * @param desc * the descriptor of the field or method designated by this * handle. + * + * @deprecated this constructor has been superseded + * by {@link #Handle(int, String, String, String, boolean)}. */ + @Deprecated public Handle(int tag, String owner, String name, String desc) { + this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); + } + + /** + * Constructs a new field or method handle. + * + * @param tag + * the kind of field or method designated by this Handle. Must be + * {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, + * {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, + * {@link Opcodes#H_INVOKEVIRTUAL}, + * {@link Opcodes#H_INVOKESTATIC}, + * {@link Opcodes#H_INVOKESPECIAL}, + * {@link Opcodes#H_NEWINVOKESPECIAL} or + * {@link Opcodes#H_INVOKEINTERFACE}. + * @param owner + * the internal name of the class that owns the field or method + * designated by this handle. + * @param name + * the name of the field or method designated by this handle. + * @param desc + * the descriptor of the field or method designated by this + * handle. + * @param itf + * true if the owner is an interface. + */ + public Handle(int tag, String owner, String name, String desc, boolean itf) { this.tag = tag; this.owner = owner; this.name = name; this.desc = desc; + this.itf = itf; } /** @@ -164,6 +202,17 @@ public final class Handle { return desc; } + /** + * Returns true if the owner of the field or method designated + * by this handle is an interface. + * + * @return true if the owner of the field or method designated + * by this handle is an interface. + */ + public boolean isInterface() { + return itf; + } + @Override public boolean equals(Object obj) { if (obj == this) { @@ -173,13 +222,13 @@ public final class Handle { return false; } Handle h = (Handle) obj; - return tag == h.tag && owner.equals(h.owner) && name.equals(h.name) - && desc.equals(h.desc); + return tag == h.tag && itf == h.itf && owner.equals(h.owner) + && name.equals(h.name) && desc.equals(h.desc); } @Override public int hashCode() { - return tag + owner.hashCode() * name.hashCode() * desc.hashCode(); + return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode(); } /** @@ -187,13 +236,16 @@ public final class Handle { * representation is: * *
    +     * for a reference to a class:
          * owner '.' name desc ' ' '(' tag ')'
    +     * for a reference to an interface:
    +     * owner '.' name desc ' ' '(' tag ' ' itf ')'
          * 
    * * . As this format is unambiguous, it can be parsed if necessary. */ @Override public String toString() { - return owner + '.' + name + desc + " (" + tag + ')'; + return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')'; } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java index bbea0001235..63e42a020bc 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Label.java @@ -160,7 +160,11 @@ public class Label { int status; /** - * The line number corresponding to this label, if known. + * The line number corresponding to this label, if known. If there are + * several lines, each line is stored in a separate label, all linked via + * their next field (these links are created in ClassReader and removed just + * before visitLabel is called, so that this does not impact the rest of the + * code). */ int line; @@ -268,7 +272,8 @@ public class Label { * The next basic block in the basic block stack. This stack is used in the * main loop of the fix point algorithm used in the second step of the * control flow analysis algorithms. It is also used in - * {@link #visitSubroutine} to avoid using a recursive method. + * {@link #visitSubroutine} to avoid using a recursive method, and in + * ClassReader to temporarily store multiple source lines for a label. * * @see MethodWriter#visitMaxs */ diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java index 0bb1a05b805..1448067a467 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodVisitor.java @@ -62,15 +62,16 @@ package jdk.internal.org.objectweb.asm; * A visitor to visit a Java method. The methods of this class must be called in * the following order: ( visitParameter )* [ * visitAnnotationDefault ] ( visitAnnotation | - * visitTypeAnnotation | visitAttribute )* [ - * visitCode ( visitFrame | visitXInsn | - * visitLabel | visitInsnAnnotation | - * visitTryCatchBlock | visitTryCatchBlockAnnotation | - * visitLocalVariable | visitLocalVariableAnnotation | - * visitLineNumber )* visitMaxs ] visitEnd. In - * addition, the visitXInsn and visitLabel methods must - * be called in the sequential order of the bytecode instructions of the visited - * code, visitInsnAnnotation must be called after the annotated + * visitParameterAnnotation visitTypeAnnotation | + * visitAttribute )* [ visitCode ( visitFrame | + * visitXInsn | visitLabel | + * visitInsnAnnotation | visitTryCatchBlock | + * visitTryCatchAnnotation | visitLocalVariable | + * visitLocalVariableAnnotation | visitLineNumber )* + * visitMaxs ] visitEnd. In addition, the + * visitXInsn and visitLabel methods must be called in + * the sequential order of the bytecode instructions of the visited code, + * visitInsnAnnotation must be called after the annotated * instruction, visitTryCatchBlock must be called before the * labels passed as arguments have been visited, * visitTryCatchBlockAnnotation must be called after the diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java index e02fad465d9..c2e4031e304 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/MethodWriter.java @@ -2061,7 +2061,7 @@ class MethodWriter extends MethodVisitor { } int size = 8; if (code.length > 0) { - if (code.length > 65536) { + if (code.length > 65535) { throw new RuntimeException("Method code too large!"); } cw.newUTF8("Code"); @@ -2735,11 +2735,13 @@ class MethodWriter extends MethodVisitor { l = l.successor; } // Update the offsets in the uninitialized types - for (i = 0; i < cw.typeTable.length; ++i) { - Item item = cw.typeTable[i]; - if (item != null && item.type == ClassWriter.TYPE_UNINIT) { - item.intVal = getNewOffset(allIndexes, allSizes, 0, - item.intVal); + if (cw.typeTable != null) { + for (i = 0; i < cw.typeTable.length; ++i) { + Item item = cw.typeTable[i]; + if (item != null && item.type == ClassWriter.TYPE_UNINIT) { + item.intVal = getNewOffset(allIndexes, allSizes, 0, + item.intVal); + } } } // The stack map frames are not serialized yet, so we don't need diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java index 286853352d2..d40facdafa4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Opcodes.java @@ -87,6 +87,7 @@ public interface Opcodes { int V1_6 = 0 << 16 | 50; int V1_7 = 0 << 16 | 51; int V1_8 = 0 << 16 | 52; + int V1_9 = 0 << 16 | 53; // access flags diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java index 633a4a024ea..056ace15fa8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/Type.java @@ -654,7 +654,7 @@ public class Type { * @return the descriptor corresponding to this Java type. */ public String getDescriptor() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf); return buf.toString(); } @@ -672,7 +672,7 @@ public class Type { */ public static String getMethodDescriptor(final Type returnType, final Type... argumentTypes) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < argumentTypes.length; ++i) { argumentTypes[i].getDescriptor(buf); @@ -689,7 +689,7 @@ public class Type { * @param buf * the string buffer to which the descriptor must be appended. */ - private void getDescriptor(final StringBuffer buf) { + private void getDescriptor(final StringBuilder buf) { if (this.buf == null) { // descriptor is in byte 3 of 'off' for primitive types (buf == // null) @@ -729,7 +729,7 @@ public class Type { * @return the descriptor corresponding to the given class. */ public static String getDescriptor(final Class c) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); getDescriptor(buf, c); return buf.toString(); } @@ -743,7 +743,7 @@ public class Type { */ public static String getConstructorDescriptor(final Constructor c) { Class[] parameters = c.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -760,7 +760,7 @@ public class Type { */ public static String getMethodDescriptor(final Method m) { Class[] parameters = m.getParameterTypes(); - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); buf.append('('); for (int i = 0; i < parameters.length; ++i) { getDescriptor(buf, parameters[i]); @@ -778,7 +778,7 @@ public class Type { * @param c * the class whose descriptor must be computed. */ - private static void getDescriptor(final StringBuffer buf, final Class c) { + private static void getDescriptor(final StringBuilder buf, final Class c) { Class d = c; while (true) { if (d.isPrimitive()) { diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java index a48a39d8b46..31fe2bc6826 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypePath.java @@ -71,25 +71,25 @@ public class TypePath { * A type path step that steps into the element type of an array type. See * {@link #getStep getStep}. */ - public static final int ARRAY_ELEMENT = 0; + public final static int ARRAY_ELEMENT = 0; /** * A type path step that steps into the nested type of a class type. See * {@link #getStep getStep}. */ - public static final int INNER_TYPE = 1; + public final static int INNER_TYPE = 1; /** * A type path step that steps into the bound of a wildcard type. See * {@link #getStep getStep}. */ - public static final int WILDCARD_BOUND = 2; + public final static int WILDCARD_BOUND = 2; /** * A type path step that steps into a type argument of a generic type. See * {@link #getStep getStep}. */ - public static final int TYPE_ARGUMENT = 3; + public final static int TYPE_ARGUMENT = 3; /** * The byte array where the path is stored, in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java index b366df0afb7..4caf8f10db0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/TypeReference.java @@ -74,133 +74,133 @@ public class TypeReference { * The sort of type references that target a type parameter of a generic * class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER = 0x00; + public final static int CLASS_TYPE_PARAMETER = 0x00; /** * The sort of type references that target a type parameter of a generic * method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER = 0x01; + public final static int METHOD_TYPE_PARAMETER = 0x01; /** * The sort of type references that target the super class of a class or one * of the interfaces it implements. See {@link #getSort getSort}. */ - public static final int CLASS_EXTENDS = 0x10; + public final static int CLASS_EXTENDS = 0x10; /** * The sort of type references that target a bound of a type parameter of a * generic class. See {@link #getSort getSort}. */ - public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11; + public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11; /** * The sort of type references that target a bound of a type parameter of a * generic method. See {@link #getSort getSort}. */ - public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12; + public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12; /** * The sort of type references that target the type of a field. See * {@link #getSort getSort}. */ - public static final int FIELD = 0x13; + public final static int FIELD = 0x13; /** * The sort of type references that target the return type of a method. See * {@link #getSort getSort}. */ - public static final int METHOD_RETURN = 0x14; + public final static int METHOD_RETURN = 0x14; /** * The sort of type references that target the receiver type of a method. * See {@link #getSort getSort}. */ - public static final int METHOD_RECEIVER = 0x15; + public final static int METHOD_RECEIVER = 0x15; /** * The sort of type references that target the type of a formal parameter of * a method. See {@link #getSort getSort}. */ - public static final int METHOD_FORMAL_PARAMETER = 0x16; + public final static int METHOD_FORMAL_PARAMETER = 0x16; /** * The sort of type references that target the type of an exception declared * in the throws clause of a method. See {@link #getSort getSort}. */ - public static final int THROWS = 0x17; + public final static int THROWS = 0x17; /** * The sort of type references that target the type of a local variable in a * method. See {@link #getSort getSort}. */ - public static final int LOCAL_VARIABLE = 0x40; + public final static int LOCAL_VARIABLE = 0x40; /** * The sort of type references that target the type of a resource variable * in a method. See {@link #getSort getSort}. */ - public static final int RESOURCE_VARIABLE = 0x41; + public final static int RESOURCE_VARIABLE = 0x41; /** * The sort of type references that target the type of the exception of a * 'catch' clause in a method. See {@link #getSort getSort}. */ - public static final int EXCEPTION_PARAMETER = 0x42; + public final static int EXCEPTION_PARAMETER = 0x42; /** * The sort of type references that target the type declared in an * 'instanceof' instruction. See {@link #getSort getSort}. */ - public static final int INSTANCEOF = 0x43; + public final static int INSTANCEOF = 0x43; /** * The sort of type references that target the type of the object created by * a 'new' instruction. See {@link #getSort getSort}. */ - public static final int NEW = 0x44; + public final static int NEW = 0x44; /** * The sort of type references that target the receiver type of a * constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE = 0x45; + public final static int CONSTRUCTOR_REFERENCE = 0x45; /** * The sort of type references that target the receiver type of a method * reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE = 0x46; + public final static int METHOD_REFERENCE = 0x46; /** * The sort of type references that target the type declared in an explicit * or implicit cast instruction. See {@link #getSort getSort}. */ - public static final int CAST = 0x47; + public final static int CAST = 0x47; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor call. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; /** * The sort of type references that target a type parameter of a generic * method in a method call. See {@link #getSort getSort}. */ - public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; /** * The sort of type references that target a type parameter of a generic * constructor in a constructor reference. See {@link #getSort getSort}. */ - public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; /** * The sort of type references that target a type parameter of a generic * method in a method reference. See {@link #getSort getSort}. */ - public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; /** * The type reference value in Java class file format. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java index c07917784df..00dccd549f0 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AdviceAdapter.java @@ -388,10 +388,10 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } break; case PUTFIELD: + popValue(); popValue(); if (longOrDouble) { popValue(); - popValue(); } break; // case GETFIELD: @@ -619,7 +619,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes } /** - * Called at the beginning of the method or after super class class call in + * Called at the beginning of the method or after super class call in * the constructor.
    *
    * diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java new file mode 100644 index 00000000000..3482ac95f6c --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/AnnotationRemapper.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/* + * 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +/** + * An {@link AnnotationVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class AnnotationRemapper extends AnnotationVisitor { + + protected final Remapper remapper; + + public AnnotationRemapper(final AnnotationVisitor av, + final Remapper remapper) { + this(Opcodes.ASM5, av, remapper); + } + + protected AnnotationRemapper(final int api, final AnnotationVisitor av, + final Remapper remapper) { + super(api, av); + this.remapper = remapper; + } + + @Override + public void visit(String name, Object value) { + av.visit(name, remapper.mapValue(value)); + } + + @Override + public void visitEnum(String name, String desc, String value) { + av.visitEnum(name, remapper.mapDesc(desc), value); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String desc) { + AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } + + @Override + public AnnotationVisitor visitArray(String name) { + AnnotationVisitor v = av.visitArray(name); + return v == null ? null : (v == av ? this : new AnnotationRemapper(v, + remapper)); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java new file mode 100644 index 00000000000..8a8ea738ae9 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/ClassRemapper.java @@ -0,0 +1,161 @@ +/* + * 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. + */ + +/* + * 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link ClassVisitor} for type remapping. + * + * @author Eugene Kuleshov + */ +public class ClassRemapper extends ClassVisitor { + + protected final Remapper remapper; + + protected String className; + + public ClassRemapper(final ClassVisitor cv, final Remapper remapper) { + this(Opcodes.ASM5, cv, remapper); + } + + protected ClassRemapper(final int api, final ClassVisitor cv, + final Remapper remapper) { + super(api, cv); + this.remapper = remapper; + } + + @Override + public void visit(int version, int access, String name, String signature, + String superName, String[] interfaces) { + this.className = name; + super.visit(version, access, remapper.mapType(name), remapper + .mapSignature(signature, false), remapper.mapType(superName), + interfaces == null ? null : remapper.mapTypes(interfaces)); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : createAnnotationRemapper(av); + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, + String signature, Object value) { + FieldVisitor fv = super.visitField(access, + remapper.mapFieldName(className, name, desc), + remapper.mapDesc(desc), remapper.mapSignature(signature, true), + remapper.mapValue(value)); + return fv == null ? null : createFieldRemapper(fv); + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + String newDesc = remapper.mapMethodDesc(desc); + MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( + className, name, desc), newDesc, remapper.mapSignature( + signature, false), + exceptions == null ? null : remapper.mapTypes(exceptions)); + return mv == null ? null : createMethodRemapper(mv); + } + + @Override + public void visitInnerClass(String name, String outerName, + String innerName, int access) { + // TODO should innerName be changed? + super.visitInnerClass(remapper.mapType(name), outerName == null ? null + : remapper.mapType(outerName), innerName, access); + } + + @Override + public void visitOuterClass(String owner, String name, String desc) { + super.visitOuterClass(remapper.mapType(owner), name == null ? null + : remapper.mapMethodName(owner, name, desc), + desc == null ? null : remapper.mapMethodDesc(desc)); + } + + protected FieldVisitor createFieldRemapper(FieldVisitor fv) { + return new FieldRemapper(fv, remapper); + } + + protected MethodVisitor createMethodRemapper(MethodVisitor mv) { + return new MethodRemapper(mv, remapper); + } + + protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) { + return new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java new file mode 100644 index 00000000000..13f8b7fd154 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/FieldRemapper.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link FieldVisitor} adapter for type remapping. + * + * @author Eugene Kuleshov + */ +public class FieldRemapper extends FieldVisitor { + + private final Remapper remapper; + + public FieldRemapper(final FieldVisitor fv, final Remapper remapper) { + this(Opcodes.ASM5, fv, remapper); + } + + protected FieldRemapper(final int api, final FieldVisitor fv, + final Remapper remapper) { + super(api, fv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? null : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java index 8ecb1c9c4b1..2df144ef70c 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/InstructionAdapter.java @@ -73,7 +73,7 @@ import jdk.internal.org.objectweb.asm.Type; */ public class InstructionAdapter extends MethodVisitor { - public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); + public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;"); /** * Creates a new {@link InstructionAdapter}. Subclasses must not use this diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java index 5d02c53768d..7aad39658e8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/LocalVariablesSorter.java @@ -104,11 +104,6 @@ public class LocalVariablesSorter extends MethodVisitor { */ protected int nextLocal; - /** - * Indicates if at least one local variable has moved due to remapping. - */ - private boolean changed; - /** * Creates a new {@link LocalVariablesSorter}. Subclasses must not use * this constructor. Instead, they must use the @@ -228,11 +223,6 @@ public class LocalVariablesSorter extends MethodVisitor { "ClassReader.accept() should be called with EXPAND_FRAMES flag"); } - if (!changed) { // optimization for the case where mapping = identity - mv.visitFrame(type, nLocal, local, nStack, stack); - return; - } - // creates a copy of newLocals Object[] oldLocals = new Object[newLocals.length]; System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length); @@ -328,7 +318,6 @@ public class LocalVariablesSorter extends MethodVisitor { int local = newLocalMapping(type); setLocalType(local, type); setFrameLocal(local, t); - changed = true; return local; } @@ -396,9 +385,6 @@ public class LocalVariablesSorter extends MethodVisitor { } else { value--; } - if (value != var) { - changed = true; - } return value; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java new file mode 100644 index 00000000000..486cc6b7c57 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/MethodRemapper.java @@ -0,0 +1,252 @@ +/* + * 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. + */ + +/* + * 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import jdk.internal.org.objectweb.asm.AnnotationVisitor; +import jdk.internal.org.objectweb.asm.Handle; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.TypePath; + +/** + * A {@link LocalVariablesSorter} for type mapping. + * + * @author Eugene Kuleshov + */ +public class MethodRemapper extends MethodVisitor { + + protected final Remapper remapper; + + public MethodRemapper(final MethodVisitor mv, final Remapper remapper) { + this(Opcodes.ASM5, mv, remapper); + } + + protected MethodRemapper(final int api, final MethodVisitor mv, + final Remapper remapper) { + super(api, mv); + this.remapper = remapper; + } + + @Override + public AnnotationVisitor visitAnnotationDefault() { + AnnotationVisitor av = super.visitAnnotationDefault(); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitAnnotation(String desc, boolean visible) { + AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), + visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitTypeAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public AnnotationVisitor visitParameterAnnotation(int parameter, + String desc, boolean visible) { + AnnotationVisitor av = super.visitParameterAnnotation(parameter, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitFrame(int type, int nLocal, Object[] local, int nStack, + Object[] stack) { + super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, + remapEntries(nStack, stack)); + } + + private Object[] remapEntries(int n, Object[] entries) { + for (int i = 0; i < n; i++) { + if (entries[i] instanceof String) { + Object[] newEntries = new Object[n]; + if (i > 0) { + System.arraycopy(entries, 0, newEntries, 0, i); + } + do { + Object t = entries[i]; + newEntries[i++] = t instanceof String ? remapper + .mapType((String) t) : t; + } while (i < n); + return newEntries; + } + } + return entries; + } + + @Override + public void visitFieldInsn(int opcode, String owner, String name, + String desc) { + super.visitFieldInsn(opcode, remapper.mapType(owner), + remapper.mapFieldName(owner, name, desc), + remapper.mapDesc(desc)); + } + + @Deprecated + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc) { + if (api >= Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, + opcode == Opcodes.INVOKEINTERFACE); + } + + @Override + public void visitMethodInsn(final int opcode, final String owner, + final String name, final String desc, final boolean itf) { + if (api < Opcodes.ASM5) { + super.visitMethodInsn(opcode, owner, name, desc, itf); + return; + } + doVisitMethodInsn(opcode, owner, name, desc, itf); + } + + private void doVisitMethodInsn(int opcode, String owner, String name, + String desc, boolean itf) { + // Calling super.visitMethodInsn requires to call the correct version + // depending on this.api (otherwise infinite loops can occur). To + // simplify and to make it easier to automatically remove the backward + // compatibility code, we inline the code of the overridden method here. + // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN + // LocalVariableSorter. + if (mv != null) { + mv.visitMethodInsn(opcode, remapper.mapType(owner), + remapper.mapMethodName(owner, name, desc), + remapper.mapMethodDesc(desc), itf); + } + } + + @Override + public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, + Object... bsmArgs) { + for (int i = 0; i < bsmArgs.length; i++) { + bsmArgs[i] = remapper.mapValue(bsmArgs[i]); + } + super.visitInvokeDynamicInsn( + remapper.mapInvokeDynamicMethodName(name, desc), + remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm), + bsmArgs); + } + + @Override + public void visitTypeInsn(int opcode, String type) { + super.visitTypeInsn(opcode, remapper.mapType(type)); + } + + @Override + public void visitLdcInsn(Object cst) { + super.visitLdcInsn(remapper.mapValue(cst)); + } + + @Override + public void visitMultiANewArrayInsn(String desc, int dims) { + super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); + } + + @Override + public AnnotationVisitor visitInsnAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitTryCatchBlock(Label start, Label end, Label handler, + String type) { + super.visitTryCatchBlock(start, end, handler, type == null ? null + : remapper.mapType(type)); + } + + @Override + public AnnotationVisitor visitTryCatchAnnotation(int typeRef, + TypePath typePath, String desc, boolean visible) { + AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath, + remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } + + @Override + public void visitLocalVariable(String name, String desc, String signature, + Label start, Label end, int index) { + super.visitLocalVariable(name, remapper.mapDesc(desc), + remapper.mapSignature(signature, true), start, end, index); + } + + @Override + public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, + TypePath typePath, Label[] start, Label[] end, int[] index, + String desc, boolean visible) { + AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef, + typePath, start, end, index, remapper.mapDesc(desc), visible); + return av == null ? av : new AnnotationRemapper(av, remapper); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java index d5edd06363f..b90aee05590 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/Remapper.java @@ -168,17 +168,19 @@ public abstract class Remapper { Handle h = (Handle) value; return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName( h.getOwner(), h.getName(), h.getDesc()), - mapMethodDesc(h.getDesc())); + mapMethodDesc(h.getDesc()), h.isInterface()); } return value; } /** - * + * @param signature + * signature for mapper * @param typeSignature * true if signature is a FieldTypeSignature, such as the * signature parameter of the ClassVisitor.visitField or * MethodVisitor.visitLocalVariable methods + * @return signature rewritten as a string */ public String mapSignature(String signature, boolean typeSignature) { if (signature == null) { @@ -186,7 +188,7 @@ public abstract class Remapper { } SignatureReader r = new SignatureReader(signature); SignatureWriter w = new SignatureWriter(); - SignatureVisitor a = createRemappingSignatureAdapter(w); + SignatureVisitor a = createSignatureRemapper(w); if (typeSignature) { r.acceptType(a); } else { @@ -195,9 +197,18 @@ public abstract class Remapper { return w.toString(); } + /** + * @deprecated use {@link #createSignatureRemapper} instead. + */ + @Deprecated protected SignatureVisitor createRemappingSignatureAdapter( SignatureVisitor v) { - return new RemappingSignatureAdapter(v, this); + return new SignatureRemapper(v, this); + } + + protected SignatureVisitor createSignatureRemapper( + SignatureVisitor v) { + return createRemappingSignatureAdapter(v); } /** @@ -245,6 +256,10 @@ public abstract class Remapper { /** * Map type name to the new name. Subclasses can override. + * + * @param typeName + * the type name + * @return new name, default implementation is the identity. */ public String map(String typeName) { return typeName; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java index b9a1bc874aa..af0fe2b4fb4 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingAnnotationAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.Opcodes; /** * An {@link AnnotationVisitor} adapter for type remapping. * + * //@deprecated use {@link AnnotationRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingAnnotationAdapter extends AnnotationVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java index 28b736be7a4..e36d79e931d 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingClassAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link ClassVisitor} for type remapping. * + * @deprecated use {@link ClassRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingClassAdapter extends ClassVisitor { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java index 9d94e5ee327..8bafee1bf4a 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingFieldAdapter.java @@ -67,8 +67,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link FieldVisitor} adapter for type remapping. * + * @deprecated use {@link FieldRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingFieldAdapter extends FieldVisitor { private final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java index d5493a1b1b5..f58963db6ef 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingMethodAdapter.java @@ -69,8 +69,10 @@ import jdk.internal.org.objectweb.asm.TypePath; /** * A {@link LocalVariablesSorter} for type mapping. * + * //@deprecated use {@link MethodRemapper} instead. * @author Eugene Kuleshov */ +//@Deprecated public class RemappingMethodAdapter extends LocalVariablesSorter { protected final Remapper remapper; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java index 3b8ab02a3f1..4aa8428f344 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RemappingSignatureAdapter.java @@ -65,8 +65,10 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; /** * A {@link SignatureVisitor} adapter for type mapping. * + * @deprecated use {@link SignatureRemapper} instead. * @author Eugene Kuleshov */ +@Deprecated public class RemappingSignatureAdapter extends SignatureVisitor { private final SignatureVisitor v; diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java index cd407fd8063..0486710dd47 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SerialVersionUIDAdder.java @@ -234,7 +234,7 @@ public class SerialVersionUIDAdder extends ClassVisitor { public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) { - computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0; + computeSVUID = (access & Opcodes.ACC_ENUM) == 0; if (computeSVUID) { this.name = name; @@ -396,6 +396,11 @@ public class SerialVersionUIDAdder extends ClassVisitor { /* * 2. The class modifiers written as a 32-bit integer. */ + int access = this.access; + if ((access & Opcodes.ACC_INTERFACE) != 0) { + access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT) + : (access & ~Opcodes.ACC_ABSTRACT); + } dos.writeInt(access & (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL | Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT)); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java new file mode 100644 index 00000000000..cf18f2bbb58 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SignatureRemapper.java @@ -0,0 +1,188 @@ +/* + * 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. + */ + +/* + * 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: + * + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2011 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +package jdk.internal.org.objectweb.asm.commons; + +import java.util.Stack; + +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; + +/** + * A {@link SignatureVisitor} adapter for type mapping. + * + * @author Eugene Kuleshov + */ +public class SignatureRemapper extends SignatureVisitor { + + private final SignatureVisitor v; + + private final Remapper remapper; + + private Stack classNames = new Stack(); + + public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) { + this(Opcodes.ASM5, v, remapper); + } + + protected SignatureRemapper(final int api, final SignatureVisitor v, + final Remapper remapper) { + super(api); + this.v = v; + this.remapper = remapper; + } + + @Override + public void visitClassType(String name) { + classNames.push(name); + v.visitClassType(remapper.mapType(name)); + } + + @Override + public void visitInnerClassType(String name) { + String outerClassName = classNames.pop(); + String className = outerClassName + '$' + name; + classNames.push(className); + String remappedOuter = remapper.mapType(outerClassName) + '$'; + String remappedName = remapper.mapType(className); + int index = remappedName.startsWith(remappedOuter) ? remappedOuter + .length() : remappedName.lastIndexOf('$') + 1; + v.visitInnerClassType(remappedName.substring(index)); + } + + @Override + public void visitFormalTypeParameter(String name) { + v.visitFormalTypeParameter(name); + } + + @Override + public void visitTypeVariable(String name) { + v.visitTypeVariable(name); + } + + @Override + public SignatureVisitor visitArrayType() { + v.visitArrayType(); + return this; + } + + @Override + public void visitBaseType(char descriptor) { + v.visitBaseType(descriptor); + } + + @Override + public SignatureVisitor visitClassBound() { + v.visitClassBound(); + return this; + } + + @Override + public SignatureVisitor visitExceptionType() { + v.visitExceptionType(); + return this; + } + + @Override + public SignatureVisitor visitInterface() { + v.visitInterface(); + return this; + } + + @Override + public SignatureVisitor visitInterfaceBound() { + v.visitInterfaceBound(); + return this; + } + + @Override + public SignatureVisitor visitParameterType() { + v.visitParameterType(); + return this; + } + + @Override + public SignatureVisitor visitReturnType() { + v.visitReturnType(); + return this; + } + + @Override + public SignatureVisitor visitSuperclass() { + v.visitSuperclass(); + return this; + } + + @Override + public void visitTypeArgument() { + v.visitTypeArgument(); + } + + @Override + public SignatureVisitor visitTypeArgument(char wildcard) { + v.visitTypeArgument(wildcard); + return this; + } + + @Override + public void visitEnd() { + v.visitEnd(); + classNames.pop(); + } +} diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java index 56b9bb57dcf..ebf59f4bf53 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/SimpleRemapper.java @@ -85,6 +85,12 @@ public class SimpleRemapper extends Remapper { return s == null ? name : s; } + @Override + public String mapInvokeDynamicMethodName(String name, String desc) { + String s = map('.' + name + desc); + return s == null ? name : s; + } + @Override public String mapFieldName(String owner, String name, String desc) { String s = map(owner + '.' + name); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java index 9114bcd348e..8ad2de61230 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureVisitor.java @@ -68,7 +68,7 @@ import jdk.internal.org.objectweb.asm.Opcodes; *
      *
    • ClassSignature = ( visitFormalTypeParameter * visitClassBound? visitInterfaceBound* )* ( - * visitSuperClass visitInterface* )
    • + * visitSuperclass visitInterface* ) *
    • MethodSignature = ( visitFormalTypeParameter * visitClassBound? visitInterfaceBound* )* ( * visitParameterType* visitReturnType @@ -88,17 +88,17 @@ public abstract class SignatureVisitor { /** * Wildcard for an "extends" type argument. */ - public static final char EXTENDS = '+'; + public final static char EXTENDS = '+'; /** * Wildcard for a "super" type argument. */ - public static final char SUPER = '-'; + public final static char SUPER = '-'; /** * Wildcard for a normal type argument. */ - public static final char INSTANCEOF = '='; + public final static char INSTANCEOF = '='; /** * The ASM API version implemented by this visitor. The value of this field diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java index 0d761663ea0..a1eceb8d5c9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/signature/SignatureWriter.java @@ -69,9 +69,9 @@ import jdk.internal.org.objectweb.asm.Opcodes; public class SignatureWriter extends SignatureVisitor { /** - * Buffer used to construct the signature. + * Builder used to construct the signature. */ - private final StringBuffer buf = new StringBuffer(); + private final StringBuilder buf = new StringBuilder(); /** * Indicates if the signature contains formal type parameters. diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java index 8dec6eda0bd..768130c94c1 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/InsnList.java @@ -205,6 +205,9 @@ public class InsnList { /** * Returns an iterator over the instructions in this list. * + * @param index + * index of instruction for the iterator to start at + * * @return an iterator over the instructions in this list. */ @SuppressWarnings("unchecked") diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java index 26e208a4cef..d7c1becfe46 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/ASMifier.java @@ -856,7 +856,11 @@ public class ASMifier extends Printer { buf.append("{\n").append("av0 = ").append(name) .append(".visitLocalVariableAnnotation("); buf.append(typeRef); - buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + if (typePath == null) { + buf.append(", null, "); + } else { + buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + } buf.append("new Label[] {"); for (int i = 0; i < start.length; ++i) { buf.append(i == 0 ? " " : ", "); @@ -934,7 +938,11 @@ public class ASMifier extends Printer { buf.append("{\n").append("av0 = ").append(name).append(".") .append(method).append("("); buf.append(typeRef); - buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + if (typePath == null) { + buf.append(", null, "); + } else { + buf.append(", TypePath.fromString(\"").append(typePath).append("\"), "); + } appendConstant(desc); buf.append(", ").append(visible).append(");\n"); text.add(buf.toString()); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java index 25673195f1c..a0afdc650a8 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckMethodAdapter.java @@ -437,6 +437,9 @@ public class CheckMethodAdapter extends MethodVisitor { * will not perform any data flow check (see * {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * + * @param api + * the ASM API version implemented by this CheckMethodAdapter. + * Must be one of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. * @param mv * the method visitor to which this adapter must delegate calls. * @param labels diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java index 87e79f47e14..650e1f0b878 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/Printer.java @@ -171,6 +171,10 @@ public abstract class Printer { /** * Constructs a new {@link Printer}. + * + * @param api + * the ASM API version implemented by this printer. Must be one + * of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}. */ protected Printer(final int api) { this.api = api; @@ -179,34 +183,103 @@ public abstract class Printer { } /** - * Class header. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}. + * Class header. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}. + * + * @param version + * the class version. + * @param access + * the class's access flags (see {@link Opcodes}). This parameter + * also indicates if the class is deprecated. + * @param name + * the internal name of the class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param signature + * the signature of this class. May be null if the class + * is not a generic one, and does not extend or implement generic + * classes or interfaces. + * @param superName + * the internal of name of the super class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * For interfaces, the super class is {@link Object}. May be + * null, but only for the {@link Object} class. + * @param interfaces + * the internal names of the class's interfaces (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * May be null. */ public abstract void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces); /** - * Class source. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitSource}. + * Class source. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitSource}. + * + * @param source + * the name of the source file from which the class was compiled. + * May be null. + * @param debug + * additional debug information to compute the correspondance + * between source and compiled elements of the class. May be + * null. */ - public abstract void visitSource(final String file, final String debug); + public abstract void visitSource(final String source, final String debug); /** - * Class outer class. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. + * Class outer class. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitOuterClass}. + * + * Visits the enclosing class of the class. This method must be called only + * if the class has an enclosing class. + * + * @param owner + * internal name of the enclosing class of the class. + * @param name + * the name of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. + * @param desc + * the descriptor of the method that contains the class, or + * null if the class is not enclosed in a method of its + * enclosing class. */ public abstract void visitOuterClass(final String owner, final String name, final String desc); /** - * Class annotation. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAnnotation}. + * Class annotation. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitClassAnnotation(final String desc, final boolean visible); /** - * Class type annotation. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitTypeAnnotation}. + * Class type annotation. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be + * {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} + * or {@link jdk.internal.org.objectweb.asm.TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitClassTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -214,26 +287,85 @@ public abstract class Printer { } /** - * Class attribute. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAttribute}. + * Class attribute. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitClassAttribute(final Attribute attr); /** - * Class inner name. See - * {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}. + * Class inner name. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}. + * + * @param name + * the internal name of an inner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param outerName + * the internal name of the class to which the inner class + * belongs (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * May be null for not member classes. + * @param innerName + * the (simple) name of the inner class inside its enclosing + * class. May be null for anonymous inner classes. + * @param access + * the access flags of the inner class as originally declared in + * the enclosing class. */ public abstract void visitInnerClass(final String name, final String outerName, final String innerName, final int access); /** - * Class field. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}. + * Class field. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}. + * + * @param access + * the field's access flags (see {@link Opcodes}). This parameter + * also indicates if the field is synthetic and/or deprecated. + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param signature + * the field's signature. May be null if the field's + * type does not use generic types. + * @param value + * the field's initial value. This parameter, which may be + * null if the field does not have an initial value, + * must be an {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double} or a {@link String} (for int, + * float, long or String fields + * respectively). This parameter is only used for static + * fields. Its value is ignored for non static fields, which + * must be initialized through bytecode instructions in + * constructors or methods. + * @return the printer */ public abstract Printer visitField(final int access, final String name, final String desc, final String signature, final Object value); /** - * Class method. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod}. + * Class method. + * See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod}. + * + * @param access + * the method's access flags (see {@link Opcodes}). This + * parameter also indicates if the method is synthetic and/or + * deprecated. + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param signature + * the method's signature. May be null if the method + * parameters, return type and exceptions do not use generic + * types. + * @param exceptions + * the internal names of the method's exception classes (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). May be + * null. + * @return the printer */ public abstract Printer visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions); @@ -248,26 +380,64 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Annotation value. See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visit}. + * Annotation value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visit}. + * + * @param name + * the value name. + * @param value + * the actual value, whose type must be {@link Byte}, + * {@link Boolean}, {@link Character}, {@link Short}, + * {@link Integer} , {@link Long}, {@link Float}, {@link Double}, + * {@link String} or {@link jdk.internal.org.objectweb.asm.Type} + * or OBJECT or ARRAY sort. + * This value can also be an array of byte, boolean, short, char, int, + * long, float or double values (this is equivalent to using + * {@link #visitArray visitArray} and visiting each array element + * in turn, but is more convenient). */ public abstract void visit(final String name, final Object value); /** - * Annotation enum value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnum}. + * Annotation enum value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnum}. + * + * Visits an enumeration value of the annotation. + * + * @param name + * the value name. + * @param desc + * the class descriptor of the enumeration class. + * @param value + * the actual enumeration value. */ public abstract void visitEnum(final String name, final String desc, final String value); /** - * Nested annotation value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * Nested annotation value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitAnnotation}. + * + * @param name + * the value name. + * @param desc + * the class descriptor of the nested annotation class. + * @return the printer */ public abstract Printer visitAnnotation(final String name, final String desc); /** - * Annotation array value. See - * {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitArray}. + * Annotation array value. + * See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitArray}. + * + * Visits an array value of the annotation. Note that arrays of primitive + * types (such as byte, boolean, short, char, int, long, float or double) + * can be passed as value to {@link #visit visit}. This is what + * {@link jdk.internal.org.objectweb.asm.ClassReader} does. + * + * @param name + * the value name. + * @return the printer */ public abstract Printer visitArray(final String name); @@ -281,15 +451,35 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Field annotation. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAnnotation}. + * Field annotation. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitFieldAnnotation(final String desc, final boolean visible); /** - * Field type annotation. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitTypeAnnotation}. + * Field type annotation. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#FIELD FIELD}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitFieldTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -297,13 +487,17 @@ public abstract class Printer { } /** - * Field attribute. See - * {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAttribute}. + * Field attribute. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitFieldAttribute(final Attribute attr); /** - * Field end. See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitEnd}. + * Field end. + * See {@link jdk.internal.org.objectweb.asm.FieldVisitor#visitEnd}. */ public abstract void visitFieldEnd(); @@ -312,29 +506,58 @@ public abstract class Printer { // ------------------------------------------------------------------------ /** - * Method parameter. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. + * Method parameter. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. + * + * @param name + * parameter name or null if none is provided. + * @param access + * the parameter's access flags, only ACC_FINAL, + * ACC_SYNTHETIC or/and ACC_MANDATED are + * allowed (see {@link Opcodes}). */ public void visitParameter(String name, int access) { throw new RuntimeException("Must be overriden"); } /** - * Method default annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * Method default annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotationDefault}. + * + * @return the printer */ public abstract Printer visitAnnotationDefault(); /** - * Method annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotation}. + * Method annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAnnotation}. + * + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitMethodAnnotation(final String desc, final boolean visible); /** - * Method type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeAnnotation}. + * Method type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#FIELD FIELD}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitMethodTypeAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -342,64 +565,225 @@ public abstract class Printer { } /** - * Method parameter annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * Method parameter annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameterAnnotation}. + * + * @param parameter + * the parameter index. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public abstract Printer visitParameterAnnotation(final int parameter, final String desc, final boolean visible); /** - * Method attribute. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAttribute}. + * Method attribute. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitAttribute}. + * + * @param attr + * an attribute. */ public abstract void visitMethodAttribute(final Attribute attr); /** - * Method start. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitCode}. + * Method start. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitCode}. */ public abstract void visitCode(); /** - * Method stack frame. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFrame}. + * Method stack frame. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFrame}. + * + * Visits the current state of the local variables and operand stack + * elements. This method must(*) be called just before any + * instruction i that follows an unconditional branch instruction + * such as GOTO or THROW, that is the target of a jump instruction, or that + * starts an exception handler block. The visited types must describe the + * values of the local variables and of the operand stack elements just + * before i is executed.
      + *
      + * (*) this is mandatory only for classes whose version is greater than or + * equal to {@link Opcodes#V1_6 V1_6}.
      + *
      + * The frames of a method must be given either in expanded form, or in + * compressed form (all frames must use the same format, i.e. you must not + * mix expanded and compressed frames within a single method): + *
        + *
      • In expanded form, all frames must have the F_NEW type.
      • + *
      • In compressed form, frames are basically "deltas" from the state of + * the previous frame: + *
          + *
        • {@link Opcodes#F_SAME} representing frame with exactly the same + * locals as the previous frame and with the empty stack.
        • + *
        • {@link Opcodes#F_SAME1} representing frame with exactly the same + * locals as the previous frame and with single value on the stack ( + * nStack is 1 and stack[0] contains value for the + * type of the stack item).
        • + *
        • {@link Opcodes#F_APPEND} representing frame with current locals are + * the same as the locals in the previous frame, except that additional + * locals are defined (nLocal is 1, 2 or 3 and + * local elements contains values representing added types).
        • + *
        • {@link Opcodes#F_CHOP} representing frame with current locals are the + * same as the locals in the previous frame, except that the last 1-3 locals + * are absent and with the empty stack (nLocals is 1, 2 or 3).
        • + *
        • {@link Opcodes#F_FULL} representing complete frame data.
        • + *
        + *
      • + *
      + *
      + * In both cases the first frame, corresponding to the method's parameters + * and access flags, is implicit and must not be visited. Also, it is + * illegal to visit two or more frames for the same code location (i.e., at + * least one instruction must be visited between two calls to visitFrame). + * + * @param type + * the type of this stack map frame. Must be + * {@link Opcodes#F_NEW} for expanded frames, or + * {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, + * {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or + * {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for + * compressed frames. + * @param nLocal + * the number of local variables in the visited frame. + * @param local + * the local variable types in this frame. This array must not be + * modified. Primitive types are represented by + * {@link Opcodes#TOP}, {@link Opcodes#INTEGER}, + * {@link Opcodes#FLOAT}, {@link Opcodes#LONG}, + * {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or + * {@link Opcodes#UNINITIALIZED_THIS} (long and double are + * represented by a single element). Reference types are + * represented by String objects (representing internal names), + * and uninitialized types by Label objects (this label + * designates the NEW instruction that created this uninitialized + * value). + * @param nStack + * the number of operand stack elements in the visited frame. + * @param stack + * the operand stack types in this frame. This array must not be + * modified. Its content has the same format as the "local" + * array. + * @throws IllegalStateException + * if a frame is visited just after another one, without any + * instruction between the two (unless this frame is a + * Opcodes#F_SAME frame, in which case it is silently ignored). */ public abstract void visitFrame(final int type, final int nLocal, final Object[] local, final int nStack, final Object[] stack); /** - * Method instruction. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsn} - * . + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsn} + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, + * ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1, + * FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, + * LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, + * IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, + * SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, + * DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, + * IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM, + * FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, + * IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, + * L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S, + * LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN, + * DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, + * or MONITOREXIT. */ public abstract void visitInsn(final int opcode); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIntInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIntInsn}. + * + * @param opcode + * the opcode of the instruction to be visited. This opcode is + * either BIPUSH, SIPUSH or NEWARRAY. + * @param operand + * the operand of the instruction to be visited.
      + * When opcode is BIPUSH, operand value should be between + * Byte.MIN_VALUE and Byte.MAX_VALUE.
      + * When opcode is SIPUSH, operand value should be between + * Short.MIN_VALUE and Short.MAX_VALUE.
      + * When opcode is NEWARRAY, operand value should be one of + * {@link Opcodes#T_BOOLEAN}, {@link Opcodes#T_CHAR}, + * {@link Opcodes#T_FLOAT}, {@link Opcodes#T_DOUBLE}, + * {@link Opcodes#T_BYTE}, {@link Opcodes#T_SHORT}, + * {@link Opcodes#T_INT} or {@link Opcodes#T_LONG}. */ public abstract void visitIntInsn(final int opcode, final int operand); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitVarInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitVarInsn}. + * + * @param opcode + * the opcode of the local variable instruction to be visited. + * This opcode is either ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, + * ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET. + * @param var + * the operand of the instruction to be visited. This operand is + * the index of a local variable. */ public abstract void visitVarInsn(final int opcode, final int var); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTypeInsn}. + * + /** + * Visits a type instruction. A type instruction is an instruction that + * takes the internal name of a class as parameter. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. + * @param type + * the operand of the instruction to be visited. This operand + * must be the internal name of an object or array class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). */ public abstract void visitTypeInsn(final int opcode, final String type); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitFieldInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. + * @param owner + * the internal name of the field's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the field's name. + * @param desc + * the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). */ public abstract void visitFieldInsn(final int opcode, final String owner, final String name, final String desc); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). */ @Deprecated public void visitMethodInsn(final int opcode, final String owner, @@ -413,8 +797,22 @@ public abstract class Printer { } /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMethodInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or + * INVOKEINTERFACE. + * @param owner + * the internal name of the method's owner class (see + * {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param itf + * if the method's owner class is an interface. */ public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) { @@ -430,59 +828,181 @@ public abstract class Printer { } /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInvokeDynamicInsn}. + * + * Visits an invokedynamic instruction. + * + * @param name + * the method's name. + * @param desc + * the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param bsm + * the bootstrap method. + * @param bsmArgs + * the bootstrap method constant arguments. Each argument must be + * an {@link Integer}, {@link Float}, {@link Long}, + * {@link Double}, {@link String}, {@link jdk.internal.org.objectweb.asm.Type} or {@link Handle} + * value. This method is allowed to modify the content of the + * array so a caller should expect that this array may change. */ public abstract void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * Method jump instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitJumpInsn}. + * + * @param opcode + * the opcode of the type instruction to be visited. This opcode + * is either IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, + * IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, + * IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL. + * @param label + * the operand of the instruction to be visited. This operand is + * a label that designates the instruction to which the jump + * instruction may jump. */ public abstract void visitJumpInsn(final int opcode, final Label label); /** - * Method label. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLabel}. + * Method label. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLabel}. + * + * @param label + * a {@link Label Label} object. */ public abstract void visitLabel(final Label label); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLdcInsn}. + * + * Visits a LDC instruction. Note that new constant types may be added in + * future versions of the Java Virtual Machine. To easily detect new + * constant types, implementations of this method should check for + * unexpected constant types, like this: + * + *
      +     * if (cst instanceof Integer) {
      +     *     // ...
      +     * } else if (cst instanceof Float) {
      +     *     // ...
      +     * } else if (cst instanceof Long) {
      +     *     // ...
      +     * } else if (cst instanceof Double) {
      +     *     // ...
      +     * } else if (cst instanceof String) {
      +     *     // ...
      +     * } else if (cst instanceof Type) {
      +     *     int sort = ((Type) cst).getSort();
      +     *     if (sort == Type.OBJECT) {
      +     *         // ...
      +     *     } else if (sort == Type.ARRAY) {
      +     *         // ...
      +     *     } else if (sort == Type.METHOD) {
      +     *         // ...
      +     *     } else {
      +     *         // throw an exception
      +     *     }
      +     * } else if (cst instanceof Handle) {
      +     *     // ...
      +     * } else {
      +     *     // throw an exception
      +     * }
      +     * 
      + * + * @param cst + * the constant to be loaded on the stack. This parameter must be + * a non null {@link Integer}, a {@link Float}, a {@link Long}, a + * {@link Double}, a {@link String}, a {@link jdk.internal.org.objectweb.asm.Type} + * of OBJECT or ARRAY sort for .class constants, for classes whose + * version is 49.0, a {@link jdk.internal.org.objectweb.asm.Type} of METHOD sort or a + * {@link Handle} for MethodType and MethodHandle constants, for + * classes whose version is 51.0. */ public abstract void visitLdcInsn(final Object cst); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIincInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitIincInsn}. + * + * @param var + * index of the local variable to be incremented. + * @param increment + * amount to increment the local variable by. */ public abstract void visitIincInsn(final int var, final int increment); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTableSwitchInsn}. + * + * @param min + * the minimum key value. + * @param max + * the maximum key value. + * @param dflt + * beginning of the default handler block. + * @param labels + * beginnings of the handler blocks. labels[i] is the + * beginning of the handler block for the min + i key. */ public abstract void visitTableSwitchInsn(final int min, final int max, final Label dflt, final Label... labels); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLookupSwitchInsn}. + * + * @param dflt + * beginning of the default handler block. + * @param keys + * the values of the keys. + * @param labels + * beginnings of the handler blocks. labels[i] is the + * beginning of the handler block for the keys[i] key. */ public abstract void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels); /** - * Method instruction. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * Method instruction. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMultiANewArrayInsn}. + * + * @param desc + * an array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type Type}). + * @param dims + * number of dimensions of the array to allocate. */ public abstract void visitMultiANewArrayInsn(final String desc, final int dims); /** - * Instruction type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsnAnnotation}. + * Instruction type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitInsnAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#INSTANCEOF INSTANCEOF}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#NEW NEW}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_REFERENCE METHOD_REFERENCE}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CAST CAST}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, + * {@link jdk.internal.org.objectweb.asm.TypeReference#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, + * or {@link jdk.internal.org.objectweb.asm.TypeReference#METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitInsnAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -490,15 +1010,44 @@ public abstract class Printer { } /** - * Method exception handler. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * Method exception handler. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchBlock}. + * + * @param start + * beginning of the exception handler's scope (inclusive). + * @param end + * end of the exception handler's scope (exclusive). + * @param handler + * beginning of the exception handler's code. + * @param type + * internal name of the type of exceptions handled by the + * handler, or null to catch any exceptions (for + * "finally" blocks). + * @throws IllegalArgumentException + * if one of the labels has already been visited by this visitor + * (by the {@link #visitLabel visitLabel} method). */ public abstract void visitTryCatchBlock(final Label start, final Label end, final Label handler, final String type); /** - * Try catch block type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * Try catch block type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#EXCEPTION_PARAMETER + * EXCEPTION_PARAMETER}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitTryCatchAnnotation(final int typeRef, final TypePath typePath, final String desc, final boolean visible) { @@ -506,16 +1055,62 @@ public abstract class Printer { } /** - * Method debug info. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * Method debug info. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable}. + * + * @param name + * the name of a local variable. + * @param desc + * the type descriptor of this local variable. + * @param signature + * the type signature of this local variable. May be + * null if the local variable type does not use generic + * types. + * @param start + * the first instruction corresponding to the scope of this local + * variable (inclusive). + * @param end + * the last instruction corresponding to the scope of this local + * variable (exclusive). + * @param index + * the local variable's index. + * @throws IllegalArgumentException + * if one of the labels has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public abstract void visitLocalVariable(final String name, final String desc, final String signature, final Label start, final Label end, final int index); /** - * Local variable type annotation. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * Local variable type annotation. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitTryCatchAnnotation}. + * + * @param typeRef + * a reference to the annotated type. The sort of this type + * reference must be {@link jdk.internal.org.objectweb.asm.TypeReference#LOCAL_VARIABLE + * LOCAL_VARIABLE} or {@link jdk.internal.org.objectweb.asm.TypeReference#RESOURCE_VARIABLE + * RESOURCE_VARIABLE}. + * See {@link jdk.internal.org.objectweb.asm.TypeReference}. + * @param typePath + * the path to the annotated type argument, wildcard bound, array + * element type, or static inner type within 'typeRef'. May be + * null if the annotation targets 'typeRef' as a whole. + * @param start + * the fist instructions corresponding to the continuous ranges + * that make the scope of this local variable (inclusive). + * @param end + * the last instructions corresponding to the continuous ranges + * that make the scope of this local variable (exclusive). This + * array must have the same size as the 'start' array. + * @param index + * the local variable's index in each range. This array must have + * the same size as the 'start' array. + * @param desc + * the class descriptor of the annotation class. + * @param visible + * true if the annotation is visible at runtime. + * @return the printer */ public Printer visitLocalVariableAnnotation(final int typeRef, final TypePath typePath, final Label[] start, final Label[] end, @@ -524,19 +1119,34 @@ public abstract class Printer { } /** - * Method debug info. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLineNumber}. + * Method debug info. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLineNumber}. + * + * @param line + * a line number. This number refers to the source file from + * which the class was compiled. + * @param start + * the first instruction corresponding to this line number. + * @throws IllegalArgumentException + * if start has not already been visited by this + * visitor (by the {@link #visitLabel visitLabel} method). */ public abstract void visitLineNumber(final int line, final Label start); /** - * Method max stack and max locals. See - * {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMaxs}. + * Method max stack and max locals. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitMaxs}. + * + * @param maxStack + * maximum stack size of the method. + * @param maxLocals + * maximum number of local variables for the method. */ public abstract void visitMaxs(final int maxStack, final int maxLocals); /** - * Method end. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitEnd}. + * Method end. + * See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitEnd}. */ public abstract void visitMethodEnd(); diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java index 97163ce47f1..e927bff9ea5 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceClassVisitor.java @@ -74,34 +74,36 @@ import jdk.internal.org.objectweb.asm.TypePath; * visitor chain to trace the class that is visited at a given point in this * chain. This may be useful for debugging purposes. *

      - * The trace printed when visiting the {@code Hello} class is the following: + * The trace printed when visiting the Hello class is the following: + *

      *

      * - *
      {@code
      + * 
        * // class version 49.0 (49) // access flags 0x21 public class Hello {
        *
        * // compiled from: Hello.java
        *
      - * // access flags 0x1 public  ()V ALOAD 0 INVOKESPECIAL
      - * java/lang/Object  ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
      + * // access flags 0x1 public <init> ()V ALOAD 0 INVOKESPECIAL
      + * java/lang/Object <init> ()V RETURN MAXSTACK = 1 MAXLOCALS = 1
        *
        * // access flags 0x9 public static main ([Ljava/lang/String;)V GETSTATIC
      - * java/lang/System out Ljava/io/PrintStream; LDC "hello"
      + * java/lang/System out Ljava/io/PrintStream; LDC "hello"
        * INVOKEVIRTUAL java/io/PrintStream println (Ljava/lang/String;)V RETURN
        * MAXSTACK = 2 MAXLOCALS = 1 }
      - * }
      + *
      * - *
      where {@code Hello} is defined by: + * where Hello is defined by: + *

      *

      * - *
      {@code
      + * 
        * public class Hello {
        *
        *     public static void main(String[] args) {
      - *         System.out.println("hello");
      + *         System.out.println("hello");
        *     }
        * }
      - * }
      + *
      * *
      * @@ -135,7 +137,7 @@ public final class TraceClassVisitor extends ClassVisitor { * * @param cv * the {@link ClassVisitor} to which this visitor delegates - * calls. May be {@code null}. + * calls. May be null. * @param pw * the print writer to be used to print the class. */ @@ -148,7 +150,7 @@ public final class TraceClassVisitor extends ClassVisitor { * * @param cv * the {@link ClassVisitor} to which this visitor delegates - * calls. May be {@code null}. + * calls. May be null. * @param p * the object that actually converts visit events into text. * @param pw diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java index f4925846c59..ef78b14b8a2 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceSignatureVisitor.java @@ -70,7 +70,7 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; */ public final class TraceSignatureVisitor extends SignatureVisitor { - private final StringBuffer declaration; + private final StringBuilder declaration; private boolean isInterface; @@ -82,9 +82,9 @@ public final class TraceSignatureVisitor extends SignatureVisitor { private boolean seenInterface; - private StringBuffer returnType; + private StringBuilder returnType; - private StringBuffer exceptions; + private StringBuilder exceptions; /** * Stack used to keep track of class types that have arguments. Each element @@ -106,10 +106,10 @@ public final class TraceSignatureVisitor extends SignatureVisitor { public TraceSignatureVisitor(final int access) { super(Opcodes.ASM5); isInterface = (access & Opcodes.ACC_INTERFACE) != 0; - this.declaration = new StringBuffer(); + this.declaration = new StringBuilder(); } - private TraceSignatureVisitor(final StringBuffer buf) { + private TraceSignatureVisitor(final StringBuilder buf) { super(Opcodes.ASM5); this.declaration = buf; } @@ -175,14 +175,14 @@ public final class TraceSignatureVisitor extends SignatureVisitor { declaration.append('('); } declaration.append(')'); - returnType = new StringBuffer(); + returnType = new StringBuilder(); return new TraceSignatureVisitor(returnType); } @Override public SignatureVisitor visitExceptionType() { if (exceptions == null) { - exceptions = new StringBuffer(); + exceptions = new StringBuilder(); } else { exceptions.append(", "); } diff --git a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt index 5ba3a332b48..5c62bb6faf9 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt +++ b/jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm/version.txt @@ -1,12 +1,12 @@ Path: . -Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2014-10-15 +Working Copy Root Path: /hudson/jobs/objectweb-init/workspace/asm-svn-2016-01-25 URL: file:///svnroot/asm/trunk/asm Repository Root: file:///svnroot/asm Repository UUID: 271bd773-ee82-43a6-9b2b-1890ed8ce7f9 -Revision: 1772 +Revision: 1795 Node Kind: directory Schedule: normal Last Changed Author: ebruneton -Last Changed Rev: 1772 -Last Changed Date: 2014-09-06 09:13:07 +0200 (Sat, 06 Sep 2014) +Last Changed Rev: 1795 +Last Changed Date: 2016-01-24 14:17:10 +0100 (Sun, 24 Jan 2016) diff --git a/jdk/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java b/jdk/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java index 1c0d0a1f341..790bbeb7e48 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java +++ b/jdk/src/java.base/share/classes/jdk/internal/perf/PerfCounter.java @@ -67,11 +67,11 @@ public class PerfCounter { this.lb = bb.asLongBuffer(); } - static PerfCounter newPerfCounter(String name) { + public static PerfCounter newPerfCounter(String name) { return new PerfCounter(name, V_Variable); } - static PerfCounter newConstantPerfCounter(String name) { + public static PerfCounter newConstantPerfCounter(String name) { PerfCounter c = new PerfCounter(name, V_Constant); return c; } diff --git a/jdk/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat b/jdk/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat new file mode 100644 index 00000000000..a634d5b03d4 --- /dev/null +++ b/jdk/src/java.base/share/classes/jdk/internal/vm/cds/resources/ModuleLoaderMap.dat @@ -0,0 +1,4 @@ +BOOT +@@BOOT_MODULE_NAMES@@ +PLATFORM +@@PLATFORM_MODULE_NAMES@@ diff --git a/jdk/src/java.base/share/classes/module-info.java b/jdk/src/java.base/share/classes/module-info.java new file mode 100644 index 00000000000..f54043d888e --- /dev/null +++ b/jdk/src/java.base/share/classes/module-info.java @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +/** + * java.base defines and exports the core APIs of the Java SE platform. + */ + +module java.base { + + exports java.io; + exports java.lang; + exports java.lang.annotation; + exports java.lang.invoke; + exports java.lang.module; + exports java.lang.ref; + exports java.lang.reflect; + exports java.math; + exports java.net; + exports java.net.spi; + exports java.nio; + exports java.nio.channels; + exports java.nio.channels.spi; + exports java.nio.charset; + exports java.nio.charset.spi; + exports java.nio.file; + exports java.nio.file.attribute; + exports java.nio.file.spi; + exports java.security; + exports java.security.acl; + exports java.security.cert; + exports java.security.interfaces; + exports java.security.spec; + exports java.text; + exports java.text.spi; + exports java.time; + exports java.time.chrono; + exports java.time.format; + exports java.time.temporal; + exports java.time.zone; + exports java.util; + exports java.util.concurrent; + exports java.util.concurrent.atomic; + exports java.util.concurrent.locks; + exports java.util.function; + exports java.util.jar; + exports java.util.regex; + exports java.util.spi; + exports java.util.stream; + exports java.util.zip; + exports javax.crypto; + exports javax.crypto.interfaces; + exports javax.crypto.spec; + exports javax.net; + exports javax.net.ssl; + exports javax.security.auth; + exports javax.security.auth.callback; + exports javax.security.auth.login; + exports javax.security.auth.spi; + exports javax.security.auth.x500; + exports javax.security.cert; + + // see JDK-8144062 + exports jdk; + // see JDK-8044773 + exports jdk.net; + + // These will move to a jdk.internal module via JEP-260 + exports sun.misc; + exports sun.reflect; + + + // the service types defined by the APIs in this module + + uses java.lang.System.LoggerFinder; + uses java.net.ContentHandlerFactory; + uses java.net.spi.URLStreamHandlerProvider; + uses java.nio.channels.spi.AsynchronousChannelProvider; + uses java.nio.channels.spi.SelectorProvider; + uses java.nio.charset.spi.CharsetProvider; + uses java.nio.file.spi.FileSystemProvider; + uses java.nio.file.spi.FileTypeDetector; + uses java.security.Provider; + uses java.text.spi.BreakIteratorProvider; + uses java.text.spi.CollatorProvider; + uses java.text.spi.DateFormatProvider; + uses java.text.spi.DateFormatSymbolsProvider; + uses java.text.spi.DecimalFormatSymbolsProvider; + uses java.text.spi.NumberFormatProvider; + uses java.time.chrono.AbstractChronology; + uses java.time.chrono.Chronology; + uses java.time.zone.ZoneRulesProvider; + uses java.util.spi.CalendarDataProvider; + uses java.util.spi.CalendarNameProvider; + uses java.util.spi.CurrencyNameProvider; + uses java.util.spi.LocaleNameProvider; + uses java.util.spi.ResourceBundleControlProvider; + uses java.util.spi.ResourceBundleProvider; + uses java.util.spi.TimeZoneNameProvider; + uses javax.security.auth.spi.LoginModule; + + + // additional qualified exports may be inserted at build time + // see make/gensrc/GenModuleInfo.gmk + + // CORBA serialization needs reflective access + exports sun.util.calendar to + java.corba; + + exports com.sun.security.ntlm to + java.security.sasl; + exports jdk.internal.jimage to + jdk.jlink; + exports jdk.internal.jimage.decompressor to + jdk.jlink; + exports jdk.internal.logger to + java.logging; + exports jdk.internal.org.objectweb.asm to + jdk.jlink, + jdk.scripting.nashorn, + jdk.vm.ci; + exports jdk.internal.org.objectweb.asm.tree to + jdk.jlink; + exports jdk.internal.org.objectweb.asm.util to + jdk.jlink, + jdk.scripting.nashorn; + exports jdk.internal.org.objectweb.asm.tree.analysis to + jdk.jlink; + exports jdk.internal.org.objectweb.asm.commons to + jdk.scripting.nashorn; + exports jdk.internal.org.objectweb.asm.signature to + jdk.scripting.nashorn; + exports jdk.internal.math to + java.desktop; + exports jdk.internal.module to + java.instrument, + java.management, + java.xml, + jdk.dynalink, + jdk.jartool, + jdk.jlink, + jdk.scripting.nashorn; + exports jdk.internal.misc to + java.corba, + java.desktop, + java.logging, + java.management, + java.naming, + java.rmi, + java.security.jgss, + java.sql, + java.xml, + jdk.charsets, + jdk.scripting.nashorn, + jdk.vm.ci; + exports jdk.internal.perf to + java.desktop, + java.management, + jdk.jvmstat; + exports jdk.internal.ref to + java.desktop; + exports sun.net to + java.httpclient; + exports sun.net.dns to + java.security.jgss, + jdk.naming.dns; + exports sun.net.spi.nameservice to + jdk.naming.dns; + exports sun.net.util to + java.desktop, + jdk.jconsole, + jdk.naming.dns; + exports sun.net.www to + java.desktop, + jdk.jartool; + exports sun.net.www.protocol.http to + java.security.jgss; + exports sun.nio.ch to + java.management, + jdk.crypto.pkcs11, + jdk.sctp; + exports sun.nio.cs to + java.desktop, + jdk.charsets; + exports sun.reflect.annotation to + jdk.compiler; + exports sun.reflect.generics.reflectiveObjects to + java.desktop; + exports sun.reflect.misc to + java.corba, + java.desktop, + java.datatransfer, + java.management, + java.rmi, + java.sql.rowset, + java.xml, + java.xml.ws; + exports sun.security.action to + java.desktop, + java.security.jgss, + jdk.crypto.pkcs11; + exports sun.security.internal.interfaces to + jdk.crypto.pkcs11; + exports sun.security.internal.spec to + jdk.crypto.pkcs11; + exports sun.security.jca to + java.smartcardio, + java.xml.crypto, + jdk.crypto.ec, + jdk.crypto.pkcs11, + jdk.naming.dns; + exports sun.security.pkcs to + jdk.crypto.ec, + jdk.jartool; + exports sun.security.provider to + java.rmi, + java.security.jgss, + jdk.crypto.pkcs11, + jdk.policytool, + jdk.security.auth; + exports sun.security.provider.certpath to + java.naming; + exports sun.security.rsa to + jdk.crypto.pkcs11; + exports sun.security.ssl to + java.security.jgss; + exports sun.security.tools to + jdk.jartool; + exports sun.security.util to + java.desktop, + java.naming, + java.rmi, + java.security.jgss, + java.security.sasl, + java.smartcardio, + jdk.crypto.ec, + jdk.crypto.pkcs11, + jdk.jartool, + jdk.policytool, + jdk.security.auth, + jdk.security.jgss; + exports sun.security.x509 to + jdk.crypto.ec, + jdk.crypto.pkcs11, + jdk.jartool, + jdk.security.auth; + exports sun.text.resources to + jdk.localedata; + exports sun.util.resources to + jdk.localedata; + exports sun.util.locale.provider to + java.desktop, + jdk.localedata; + exports sun.util.logging to + java.desktop, + java.httpclient, + java.logging, + java.prefs; + + // JDK-internal service types + uses jdk.internal.logger.DefaultLoggerFinder; + uses sun.net.spi.nameservice.NameServiceDescriptor; + uses sun.security.ssl.ClientKeyExchangeService; + uses sun.util.spi.CalendarProvider; + uses sun.util.locale.provider.LocaleDataMetaInfo; + uses sun.util.resources.LocaleData.CommonResourceBundleProvider; + uses sun.util.resources.LocaleData.SupplementaryResourceBundleProvider; + + + // Built-in service providers that are located via ServiceLoader + + provides java.nio.file.spi.FileSystemProvider with + jdk.internal.jrtfs.JrtFileSystemProvider; + provides java.security.Provider with sun.security.provider.Sun; + provides java.security.Provider with sun.security.rsa.SunRsaSign; + provides java.security.Provider with com.sun.crypto.provider.SunJCE; + provides java.security.Provider with com.sun.net.ssl.internal.ssl.Provider; +} + 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 e10d2e1117f..2d6b234a63d 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 @@ -27,6 +27,7 @@ package sun.invoke.util; import java.lang.reflect.Modifier; import static java.lang.reflect.Modifier.*; +import java.lang.reflect.Module; import sun.reflect.Reflection; /** @@ -37,6 +38,7 @@ public class VerifyAccess { private VerifyAccess() { } // cannot instantiate + 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; private static final int PROTECTED_OR_PACKAGE_ALLOWED = (PACKAGE_ALLOWED|PROTECTED); @@ -89,7 +91,7 @@ public class VerifyAccess { int allowedModes) { if (allowedModes == 0) return false; assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0); + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0); // The symbolic reference class (refc) must always be fully verified. if (!isClassAccessible(refc, lookupClass, allowedModes)) { return false; @@ -157,8 +159,10 @@ public class VerifyAccess { * Evaluate the JVM linkage rules for access to the given class on behalf of caller. *

      JVM Specification, 5.4.4 "Access Control"

      * A class or interface C is accessible to a class or interface D - * if and only if either of the following conditions are true:
        - *
      • C is public. + * if and only if any of the following conditions are true:
          + *
        • C is public and in the same module as D. + *
        • D is in a module that reads the module containing C, C is public and in a + * package that is exported to the module that contains D. *
        • C and D are members of the same runtime package. *
        * @param refc the symbolic reference class to which access is being checked (C) @@ -168,10 +172,52 @@ public class VerifyAccess { int allowedModes) { if (allowedModes == 0) return false; assert((allowedModes & PUBLIC) != 0 && - (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED)) == 0); + (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0); int mods = getClassModifiers(refc); - if (isPublic(mods)) - return true; + if (isPublic(mods)) { + + Module lookupModule = lookupClass.getModule(); + Module refModule = refc.getModule(); + + // early VM startup case, java.base not defined + if (lookupModule == null) { + assert refModule == null; + return true; + } + + // trivially allow + if ((allowedModes & MODULE_ALLOWED) != 0 && + (lookupModule == refModule)) + return true; + + // check readability + if (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)) + return true; + } else { + // exported unconditionally + if (refModule.isExported(c.getPackageName())) + return true; + } + + // not exported but allow access during VM initialization + // because java.base does not have its exports setup + if (!jdk.internal.misc.VM.isModuleSystemInited()) + return true; + } + + // public class not accessible to lookupClass + return false; + } if ((allowedModes & PACKAGE_ALLOWED) != 0 && isSamePackage(lookupClass, refc)) return true; @@ -218,6 +264,16 @@ public class VerifyAccess { return true; } + /** + * Tests if two classes are in the same module. + * @param class1 a class + * @param class2 another class + * @return whether they are in the same module + */ + public static boolean isSameModule(Class class1, Class class2) { + return class1.getModule() == class2.getModule(); + } + /** * Test if two classes have the same class loader and package qualifier. * @param class1 a class @@ -244,10 +300,10 @@ public class VerifyAccess { /** Return the package name for this class. */ public static String getPackageName(Class cls) { - assert(!cls.isArray()); + assert (!cls.isArray()); String name = cls.getName(); int dot = name.lastIndexOf('.'); - if (dot < 0) return ""; + if (dot < 0) return ""; return name.substring(0, dot); } 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 3f9e3668e69..e8a4b78cff5 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java +++ b/jdk/src/java.base/share/classes/sun/launcher/LauncherHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -43,24 +43,39 @@ import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.reflect.Layer; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Module; import java.math.BigDecimal; import java.math.RoundingMode; +import java.net.URI; import java.nio.charset.Charset; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.text.Normalizer; -import java.util.ResourceBundle; import java.text.MessageFormat; +import java.util.ResourceBundle; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Locale.Category; +import java.util.Optional; import java.util.Properties; +import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.jar.Attributes; @@ -68,6 +83,7 @@ import java.util.jar.JarFile; import java.util.jar.Manifest; import jdk.internal.misc.VM; + public enum LauncherHelper { INSTANCE; @@ -98,7 +114,6 @@ public enum LauncherHelper { ResourceBundle.getBundle(defaultBundleName); } private static PrintStream ostream; - private static final ClassLoader scloader = ClassLoader.getSystemClassLoader(); private static Class appClass; // application class, for GUI/reporting purposes /* @@ -439,11 +454,12 @@ public enum LauncherHelper { } // From src/share/bin/java.c: - // enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR }; + // enum LaunchMode { LM_UNKNOWN = 0, LM_CLASS, LM_JAR, LM_MODULE } private static final int LM_UNKNOWN = 0; private static final int LM_CLASS = 1; private static final int LM_JAR = 2; + private static final int LM_MODULE = 3; static void abort(Throwable t, String msgKey, Object... args) { if (msgKey != null) { @@ -460,33 +476,95 @@ public enum LauncherHelper { } /** - * This method does the following: - * 1. gets the classname from a Jar's manifest, if necessary - * 2. loads the class using the System ClassLoader - * 3. ensures the availability and accessibility of the main method, - * using signatureDiagnostic method. - * a. does the class exist - * b. is there a main - * c. is the main public - * d. is the main static - * e. does the main take a String array for args - * 4. if no main method and if the class extends FX Application, then call - * on FXHelper to determine the main class to launch - * 5. and off we go...... + * This method: + * 1. Loads the main class from the module or class path + * 2. Checks the public static void main method. * * @param printToStderr if set, all output will be routed to stderr * @param mode LaunchMode as determined by the arguments passed on the - * command line - * @param what either the jar file to launch or the main class when using - * LM_CLASS mode + * command line + * @param what the module name[/class], JAR file, or the main class + * depending on the mode + * * @return the application's main class */ public static Class checkAndLoadMain(boolean printToStderr, int mode, String what) { initOutput(printToStderr); + + Class mainClass = (mode == LM_MODULE) ? loadModuleMainClass(what) + : loadMainClass(mode, what); + + validateMainClass(mainClass); + + // record main class if not already set + if (appClass == null) + appClass = mainClass; + + return mainClass; + } + + /** + * Returns the main class for a module. The query is either a module name + * or module-name/main-class. For the former then the module's main class + * is obtained from the module descriptor (MainClass attribute). + */ + private static Class loadModuleMainClass(String what) { + int i = what.indexOf('/'); + String mainModule; + String mainClass; + if (i == -1) { + mainModule = what; + mainClass = null; + } else { + mainModule = what.substring(0, i); + mainClass = what.substring(i+1); + } + + // main module is in the boot layer + Layer layer = Layer.boot(); + Optional om = layer.findModule(mainModule); + if (!om.isPresent()) { + // should not happen + throw new InternalError("Module " + mainModule + " not in boot Layer"); + } + Module m = om.get(); + + // get main class + if (mainClass == null) { + Optional omc = m.getDescriptor().mainClass(); + if (!omc.isPresent()) { + abort(null, "java.launcher.module.error1", mainModule); + } + mainClass = omc.get(); + } + + // load the class from the module + Class c = Class.forName(m, mainClass); + if (c == null && System.getProperty("os.name", "").contains("OS X") + && Normalizer.isNormalized(mainClass, Normalizer.Form.NFD)) { + + String cn = Normalizer.normalize(mainClass, Normalizer.Form.NFC); + c = Class.forName(m, cn); + + } + if (c == null) { + abort(null, "java.launcher.module.error2", mainClass, mainModule); + } + + System.setProperty("jdk.module.main.class", c.getName()); + return c; + } + + /** + * Loads the main class from the class path (LM_CLASS or LM_JAR). + * If the main class extends FX Application then call on FXHelper to + * determine the main class to launch. + */ + private static Class loadMainClass(int mode, String what) { // get the class name - String cn = null; + String cn; switch (mode) { case LM_CLASS: cn = what; @@ -498,18 +576,21 @@ public enum LauncherHelper { // should never happen throw new InternalError("" + mode + ": Unknown launch mode"); } + + // load the main class cn = cn.replace('/', '.'); Class mainClass = null; + ClassLoader scl = ClassLoader.getSystemClassLoader(); try { - mainClass = scloader.loadClass(cn); + mainClass = scl.loadClass(cn); } catch (NoClassDefFoundError | ClassNotFoundException cnfe) { if (System.getProperty("os.name", "").contains("OS X") - && Normalizer.isNormalized(cn, Normalizer.Form.NFD)) { + && Normalizer.isNormalized(cn, Normalizer.Form.NFD)) { try { // On Mac OS X since all names with diacretic symbols are given as decomposed it // is possible that main class name comes incorrectly from the command line // and we have to re-compose it - mainClass = scloader.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC)); + mainClass = scl.loadClass(Normalizer.normalize(cn, Normalizer.Form.NFC)); } catch (NoClassDefFoundError | ClassNotFoundException cnfe1) { abort(cnfe, "java.launcher.cls.error1", cn); } @@ -517,7 +598,8 @@ public enum LauncherHelper { abort(cnfe, "java.launcher.cls.error1", cn); } } - // set to mainClass + + // record the main class appClass = mainClass; /* @@ -531,8 +613,6 @@ public enum LauncherHelper { FXHelper.setFXLaunchParameters(what, mode); return FXHelper.class; } - - validateMainClass(mainClass); return mainClass; } @@ -693,6 +773,9 @@ public enum LauncherHelper { static final class FXHelper { + private static final String JAVAFX_GRAPHICS_MODULE_NAME = + "javafx.graphics"; + private static final String JAVAFX_LAUNCHER_CLASS_NAME = "com.sun.javafx.application.LauncherImpl"; @@ -725,9 +808,20 @@ public enum LauncherHelper { * issue with loading the FX runtime or with the launcher method. */ private static void setFXLaunchParameters(String what, int mode) { - // Check for the FX launcher classes + + // find the module with the FX launcher + Optional om = Layer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME); + if (!om.isPresent()) { + abort(null, "java.launcher.cls.error5"); + } + + // load the FX launcher class + fxLauncherClass = Class.forName(om.get(), JAVAFX_LAUNCHER_CLASS_NAME); + if (fxLauncherClass == null) { + abort(null, "java.launcher.cls.error5"); + } + try { - fxLauncherClass = scloader.loadClass(JAVAFX_LAUNCHER_CLASS_NAME); /* * signature must be: * public static void launchApplication(String launchName, @@ -744,7 +838,7 @@ public enum LauncherHelper { if (fxLauncherMethod.getReturnType() != java.lang.Void.TYPE) { abort(null, "java.launcher.javafx.error1"); } - } catch (ClassNotFoundException | NoSuchMethodException ex) { + } catch (NoSuchMethodException ex) { abort(ex, "java.launcher.cls.error5", ex); } @@ -773,4 +867,97 @@ public enum LauncherHelper { new Object[] {fxLaunchName, fxLaunchMode, args}); } } + + private static void formatCommaList(PrintStream out, + String prefix, + Collection list) + { + if (list.isEmpty()) + return; + out.format("%s", prefix); + boolean first = true; + for (Object ob : list) { + if (first) { + out.format(" %s", ob); + first = false; + } else { + out.format(", %s", ob); + } + } + out.format("%n"); + } + + /** + * Called by the launcher to list the observable modules. + * If called without any sub-options then the output is a simple list of + * the modules. If called with sub-options then the sub-options are the + * names of the modules to list (-listmods:java.base,java.desktop for + * example). + */ + static void listModules(boolean printToStderr, String optionFlag) + throws IOException, ClassNotFoundException + { + initOutput(printToStderr); + + ModuleFinder finder = jdk.internal.module.ModuleBootstrap.finder(); + + int colon = optionFlag.indexOf(':'); + if (colon == -1) { + finder.findAll().stream() + .sorted(Comparator.comparing(ModuleReference::descriptor)) + .forEach(md -> { + ostream.println(midAndLocation(md.descriptor(), + md.location())); + }); + } else { + String[] names = optionFlag.substring(colon+1).split(","); + for (String name: names) { + ModuleReference mref = finder.find(name).orElse(null); + if (mref == null) { + // not found + continue; + } + + ModuleDescriptor md = mref.descriptor(); + ostream.println(midAndLocation(md, mref.location())); + + for (Requires d : md.requires()) { + ostream.format(" requires %s%n", d); + } + for (String s : md.uses()) { + ostream.format(" uses %s%n", s); + } + + // sorted exports + Set exports = new TreeSet<>(Comparator.comparing(Exports::source)); + exports.addAll(md.exports()); + for (Exports e : exports) { + ostream.format(" exports %s", e.source()); + if (e.isQualified()) { + formatCommaList(ostream, " to", e.targets()); + } else { + ostream.println(); + } + } + + // concealed packages + new TreeSet<>(md.conceals()) + .forEach(p -> ostream.format(" conceals %s%n", p)); + + Map provides = md.provides(); + for (Provides ps : provides.values()) { + for (String impl : ps.providers()) + ostream.format(" provides %s with %s%n", ps.service(), impl); + } + } + } + } + + static String midAndLocation(ModuleDescriptor md, Optional location ) { + URI loc = location.orElse(null); + if (loc == null || loc.getScheme().equalsIgnoreCase("jrt")) + return md.toNameAndVersion(); + else + return md.toNameAndVersion() + " (" + loc + ")"; + } } diff --git a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties index 7809020beed..52d621b414d 100644 --- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -27,6 +27,8 @@ java.launcher.opt.header = Usage: {0} [options] class [args...]\n\ \ (to execute a class)\n or {0} [options] -jar jarfile [args...]\n\ \ (to execute a jar file)\n\ +\ or {0} [-options] -mp -m | /\n\ +\ (to execute the main class in a module)\n\ where options include:\n java.launcher.opt.datamodel =\ -d{0}\t use a {0}-bit data model if available\n @@ -41,6 +43,22 @@ java.launcher.opt.footer =\ -cp \n\ \ A {0} separated list of directories, JAR archives,\n\ \ and ZIP archives to search for class files.\n\ +\ -mp \n\ +\ -modulepath ...\n\ +\ A {0} separated list of directories, each directory\n\ +\ is a directory of modules.\n\ +\ -upgrademodulepath ...\n\ +\ A {0} separated list of directories, each directory\n\ +\ is a directory of modules that replace upgradeable\n\ +\ modules in the runtime image\n\ +\ -m | /\n\ +\ the initial or main module to resolve\n\ +\ -addmods [,...]\n\ +\ root modules to resolve in addition to the initial module\n\ +\ -limitmods [,...]\n\ +\ limit the universe of observable modules\n\ +\ -listmods[:[,...]]\n\ +\ list the observable modules and exit\n\ \ -D=\n\ \ set a system property\n\ \ -verbose:[class|gc|jni]\n\ @@ -76,13 +94,10 @@ See http://www.oracle.com/technetwork/java/javase/documentation/index.html for m java.launcher.X.usage=\ \ -Xmixed mixed mode execution (default)\n\ \ -Xint interpreted mode execution only\n\ -\ -Xbootclasspath:\n\ -\ set search path for bootstrap classes and resources\n\ \ -Xbootclasspath/a:\n\ \ append to end of bootstrap class path\n\ -\ -Xbootclasspath/p:\n\ -\ prepend in front of bootstrap class path\n\ \ -Xdiag show additional diagnostic messages\n\ +\ -Xdiag:resolver show resolver diagnostic messages\n\ \ -Xnoclassgc disable class garbage collection\n\ \ -Xincgc enable incremental garbage collection\n\ \ -Xloggc: log GC status to a file with time stamps\n\ @@ -105,6 +120,15 @@ java.launcher.X.usage=\ \ show all property settings and continue\n\ \ -XshowSettings:locale\n\ \ show all locale related settings and continue\n\ +\ -XaddReads:=(,)*\n\ +\ reads other modules,\n\ +\ regardless of module declaration\n\ +\ -XaddExports:/=(,)*\n\ +\ exports to other modules,\n\ +\ regardless of module declaration\n\ +\ -Xpatch:=({0})*\n\ +\ Override or augment a module with classes and resources\n\ +\ in JAR files or directories\n\ \ -Xdisable-@files disable further argument file expansion\n\n\ The -X options are non-standard and subject to change without notice.\n @@ -142,3 +166,7 @@ java.launcher.init.error=initialization error java.launcher.javafx.error1=\ Error: The JavaFX launchApplication method has the wrong signature, it\n\ must be declared static and return a value of type void +java.launcher.module.error1=\ + module {0} does not have a MainClass attribute, use -m / +java.launcher.module.error2=\ + Error: Could not find or load main class {0} in module {1} diff --git a/jdk/src/java.base/share/classes/sun/misc/Launcher.java b/jdk/src/java.base/share/classes/sun/misc/Launcher.java deleted file mode 100644 index 3784474d671..00000000000 --- a/jdk/src/java.base/share/classes/sun/misc/Launcher.java +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.io.File; -import java.io.FilePermission; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.MalformedURLException; -import java.net.URLStreamHandler; -import java.net.URLStreamHandlerFactory; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; -import java.security.AccessControlContext; -import java.security.PermissionCollection; -import java.security.Permissions; -import java.security.Permission; -import java.security.ProtectionDomain; -import java.security.CodeSource; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import sun.net.www.ParseUtil; -import sun.security.util.SecurityConstants; - -/** - * This class is used by the system to launch the main application. -Launcher */ -public class Launcher { - - // ensure URLClassPath for boot loader is initialized first - static { - URLClassPath ucp = BootClassPathHolder.bcp; - } - - private static URLStreamHandlerFactory factory = new Factory(); - private static Launcher launcher = new Launcher(); - - public static Launcher getLauncher() { - return launcher; - } - - private ClassLoader loader; - - public Launcher() { - // Create the extension class loader - ClassLoader extcl; - try { - extcl = ExtClassLoader.getExtClassLoader(); - } catch (IOException e) { - throw new InternalError( - "Could not create extension class loader", e); - } - - // Now create the class loader to use to launch the application - try { - loader = AppClassLoader.getAppClassLoader(extcl); - } catch (IOException e) { - throw new InternalError( - "Could not create application class loader", e); - } - - // Also set the context class loader for the primordial thread. - Thread.currentThread().setContextClassLoader(loader); - - // Finally, install a security manager if requested - String s = System.getProperty("java.security.manager"); - if (s != null) { - SecurityManager sm = null; - if ("".equals(s) || "default".equals(s)) { - sm = new java.lang.SecurityManager(); - } else { - try { - sm = (SecurityManager)loader.loadClass(s).newInstance(); - } catch (IllegalAccessException e) { - } catch (InstantiationException e) { - } catch (ClassNotFoundException e) { - } catch (ClassCastException e) { - } - } - if (sm != null) { - System.setSecurityManager(sm); - } else { - throw new InternalError( - "Could not create SecurityManager: " + s); - } - } - } - - /* - * Returns the class loader used to launch the main application. - */ - public ClassLoader getClassLoader() { - return loader; - } - - /* - * The class loader used for loading installed extensions. - */ - static class ExtClassLoader extends URLClassLoader { - - static { - ClassLoader.registerAsParallelCapable(); - } - - /** - * create an ExtClassLoader. The ExtClassLoader is created - * within a context that limits which files it can read - */ - public static ExtClassLoader getExtClassLoader() throws IOException { - try { - // Prior implementations of this doPrivileged() block supplied - // aa synthesized ACC via a call to the private method - // ExtClassLoader.getContext(). - - return AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public ExtClassLoader run() throws IOException { - // ext modules linked into image - String home = System.getProperty("java.home"); - File dir = new File(new File(home, "lib"), "modules"); - File jimage = new File(dir, "extmodules.jimage"); - - File jfxrt = new File(new File(home, "lib"), "jfxrt.jar"); - File[] files = jfxrt.exists() ? new File[] {jimage, jfxrt} - : new File[] {jimage}; - return new ExtClassLoader(files); - } - }); - } catch (java.security.PrivilegedActionException e) { - throw (IOException) e.getException(); - } - } - - void addExtURL(URL url) { - super.addURL(url); - } - - /* - * Creates a new ExtClassLoader for the specified directories. - */ - public ExtClassLoader(File[] files) throws IOException { - super(getExtURLs(files), null, factory); - } - - private static URL[] getExtURLs(File[] files) throws IOException { - int len = files.length; - URL[] urls = new URL[len]; - for (int i=0; i() { - public AppClassLoader run() { - URL[] urls = pathToURLs(path); - return new AppClassLoader(urls, extcl); - } - }); - } - - /* - * Creates a new AppClassLoader - */ - AppClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent, factory); - } - - /** - * Override loadClass so we can checkPackageAccess. - */ - public Class loadClass(String name, boolean resolve) - throws ClassNotFoundException - { - int i = name.lastIndexOf('.'); - if (i != -1) { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPackageAccess(name.substring(0, i)); - } - } - return (super.loadClass(name, resolve)); - } - - /** - * allow any classes loaded from classpath to exit the VM. - */ - protected PermissionCollection getPermissions(CodeSource codesource) { - PermissionCollection perms = super.getPermissions(codesource); - perms.add(new RuntimePermission("exitVM")); - return perms; - } - - /** - * This class loader supports dynamic additions to the class path - * at runtime. - * - * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch - */ - private void appendToClassPathForInstrumentation(String path) { - assert(Thread.holdsLock(this)); - - // addURL is a no-op if path already contains the URL - super.addURL( getFileURL(new File(path)) ); - } - - /** - * create a context that can read any directories (recursively) - * mentioned in the class path. In the case of a jar, it has to - * be the directory containing the jar, not just the jar, as jar - * files might refer to other jar files. - */ - - private static AccessControlContext getContext(File[] cp) - throws java.net.MalformedURLException - { - PathPermissions perms = - new PathPermissions(cp); - - ProtectionDomain domain = - new ProtectionDomain(new CodeSource(perms.getCodeBase(), - (java.security.cert.Certificate[]) null), - perms); - - AccessControlContext acc = - new AccessControlContext(new ProtectionDomain[] { domain }); - - return acc; - } - } - - private static class BootClassPathHolder { - static final URLClassPath bcp; - static { - URL[] urls = AccessController.doPrivileged( - new PrivilegedAction() { - public URL[] run() { - String bootClassPath = System.getProperty("sun.boot.class.path"); - if (bootClassPath == null) - return new URL[0]; - // Skip empty path in boot class path i.e. not default to use CWD - return pathToURLs(getClassPath(bootClassPath, false)); - } - } - ); - bcp = new URLClassPath(urls, factory); - } - } - - public static URLClassPath getBootstrapClassPath() { - return BootClassPathHolder.bcp; - } - - private static URL[] pathToURLs(File[] path) { - URL[] urls = new URL[path.length]; - for (int i = 0; i < path.length; i++) { - urls[i] = getFileURL(path[i]); - } - // DEBUG - //for (int i = 0; i < urls.length; i++) { - // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"'); - //} - return urls; - } - - private static File[] getClassPath(String cp, boolean defaultToCwd) { - File[] path; - if (cp != null) { - int count = 0, maxCount = 1; - int pos = 0, lastPos = 0; - // Count the number of separators first - while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { - maxCount++; - lastPos = pos + 1; - } - path = new File[maxCount]; - lastPos = pos = 0; - // Now scan for each path component - while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { - if (pos > lastPos) { - path[count++] = new File(cp.substring(lastPos, pos)); - } else if (defaultToCwd) { - // empty path component translates to "." - path[count++] = new File("."); - } - lastPos = pos + 1; - } - // Make sure we include the last path component - if (lastPos < cp.length()) { - path[count++] = new File(cp.substring(lastPos)); - } else if (defaultToCwd) { - path[count++] = new File("."); - } - // Trim array to correct size - if (count != maxCount) { - File[] tmp = new File[count]; - System.arraycopy(path, 0, tmp, 0, count); - path = tmp; - } - } else { - path = new File[0]; - } - // DEBUG - //for (int i = 0; i < path.length; i++) { - // System.out.println("path[" + i + "] = " + '"' + path[i] + '"'); - //} - return path; - } - - private static URLStreamHandler fileHandler; - - static URL getFileURL(File file) { - try { - file = file.getCanonicalFile(); - } catch (IOException e) {} - - try { - return ParseUtil.fileToEncodedURL(file); - } catch (MalformedURLException e) { - // Should never happen since we specify the protocol... - throw new InternalError(e); - } - } - - /* - * The stream handler factory for loading system protocol handlers. - */ - private static class Factory implements URLStreamHandlerFactory { - private static String PREFIX = "sun.net.www.protocol"; - - public URLStreamHandler createURLStreamHandler(String protocol) { - String name = PREFIX + "." + protocol + ".Handler"; - try { - Class c = Class.forName(name); - return (URLStreamHandler)c.newInstance(); - } catch (ReflectiveOperationException e) { - throw new InternalError("could not load " + protocol + - "system protocol handler", e); - } - } - } -} - -class PathPermissions extends PermissionCollection { - // use serialVersionUID from JDK 1.2.2 for interoperability - private static final long serialVersionUID = 8133287259134945693L; - - private File path[]; - private Permissions perms; - - URL codeBase; - - PathPermissions(File path[]) - { - this.path = path; - this.perms = null; - this.codeBase = null; - } - - URL getCodeBase() - { - return codeBase; - } - - public void add(java.security.Permission permission) { - throw new SecurityException("attempt to add a permission"); - } - - private synchronized void init() - { - if (perms != null) - return; - - perms = new Permissions(); - - // this is needed to be able to create the classloader itself! - perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); - - // add permission to read any "java.*" property - perms.add(new java.util.PropertyPermission("java.*", - SecurityConstants.PROPERTY_READ_ACTION)); - - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - for (int i=0; i < path.length; i++) { - File f = path[i]; - String path; - try { - path = f.getCanonicalPath(); - } catch (IOException ioe) { - path = f.getAbsolutePath(); - } - if (i == 0) { - codeBase = Launcher.getFileURL(new File(path)); - } - if (f.isDirectory()) { - if (path.endsWith(File.separator)) { - perms.add(new FilePermission(path+"-", - SecurityConstants.FILE_READ_ACTION)); - } else { - perms.add(new FilePermission( - path + File.separator+"-", - SecurityConstants.FILE_READ_ACTION)); - } - } else { - int endIndex = path.lastIndexOf(File.separatorChar); - if (endIndex != -1) { - path = path.substring(0, endIndex+1) + "-"; - perms.add(new FilePermission(path, - SecurityConstants.FILE_READ_ACTION)); - } else { - // XXX? - } - } - } - return null; - } - }); - } - - public boolean implies(java.security.Permission permission) { - if (perms == null) - init(); - return perms.implies(permission); - } - - public java.util.Enumeration elements() { - if (perms == null) - init(); - synchronized (perms) { - return perms.elements(); - } - } - - public String toString() { - if (perms == null) - init(); - return perms.toString(); - } -} diff --git a/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java b/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java index ac86bdc5756..8c4c7368dd6 100644 --- a/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java +++ b/jdk/src/java.base/share/classes/sun/misc/URLClassPath.java @@ -25,7 +25,6 @@ package sun.misc; -import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; @@ -56,7 +55,6 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.Stack; import java.util.StringTokenizer; -import java.util.concurrent.atomic.AtomicInteger; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.jar.JarEntry; @@ -65,14 +63,10 @@ import java.util.jar.Attributes; import java.util.jar.Attributes.Name; import java.util.zip.ZipFile; -import jdk.internal.jimage.ImageLocation; -import jdk.internal.jimage.ImageReader; import jdk.internal.misc.JavaUtilZipFileAccess; import jdk.internal.misc.SharedSecrets; - import sun.net.util.URLUtil; import sun.net.www.ParseUtil; -import sun.net.www.protocol.jrt.JavaRuntimeURLConnection; /** * This class is used to maintain a search path of URLs for loading classes @@ -387,10 +381,6 @@ public class URLClassPath { return new Loader(url); } } else { - if (file != null && "file".equals(url.getProtocol())) { - if (file.endsWith(".jimage")) - return new JImageLoader(url); - } return new JarLoader(url, jarHandler, lmap); } } @@ -446,13 +436,14 @@ public class URLClassPath { * Return null on security check failure. * Called by java.net.URLClassLoader. */ - public URL checkURL(URL url) { - try { - check(url); - } catch (Exception e) { - return null; + public static URL checkURL(URL url) { + if (url != null) { + try { + check(url); + } catch (Exception e) { + return null; + } } - return url; } @@ -461,7 +452,7 @@ public class URLClassPath { * Throw exception on failure. * Called internally within this file. */ - static void check(URL url) throws IOException { + public static void check(URL url) throws IOException { SecurityManager security = System.getSecurityManager(); if (security != null) { URLConnection urlConnection = url.openConnection(); @@ -1086,132 +1077,4 @@ public class URLClassPath { return null; } } - - /** - * A Loader of classes and resources from a jimage file located in the - * runtime image. - */ - private static class JImageLoader - extends Loader implements JavaRuntimeURLConnection.ResourceFinder - { - private static final AtomicInteger NEXT_INDEX = new AtomicInteger(); - - private final ImageReader jimage; - private final int index; - - JImageLoader(URL url) throws IOException { - super(url); - - // get path to image file and check that it's in the runtime - String urlPath = url.getFile().replace('/', File.separatorChar); - - File filePath = new File(ParseUtil.decode(urlPath)); - File home = new File(JAVA_HOME).getCanonicalFile(); - File parent = filePath.getParentFile(); - while (parent != null) { - if (parent.equals(home)) - break; - parent = parent.getParentFile(); - } - if (parent == null) - throw new IOException(filePath + " not in runtime image"); - - this.jimage = ImageReader.open(filePath.toString()); - this.index = NEXT_INDEX.getAndIncrement(); - - // register with the jimage protocol handler - JavaRuntimeURLConnection.register(this); - } - - /** - * Maps the given resource name to a module. - */ - private String nameToModule(String name) { - int pos = name.lastIndexOf('/'); - if (pos > 0) { - String pkg = name.substring(0, pos); - String module = jimage.getModule(pkg); - if (module != null) - return module; - } - // cannot map to module - return "UNNAMED" + index; - } - - /** - * Constructs a URL for the resource name. - */ - private URL toURL(String name) { - String module = nameToModule(name); - String encodedName = ParseUtil.encodePath(name, false); - try { - return new URL("jrt:/" + module + "/" + encodedName); - } catch (MalformedURLException e) { - throw new InternalError(e); - } - } - - @Override - URL findResource(String name, boolean check) { - ImageLocation location = jimage.findLocation(name); - if (location == null) - return null; - URL url = toURL(name); - if (check) { - try { - URLClassPath.check(url); - } catch (IOException | SecurityException e) { - return null; - } - } - return url; - } - - @Override - Resource getResource(String name, boolean check) { - ImageLocation location = jimage.findLocation(name); - if (location == null) - return null; - URL url = toURL(name); - if (check) { - try { - URLClassPath.check(url); - } catch (IOException | SecurityException e) { - return null; - } - } - return new Resource() { - @Override - public String getName() { return name; } - @Override - public URL getURL() { return url; } - @Override - public URL getCodeSourceURL() { - try { - return new URL("jrt:/" + nameToModule(name)); - } catch (MalformedURLException e) { - throw new InternalError(e); - } - } - @Override - public InputStream getInputStream() throws IOException { - byte[] resource = jimage.getResource(location); - return new ByteArrayInputStream(resource); - } - public int getContentLength() { - long size = location.getUncompressedSize(); - return (size > Integer.MAX_VALUE) ? -1 : (int)size; - } - }; - } - - @Override - public Resource find(String module, String name) throws IOException { - String m = nameToModule(name); - if (!m.equals(module)) - return null; - // URLConnection will do the permission check - return getResource(name, false); - } - } } diff --git a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java b/jdk/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java similarity index 61% rename from jdk/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java rename to jdk/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java index 9d5b09d2ba9..95bc2179a31 100644 --- a/jdk/src/java.base/share/classes/jdk/internal/jimage/ImageSubstrate.java +++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jmod/Handler.java @@ -22,24 +22,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package jdk.internal.jimage; -import java.io.Closeable; -import java.nio.ByteBuffer; +package sun.net.www.protocol.jmod; + +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.MalformedURLException; +import java.io.IOException; + +/** + * Placeholder protocol handler for the jmod protocol. + */ + +public class Handler extends URLStreamHandler { + public Handler() { } -interface ImageSubstrate extends Closeable { @Override - void close(); - boolean supportsDataBuffer(); - ByteBuffer getIndexBuffer(long offset, long size); - ByteBuffer getDataBuffer(long offset, long size); - boolean read(long offset, - ByteBuffer compressedBuffer, long compressedSize, - ByteBuffer uncompressedBuffer, long uncompressedSize); - boolean read(long offset, - ByteBuffer uncompressedBuffer, long uncompressedSize); - byte[] getStringBytes(int offset); - long[] getAttributes(int offset); - ImageLocation findLocation(UTF8String name, ImageStringsReader strings); - int[] attributeOffsets(); + protected URLConnection openConnection(URL url) throws IOException { + String s = url.toString(); + int index = s.indexOf("!/"); + if (index == -1) + throw new MalformedURLException("no !/ found in url spec:" + s); + + throw new IOException("Can't connect to jmod URL"); + } } 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 33b6840a8a5..8f6a8c3ab89 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 @@ -25,6 +25,7 @@ package sun.net.www.protocol.jrt; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FilePermission; import java.io.IOException; @@ -35,8 +36,12 @@ import java.security.AccessController; import java.security.Permission; import java.security.PrivilegedAction; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; +import jdk.internal.jimage.ImageLocation; +import jdk.internal.jimage.ImageReader; +import jdk.internal.jimage.ImageReaderFactory; + +import sun.misc.URLClassPath; import sun.misc.Resource; import sun.net.www.ParseUtil; import sun.net.www.URLConnection; @@ -47,33 +52,8 @@ import sun.net.www.URLConnection; */ public class JavaRuntimeURLConnection extends URLConnection { - /** - * Finds resource {@code name} in module {@code module}. - */ - public interface ResourceFinder { - Resource find(String module, String name) throws IOException; - } - - /** - * The list of resource finders for jimages in the runtime image. - */ - private static final List finders = new CopyOnWriteArrayList<>(); - - /** - * Called on behalf of the boot, extension and system class loaders to - * register a resource finder. - */ - public static void register(ResourceFinder finder) { - finders.add(finder); - } - - private static Resource find(String module, String name) throws IOException { - for (ResourceFinder finder: finders) { - Resource r = finder.find(module, name); - if (r != null) return r; - } - return null; - } + // ImageReader to access resources in jimage + private static final ImageReader reader = ImageReaderFactory.getImageReader(); // the module and resource name in the URL private final String module; @@ -105,6 +85,44 @@ public class JavaRuntimeURLConnection extends URLConnection { } } + /** + * Finds a resource in a module, returning {@code null} if the resource + * is not found. + */ + private static Resource findResource(String module, String name) { + if (reader != null) { + URL url = toJrtURL(module, name); + ImageLocation location = reader.findLocation(module, name); + if (location != null && URLClassPath.checkURL(url) != null) { + return new Resource() { + @Override + public String getName() { + return name; + } + @Override + public URL getURL() { + return url; + } + @Override + public URL getCodeSourceURL() { + return toJrtURL(module); + } + @Override + public InputStream getInputStream() throws IOException { + byte[] resource = reader.getResource(location); + return new ByteArrayInputStream(resource); + } + @Override + public int getContentLength() { + long size = location.getUncompressedSize(); + return (size > Integer.MAX_VALUE) ? -1 : (int) size; + } + }; + } + } + return null; + } + @Override public synchronized void connect() throws IOException { if (!connected) { @@ -112,7 +130,7 @@ public class JavaRuntimeURLConnection extends URLConnection { String s = (module == null) ? "" : module; throw new IOException("cannot connect to jrt:/" + s); } - resource = find(module, name); + resource = findResource(module, name); if (resource == null) throw new IOException(module + "/" + name + " not found"); connected = true; @@ -155,4 +173,26 @@ public class JavaRuntimeURLConnection extends URLConnection { } return p; } + + /** + * Returns a jrt URL for the given module and resource name. + */ + private static URL toJrtURL(String module, String name) { + try { + return new URL("jrt:/" + module + "/" + name); + } catch (MalformedURLException e) { + throw new InternalError(e); + } + } + + /** + * Returns a jrt URL for the given module. + */ + private static URL toJrtURL(String module) { + try { + return new URL("jrt:/" + module); + } catch (MalformedURLException e) { + throw new InternalError(e); + } + } } diff --git a/jdk/src/java.base/share/classes/sun/reflect/Reflection.java b/jdk/src/java.base/share/classes/sun/reflect/Reflection.java index 07ff36493d2..084995f268b 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/Reflection.java +++ b/jdk/src/java.base/share/classes/sun/reflect/Reflection.java @@ -25,9 +25,13 @@ package sun.reflect; + import java.lang.reflect.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.VM; @@ -80,13 +84,6 @@ public class Reflection { @HotSpotIntrinsicCandidate public static native int getClassAccessFlags(Class c); - /** A quick "fast-path" check to try to avoid getCallerClass() - calls. */ - public static boolean quickCheckMemberAccess(Class memberClass, - int modifiers) - { - return Modifier.isPublic(getClassAccessFlags(memberClass) & modifiers); - } public static void ensureMemberAccess(Class currentClass, Class memberClass, @@ -99,12 +96,7 @@ public class Reflection { } if (!verifyMemberAccess(currentClass, memberClass, target, modifiers)) { - throw new IllegalAccessException("Class " + currentClass.getName() + - " can not access a member of class " + - memberClass.getName() + - " with modifiers \"" + - Modifier.toString(modifiers) + - "\""); + throwIllegalAccessException(currentClass, memberClass, target, modifiers); } } @@ -128,6 +120,10 @@ public class Reflection { return true; } + if (!verifyModuleAccess(currentClass, memberClass)) { + return false; + } + if (!Modifier.isPublic(getClassAccessFlags(memberClass))) { isSameClassPackage = isSameClassPackage(currentClass, memberClass); gotIsSameClassPackage = true; @@ -186,59 +182,45 @@ public class Reflection { return true; } - private static boolean isSameClassPackage(Class c1, Class c2) { - return isSameClassPackage(c1.getClassLoader(), c1.getName(), - c2.getClassLoader(), c2.getName()); + /** + * Returns {@code true} if memberClass's's module exports memberClass's + * package to currentClass's module. + */ + public static boolean verifyModuleAccess(Class currentClass, + Class memberClass) { + return verifyModuleAccess(currentClass.getModule(), memberClass); } - /** Returns true if two classes are in the same package; classloader - and classname information is enough to determine a class's package */ - private static boolean isSameClassPackage(ClassLoader loader1, String name1, - ClassLoader loader2, String name2) - { - if (loader1 != loader2) { - return false; - } else { - int lastDot1 = name1.lastIndexOf('.'); - int lastDot2 = name2.lastIndexOf('.'); - if ((lastDot1 == -1) || (lastDot2 == -1)) { - // One of the two doesn't have a package. Only return true - // if the other one also doesn't have a package. - return (lastDot1 == lastDot2); - } else { - int idx1 = 0; - int idx2 = 0; + public static boolean verifyModuleAccess(Module currentModule, Class memberClass) { + Module memberModule = memberClass.getModule(); - // Skip over '['s - if (name1.charAt(idx1) == '[') { - do { - idx1++; - } while (name1.charAt(idx1) == '['); - if (name1.charAt(idx1) != 'L') { - // Something is terribly wrong. Shouldn't be here. - throw new InternalError("Illegal class name " + name1); - } - } - if (name2.charAt(idx2) == '[') { - do { - idx2++; - } while (name2.charAt(idx2) == '['); - if (name2.charAt(idx2) != 'L') { - // Something is terribly wrong. Shouldn't be here. - throw new InternalError("Illegal class name " + name2); - } - } + // module may be null during startup (initLevel 0) + if (currentModule == memberModule) + return true; // same module (named or unnamed) - // Check that package part is identical - int length1 = lastDot1 - idx1; - int length2 = lastDot2 - idx2; - - if (length1 != length2) { - return false; - } - return name1.regionMatches(false, idx1, name2, idx2, length1); - } + // memberClass may be primitive or array class + Class c = memberClass; + while (c.isArray()) { + c = c.getComponentType(); } + if (c.isPrimitive()) + return true; + + // check that memberModule exports the package to currentModule + return memberModule.isExported(c.getPackageName(), currentModule); + } + + /** + * Returns true if two classes in the same package. + */ + 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()); } static boolean isSubclassOf(Class queryClass, @@ -332,7 +314,7 @@ public class Reflection { /** * Tests if the given method is caller-sensitive and the declaring class - * is defined by either the bootstrap class loader or extension class loader. + * is defined by either the bootstrap class loader or platform class loader. */ public static boolean isCallerSensitive(Method m) { final ClassLoader loader = m.getDeclaringClass().getClassLoader(); @@ -352,4 +334,92 @@ public class Reflection { } return false; } + + + // true to print a stack trace when IAE is thrown + private static volatile boolean printStackWhenAccessFails; + + // true if printStackWhenAccessFails has been initialized + private static volatile boolean printStackWhenAccessFailsSet; + + private static void printStackTraceIfNeeded(Throwable e) { + if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) { + // can't use method reference here, might be too early in startup + PrivilegedAction pa = new PrivilegedAction() { + public Boolean run() { + String s; + s = System.getProperty("sun.reflect.debugModuleAccessChecks"); + return (s != null && !s.equalsIgnoreCase("false")); + } + }; + printStackWhenAccessFails = AccessController.doPrivileged(pa); + printStackWhenAccessFailsSet = true; + } + if (printStackWhenAccessFails) { + e.printStackTrace(); + } + } + + /** + * Throws IllegalAccessException with the an exception message based on + * the access that is denied. + */ + private static void throwIllegalAccessException(Class currentClass, + Class memberClass, + Object target, + int modifiers) + throws IllegalAccessException + { + String currentSuffix = ""; + String memberSuffix = ""; + Module m1 = currentClass.getModule(); + if (m1.isNamed()) + currentSuffix = " (in " + m1 + ")"; + Module m2 = memberClass.getModule(); + if (m2.isNamed()) + memberSuffix = " (in " + m2 + ")"; + + Class c = memberClass; + while (c.isArray()) { + c = c.getComponentType(); + } + String memberPackageName = c.getPackageName(); + + String msg = currentClass + currentSuffix + " cannot access "; + if (m2.isExported(memberPackageName, m1)) { + + // module access okay so include the modifiers in the message + msg += "a member of " + memberClass + memberSuffix + + " with modifiers \"" + Modifier.toString(modifiers) + "\""; + + } else { + // module access failed + msg += memberClass + memberSuffix+ " because " + + m2 + " does not export " + memberPackageName; + if (m2.isNamed()) msg += " to " + m1; + } + + throwIllegalAccessException(msg); + } + + /** + * Throws IllegalAccessException with the given exception message. + */ + public static void throwIllegalAccessException(String msg) + throws IllegalAccessException + { + IllegalAccessException e = new IllegalAccessException(msg); + printStackTraceIfNeeded(e); + throw e; + } + + /** + * Throws InaccessibleObjectException with the given exception message. + */ + public static void throwInaccessibleObjectException(String msg) { + InaccessibleObjectException e = new InaccessibleObjectException(msg); + printStackTraceIfNeeded(e); + throw e; + } + } diff --git a/jdk/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java b/jdk/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java index f1100d805c2..d3d34da4967 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java +++ b/jdk/src/java.base/share/classes/sun/reflect/misc/MethodUtil.java @@ -25,6 +25,7 @@ package sun.reflect.misc; +import java.lang.reflect.Module; import java.io.EOFException; import java.security.AllPermission; import java.security.AccessController; @@ -39,7 +40,6 @@ import java.net.URL; import java.net.URLConnection; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.AccessibleObject; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.HashMap; @@ -329,24 +329,26 @@ public final class MethodUtil extends SecureClassLoader { throw new ClassNotFoundException(name); } String path = name.replace('.', '/').concat(".class"); - URL res = getResource(path); - if (res != null) { - try { - return defineClass(name, res); - } catch (IOException e) { - throw new ClassNotFoundException(name, e); + try { + InputStream in = Object.class.getModule().getResourceAsStream(path); + if (in != null) { + try (in) { + byte[] b = in.readAllBytes(); + return defineClass(name, b); + } } - } else { - throw new ClassNotFoundException(name); + } catch (IOException e) { + throw new ClassNotFoundException(name, e); } + + throw new ClassNotFoundException(name); } /* * Define the proxy classes */ - private Class defineClass(String name, URL url) throws IOException { - byte[] b = getBytes(url); + private Class defineClass(String name, byte[] b) throws IOException { CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null); if (!name.equals(TRAMPOLINE)) { throw new IOException("MethodUtil: bad name " + name); @@ -354,29 +356,6 @@ public final class MethodUtil extends SecureClassLoader { return defineClass(name, b, 0, b.length, cs); } - - /* - * Returns the contents of the specified URL as an array of bytes. - */ - private static byte[] getBytes(URL url) throws IOException { - URLConnection uc = url.openConnection(); - if (uc instanceof java.net.HttpURLConnection) { - java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc; - int code = huc.getResponseCode(); - if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) { - throw new IOException("open HTTP connection failed."); - } - } - int len = uc.getContentLength(); - try (InputStream in = new BufferedInputStream(uc.getInputStream())) { - byte[] b = in.readAllBytes(); - if (len != -1 && b.length != len) - throw new EOFException("Expected:" + len + ", read:" + b.length); - return b; - } - } - - protected PermissionCollection getPermissions(CodeSource codesource) { PermissionCollection perms = super.getPermissions(codesource); diff --git a/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java b/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java index c90a630e2fa..97bd9c2e303 100644 --- a/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java +++ b/jdk/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java @@ -30,7 +30,6 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; -import java.util.Arrays; import sun.reflect.Reflection; import sun.security.util.SecurityConstants; @@ -45,12 +44,6 @@ public final class ReflectUtil { return Class.forName(name); } - public static Object newInstance(Class cls) - throws InstantiationException, IllegalAccessException { - checkPackageAccess(cls); - return cls.newInstance(); - } - /* * Reflection.ensureMemberAccess is overly-restrictive * due to a bug. We awkwardly work around it for now. @@ -286,7 +279,7 @@ public final class ReflectUtil { String name = cls.getName(); int i = name.lastIndexOf('.'); String pkg = (i != -1) ? name.substring(0, i) : ""; - return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE); + return Proxy.isProxyClass(cls) && !pkg.startsWith(PROXY_PACKAGE); } /** diff --git a/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java b/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java index 1db2d089932..9082670609e 100644 --- a/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java +++ b/jdk/src/java.base/share/classes/sun/security/jca/ProviderList.java @@ -36,8 +36,10 @@ import java.security.Security; /** * List of Providers. Used to represent the provider preferences. * - * The system starts out with a ProviderList that only has the classNames - * of the Providers. Providers are loaded on demand only when needed. + * The system starts out with a ProviderList that only has the names + * of the Providers. + * When using ServiceLoader to load the providers, Providers are created + * semi-eagerly as we iterate through them looking for a match. * * For compatibility reasons, Providers that could not be loaded are ignored * and internally presented as the instance EMPTY_PROVIDER. However, those diff --git a/jdk/src/java.base/share/classes/sun/security/jca/Providers.java b/jdk/src/java.base/share/classes/sun/security/jca/Providers.java index 94e77381edf..ec66be4a6a9 100644 --- a/jdk/src/java.base/share/classes/sun/security/jca/Providers.java +++ b/jdk/src/java.base/share/classes/sun/security/jca/Providers.java @@ -86,10 +86,7 @@ public class Providers { "SunRsaSign", // Note: when SunEC is in a signed JAR file, it's not signed // by EC algorithms. So it's still safe to be listed here. - // Need to use class name here, otherwise it cannot be loaded for - // jar verification. Only those providers in java.base are created - // directly by ProviderConfig class. - "sun.security.ec.SunEC", + "SunEC", }; // Return Sun provider. diff --git a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java index a9af102f563..5861b6c7a85 100644 --- a/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java +++ b/jdk/src/java.base/share/classes/sun/security/provider/PolicyFile.java @@ -275,7 +275,6 @@ public class PolicyFile extends java.security.Policy { // contains the policy grant entries, PD cache, and alias mapping private AtomicReference policyInfo = new AtomicReference<>(); - private boolean constructed = false; private boolean expandProperties = true; private boolean allowSystemProperties = true; @@ -910,9 +909,8 @@ public class PolicyFile extends java.security.Policy { NoSuchMethodException, InvocationTargetException { - //XXX we might want to keep a hash of created factories... Class pc = Class.forName(type, false, null); - Permission answer = getKnownInstance(pc, name, actions); + Permission answer = getKnownPermission(pc, name, actions); if (answer != null) { return answer; } @@ -955,12 +953,12 @@ public class PolicyFile extends java.security.Policy { } /** - * Creates one of the well-known permissions directly instead of - * via reflection. Keep list short to not penalize non-JDK-defined - * permissions. + * Creates one of the well-known permissions in the java.base module + * directly instead of via reflection. Keep list short to not penalize + * permissions from other modules. */ - private static final Permission getKnownInstance(Class claz, - String name, String actions) { + private static Permission getKnownPermission(Class claz, String name, + String actions) { if (claz.equals(FilePermission.class)) { return new FilePermission(name, actions); } else if (claz.equals(SocketPermission.class)) { @@ -973,6 +971,21 @@ public class PolicyFile extends java.security.Policy { return new NetPermission(name, actions); } else if (claz.equals(AllPermission.class)) { return SecurityConstants.ALL_PERMISSION; + } else if (claz.equals(SecurityPermission.class)) { + return new SecurityPermission(name, actions); + } else { + return null; + } + } + + /** + * Creates one of the well-known principals in the java.base module + * directly instead of via reflection. Keep list short to not penalize + * principals from other modules. + */ + private static Principal getKnownPrincipal(Class claz, String name) { + if (claz.equals(X500Principal.class)) { + return new X500Principal(name); } else { return null; } @@ -1305,15 +1318,19 @@ public class PolicyFile extends java.security.Policy { try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class pClass = Class.forName(pppe.principalClass, false, cl); - if (!Principal.class.isAssignableFrom(pClass)) { - // not the right subtype - throw new ClassCastException(pppe.principalClass + - " is not a Principal"); - } + Principal p = getKnownPrincipal(pClass, pppe.principalName); + if (p == null) { + if (!Principal.class.isAssignableFrom(pClass)) { + // not the right subtype + throw new ClassCastException(pppe.principalClass + + " is not a Principal"); + } - Constructor c = pClass.getConstructor(PARAMS1); - Principal p = (Principal)c.newInstance(new Object[] { - pppe.principalName }); + Constructor c = pClass.getConstructor(PARAMS1); + p = (Principal)c.newInstance(new Object[] { + pppe.principalName }); + + } if (debug != null) { debug.println("found Principal " + p.getClass().getName()); diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java index 86c72bac38a..b49723aa462 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -700,7 +700,7 @@ static final class CertificateStatus extends HandshakeMessage * OCSP response data is provided. */ CertificateStatus(StatusRequestType type, X509Certificate[] chain, - Map responses) throws SSLException { + Map responses) { statusType = type; encodedResponsesLen = 0; encodedResponses = new ArrayList<>(chain.length); @@ -715,7 +715,7 @@ static final class CertificateStatus extends HandshakeMessage encodedResponses.add(respDER); encodedResponsesLen = 3 + respDER.length; } else { - throw new SSLHandshakeException("Zero-length or null " + + throw new IllegalArgumentException("Zero-length or null " + "OCSP Response"); } } else if (statusType == StatusRequestType.OCSP_MULTI) { @@ -732,8 +732,8 @@ static final class CertificateStatus extends HandshakeMessage } } } else { - throw new SSLHandshakeException("Unsupported StatusResponseType: " + - statusType); + throw new IllegalArgumentException( + "Unsupported StatusResponseType: " + statusType); } } diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 86b772c09da..412c3ec8544 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -365,17 +365,6 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { /* Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); - /* - * Is it the first application record to write? - */ - private boolean isFirstAppOutputRecord = true; - - /* - * If AppOutputStream needs to delay writes of small packets, we - * will use this to store the data until we actually do the write. - */ - private ByteArrayOutputStream heldRecordBuffer = null; - /* * Whether local cipher suites preference in server side should be * honored during handshaking? @@ -998,9 +987,21 @@ public final class SSLSocketImpl extends BaseSSLSocketImpl { Plaintext plainText = null; while (((state = getConnectionState()) != cs_CLOSED) && (state != cs_ERROR) && (state != cs_APP_CLOSED)) { - // clean the buffer + + /* + * clean the buffer and check if it is too small, e.g. because + * the AppInputStream did not have the chance to see the + * current packet length but rather something like that of the + * handshake before. In that case we return 0 at this point to + * give the caller the chance to adjust the buffer. + */ if (buffer != null) { buffer.clear(); + + if (buffer.remaining() < + inputRecord.bytesInCompletePacket(sockInput)) { + return 0; + } } /* diff --git a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java index eb3484c6c4b..a4c119faf25 100644 --- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java @@ -36,7 +36,6 @@ import java.security.spec.ECParameterSpec; import java.math.BigInteger; import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.*; import sun.security.action.GetLongAction; @@ -67,7 +66,6 @@ final class ServerHandshaker extends Handshaker { // our authentication info private X509Certificate[] certs; - private Map responseMap; private PrivateKey privateKey; private Object serviceCreds; @@ -118,7 +116,6 @@ final class ServerHandshaker extends Handshaker { LegacyAlgorithmConstraints.PROPERTY_TLS_LEGACY_ALGS, new SSLAlgorithmDecomposer()); - private boolean staplingActive = false; private long statusRespTimeout; static { @@ -578,16 +575,6 @@ final class ServerHandshaker extends Handshaker { } } - // Check if the client has asserted the status_request[_v2] extension(s) - CertStatusReqExtension statReqExt = (CertStatusReqExtension) - mesg.extensions.get(ExtensionType.EXT_STATUS_REQUEST); - CertStatusReqListV2Extension statReqExtV2 = - (CertStatusReqListV2Extension)mesg.extensions.get( - ExtensionType.EXT_STATUS_REQUEST_V2); - // Keep stapling active if at least one of the extensions has been set - staplingActive = sslContext.isStaplingEnabled(false) && - (statReqExt != null || statReqExtV2 != null); - /* * FIRST, construct the ServerHello using the options and priorities * from the ClientHello. Update the (pending) cipher spec as we do @@ -883,79 +870,17 @@ final class ServerHandshaker extends Handshaker { m1.extensions.add(maxFragLenExt); } - StatusRequestType statReqType = null; - StatusRequest statReqData = null; - if (staplingActive && !resumingSession) { - ExtensionType statusRespExt = ExtensionType.EXT_STATUS_REQUEST; - - // Determine which type of stapling we are doing and assert the - // proper extension in the server hello. - // Favor status_request_v2 over status_request and ocsp_multi - // over ocsp. - // If multiple ocsp or ocsp_multi types exist, select the first - // instance of a given type - if (statReqExtV2 != null) { // RFC 6961 stapling - statusRespExt = ExtensionType.EXT_STATUS_REQUEST_V2; - List reqItems = - statReqExtV2.getRequestItems(); - int ocspIdx = -1; - int ocspMultiIdx = -1; - for (int pos = 0; pos < reqItems.size(); pos++) { - CertStatusReqItemV2 item = reqItems.get(pos); - if (ocspIdx < 0 && item.getType() == - StatusRequestType.OCSP) { - ocspIdx = pos; - } else if (ocspMultiIdx < 0 && item.getType() == - StatusRequestType.OCSP_MULTI) { - ocspMultiIdx = pos; - } - } - if (ocspMultiIdx >= 0) { - statReqType = reqItems.get(ocspMultiIdx).getType(); - statReqData = reqItems.get(ocspMultiIdx).getRequest(); - } else if (ocspIdx >= 0) { - statReqType = reqItems.get(ocspIdx).getType(); - statReqData = reqItems.get(ocspIdx).getRequest(); - } else { - // Some unknown type. We will not do stapling for - // this connection since we cannot understand the - // requested type. - staplingActive = false; - } - } else { // RFC 6066 stapling - statReqType = StatusRequestType.OCSP; - statReqData = statReqExt.getRequest(); - } - - if (statReqType != null && statReqData != null) { - StatusResponseManager statRespMgr = - sslContext.getStatusResponseManager(); - if (statRespMgr != null) { - responseMap = statRespMgr.get(statReqType, statReqData, - certs, statusRespTimeout, TimeUnit.MILLISECONDS); - if (!responseMap.isEmpty()) { - // We now can safely assert status_request[_v2] in our - // ServerHello, and know for certain that we can provide - // responses back to this client for this connection. - if (statusRespExt == ExtensionType.EXT_STATUS_REQUEST) { - m1.extensions.add(new CertStatusReqExtension()); - } else if (statusRespExt == - ExtensionType.EXT_STATUS_REQUEST_V2) { - m1.extensions.add( - new CertStatusReqListV2Extension()); - } - } - } else { - // This should not happen if stapling is active, but - // if lazy initialization of the StatusResponseManager - // doesn't occur we should turn off stapling. - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Warning: lazy initialization " + - "of the StatusResponseManager failed. " + - "Stapling has been disabled."); - staplingActive = false; - } - } + StaplingParameters staplingParams = processStapling(mesg); + if (staplingParams != null) { + // We now can safely assert status_request[_v2] in our + // ServerHello, and know for certain that we can provide + // responses back to this client for this connection. + if (staplingParams.statusRespExt == + ExtensionType.EXT_STATUS_REQUEST) { + m1.extensions.add(new CertStatusReqExtension()); + } else if (staplingParams.statusRespExt == + ExtensionType.EXT_STATUS_REQUEST_V2) { + m1.extensions.add(new CertStatusReqListV2Extension()); } } @@ -1031,24 +956,15 @@ final class ServerHandshaker extends Handshaker { * supports status stapling and there is at least one response to * return to the client. */ - if (staplingActive && !responseMap.isEmpty()) { - try { - CertificateStatus csMsg = new CertificateStatus(statReqType, - certs, responseMap); - if (debug != null && Debug.isOn("handshake")) { - csMsg.print(System.out); - } - csMsg.write(output); - handshakeState.update(csMsg, resumingSession); - responseMap = null; - } catch (SSLException ssle) { - // We don't want the exception to be fatal, we just won't - // send the message if we fail on construction. - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Failed during CertificateStatus " + - "construction: " + ssle); - } + if (staplingParams != null) { + CertificateStatus csMsg = new CertificateStatus( + staplingParams.statReqType, certs, + staplingParams.responseMap); + if (debug != null && Debug.isOn("handshake")) { + csMsg.print(System.out); } + csMsg.write(output); + handshakeState.update(csMsg, resumingSession); } /* @@ -2078,4 +1994,121 @@ final class ServerHandshaker extends Handshaker { session.setPeerCertificates(peerCerts); } + + private StaplingParameters processStapling(ClientHello mesg) { + StaplingParameters params = null; + ExtensionType ext; + StatusRequestType type = null; + StatusRequest req = null; + Map responses; + + // If this feature has not been enabled, then no more processing + // is necessary. Also we will only staple if we're doing a full + // handshake. + if (!sslContext.isStaplingEnabled(false) || resumingSession) { + return null; + } + + // Check if the client has asserted the status_request[_v2] extension(s) + CertStatusReqExtension statReqExt = (CertStatusReqExtension) + mesg.extensions.get(ExtensionType.EXT_STATUS_REQUEST); + CertStatusReqListV2Extension statReqExtV2 = + (CertStatusReqListV2Extension)mesg.extensions.get( + ExtensionType.EXT_STATUS_REQUEST_V2); + // Keep processing only if either status_request or status_request_v2 + // has been sent in the ClientHello. + if (statReqExt == null && statReqExtV2 == null) { + return null; + } + + // Determine which type of stapling we are doing and assert the + // proper extension in the server hello. + // Favor status_request_v2 over status_request and ocsp_multi + // over ocsp. + // If multiple ocsp or ocsp_multi types exist, select the first + // instance of a given type + ext = ExtensionType.EXT_STATUS_REQUEST; + if (statReqExtV2 != null) { // RFC 6961 stapling + ext = ExtensionType.EXT_STATUS_REQUEST_V2; + List reqItems = + statReqExtV2.getRequestItems(); + int ocspIdx = -1; + int ocspMultiIdx = -1; + for (int pos = 0; pos < reqItems.size(); pos++) { + CertStatusReqItemV2 item = reqItems.get(pos); + if (ocspIdx < 0 && item.getType() == + StatusRequestType.OCSP) { + ocspIdx = pos; + } else if (ocspMultiIdx < 0 && item.getType() == + StatusRequestType.OCSP_MULTI) { + ocspMultiIdx = pos; + } + } + if (ocspMultiIdx >= 0) { + type = reqItems.get(ocspMultiIdx).getType(); + req = reqItems.get(ocspMultiIdx).getRequest(); + } else if (ocspIdx >= 0) { + type = reqItems.get(ocspIdx).getType(); + req = reqItems.get(ocspIdx).getRequest(); + } + } else { // RFC 6066 stapling + type = StatusRequestType.OCSP; + req = statReqExt.getRequest(); + } + + // If, after walking through the extensions we were unable to + // find a suitable StatusRequest, then stapling is disabled. + // Both statReqType and statReqData must have been set to continue. + if (type == null || req == null) { + return null; + } + + // Get the OCSP responses from the StatusResponseManager + StatusResponseManager statRespMgr = + sslContext.getStatusResponseManager(); + if (statRespMgr != null) { + responses = statRespMgr.get(type, req, certs, statusRespTimeout, + TimeUnit.MILLISECONDS); + if (!responses.isEmpty()) { + // If this RFC 6066-style stapling (SSL cert only) then the + // response cannot be zero length + if (type == StatusRequestType.OCSP) { + byte[] respDER = responses.get(certs[0]); + if (respDER == null || respDER.length <= 0) { + return null; + } + } + params = new StaplingParameters(ext, type, req, responses); + } + } else { + // This should not happen, but if lazy initialization of the + // StatusResponseManager doesn't occur we should turn off stapling. + if (debug != null && Debug.isOn("handshake")) { + System.out.println("Warning: lazy initialization " + + "of the StatusResponseManager failed. " + + "Stapling has been disabled."); + } + } + + return params; + } + + /** + * Inner class used to hold stapling parameters needed by the handshaker + * when stapling is active. + */ + private class StaplingParameters { + private final ExtensionType statusRespExt; + private final StatusRequestType statReqType; + private final StatusRequest statReqData; + private final Map responseMap; + + StaplingParameters(ExtensionType ext, StatusRequestType type, + StatusRequest req, Map responses) { + statusRespExt = ext; + statReqType = type; + statReqData = req; + responseMap = responses; + } + } } diff --git a/jdk/src/java.base/share/classes/sun/security/util/SecurityConstants.java b/jdk/src/java.base/share/classes/sun/security/util/SecurityConstants.java index 8a06fa8dd29..4a928b1d174 100644 --- a/jdk/src/java.base/share/classes/sun/security/util/SecurityConstants.java +++ b/jdk/src/java.base/share/classes/sun/security/util/SecurityConstants.java @@ -98,7 +98,7 @@ public final class SecurityConstants { public static final NetPermission GET_RESPONSECACHE_PERMISSION = new NetPermission("getResponseCache"); - // java.lang.SecurityManager, sun.applet.AppletPanel, sun.misc.Launcher + // java.lang.SecurityManager, sun.applet.AppletPanel public static final RuntimePermission CREATE_CLASSLOADER_PERMISSION = new RuntimePermission("createClassLoader"); diff --git a/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorInfoProvider.java b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorInfoProvider.java new file mode 100644 index 00000000000..9a6f05ea217 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorInfoProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface BreakIteratorInfoProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorRulesProvider.java b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorRulesProvider.java new file mode 100644 index 00000000000..4bbb1cec212 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/BreakIteratorRulesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface BreakIteratorRulesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/text/resources/CollationDataProvider.java b/jdk/src/java.base/share/classes/sun/text/resources/CollationDataProvider.java new file mode 100644 index 00000000000..e73b9582cb6 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/CollationDataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface CollationDataProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/text/resources/FormatDataProvider.java b/jdk/src/java.base/share/classes/sun/text/resources/FormatDataProvider.java new file mode 100644 index 00000000000..4f78996be89 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/FormatDataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface FormatDataProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementaryProvider.java b/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementaryProvider.java new file mode 100644 index 00000000000..261e9803015 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/JavaTimeSupplementaryProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface JavaTimeSupplementaryProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/text/resources/cldr/FormatDataProvider.java b/jdk/src/java.base/share/classes/sun/text/resources/cldr/FormatDataProvider.java new file mode 100644 index 00000000000..573b9e85eba --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/text/resources/cldr/FormatDataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.text.resources.cldr; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface FormatDataProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template b/jdk/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template deleted file mode 100644 index 0f34122e68b..00000000000 --- a/jdk/src/java.base/share/classes/sun/util/CoreResourceBundleControl-XLocales.java.template +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#warn This file is preprocessed before being compiled - -package sun.util; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.ResourceBundle; -import java.util.ResourceBundle.Control; - -/** - * This is a convenient class for loading some of internal resources faster - * if they are built with Resources.gmk defined in J2SE workspace. Also, - * they have to be in class file format. - * - * "LOCALE_LIST" will be replaced at built time by a list of locales we - * defined in Defs.gmk. We want to exclude these locales from search to - * gain better performance. For example, since we know if the resource - * is built with Resources.gmk, they are not going to provide basename_en.class - * & basename_en_US.class resources, in that case, continuing searching them - * is expensive. By excluding them from the candidate locale list, these - * resources won't be searched. - * - * @since 1.6. - */ -public class CoreResourceBundleControl extends ResourceBundle.Control { - /* the candidate locale list to search */ - private final Collection excludedJDKLocales; - /* singlton instance of the resource bundle control. */ - private static CoreResourceBundleControl resourceBundleControlInstance = - new CoreResourceBundleControl(); - - protected CoreResourceBundleControl() { - excludedJDKLocales = Arrays.asList(#LOCALE_LIST#); - } - - /** - * This method is to provide a customized ResourceBundle.Control to speed - * up the search of resources in JDK. - * - * @return the instance of resource bundle control. - */ - public static CoreResourceBundleControl getRBControlInstance() { - return resourceBundleControlInstance; - } - - /** - * This method is to provide a customized ResourceBundle.Control to speed - * up the search of resources in JDK, with the bundle's package name check. - * - * @param bundleName bundle name to check - * @return the instance of resource bundle control if the bundle is JDK's, - * otherwise returns null. - */ - public static CoreResourceBundleControl getRBControlInstance(String bundleName) { - if (bundleName.startsWith("com.sun.") || - bundleName.startsWith("java.") || - bundleName.startsWith("javax.") || - bundleName.startsWith("sun.")) { - return resourceBundleControlInstance; - } else { - return null; - } - } - - /** - * @return a list of candidate locales to search from. - * @exception NullPointerException if baseName or locale is null. - */ - @Override - public List getCandidateLocales(String baseName, Locale locale) { - List candidates = super.getCandidateLocales(baseName, locale); - candidates.removeAll(excludedJDKLocales); - return candidates; - } - - /** - * @ returns TTL_DONT_CACHE so that ResourceBundle instance won't be cached. - * User of this CoreResourceBundleControl should probably maintain a hard reference - * to the ResourceBundle object themselves. - */ - @Override - public long getTimeToLive(String baseName, Locale locale) { - return ResourceBundle.Control.TTL_DONT_CACHE; - } -} diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java index b612a0d0404..ddb4bb53f2c 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakDictionary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -40,7 +40,9 @@ package sun.util.locale.provider; import java.io.BufferedInputStream; +import java.io.InputStream; import java.io.IOException; +import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -135,25 +137,29 @@ class BreakDictionary { // deserialization //========================================================================= - BreakDictionary(String dictionaryName) + BreakDictionary(Module module, String dictionaryName) throws IOException, MissingResourceException { - readDictionaryFile(dictionaryName); + readDictionaryFile(module, dictionaryName); } - private void readDictionaryFile(final String dictionaryName) + private void readDictionaryFile(final Module module, final String dictionaryName) throws IOException, MissingResourceException { BufferedInputStream in; try { - in = AccessController.doPrivileged( - new PrivilegedExceptionAction() { - @Override - public BufferedInputStream run() throws Exception { - return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + dictionaryName)); - } + PrivilegedExceptionAction pa = () -> { + InputStream is = module.getResourceAsStream("sun/text/resources/" + dictionaryName); + if (is == null) { + // Try to load the file with "java.base" module instance. Assumption + // here is that the fall back data files to be read should reside in + // java.base. + is = BreakDictionary.class.getModule().getResourceAsStream("sun/text/resources/" + dictionaryName); } - ); + + return new BufferedInputStream(is); + }; + in = AccessController.doPrivileged(pa); } catch (PrivilegedActionException e) { throw new InternalError(e.toString(), e); diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java index 2d37412d2f7..2de50a98962 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/BreakIteratorProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -30,6 +30,7 @@ import java.text.BreakIterator; import java.text.spi.BreakIteratorProvider; import java.util.Locale; import java.util.MissingResourceException; +import java.util.Objects; import java.util.Set; /** @@ -155,9 +156,7 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider int type, String dataName, String dictionaryName) { - if (locale == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(locale); LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(locale); String[] classNames = (String[]) lr.getBreakIteratorInfo("BreakIteratorClasses"); @@ -166,10 +165,12 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider try { switch (classNames[type]) { case "RuleBasedBreakIterator": - return new RuleBasedBreakIterator(dataFile); + return new RuleBasedBreakIterator( + lr.getBreakIteratorDataModule(), dataFile); case "DictionaryBasedBreakIterator": String dictionaryFile = (String) lr.getBreakIteratorInfo(dictionaryName); - return new DictionaryBasedBreakIterator(dataFile, dictionaryFile); + return new DictionaryBasedBreakIterator( + lr.getBreakIteratorDataModule(), dataFile, dictionaryFile); default: throw new IllegalArgumentException("Invalid break iterator class \"" + classNames[type] + "\""); @@ -187,5 +188,5 @@ public class BreakIteratorProviderImpl extends BreakIteratorProvider @Override public boolean isSupportedLocale(Locale locale) { return LocaleProviderAdapter.forType(type).isSupportedProviderLocale(locale, langtags); -} + } } diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java index 7d0b8c4a8ce..f7eff4e80cf 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/DictionaryBasedBreakIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -41,6 +41,7 @@ package sun.util.locale.provider; import java.io.IOException; +import java.lang.reflect.Module; import java.text.CharacterIterator; import java.util.ArrayList; import java.util.List; @@ -108,20 +109,18 @@ class DictionaryBasedBreakIterator extends RuleBasedBreakIterator { /** * Constructs a DictionaryBasedBreakIterator. - * @param description Same as the description parameter on RuleBasedBreakIterator, - * except for the special meaning of "". This parameter is just - * passed through to RuleBasedBreakIterator's constructor. + * @param module The module where the dictionary file resides * @param dictionaryFilename The filename of the dictionary file to use */ - DictionaryBasedBreakIterator(String dataFile, String dictionaryFile) + DictionaryBasedBreakIterator(Module module, String dataFile, String dictionaryFile) throws IOException { - super(dataFile); + super(module, dataFile); byte[] tmp = super.getAdditionalData(); if (tmp != null) { prepareCategoryFlags(tmp); super.setAdditionalData(null); } - dictionary = new BreakDictionary(dictionaryFile); + dictionary = new BreakDictionary(module, dictionaryFile); } private void prepareCategoryFlags(byte[] data) { diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java index c9cdba78edc..c16c012fcf1 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java @@ -431,25 +431,21 @@ public class JRELocaleProviderAdapter extends LocaleProviderAdapter implements R // Use ServiceLoader to dynamically acquire installed locales' tags. try { - String nonBaseTags = AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public String run() { - String tags = null; - for (LocaleDataMetaInfo ldmi : - ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) { - if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) { - String t = ldmi.availableLanguageTags(category); - if (t != null) { - if (tags == null) { - tags = t; - } else { - tags += " " + t; - } + String nonBaseTags = AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + StringBuilder tags = new StringBuilder(); + for (LocaleDataMetaInfo ldmi : + ServiceLoader.loadInstalled(LocaleDataMetaInfo.class)) { + if (ldmi.getType() == LocaleProviderAdapter.Type.JRE) { + String t = ldmi.availableLanguageTags(category); + if (t != null) { + if (tags.length() > 0) { + tags.append(' '); } + tags.append(t); } } - return tags; } + return tags.toString(); }); if (nonBaseTags != null) { diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index 25ce39f30fc..2269d608eb5 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -42,6 +42,7 @@ package sun.util.locale.provider; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; +import java.lang.reflect.Module; import java.text.MessageFormat; import java.util.Calendar; import java.util.LinkedHashSet; @@ -117,6 +118,10 @@ public class LocaleResources { return biInfo; } + Module getBreakIteratorDataModule() { + return localeData.getBreakIteratorInfo(locale).getClass().getModule(); + } + int getCalendarData(String key) { Integer caldata; String cacheKey = CALENDAR_DATA + key; diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java new file mode 100644 index 00000000000..114a7fa63c7 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/ResourceBundleProviderSupport.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.locale.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.lang.reflect.Module; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +/** + * ResourceBundleProviderSupport provides convenience methods for loading + * resource bundles. + */ +public class ResourceBundleProviderSupport { + /** + * Loads a {@code ResourceBundle} of the given {@code bundleName} local to + * the given {@code module}. + * + * @apiNote + * {@link Class#forName(Module, String)} does a stack-based permission check. + * Caller of this method is responsible for doing an appropriate permission + * on behalf of the caller before calling this method. + * + * @param module the module from which the {@code ResourceBundle} is loaded + * @param bundleName the bundle name for the {@code ResourceBundle} class, + * such as "com.example.app.MyResources_fr" + * @return the {@code ResourceBundle}, or null if no {@code ResourceBundle} is found + * @throws SecurityException + * if a security manager exists, it denies loading the class given by + * {@code bundleName} from the given {@code module}. + * If the given module is "java.base", this method will not do security check. + * @throws NullPointerException + * if {@code module} or {@code bundleName) is null + * @see Class#forName(Module, String) + */ + public static ResourceBundle loadResourceBundle(Module module, String bundleName) + { + Class c = Class.forName(module, bundleName); + if (c != null && ResourceBundle.class.isAssignableFrom(c)) { + try { + @SuppressWarnings("unchecked") + Class bundleClass = (Class) c; + Constructor ctor = bundleClass.getConstructor(); + if (!Modifier.isPublic(ctor.getModifiers())) { + return null; + } + // java.base may not be able to read the bundleClass's module. + PrivilegedAction pa1 = () -> { ctor.setAccessible(true); return null; }; + AccessController.doPrivileged(pa1); + try { + return ctor.newInstance((Object[]) null); + } catch (InvocationTargetException e) { + uncheckedThrow(e); + } catch (InstantiationException | IllegalAccessException e) { + throw new InternalError(e); + } + } catch (NoSuchMethodException e) { + } + } + return null; + } + + @SuppressWarnings("unchecked") + private static void uncheckedThrow(Throwable t) throws T { + if (t != null) + throw (T)t; + else + throw new Error("Unknown Exception"); + } + + /** + * Loads properties of the given {@code bundleName} local to the given + * {@code module} and returns a {@code ResourceBundle} produced from the + * loaded properties. + * + * @apiNote This method is intended for internal use. Need to refactor. + * + * @param module the module from which the properties are loaded + * @param bundleName the bundle name of the properties, + * such as "com.example.app.MyResources_de" + * @return the {@code ResourceBundle} produced from the loaded properties, + * or null if no properties are found + * @see PropertyResourceBundle + */ + public static ResourceBundle loadPropertyResourceBundle(Module module, String bundleName) + throws IOException + { + String resourceName = toResourceName(bundleName, "properties"); + if (resourceName == null) { + return null; + } + + PrivilegedAction pa = () -> { + try { + return module.getResourceAsStream(resourceName); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }; + try (InputStream stream = AccessController.doPrivileged(pa)) { + if (stream != null) { + return new PropertyResourceBundle(stream); + } else { + return null; + } + } catch (UncheckedIOException e) { + throw e.getCause(); + } + } + + private static String toResourceName(String bundleName, String suffix) { + if (bundleName.contains("://")) { + return null; + } + StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length()); + sb.append(bundleName.replace('.', '/')).append('.').append(suffix); + return sb.toString(); + } +} diff --git a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java b/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java index a1962e463da..7c00ee052f1 100644 --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/RuleBasedBreakIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -41,7 +41,9 @@ package sun.util.locale.provider; import java.io.BufferedInputStream; +import java.io.InputStream; import java.io.IOException; +import java.lang.reflect.Module; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -313,12 +315,12 @@ class RuleBasedBreakIterator extends BreakIterator { //======================================================================= /** - * Constructs a RuleBasedBreakIterator according to the datafile + * Constructs a RuleBasedBreakIterator according to the module and the datafile * provided. */ - RuleBasedBreakIterator(String datafile) + RuleBasedBreakIterator(Module module, String datafile) throws IOException, MissingResourceException { - readTables(datafile); + readTables(module, datafile); } /** @@ -369,10 +371,10 @@ class RuleBasedBreakIterator extends BreakIterator { * } * */ - protected final void readTables(String datafile) + protected final void readTables(Module module, String datafile) throws IOException, MissingResourceException { - byte[] buffer = readFile(datafile); + byte[] buffer = readFile(module, datafile); /* Read header_info. */ int stateTableLength = getInt(buffer, 0); @@ -436,21 +438,24 @@ class RuleBasedBreakIterator extends BreakIterator { numCategories = stateTable.length / endStates.length; } - protected byte[] readFile(final String datafile) + protected byte[] readFile(final Module module, final String datafile) throws IOException, MissingResourceException { BufferedInputStream is; try { - is = AccessController.doPrivileged( - new PrivilegedExceptionAction() { - @Override - public BufferedInputStream run() throws Exception { - return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + datafile)); - } + PrivilegedExceptionAction pa = () -> { + InputStream in = module.getResourceAsStream("sun/text/resources/" + datafile); + if (in == null) { + // Try to load the file with "java.base" module instance. Assumption + // here is that the fall back data files to be read should reside in + // java.base. + in = RuleBasedBreakIterator.class.getModule().getResourceAsStream("sun/text/resources/" + datafile); } - ); - } - catch (PrivilegedActionException e) { + + return new BufferedInputStream(in); + }; + is = AccessController.doPrivileged(pa); + } catch (PrivilegedActionException e) { throw new InternalError(e.toString(), e); } diff --git a/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java new file mode 100644 index 00000000000..5966bb59acc --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/Bundles.java @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved + * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved + * + * The original version of this source code and documentation + * is copyrighted and owned by Taligent, Inc., a wholly-owned + * subsidiary of IBM. These materials are provided under terms + * of a License Agreement between Taligent and Sun. This technology + * is protected by multiple US and International patents. + * + * This notice and attribution to Taligent may not be removed. + * Taligent is a registered trademark of Taligent, Inc. + * + */ + +package sun.util.resources; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.Objects; +import java.util.ResourceBundle; +import java.util.ServiceConfigurationError; +import java.util.ServiceLoader; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.spi.ResourceBundleProvider; +import jdk.internal.misc.JavaUtilResourceBundleAccess; +import jdk.internal.misc.SharedSecrets; +import sun.util.locale.provider.ResourceBundleProviderSupport; + + +/** + */ +public abstract class Bundles { + + /** initial size of the bundle cache */ + private static final int INITIAL_CACHE_SIZE = 32; + + /** constant indicating that no resource bundle exists */ + private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() { + @Override + public Enumeration getKeys() { return null; } + @Override + protected Object handleGetObject(String key) { return null; } + @Override + public String toString() { return "NONEXISTENT_BUNDLE"; } + }; + + private static final JavaUtilResourceBundleAccess bundleAccess + = SharedSecrets.getJavaUtilResourceBundleAccess(); + + /** + * The cache is a map from cache keys (with bundle base name, locale, and + * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a + * BundleReference. + * + * The cache is a ConcurrentMap, allowing the cache to be searched + * concurrently by multiple threads. This will also allow the cache keys + * to be reclaimed along with the ClassLoaders they reference. + * + * This variable would be better named "cache", but we keep the old + * name for compatibility with some workarounds for bug 4212439. + */ + private static final ConcurrentMap cacheList + = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE); + + /** + * Queue for reference objects referring to class loaders or bundles. + */ + private static final ReferenceQueue referenceQueue = new ReferenceQueue<>(); + + private Bundles() { + } + + public static ResourceBundle of(String baseName, Locale locale, Strategy strategy) { + return loadBundleOf(baseName, locale, strategy); + } + + private static ResourceBundle loadBundleOf(String baseName, + Locale targetLocale, + Strategy strategy) { + Objects.requireNonNull(baseName); + Objects.requireNonNull(targetLocale); + Objects.requireNonNull(strategy); + + CacheKey cacheKey = new CacheKey(baseName, targetLocale); + + ResourceBundle bundle = null; + + // Quick lookup of the cache. + BundleReference bundleRef = cacheList.get(cacheKey); + if (bundleRef != null) { + bundle = bundleRef.get(); + } + + // If this bundle and all of its parents are valid, + // then return this bundle. + if (isValidBundle(bundle)) { + return bundle; + } + + // Get the providers for loading the "leaf" bundle (i.e., bundle for + // targetLocale). If no providers are required for the bundle, + // none of its parents will require providers. + Class type + = strategy.getResourceBundleProviderType(baseName, targetLocale); + if (type != null) { + @SuppressWarnings("unchecked") + ServiceLoader providers + = (ServiceLoader) ServiceLoader.loadInstalled(type); + cacheKey.setProviders(providers); + } + + List candidateLocales = strategy.getCandidateLocales(baseName, targetLocale); + bundle = findBundleOf(cacheKey, strategy, baseName, candidateLocales, 0); + if (bundle == null) { + throwMissingResourceException(baseName, targetLocale, cacheKey.getCause()); + } + return bundle; + } + + private static ResourceBundle findBundleOf(CacheKey cacheKey, + Strategy strategy, + String baseName, + List candidateLocales, + int index) { + ResourceBundle parent = null; + Locale targetLocale = candidateLocales.get(index); + if (index != candidateLocales.size() - 1) { + parent = findBundleOf(cacheKey, strategy, baseName, candidateLocales, index + 1); + } + + // Before we do the real loading work, see whether we need to + // do some housekeeping: If resource bundles have been nulled out, + // remove all related information from the cache. + cleanupCache(); + + // find an individual ResourceBundle in the cache + cacheKey.setLocale(targetLocale); + ResourceBundle bundle = findBundleInCache(cacheKey); + if (bundle != null) { + if (bundle == NONEXISTENT_BUNDLE) { + return parent; + } + if (bundleAccess.getParent(bundle) == parent) { + return bundle; + } + // Remove bundle from the cache. + BundleReference bundleRef = cacheList.get(cacheKey); + if (bundleRef != null && bundleRef.get() == bundle) { + cacheList.remove(cacheKey, bundleRef); + } + } + + // Determine if providers should be used for loading the bundle. + // An assumption here is that if the leaf bundle of a look-up path is + // in java.base, all bundles of the path are in java.base. + // (e.g., en_US of path en_US -> en -> root is in java.base and the rest + // are in java.base as well) + // This assumption isn't valid for general bundle loading. + ServiceLoader providers = cacheKey.getProviders(); + if (providers != null) { + if (strategy.getResourceBundleProviderType(baseName, targetLocale) == null) { + providers = null; + } + } + + CacheKey constKey = (CacheKey) cacheKey.clone(); + try { + if (providers != null) { + bundle = loadBundleFromProviders(baseName, targetLocale, providers, cacheKey); + } else { + try { + bundle = ResourceBundleProviderSupport + .loadResourceBundle(Bundles.class.getModule(), + strategy.toBundleName(baseName, targetLocale)); + } catch (Exception e) { + cacheKey.setCause(e); + } + } + } finally { + if (constKey.getCause() instanceof InterruptedException) { + Thread.currentThread().interrupt(); + } + } + + if (bundle == null) { + // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle + // instance for the locale. + putBundleInCache(cacheKey, NONEXISTENT_BUNDLE); + return parent; + } + + if (parent != null && bundleAccess.getParent(bundle) == null) { + bundleAccess.setParent(bundle, parent); + } + bundleAccess.setLocale(bundle, targetLocale); + bundleAccess.setName(bundle, baseName); + bundle = putBundleInCache(cacheKey, bundle); + return bundle; + } + + private static void cleanupCache() { + Object ref; + while ((ref = referenceQueue.poll()) != null) { + cacheList.remove(((CacheKeyReference)ref).getCacheKey()); + } + } + + /** + * Loads ResourceBundle from service providers. + */ + private static ResourceBundle loadBundleFromProviders(String baseName, + Locale locale, + ServiceLoader providers, + CacheKey cacheKey) + { + return AccessController.doPrivileged( + new PrivilegedAction<>() { + public ResourceBundle run() { + for (Iterator itr = providers.iterator(); itr.hasNext(); ) { + try { + ResourceBundleProvider provider = itr.next(); + ResourceBundle bundle = provider.getBundle(baseName, locale); + if (bundle != null) { + return bundle; + } + } catch (ServiceConfigurationError | SecurityException e) { + if (cacheKey != null) { + cacheKey.setCause(e); + } + } + } + return null; + } + }); + + } + + private static boolean isValidBundle(ResourceBundle bundle) { + return bundle != null && bundle != NONEXISTENT_BUNDLE; + } + + /** + * Throw a MissingResourceException with proper message + */ + private static void throwMissingResourceException(String baseName, + Locale locale, + Throwable cause) { + // If the cause is a MissingResourceException, avoid creating + // a long chain. (6355009) + if (cause instanceof MissingResourceException) { + cause = null; + } + MissingResourceException e; + e = new MissingResourceException("Can't find bundle for base name " + + baseName + ", locale " + locale, + baseName + "_" + locale, // className + ""); + e.initCause(cause); + throw e; + } + + /** + * Finds a bundle in the cache. + * + * @param cacheKey the key to look up the cache + * @return the ResourceBundle found in the cache or null + */ + private static ResourceBundle findBundleInCache(CacheKey cacheKey) { + BundleReference bundleRef = cacheList.get(cacheKey); + if (bundleRef == null) { + return null; + } + return bundleRef.get(); + } + + /** + * Put a new bundle in the cache. + * + * @param cacheKey the key for the resource bundle + * @param bundle the resource bundle to be put in the cache + * @return the ResourceBundle for the cacheKey; if someone has put + * the bundle before this call, the one found in the cache is + * returned. + */ + private static ResourceBundle putBundleInCache(CacheKey cacheKey, + ResourceBundle bundle) { + CacheKey key = (CacheKey) cacheKey.clone(); + BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key); + + // Put the bundle in the cache if it's not been in the cache. + BundleReference result = cacheList.putIfAbsent(key, bundleRef); + + // If someone else has put the same bundle in the cache before + // us, we should use the one in the cache. + if (result != null) { + ResourceBundle rb = result.get(); + if (rb != null) { + // Clear the back link to the cache key + bundle = rb; + // Clear the reference in the BundleReference so that + // it won't be enqueued. + bundleRef.clear(); + } else { + // Replace the invalid (garbage collected) + // instance with the valid one. + cacheList.put(key, bundleRef); + } + } + return bundle; + } + + + /** + * The Strategy interface defines methods that are called by Bundles.of during + * the resource bundle loading process. + */ + public static interface Strategy { + /** + * Returns a list of locales to be looked up for bundle loading. + */ + public List getCandidateLocales(String baseName, Locale locale); + + /** + * Returns the bundle name for the given baseName and locale. + */ + public String toBundleName(String baseName, Locale locale); + + /** + * Returns the service provider type for the given baseName + * and locale, or null if no service providers should be used. + */ + public Class getResourceBundleProviderType(String baseName, + Locale locale); + } + + /** + * The common interface to get a CacheKey in LoaderReference and + * BundleReference. + */ + private static interface CacheKeyReference { + public CacheKey getCacheKey(); + } + + /** + * References to bundles are soft references so that they can be garbage + * collected when they have no hard references. + */ + private static class BundleReference extends SoftReference + implements CacheKeyReference { + private final CacheKey cacheKey; + + BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) { + super(referent, q); + cacheKey = key; + } + + @Override + public CacheKey getCacheKey() { + return cacheKey; + } + } + + /** + * Key used for cached resource bundles. The key checks the base + * name, the locale, and the class loader to determine if the + * resource is a match to the requested one. The loader may be + * null, but the base name and the locale must have a non-null + * value. + */ + private static class CacheKey implements Cloneable { + // These two are the actual keys for lookup in Map. + private String name; + private Locale locale; + + // Placeholder for an error report by a Throwable + private Throwable cause; + + // Hash code value cache to avoid recalculating the hash code + // of this instance. + private int hashCodeCache; + + // The service loader to load bundles or null if no service loader + // is required. + private ServiceLoader providers; + + CacheKey(String baseName, Locale locale) { + this.name = baseName; + this.locale = locale; + calculateHashCode(); + } + + String getName() { + return name; + } + + CacheKey setName(String baseName) { + if (!this.name.equals(baseName)) { + this.name = baseName; + calculateHashCode(); + } + return this; + } + + Locale getLocale() { + return locale; + } + + CacheKey setLocale(Locale locale) { + if (!this.locale.equals(locale)) { + this.locale = locale; + calculateHashCode(); + } + return this; + } + + ServiceLoader getProviders() { + return providers; + } + + void setProviders(ServiceLoader providers) { + this.providers = providers; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + try { + final CacheKey otherEntry = (CacheKey)other; + //quick check to see if they are not equal + if (hashCodeCache != otherEntry.hashCodeCache) { + return false; + } + return locale.equals(otherEntry.locale) + && name.equals(otherEntry.name); + } catch (NullPointerException | ClassCastException e) { + } + return false; + } + + @Override + public int hashCode() { + return hashCodeCache; + } + + private void calculateHashCode() { + hashCodeCache = name.hashCode() << 3; + hashCodeCache ^= locale.hashCode(); + } + + @Override + public Object clone() { + try { + CacheKey clone = (CacheKey) super.clone(); + // Clear the reference to a Throwable + clone.cause = null; + // Clear the reference to a ServiceLoader + clone.providers = null; + return clone; + } catch (CloneNotSupportedException e) { + //this should never happen + throw new InternalError(e); + } + } + + private void setCause(Throwable cause) { + if (this.cause == null) { + this.cause = cause; + } else { + // Override the cause if the previous one is + // ClassNotFoundException. + if (this.cause instanceof ClassNotFoundException) { + this.cause = cause; + } + } + } + + private Throwable getCause() { + return cause; + } + + @Override + public String toString() { + String l = locale.toString(); + if (l.isEmpty()) { + if (!locale.getVariant().isEmpty()) { + l = "__" + locale.getVariant(); + } else { + l = "\"\""; + } + } + return "CacheKey[" + name + ", lc=" + l + ")]"; + } + } +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/CalendarDataProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/CalendarDataProvider.java new file mode 100644 index 00000000000..f74aba1692e --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/CalendarDataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface CalendarDataProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/CurrencyNamesProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/CurrencyNamesProvider.java new file mode 100644 index 00000000000..be81006fb38 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/CurrencyNamesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface CurrencyNamesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java index 51fa7395b96..ddc24395ee7 100644 --- a/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java +++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -46,14 +46,17 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.spi.ResourceBundleProvider; import sun.util.locale.provider.JRELocaleProviderAdapter; import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.locale.provider.ResourceBundleBasedAdapter; import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * Provides information about and access to resource bundles in the @@ -65,6 +68,14 @@ import static sun.util.locale.provider.LocaleProviderAdapter.Type.JRE; */ public class LocaleData { + private static final ResourceBundle.Control defaultControl + = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); + + private static final String DOTCLDR = ".cldr"; + + // Map of key (base name + locale) to candidates + private static final Map> CANDIDATES_MAP = new ConcurrentHashMap<>(); + private final LocaleProviderAdapter.Type type; public LocaleData(LocaleProviderAdapter.Type type) { @@ -163,8 +174,7 @@ public class LocaleData { return AccessController.doPrivileged(new PrivilegedAction<>() { @Override public ResourceBundle run() { - return ResourceBundle - .getBundle(baseName, locale, LocaleDataResourceBundleControl.INSTANCE); + return Bundles.of(baseName, locale, LocaleDataStrategy.INSTANCE); } }); } @@ -175,9 +185,8 @@ public class LocaleData { public OpenListResourceBundle run() { OpenListResourceBundle rb = null; try { - rb = (OpenListResourceBundle) ResourceBundle.getBundle(baseName, - locale, SupplementaryResourceBundleControl.INSTANCE); - + rb = (OpenListResourceBundle) Bundles.of(baseName, locale, + SupplementaryStrategy.INSTANCE); } catch (MissingResourceException e) { // return null if no supplementary is available } @@ -186,12 +195,51 @@ public class LocaleData { }); } - private static class LocaleDataResourceBundleControl extends ResourceBundle.Control { - /* Singlton instance of ResourceBundle.Control. */ - private static final LocaleDataResourceBundleControl INSTANCE = - new LocaleDataResourceBundleControl(); + private static abstract class LocaleDataResourceBundleProvider + implements ResourceBundleProvider { + abstract protected boolean isSupportedInModule(String baseName, Locale locale); - private LocaleDataResourceBundleControl() { + /** + * Changes baseName to its module dependent package name and + * calls the super class implementation. For example, + * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP, + * the baseName is changed to "sun.text.resources.ext.FormatData". If + * baseName contains ".cldr", such as "sun.text.resources.cldr.FormatData", + * the name is changed to "sun.text.resources.cldr.ext.FormatData". + */ + protected String toBundleName(String baseName, Locale locale) { + return LocaleDataStrategy.INSTANCE.toBundleName(baseName, locale); + } + } + + /** + * A ResourceBundleProvider implementation for loading locale data + * resource bundles except for the java.time supplementary data. + */ + public static abstract class CommonResourceBundleProvider extends LocaleDataResourceBundleProvider { + @Override + protected boolean isSupportedInModule(String baseName, Locale locale) { + return LocaleDataStrategy.INSTANCE.inJavaBaseModule(baseName, locale); + } + } + + /** + * A ResourceBundleProvider implementation for loading supplementary + * resource bundles for java.time. + */ + public static abstract class SupplementaryResourceBundleProvider extends LocaleDataResourceBundleProvider { + @Override + protected boolean isSupportedInModule(String baseName, Locale locale) { + return SupplementaryStrategy.INSTANCE.inJavaBaseModule(baseName, locale); + } + } + + // Bundles.Strategy implementations + + private static class LocaleDataStrategy implements Bundles.Strategy { + private static final LocaleDataStrategy INSTANCE = new LocaleDataStrategy(); + + private LocaleDataStrategy() { } /* @@ -205,66 +253,49 @@ public class LocaleData { * @exception NullPointerException if baseName or locale is null. */ @Override - public List getCandidateLocales(String baseName, Locale locale) { - LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE; - LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); - List candidates = adapter instanceof ResourceBundleBasedAdapter ? - ((ResourceBundleBasedAdapter)adapter).getCandidateLocales(baseName, locale) : - super.getCandidateLocales(baseName, locale); + public List getCandidateLocales(String baseName, Locale locale) { + String key = baseName + '-' + locale.toLanguageTag(); + List candidates = CANDIDATES_MAP.get(key); + if (candidates == null) { + LocaleProviderAdapter.Type type = baseName.contains(DOTCLDR) ? CLDR : JRE; + LocaleProviderAdapter adapter = LocaleProviderAdapter.forType(type); + candidates = adapter instanceof ResourceBundleBasedAdapter ? + ((ResourceBundleBasedAdapter)adapter).getCandidateLocales(baseName, locale) : + defaultControl.getCandidateLocales(baseName, locale); - // Weed out Locales which are known to have no resource bundles - int lastDot = baseName.lastIndexOf('.'); - String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName; - Set langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category); - if (!langtags.isEmpty()) { - for (Iterator itr = candidates.iterator(); itr.hasNext();) { - if (!adapter.isSupportedProviderLocale(itr.next(), langtags)) { - itr.remove(); + // Weed out Locales which are known to have no resource bundles + int lastDot = baseName.lastIndexOf('.'); + String category = (lastDot >= 0) ? baseName.substring(lastDot + 1) : baseName; + Set langtags = ((JRELocaleProviderAdapter)adapter).getLanguageTagSet(category); + if (!langtags.isEmpty()) { + for (Iterator itr = candidates.iterator(); itr.hasNext();) { + if (!adapter.isSupportedProviderLocale(itr.next(), langtags)) { + itr.remove(); + } } } - } - - // Force fallback to Locale.ENGLISH for CLDR time zone names support - if (locale.getLanguage() != "en" - && type == CLDR && category.equals("TimeZoneNames")) { - candidates.add(candidates.size() - 1, Locale.ENGLISH); + // Force fallback to Locale.ENGLISH for CLDR time zone names support + if (locale.getLanguage() != "en" + && type == CLDR && category.equals("TimeZoneNames")) { + candidates.add(candidates.size() - 1, Locale.ENGLISH); + } + CANDIDATES_MAP.putIfAbsent(key, candidates); } return candidates; } - /* - * Overrides "getFallbackLocale" to return null so - * that the fallback locale will be null. - * @param baseName the resource bundle base name. - * locale the requested locale for the resource bundle. - * @return null for the fallback locale. - * @exception NullPointerException if baseName or locale is null. - */ - @Override - public Locale getFallbackLocale(String baseName, Locale locale) { - if (baseName == null || locale == null) { - throw new NullPointerException(); - } - return null; + boolean inJavaBaseModule(String baseName, Locale locale) { + // TODO: avoid hard-coded Locales + return locale.equals(Locale.ROOT) || + (locale.getLanguage() == "en" && + (locale.getCountry().isEmpty() || + locale.getCountry() == "US")); } - private static final String DOTCLDR = ".cldr"; - - /** - * Changes baseName to its module dependent package name and - * calls the super class implementation. For example, - * if the baseName is "sun.text.resources.FormatData" and locale is ja_JP, - * the baseName is changed to "sun.text.resources.ext.FormatData". If - * baseName contains "cldr", such as "sun.text.resources.cldr.FormatData", - * the name is changed to "sun.text.resources.cldr.ext.FormatData". - */ @Override public String toBundleName(String baseName, Locale locale) { String newBaseName = baseName; - String lang = locale.getLanguage(); - String ctry = locale.getCountry(); - if (lang.length() > 0 && - (lang != "en" || (ctry.length() > 0 && ctry != "US"))) { + if (!inJavaBaseModule(baseName, locale)) { if (baseName.startsWith(JRE.getUtilResourcesPackage()) || baseName.startsWith(JRE.getTextResourcesPackage())) { // Assume the lengths are the same. @@ -274,19 +305,26 @@ public class LocaleData { if (baseName.indexOf(DOTCLDR, index) > 0) { index += DOTCLDR.length(); } - newBaseName = baseName.substring(0, index + 1) + "ext" + - baseName.substring(index); + newBaseName = baseName.substring(0, index + 1) + "ext" + + baseName.substring(index); } } - return super.toBundleName(newBaseName, locale); + return defaultControl.toBundleName(newBaseName, locale); + } + + @Override + public Class getResourceBundleProviderType(String baseName, + Locale locale) { + return inJavaBaseModule(baseName, locale) ? + null : CommonResourceBundleProvider.class; } } - private static class SupplementaryResourceBundleControl extends LocaleDataResourceBundleControl { - private static final SupplementaryResourceBundleControl INSTANCE = - new SupplementaryResourceBundleControl(); + private static class SupplementaryStrategy extends LocaleDataStrategy { + private static final SupplementaryStrategy INSTANCE + = new SupplementaryStrategy(); - private SupplementaryResourceBundleControl() { + private SupplementaryStrategy() { } @Override @@ -296,9 +334,16 @@ public class LocaleData { } @Override - public long getTimeToLive(String baseName, Locale locale) { - assert baseName.contains("JavaTimeSupplementary"); - return TTL_DONT_CACHE; + public Class getResourceBundleProviderType(String baseName, + Locale locale) { + return inJavaBaseModule(baseName, locale) ? + null : SupplementaryResourceBundleProvider.class; + } + + @Override + boolean inJavaBaseModule(String baseName, Locale locale) { + // TODO: avoid hard-coded Locales + return locale.equals(Locale.ROOT) || locale.getLanguage() == "en"; } } } diff --git a/jdk/src/java.base/share/classes/sun/util/resources/LocaleDataProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/LocaleDataProvider.java new file mode 100644 index 00000000000..8369917b21f --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleDataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface LocaleDataProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/LocaleNamesProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/LocaleNamesProvider.java new file mode 100644 index 00000000000..b231ab07d58 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/LocaleNamesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface LocaleNamesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNamesProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNamesProvider.java new file mode 100644 index 00000000000..839b38ea919 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNamesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface TimeZoneNamesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/cldr/CalendarDataProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/cldr/CalendarDataProvider.java new file mode 100644 index 00000000000..d614174abc4 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/cldr/CalendarDataProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources.cldr; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface CalendarDataProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/cldr/CurrencyNamesProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/cldr/CurrencyNamesProvider.java new file mode 100644 index 00000000000..b2c8f088d91 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/cldr/CurrencyNamesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources.cldr; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface CurrencyNamesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/cldr/LocaleNamesProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/cldr/LocaleNamesProvider.java new file mode 100644 index 00000000000..05f63660c76 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/cldr/LocaleNamesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources.cldr; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface LocaleNamesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/classes/sun/util/resources/cldr/TimeZoneNamesProvider.java b/jdk/src/java.base/share/classes/sun/util/resources/cldr/TimeZoneNamesProvider.java new file mode 100644 index 00000000000..d0f95bf5c55 --- /dev/null +++ b/jdk/src/java.base/share/classes/sun/util/resources/cldr/TimeZoneNamesProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.util.resources.cldr; + +import java.util.spi.ResourceBundleProvider; + +/** + * An interface for the internal locale data provider for which {@code ResourceBundle} + * searches. + */ +public interface TimeZoneNamesProvider extends ResourceBundleProvider { +} diff --git a/jdk/src/java.base/share/conf/security/java.policy b/jdk/src/java.base/share/conf/security/java.policy index 8ea368707a2..a6b3b1bfb24 100644 --- a/jdk/src/java.base/share/conf/security/java.policy +++ b/jdk/src/java.base/share/conf/security/java.policy @@ -1,40 +1,13 @@ // permissions required by each component + +grant codeBase "jrt:/java.activation" { + permission java.security.AllPermission; +}; + grant codeBase "jrt:/java.corba" { permission java.security.AllPermission; }; -grant codeBase "jrt:/jdk.zipfs" { - permission java.io.FilePermission "<>", "read,write,delete"; - permission java.lang.RuntimePermission "fileSystemProvider"; - permission java.util.PropertyPermission "*", "read"; -}; - -grant codeBase "jrt:/jdk.localedata" { - permission java.lang.RuntimePermission "accessClassInPackage.sun.text.*"; - permission java.lang.RuntimePermission "accessClassInPackage.sun.util.*"; - permission java.util.PropertyPermission "*", "read"; -}; - -grant codeBase "jrt:/jdk.naming.dns" { - permission java.security.AllPermission; -}; - -grant codeBase "jrt:/jdk.dynalink" { - permission java.security.AllPermission; -}; - -grant codeBase "jrt:/jdk.scripting.nashorn" { - permission java.security.AllPermission; -}; - -grant codeBase "jrt:/jdk.scripting.nashorn.shell" { - permission java.security.AllPermission; -}; - -grant codeBase "jrt:/jdk.internal.le" { - permission java.security.AllPermission; -}; - grant codeBase "jrt:/jdk.crypto.ucrypto" { permission java.lang.RuntimePermission "accessClassInPackage.sun.security.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch"; @@ -72,16 +45,36 @@ grant codeBase "jrt:/jdk.crypto.pkcs11" { permission java.io.FilePermission "<>", "read"; }; -grant codeBase "jrt:/java.xml.ws" { - permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.*"; - permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal"; - permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal.*"; - permission java.lang.RuntimePermission "accessClassInPackage.com.sun.org.apache.xerces.internal.*"; - permission java.lang.RuntimePermission "accessDeclaredMembers"; - permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; +grant codeBase "jrt:/jdk.dynalink" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.internal.le" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.jsobject" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.localedata" { + permission java.lang.RuntimePermission "accessClassInPackage.sun.text.*"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.util.*"; permission java.util.PropertyPermission "*", "read"; }; +grant codeBase "jrt:/jdk.naming.dns" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.scripting.nashorn" { + permission java.security.AllPermission; +}; + +grant codeBase "jrt:/jdk.scripting.nashorn.shell" { + permission java.security.AllPermission; +}; + grant codeBase "jrt:/java.xml.bind" { permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.*"; permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal"; @@ -91,8 +84,20 @@ grant codeBase "jrt:/java.xml.bind" { permission java.util.PropertyPermission "*", "read"; }; -grant codeBase "jrt:/java.activation" { - permission java.security.AllPermission; +grant codeBase "jrt:/java.xml.ws" { + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.xml.internal.*"; + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal"; + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.istack.internal.*"; + permission java.lang.RuntimePermission "accessClassInPackage.com.sun.org.apache.xerces.internal.*"; + permission java.lang.RuntimePermission "accessDeclaredMembers"; + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.util.PropertyPermission "*", "read"; +}; + +grant codeBase "jrt:/jdk.zipfs" { + permission java.io.FilePermission "<>", "read,write,delete"; + permission java.lang.RuntimePermission "fileSystemProvider"; + permission java.util.PropertyPermission "*", "read"; }; // default permissions granted to all domains diff --git a/jdk/src/java.base/share/conf/security/java.security b/jdk/src/java.base/share/conf/security/java.security index fdcfe2be25c..2e8356b1f52 100644 --- a/jdk/src/java.base/share/conf/security/java.security +++ b/jdk/src/java.base/share/conf/security/java.security @@ -66,28 +66,28 @@ # List of providers and their preference orders (see above): # #ifdef solaris -security.provider.tbd=com.oracle.security.ucrypto.UcryptoProvider -security.provider.tbd=sun.security.pkcs11.SunPKCS11 ${java.home}/conf/security/sunpkcs11-solaris.cfg +security.provider.tbd=OracleUcrypto +security.provider.tbd=SunPKCS11 ${java.home}/conf/security/sunpkcs11-solaris.cfg #endif -security.provider.tbd=sun.security.provider.Sun -security.provider.tbd=sun.security.rsa.SunRsaSign -security.provider.tbd=sun.security.ec.SunEC -security.provider.tbd=com.sun.net.ssl.internal.ssl.Provider -security.provider.tbd=com.sun.crypto.provider.SunJCE -security.provider.tbd=sun.security.jgss.SunProvider -security.provider.tbd=com.sun.security.sasl.Provider -security.provider.tbd=org.jcp.xml.dsig.internal.dom.XMLDSigRI -security.provider.tbd=sun.security.smartcardio.SunPCSC -security.provider.tbd=sun.security.provider.certpath.ldap.JdkLDAP -security.provider.tbd=com.sun.security.sasl.gsskerb.JdkSASL +security.provider.tbd=SUN +security.provider.tbd=SunRsaSign +security.provider.tbd=SunEC +security.provider.tbd=SunJSSE +security.provider.tbd=SunJCE +security.provider.tbd=SunJGSS +security.provider.tbd=SunSASL +security.provider.tbd=XMLDSig +security.provider.tbd=SunPCSC +security.provider.tbd=JdkLDAP +security.provider.tbd=JdkSASL #ifdef windows -security.provider.tbd=sun.security.mscapi.SunMSCAPI +security.provider.tbd=SunMSCAPI #endif #ifdef macosx -security.provider.tbd=apple.security.AppleProvider +security.provider.tbd=Apple #endif #ifndef solaris -security.provider.tbd=sun.security.pkcs11.SunPKCS11 +security.provider.tbd=SunPKCS11 #endif # @@ -271,6 +271,7 @@ package.access=sun.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ + jdk.rmi.rmic.,\ jdk.tools.jimage.,\ com.sun.activation.registries.,\ com.sun.java.accessibility.util.internal.,\ @@ -327,6 +328,7 @@ package.definition=sun.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ + jdk.rmi.rmic.,\ jdk.tools.jimage.,\ com.sun.activation.registries.,\ com.sun.java.accessibility.util.internal.,\ diff --git a/jdk/src/java.base/share/native/include/jni.h b/jdk/src/java.base/share/native/include/jni.h index c09658a1fa7..dc86df3d0b1 100644 --- a/jdk/src/java.base/share/native/include/jni.h +++ b/jdk/src/java.base/share/native/include/jni.h @@ -765,6 +765,17 @@ struct JNINativeInterface_ { jobjectRefType (JNICALL *GetObjectRefType) (JNIEnv* env, jobject obj); + + /* Module Features */ + + jobject (JNICALL *GetModule) + (JNIEnv* env, jclass clazz); + + void (JNICALL *AddModuleReads) + (JNIEnv* env, jobject m1, jobject m2); + + jboolean (JNICALL *CanReadModule) + (JNIEnv* env, jobject m1, jobject m2); }; /* @@ -1857,6 +1868,20 @@ struct JNIEnv_ { return functions->GetObjectRefType(this, obj); } + /* Module Features */ + + jobject GetModule(jclass clazz) { + return functions->GetModule(this, clazz); + } + + void AddModuleReads(jobject m1, jobject m2) { + functions->AddModuleReads(this, m1, m2); + } + + jboolean CanReadModule(jobject m1, jobject m2) { + return functions->CanReadModule(this, m1, m2); + } + #endif /* __cplusplus */ }; diff --git a/jdk/src/java.base/share/native/include/jvm.h b/jdk/src/java.base/share/native/include/jvm.h index 968296604fb..c5fc7e91178 100644 --- a/jdk/src/java.base/share/native/include/jvm.h +++ b/jdk/src/java.base/share/native/include/jvm.h @@ -389,6 +389,41 @@ JVM_DefineClassWithSource(JNIEnv *env, const char *name, jobject loader, const jbyte *buf, jsize len, jobject pd, const char *source); +/* + * Module support funcions + */ + +JNIEXPORT void JNICALL +JVM_DefineModule(JNIEnv *env, jobject module, jstring version, jstring location, + jobjectArray packages); + +JNIEXPORT void JNICALL +JVM_SetBootLoaderUnnamedModule(JNIEnv *env, jobject module); + +JNIEXPORT void JNICALL +JVM_AddReadsModule(JNIEnv *env, jobject from_module, jobject to_module); + +JNIEXPORT jboolean JNICALL +JVM_CanReadModule(JNIEnv *env, jobject asking_module, jobject source_module); + +JNIEXPORT void JNICALL +JVM_AddModuleExports(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + +JNIEXPORT void JNICALL +JVM_AddModuleExportsToAll(JNIEnv *env, jobject from_module, jstring package); + +JNIEXPORT void JNICALL +JVM_AddModuleExportsToAllUnnamed(JNIEnv *env, jobject from_module, jstring package); + +JNIEXPORT jboolean JNICALL +JVM_IsExportedToModule(JNIEnv *env, jobject from_module, jstring package, jobject to_module); + +JNIEXPORT void JNICALL +JVM_AddModulePackage(JNIEnv* env, jobject module, jstring package); + +JNIEXPORT jobject JNICALL +JVM_GetModuleByPackageName(JNIEnv *env, jobject cl, jstring pkg); + /* * Reflection support functions */ diff --git a/jdk/src/java.base/share/native/include/jvmti.h b/jdk/src/java.base/share/native/include/jvmti.h index ee708cb193b..684fd2d7046 100644 --- a/jdk/src/java.base/share/native/include/jvmti.h +++ b/jdk/src/java.base/share/native/include/jvmti.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,7 @@ * questions. */ - /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ - + /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ /* Include file for the Java(tm) Virtual Machine Tool Interface */ @@ -42,8 +41,9 @@ enum { JVMTI_VERSION_1_0 = 0x30010000, JVMTI_VERSION_1_1 = 0x30010100, JVMTI_VERSION_1_2 = 0x30010200, + JVMTI_VERSION_9 = 0x30090000, - JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (2 * 0x100) + 1 /* version: 1.2.1 */ + JVMTI_VERSION = 0x30000000 + (9 * 0x10000) + (0 * 0x100) + 0 /* version: 9.0.0 */ }; JNIEXPORT jint JNICALL @@ -703,7 +703,8 @@ typedef struct { unsigned int can_retransform_any_class : 1; unsigned int can_generate_resource_exhaustion_heap_events : 1; unsigned int can_generate_resource_exhaustion_threads_events : 1; - unsigned int : 7; + unsigned int can_generate_early_vmstart : 1; + unsigned int : 6; unsigned int : 16; unsigned int : 16; unsigned int : 16; @@ -1011,8 +1012,10 @@ typedef struct jvmtiInterface_1_ { jthread event_thread, ...); - /* 3 : RESERVED */ - void *reserved3; + /* 3 : Get All Modules */ + jvmtiError (JNICALL *GetAllModules) (jvmtiEnv* env, + jint* module_count_ptr, + jobject** modules_ptr); /* 4 : Get All Threads */ jvmtiError (JNICALL *GetAllThreads) (jvmtiEnv* env, @@ -1675,7 +1678,7 @@ typedef struct jvmtiInterface_1_ { /* 132 : Set System Property */ jvmtiError (JNICALL *SetSystemProperty) (jvmtiEnv* env, const char* property, - const char* value); + const char* value_ptr); /* 133 : Get Phase */ jvmtiError (JNICALL *GetPhase) (jvmtiEnv* env, @@ -2137,6 +2140,11 @@ struct _jvmtiEnv { return functions->ClearFieldModificationWatch(this, klass, field); } + jvmtiError GetAllModules(jint* module_count_ptr, + jobject** modules_ptr) { + return functions->GetAllModules(this, module_count_ptr, modules_ptr); + } + jvmtiError GetLoadedClasses(jint* class_count_ptr, jclass** classes_ptr) { return functions->GetLoadedClasses(this, class_count_ptr, classes_ptr); @@ -2484,8 +2492,8 @@ struct _jvmtiEnv { } jvmtiError SetSystemProperty(const char* property, - const char* value) { - return functions->SetSystemProperty(this, property, value); + const char* value_ptr) { + return functions->SetSystemProperty(this, property, value_ptr); } jvmtiError GetPhase(jvmtiPhase* phase_ptr) { @@ -2531,4 +2539,3 @@ struct _jvmtiEnv { #endif /* __cplusplus */ #endif /* !_JAVA_JVMTI_H_ */ - diff --git a/jdk/src/java.base/share/native/launcher/defines.h b/jdk/src/java.base/share/native/launcher/defines.h index 4411ee0fb9f..e3b18882df4 100644 --- a/jdk/src/java.base/share/native/launcher/defines.h +++ b/jdk/src/java.base/share/native/launcher/defines.h @@ -53,9 +53,10 @@ static const char* const_jargs[] = JAVA_ARGS; * value of -cp option to the launcher. */ #ifndef APP_CLASSPATH -#define APP_CLASSPATH { "/lib/tools.jar", "/classes" } -#endif /* APP_CLASSPATH */ +static const char* const_appclasspath[] = { NULL }; +#else static const char* const_appclasspath[] = APP_CLASSPATH; +#endif /* APP_CLASSPATH */ #else /* !JAVA_ARGS */ #define HAS_JAVA_ARGS JNI_FALSE #ifdef PROGNAME @@ -64,7 +65,7 @@ static const char* const_progname = PROGNAME; static char* const_progname = NULL; #endif static const char** const_jargs = NULL; -static const char** const_appclasspath = NULL; +static const char* const_appclasspath[] = { NULL }; #endif /* JAVA_ARGS */ #ifdef LAUNCHER_NAME diff --git a/jdk/src/java.base/share/native/launcher/main.c b/jdk/src/java.base/share/native/launcher/main.c index cfbabde0532..9c24c2ebf68 100644 --- a/jdk/src/java.base/share/native/launcher/main.c +++ b/jdk/src/java.base/share/native/launcher/main.c @@ -83,7 +83,7 @@ char **__initenv; int WINAPI WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) { - int margc; + int margc, appclassc; char** margv; const jboolean const_javaw = JNI_TRUE; @@ -93,7 +93,7 @@ WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow) int main(int argc, char **argv) { - int margc; + int margc, appclassc; char** margv; const jboolean const_javaw = JNI_FALSE; #endif /* JAVAW */ @@ -148,9 +148,14 @@ main(int argc, char **argv) margv = args->elements; } #endif /* WIN32 */ + if (const_appclasspath[0] == NULL) { + appclassc = 0; + } else { + appclassc = sizeof(const_appclasspath) / sizeof(char *); + } return JLI_Launch(margc, margv, sizeof(const_jargs) / sizeof(char *), const_jargs, - sizeof(const_appclasspath) / sizeof(char *), const_appclasspath, + appclassc, const_appclasspath, VERSION_STRING, DOT_VERSION, (const_progname != NULL) ? const_progname : *margv, diff --git a/jdk/src/java.base/share/native/libjava/Package.c b/jdk/src/java.base/share/native/libjava/BootLoader.c similarity index 73% rename from jdk/src/java.base/share/native/libjava/Package.c rename to jdk/src/java.base/share/native/libjava/BootLoader.c index 72ebcc93a8a..532e33814b8 100644 --- a/jdk/src/java.base/share/native/libjava/Package.c +++ b/jdk/src/java.base/share/native/libjava/BootLoader.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -26,16 +26,23 @@ #include #include "jvm.h" #include "jni_util.h" -#include "java_lang_Package.h" +#include "jdk_internal_loader_BootLoader.h" JNIEXPORT jstring JNICALL -Java_java_lang_Package_getSystemPackage0(JNIEnv *env, jclass cls, jstring str) +Java_jdk_internal_loader_BootLoader_getSystemPackageLocation(JNIEnv *env, jclass cls, jstring str) { return JVM_GetSystemPackage(env, str); } JNIEXPORT jobject JNICALL -Java_java_lang_Package_getSystemPackages0(JNIEnv *env, jclass cls) +Java_jdk_internal_loader_BootLoader_getSystemPackageNames(JNIEnv *env, jclass cls) { return JVM_GetSystemPackages(env); } + +JNIEXPORT void JNICALL +Java_jdk_internal_loader_BootLoader_setBootLoaderUnnamedModule0(JNIEnv *env, jclass cls, jobject module) +{ + JVM_SetBootLoaderUnnamedModule(env, module); +} + diff --git a/jdk/src/java.base/share/native/libjava/Module.c b/jdk/src/java.base/share/native/libjava/Module.c new file mode 100644 index 00000000000..c31491e5036 --- /dev/null +++ b/jdk/src/java.base/share/native/libjava/Module.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "jni.h" +#include "jvm.h" + +#include "java_lang_reflect_Module.h" + +JNIEXPORT void JNICALL +Java_java_lang_reflect_Module_defineModule0(JNIEnv *env, jclass cls, jobject module, + jstring version, jstring location, + jobjectArray packages) +{ + JVM_DefineModule(env, module, version, location, packages); +} + +JNIEXPORT void JNICALL +Java_java_lang_reflect_Module_addReads0(JNIEnv *env, jclass cls, jobject from, jobject to) +{ + JVM_AddReadsModule(env, from, to); +} + +JNIEXPORT void JNICALL +Java_java_lang_reflect_Module_addExports0(JNIEnv *env, jclass cls, jobject from, + jstring pkg, jobject to) +{ + JVM_AddModuleExports(env, from, pkg, to); +} + +JNIEXPORT void JNICALL +Java_java_lang_reflect_Module_addExportsToAll0(JNIEnv *env, jclass cls, jobject from, + jstring pkg) +{ + JVM_AddModuleExportsToAll(env, from, pkg); +} + +JNIEXPORT void JNICALL +Java_java_lang_reflect_Module_addExportsToAllUnnamed0(JNIEnv *env, jclass cls, + jobject from, jstring pkg) +{ + JVM_AddModuleExportsToAllUnnamed(env, from, pkg); +} + +JNIEXPORT void JNICALL +Java_java_lang_reflect_Module_addPackage0(JNIEnv *env, jclass cls, jobject m, jstring pkg) +{ + JVM_AddModulePackage(env, m, pkg); +} diff --git a/jdk/src/java.base/share/native/libjava/Proxy.c b/jdk/src/java.base/share/native/libjava/Proxy.c deleted file mode 100644 index bdfbd905831..00000000000 --- a/jdk/src/java.base/share/native/libjava/Proxy.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include - -#include "jni.h" -#include "jni_util.h" - -#include "java_lang_reflect_Proxy.h" - -/* defined in libverify.so/verify.dll (src file common/check_format.c) */ -extern jboolean VerifyFixClassname(char *utf_name); - -/* - * Class: java_lang_reflect_Proxy - * Method: defineClass0 - * Signature: (Ljava/lang/ClassLoader;Ljava/lang/String;[BII)Ljava/lang/Class; - * - * The implementation of this native static method is a copy of that of - * the native instance method Java_java_lang_ClassLoader_defineClass0() - * with the implicit "this" parameter becoming the "loader" parameter. - */ -JNIEXPORT jclass JNICALL -Java_java_lang_reflect_Proxy_defineClass0(JNIEnv *env, - jclass ignore, - jobject loader, - jstring name, - jbyteArray data, - jint offset, - jint length) -{ - jbyte *body; - char *utfName; - jclass result = 0; - char buf[128]; - - if (data == NULL) { - JNU_ThrowNullPointerException(env, 0); - return 0; - } - - /* Work around 4153825. malloc crashes on Solaris when passed a - * negative size. - */ - if (length < 0) { - JNU_ThrowArrayIndexOutOfBoundsException(env, 0); - return 0; - } - - body = (jbyte *)malloc(length); - - if (body == 0) { - JNU_ThrowOutOfMemoryError(env, 0); - return 0; - } - - (*env)->GetByteArrayRegion(env, data, offset, length, body); - - if ((*env)->ExceptionOccurred(env)) - goto free_body; - - if (name != NULL) { - jsize len = (*env)->GetStringUTFLength(env, name); - jsize unicode_len = (*env)->GetStringLength(env, name); - if (len >= (jsize)sizeof(buf)) { - utfName = malloc(len + 1); - if (utfName == NULL) { - JNU_ThrowOutOfMemoryError(env, NULL); - goto free_body; - } - } else { - utfName = buf; - } - (*env)->GetStringUTFRegion(env, name, 0, unicode_len, utfName); - VerifyFixClassname(utfName); - } else { - utfName = NULL; - } - - result = (*env)->DefineClass(env, utfName, loader, body, length); - - if (utfName && utfName != buf) - free(utfName); - - free_body: - free(body); - return result; -} diff --git a/jdk/src/java.base/share/native/libjava/Reflection.c b/jdk/src/java.base/share/native/libjava/Reflection.c index 35cc5126efe..02b90138bcc 100644 --- a/jdk/src/java.base/share/native/libjava/Reflection.c +++ b/jdk/src/java.base/share/native/libjava/Reflection.c @@ -23,23 +23,24 @@ * questions. */ +#include "jni.h" #include "jvm.h" #include "sun_reflect_Reflection.h" -JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__ -(JNIEnv *env, jclass unused) +JNIEXPORT jclass JNICALL +Java_sun_reflect_Reflection_getCallerClass__(JNIEnv *env, jclass unused) { return JVM_GetCallerClass(env, JVM_CALLER_DEPTH); } -JNIEXPORT jclass JNICALL Java_sun_reflect_Reflection_getCallerClass__I -(JNIEnv *env, jclass unused, jint depth) +JNIEXPORT jclass JNICALL +Java_sun_reflect_Reflection_getCallerClass__I(JNIEnv *env, jclass unused, jint depth) { return JVM_GetCallerClass(env, depth); } -JNIEXPORT jint JNICALL Java_sun_reflect_Reflection_getClassAccessFlags -(JNIEnv *env, jclass unused, jclass cls) +JNIEXPORT jint JNICALL +Java_sun_reflect_Reflection_getClassAccessFlags(JNIEnv *env, jclass unused, jclass cls) { return JVM_GetClassAccessFlags(env, cls); } diff --git a/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp b/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp deleted file mode 100644 index c852c31061d..00000000000 --- a/jdk/src/java.base/share/native/libjimage/ImageNativeSubstrate.cpp +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of Oracle nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#include "jni.h" -#include "jni_util.h" - -#include "endian.hpp" -#include "imageDecompressor.hpp" -#include "imageFile.hpp" -#include "inttypes.hpp" -#include "jimage.hpp" -#include "osSupport.hpp" - -#include "jdk_internal_jimage_ImageNativeSubstrate.h" - -extern bool MemoryMapImage; - -///////////////////////////////////////////////////////////////////////////// - -// Static function for primitive throw since libjimage is not linked with libjava -static void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg) -{ - jclass cls = (env)->FindClass(name); - - if (cls != 0) /* Otherwise an exception has already been thrown */ - (env)->ThrowNew(cls, msg); -} - -// jdk.internal.jimage ///////////////////////////////////////////////////////// - -// Java entry to open an image file for sharing. - -static jlong JIMAGE_Open(JNIEnv *env, const char *nativePath, jboolean big_endian) { - // Open image file for reading. - ImageFileReader* reader = ImageFileReader::open(nativePath, big_endian != JNI_FALSE); - // Return image ID as a jlong. - return ImageFileReader::readerToID(reader); -} - -// Java entry for closing a shared image file. - -static void JIMAGE_Close(JNIEnv *env, jlong id) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // If valid reader the close. - if (reader != NULL) { - ImageFileReader::close(reader); - } -} - -// Java entry for accessing the base address of the image index. - -static jlong JIMAGE_GetIndexAddress(JNIEnv *env, jlong id) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // If valid reader return index base address (as jlong) else zero. - return reader != NULL ? (jlong) reader->get_index_address() : 0L; -} - -// Java entry for accessing the base address of the image data. - -static jlong JIMAGE_GetDataAddress(JNIEnv *env, jlong id) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // If valid reader return data base address (as jlong) else zero. - return MemoryMapImage && reader != NULL ? (jlong) reader->get_data_address() : 0L; -} - -// Java entry for reading an uncompressed resource from the image. - -static jboolean JIMAGE_Read(JNIEnv *env, jlong id, jlong offset, - unsigned char* uncompressedAddress, jlong uncompressed_size) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id);\ - // If not a valid reader the fail the read. - if (reader == NULL) return false; - // Get the file offset of resource data. - u8 file_offset = reader->get_index_size() + offset; - // Check validity of arguments. - if (offset < 0 || - uncompressed_size < 0 || - file_offset > reader->file_size() - uncompressed_size) { - return false; - } - // Read file content into buffer. - return (jboolean) reader->read_at((u1*) uncompressedAddress, uncompressed_size, - file_offset); -} - -// Java entry for reading a compressed resource from the image. - -static jboolean JIMAGE_ReadCompressed(JNIEnv *env, - jlong id, jlong offset, - unsigned char* compressedAddress, jlong compressed_size, - unsigned char* uncompressedAddress, jlong uncompressed_size) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // If not a valid reader the fail the read. - if (reader == NULL) return false; - // Get the file offset of resource data. - u8 file_offset = reader->get_index_size() + offset; - // Check validity of arguments. - if (offset < 0 || - compressed_size < 0 || - uncompressed_size < 0 || - file_offset > reader->file_size() - compressed_size) { - return false; - } - - // Read file content into buffer. - bool is_read = reader->read_at(compressedAddress, compressed_size, - file_offset); - // If successfully read then decompress. - if (is_read) { - const ImageStrings strings = reader->get_strings(); - ImageDecompressor::decompress_resource(compressedAddress, uncompressedAddress, - (u4) uncompressed_size, &strings); - } - return (jboolean) is_read; -} - -// Java entry for retrieving UTF-8 bytes from image string table. - -static const char* JIMAGE_GetStringBytes(JNIEnv *env, jlong id, jint offset) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // Fail if not valid reader. - if (reader == NULL) return NULL; - // Manage image string table. - ImageStrings strings = reader->get_strings(); - // Retrieve string adrress from table. - const char* data = strings.get(offset); - return data; -} - -// Utility function to copy location information into a jlong array. -// WARNING: This function is experimental and temporary during JDK 9 development -// cycle. It will not be supported in the eventual JDK 9 release. - -static void image_expand_location(JNIEnv *env, jlong* rawAttributes, ImageLocation& location) { - // Copy attributes from location. - for (int kind = ImageLocation::ATTRIBUTE_END + 1; - kind < ImageLocation::ATTRIBUTE_COUNT; - kind++) { - rawAttributes[kind] = location.get_attribute(kind); - } -} - -// Java entry for retrieving location attributes for attribute offset. - -static jlong* JIMAGE_GetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // Fail if not valid reader. - if (reader == NULL) return NULL; - // Retrieve first byte address of resource's location attribute stream. - u1* data = reader->get_location_offset_data(offset); - // Fail if not valid offset. - if (data == NULL) return NULL; - // Expand stream into array. - ImageLocation location(data); - image_expand_location(env, rawAttributes, location); - return rawAttributes; -} - -// Java entry for retrieving location attributes count for attribute offset. - -static jsize JIMAGE_GetAttributesCount(JNIEnv *env) { - return ImageLocation::ATTRIBUTE_COUNT; -} - -// Java entry for retrieving location attributes for named resource. - -static jlong* JIMAGE_FindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // Fail if not valid reader. - if (reader == NULL) return NULL; - // Convert byte array to a cstring. - char* path = new char[size + 1]; - if (path == NULL) { - return NULL; - } - memcpy(path, rawBytes, size); - path[size] = '\0'; - // Locate resource location data. - ImageLocation location; - bool found = reader->find_location(path, location); - delete[] path; - // Resource not found. - if (!found) return NULL; - // Expand stream into array. - image_expand_location(env, rawAttributes, location); - return rawAttributes; -} - -// Java entry for retrieving all the attribute stream offsets from an image. - -static jint* JIMAGE_AttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // Fail if not valid reader. - if (reader == NULL) return NULL; - // Determine endian for reader. - Endian* endian = reader->endian(); - // Get base address of attribute stream offsets table. - u4* offsets_table = reader->offsets_table(); - // Allocate int array result. - // Copy values to result (converting endian.) - for (u4 i = 0; i < length; i++) { - rawOffsets[i] = endian->get(offsets_table[i]); - } - return rawOffsets; -} - -// Java entry for retrieving all the attribute stream offsets length from an image. - -static unsigned int JIMAGE_AttributeOffsetsLength(JNIEnv *env, jlong id) { - // Convert image ID to image reader structure. - ImageFileReader* reader = ImageFileReader::idToReader(id); - // Fail if not valid reader. - if (reader == NULL) return 0; - // Get perfect hash table length. - u4 length = reader->table_length(); - return (jint) length; -} - -JNIEXPORT jint JNICALL -DEF_JNI_OnLoad(JavaVM *vm, void *reserved) { - JNIEnv *env; - - if (vm->GetEnv((void**) &env, JNI_VERSION_1_2) != JNI_OK) { - return JNI_EVERSION; /* JNI version not supported */ - } - - return JNI_VERSION_1_2; -} - -JNIEXPORT jlong JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env, - jclass cls, jstring path, jboolean big_endian) { - const char *nativePath; - jlong ret; - - nativePath = env->GetStringUTFChars(path, NULL); - ret = JIMAGE_Open(env, nativePath, big_endian); - env->ReleaseStringUTFChars(path, nativePath); - return ret; -} - -JNIEXPORT void JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env, - jclass cls, jlong id) { - JIMAGE_Close(env, id); -} - -JNIEXPORT jlong JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env, - jclass cls, jlong id) { - return JIMAGE_GetIndexAddress(env, id); -} - -JNIEXPORT jlong JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env, - jclass cls, jlong id) { - return JIMAGE_GetDataAddress(env, id); -} - -JNIEXPORT jboolean JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env, - jclass cls, jlong id, jlong offset, - jobject uncompressedBuffer, jlong uncompressed_size) { - unsigned char* uncompressedAddress; - - uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer); - if (uncompressedAddress == NULL) { - return JNI_FALSE; - } - return JIMAGE_Read(env, id, offset, uncompressedAddress, uncompressed_size); -} - -JNIEXPORT jboolean JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env, - jclass cls, jlong id, jlong offset, - jobject compressedBuffer, jlong compressed_size, - jobject uncompressedBuffer, jlong uncompressed_size) { - // Get address of read direct buffer. - unsigned char* compressedAddress; - unsigned char* uncompressedAddress; - - compressedAddress = (unsigned char*) env->GetDirectBufferAddress(compressedBuffer); - // Get address of decompression direct buffer. - uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer); - if (compressedAddress == NULL || uncompressedAddress == NULL) { - return JNI_FALSE; - } - return JIMAGE_ReadCompressed(env, id, offset, compressedAddress, compressed_size, - uncompressedAddress, uncompressed_size); -} - -JNIEXPORT jbyteArray JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env, - jclass cls, jlong id, jint offset) { - const char* data; - size_t size; - jbyteArray byteArray; - jbyte* rawBytes; - - data = JIMAGE_GetStringBytes(env, id, offset); - // Determine String length. - size = strlen(data); - // Allocate byte array. - byteArray = env->NewByteArray((jsize) size); - if (byteArray == NULL) { - return NULL; - } - // Get array base address. - rawBytes = env->GetByteArrayElements(byteArray, NULL); - // Copy bytes from image string table. - memcpy(rawBytes, data, size); - // Release byte array base address. - env->ReleaseByteArrayElements(byteArray, rawBytes, 0); - return byteArray; -} - -JNIEXPORT jlongArray JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env, - jclass cls, jlong id, jint offset) { - // Allocate a jlong large enough for all location attributes. - jlongArray attributes; - jlong* rawAttributes; - jlong* ret; - - attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env)); - if (attributes == NULL) { - return NULL; - } - // Get base address for jlong array. - rawAttributes = env->GetLongArrayElements(attributes, NULL); - ret = JIMAGE_GetAttributes(env, rawAttributes, id, offset); - // Release jlong array base address. - env->ReleaseLongArrayElements(attributes, rawAttributes, 0); - return ret == NULL ? NULL : attributes; -} - -JNIEXPORT jlongArray JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env, - jclass cls, jlong id, jbyteArray utf8) { - // Allocate a jlong large enough for all location attributes. - jsize count; - jlongArray attributes; - jlong* rawAttributes; - jsize size; - jbyte* rawBytes; - jlong* ret; - - count = JIMAGE_GetAttributesCount(env); - attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env)); - if (attributes == NULL) { - return NULL; - } - // Get base address for jlong array. - rawAttributes = env->GetLongArrayElements(attributes, NULL); - size = env->GetArrayLength(utf8); - rawBytes = env->GetByteArrayElements(utf8, NULL); - ret = JIMAGE_FindAttributes(env, rawAttributes, rawBytes, size, id); - env->ReleaseByteArrayElements(utf8, rawBytes, 0); - // Release jlong array base address. - env->ReleaseLongArrayElements(attributes, rawAttributes, 0); - return ret == NULL ? NULL : attributes; - -} - -JNIEXPORT jintArray JNICALL -Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env, - jclass cls, jlong id) { - unsigned int length; - jintArray offsets; - jint* rawOffsets; - jint* ret; - - length = JIMAGE_AttributeOffsetsLength(env, id); - offsets = env->NewIntArray(length); - if (offsets == NULL) { - return NULL; - } - // Get base address of result. - rawOffsets = env->GetIntArrayElements(offsets, NULL); - ret = JIMAGE_AttributeOffsets(env, rawOffsets, length, id); - if (length == 0) { - return NULL; - } - // Release result base address. - env->ReleaseIntArrayElements(offsets, rawOffsets, 0); - return ret == NULL ? NULL : offsets; -} - -/* - * Class: jdk_internal_jimage_ImageNativeSubstrate - * Method: JIMAGE_open - * Signature: (Ljava/lang/String;)J - */ -JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open -(JNIEnv *env, jclass, jstring path) { - const char *nativePath = env->GetStringUTFChars(path, NULL); - if (nativePath == NULL) - return 0; // Exception already thrown - jint error; - jlong ret = (jlong) JIMAGE_Open(nativePath, &error); - env->ReleaseStringUTFChars(path, nativePath); - return ret; -} - -/* - * Class: jdk_internal_jimage_ImageNativeSubstrate - * Method: JIMAGE_Close - * Signature: (J)J - */ -JNIEXPORT void JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close -(JNIEnv *env, jclass, jlong jimageHandle) { - JIMAGE_Close((JImageFile*) jimageHandle); -} - -/* - * Class: jdk_internal_jimage_ImageNativeSubstrate - * Method: JIMAGE_FindResource - * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[J)J - */ -JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource -(JNIEnv *env, jclass, jlong jimageHandle, jstring moduleName, - jstring version, jstring path, jlongArray output_size) { - const char *native_module = NULL; - const char *native_version = NULL; - const char *native_path = NULL; - jlong * native_array = NULL; - jlong size = 0; - jlong ret = 0; - - if (moduleName == NULL) { - ThrowByName(env, "java/lang/NullPointerException", "moduleName"); - return 0; - } - if (version == NULL) { - ThrowByName(env, "java/lang/NullPointerException", "version"); - return 0; - } - if (path == NULL) { - ThrowByName(env, "java/lang/NullPointerException", "path"); - return 0; - } - if (output_size == NULL) { - ThrowByName(env, "java/lang/NullPointerException", "size"); - return 0; - } - - do { - native_module = env->GetStringUTFChars(moduleName, NULL); - if (native_module == NULL) - break; - native_version = env->GetStringUTFChars(version, NULL); - if (native_version == NULL) - break; - native_path = env->GetStringUTFChars(path, NULL); - if (native_path == NULL) - break; - if (env->GetArrayLength(output_size) < 1) - break; - // Get base address for jlong array. - native_array = env->GetLongArrayElements(output_size, NULL); - if (native_array == NULL) - break; - - ret = (jlong) JIMAGE_FindResource((JImageFile *) jimageHandle, - native_module, native_version, native_path, &size); - if (ret != 0) - *native_array = size; - } while (0); - - if (native_array != NULL) - env->ReleaseLongArrayElements(output_size, native_array, 0); - if (native_path != NULL) - env->ReleaseStringUTFChars(path, native_path); - if (native_version != NULL) - env->ReleaseStringUTFChars(path, native_version); - if (native_module != NULL) - env->ReleaseStringUTFChars(path, native_module); - - return ret; -} - -/* - * Class: jdk_internal_jimage_ImageNativeSubstrate - * Method: JIMAGE_GetResource - * Signature: (JJ[BJ)J - */ -JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource -(JNIEnv *env, jclass, jlong jimageHandle, jlong jlocationHandle, jbyteArray buffer, jlong size) { - jbyte * native_buffer = NULL; - jlong actual_size = 0; - do { - if (env->GetArrayLength(buffer) < size) - break; - - native_buffer = env->GetByteArrayElements(buffer, NULL); - if (native_buffer == NULL) - break; - - actual_size = JIMAGE_GetResource((JImageFile*) jimageHandle, - (JImageLocationRef) jlocationHandle, - (char *) native_buffer, size); - } while (0); - // Release byte array - if (native_buffer != NULL) - env->ReleaseByteArrayElements(buffer, native_buffer, 0); - - return actual_size; -} - -// Structure passed from iterator to a visitor to accumulate the results - -struct VisitorData { - JNIEnv *env; - int size; // current number of strings - int max; // Maximum number of strings - jobjectArray array; // String array to store the strings -}; - -// Visitor to accumulate fully qualified resource names - -static bool resourceVisitor(JImageFile* image, - const char* module, const char* version, const char* package, - const char* name, const char* extension, void* arg) { - struct VisitorData *vdata = (struct VisitorData *) arg; - JNIEnv* env = vdata->env; - if (vdata->size < vdata->max) { - // Store if there is room in the array - // Concatenate to get full path - char fullpath[IMAGE_MAX_PATH]; - size_t moduleLen = strlen(module); - size_t packageLen = strlen(package); - size_t nameLen = strlen(name); - size_t extLen = strlen(extension); - size_t index; - - if (1 + moduleLen + 1 + packageLen + 1 + nameLen + 1 + extLen + 1 > IMAGE_MAX_PATH) { - ThrowByName(env, "java/lang/InternalError", "concatenated name too long"); - return true; - } - - index = 0; - if (moduleLen > 0) { - fullpath[index++] = '/'; - memcpy(&fullpath[index], module, moduleLen); - index += moduleLen; - fullpath[index++] = '/'; - } - if (packageLen > 0) { - memcpy(&fullpath[index], package, packageLen); - index += packageLen; - fullpath[index++] = '/'; - } - memcpy(&fullpath[index], name, nameLen); - index += nameLen; - if (extLen > 0) { - fullpath[index++] = '.'; - memcpy(&fullpath[index], extension, extLen); - index += extLen; - } - fullpath[index++] = '\0'; - - jobject str = env->NewStringUTF(fullpath); - if (env->ExceptionCheck()) { - return true; - } - - env->SetObjectArrayElement(vdata->array, vdata->size, str); - if (env->ExceptionCheck()) { - return true; - } - } - vdata->size++; // always count so the total size is returned - return true; -} - -/* - * Class: jdk_internal_jimage_ImageNativeSubstrate - * Method: JIMAGE_Resources - * Signature: (J)V - */ -JNIEXPORT jint JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources -(JNIEnv *env, jclass, jlong jimageHandle, - jobjectArray outputNames) { - struct VisitorData vdata; - vdata.env = env; - vdata.max = 0; - vdata.size = 0; - vdata.array = outputNames; - - vdata.max = (outputNames != NULL) ? env->GetArrayLength(outputNames) : 0; - JIMAGE_ResourceIterator((JImageFile*) jimageHandle, &resourceVisitor, &vdata); - return vdata.size; -} - -/* - * Class: jdk_internal_jimage_ImageNativeSubstrate - * Method: JIMAGE_PackageToModule - * Signature: (JLjava/lang/String;)Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule -(JNIEnv *env, jclass, jlong jimageHandle, jstring package_name) { - const char *native_package = NULL; - const char *native_module = NULL; - jstring module = NULL; - - native_package = env->GetStringUTFChars(package_name, NULL); - if (env->ExceptionCheck()) { - return NULL; - } - - - native_module = JIMAGE_PackageToModule((JImageFile*) jimageHandle, native_package); - if (native_module != NULL) { - module = env->NewStringUTF(native_module); - } - env->ReleaseStringUTFChars(package_name, native_package); - return module; -} - -JNIEXPORT void JNICALL DEF_JNI_OnUnload(JavaVM *vm, void *reserved) { - ImageDecompressor::image_decompressor_close(); -} diff --git a/jdk/src/java.base/share/native/libjimage/NativeImageBuffer.cpp b/jdk/src/java.base/share/native/libjimage/NativeImageBuffer.cpp new file mode 100644 index 00000000000..95fdeeb833d --- /dev/null +++ b/jdk/src/java.base/share/native/libjimage/NativeImageBuffer.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "jni.h" +#include "jni_util.h" + +#include "endian.hpp" +#include "imageDecompressor.hpp" +#include "imageFile.hpp" +#include "inttypes.hpp" +#include "jimage.hpp" +#include "osSupport.hpp" + +#include "jdk_internal_jimage_NativeImageBuffer.h" + + +JNIEXPORT jobject JNICALL +Java_jdk_internal_jimage_NativeImageBuffer_getNativeMap(JNIEnv *env, + jclass cls, jstring path) { + const char *nativePath = env->GetStringUTFChars(path, NULL); + ImageFileReader* reader = ImageFileReader::find_image(nativePath); + env->ReleaseStringUTFChars(path, nativePath); + + if (reader != NULL) { + return env->NewDirectByteBuffer(reader->get_index_address(), (jlong)reader->map_size()); + } + + return 0; +} diff --git a/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp b/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp index fd788fb3d2a..72de36db0ef 100644 --- a/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp +++ b/jdk/src/java.base/share/native/libjimage/imageDecompressor.cpp @@ -111,32 +111,66 @@ ImageDecompressor* ImageDecompressor::get_decompressor(const char * decompressor return NULL; } +// Sparc to read unaligned content +// u8 l = (*(u8*) ptr); +// If ptr is not aligned, sparc will fail. +u8 ImageDecompressor::getU8(u1* ptr, Endian *endian) { + u8 ret; + if (endian->is_big_endian()) { + ret = (u8)ptr[0] << 56 | (u8)ptr[1] << 48 | (u8)ptr[2]<<40 | (u8)ptr[3]<<32 | + ptr[4]<<24 | ptr[5]<<16 | ptr[6]<<8 | ptr[7]; + } else { + ret = ptr[0] | ptr[1]<<8 | ptr[2]<<16 | ptr[3]<<24 | (u8)ptr[4]<<32 | + (u8)ptr[5]<<40 | (u8)ptr[6]<<48 | (u8)ptr[7]<<56; + } + return ret; +} + +u4 ImageDecompressor::getU4(u1* ptr, Endian *endian) { + u4 ret; + if (endian->is_big_endian()) { + ret = ptr[0] << 24 | ptr[1]<<16 | (ptr[2]<<8) | ptr[3]; + } else { + ret = ptr[0] | ptr[1]<<8 | (ptr[2]<<16) | ptr[3]<<24; + } + return ret; +} + /* * Decompression entry point. Called from ImageFileReader::get_resource. */ void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed, - u4 uncompressed_size, const ImageStrings* strings) { + u8 uncompressed_size, const ImageStrings* strings, Endian *endian) { bool has_header = false; u1* decompressed_resource = compressed; u1* compressed_resource = compressed; - // Resource could have been transformed by a stack of decompressors. // Iterate and decompress resources until there is no more header. do { ResourceHeader _header; - memcpy(&_header, compressed_resource, sizeof (ResourceHeader)); + u1* compressed_resource_base = compressed_resource; + _header._magic = getU4(compressed_resource, endian); + compressed_resource += 4; + _header._size = getU8(compressed_resource, endian); + compressed_resource += 8; + _header._uncompressed_size = getU8(compressed_resource, endian); + compressed_resource += 8; + _header._decompressor_name_offset = getU4(compressed_resource, endian); + compressed_resource += 4; + _header._decompressor_config_offset = getU4(compressed_resource, endian); + compressed_resource += 4; + _header._is_terminal = *compressed_resource; + compressed_resource += 1; has_header = _header._magic == ResourceHeader::resource_header_magic; if (has_header) { // decompressed_resource array contains the result of decompression - decompressed_resource = new u1[_header._uncompressed_size]; + decompressed_resource = new u1[(size_t) _header._uncompressed_size]; // Retrieve the decompressor name const char* decompressor_name = strings->get(_header._decompressor_name_offset); assert(decompressor_name && "image decompressor not found"); // Retrieve the decompressor instance ImageDecompressor* decompressor = get_decompressor(decompressor_name); assert(decompressor && "image decompressor not found"); - u1* compressed_resource_base = compressed_resource; - compressed_resource += ResourceHeader::resource_header_length; // Ask the decompressor to decompress the compressed content decompressor->decompress_resource(compressed_resource, decompressed_resource, &_header, strings); @@ -146,8 +180,8 @@ void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed, compressed_resource = decompressed_resource; } } while (has_header); - memcpy(uncompressed, decompressed_resource, uncompressed_size); - delete[] decompressed_resource; + memcpy(uncompressed, decompressed_resource, (size_t) uncompressed_size); + delete decompressed_resource; } // Zip decompressor @@ -299,14 +333,14 @@ void SharedStringDecompressor::decompress_resource(u1* data, } } } - u4 remain = header->_size - (int)(data - data_base); - u4 computed = (u4)(uncompressed_resource - uncompressed_base) + remain; + u8 remain = header->_size - (int)(data - data_base); + u8 computed = (u8)(uncompressed_resource - uncompressed_base) + remain; if (header->_uncompressed_size != computed) - printf("Failure, expecting %d but getting %d\n", header->_uncompressed_size, + printf("Failure, expecting %llu but getting %llu\n", header->_uncompressed_size, computed); assert(header->_uncompressed_size == computed && "Constant Pool reconstruction failed"); - memcpy(uncompressed_resource, data, remain); + memcpy(uncompressed_resource, data, (size_t) remain); } /* diff --git a/jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp b/jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp index 38489528eaf..8fad62474d5 100644 --- a/jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp +++ b/jdk/src/java.base/share/native/libjimage/imageDecompressor.hpp @@ -54,13 +54,11 @@ * have been used to compress the resource. */ struct ResourceHeader { - /* Length of header, needed to retrieve content offset */ - static const u1 resource_header_length = 21; /* magic bytes that identifies a compressed resource header*/ static const u4 resource_header_magic = 0xCAFEFAFA; u4 _magic; // Resource header - u4 _size; // Resource size - u4 _uncompressed_size; // Expected uncompressed size + u8 _size; // Resource size + u8 _uncompressed_size; // Expected uncompressed size u4 _decompressor_name_offset; // Strings table decompressor offset u4 _decompressor_config_offset; // Strings table config offset u1 _is_terminal; // Last decompressor 1, otherwise 0. @@ -101,6 +99,8 @@ private: */ inline const char* get_name() const { return _name; } + static u8 getU8(u1* ptr, Endian *endian); + static u4 getU4(u1* ptr, Endian *endian); protected: ImageDecompressor(const char* name) : _name(name) { @@ -113,7 +113,7 @@ public: static void image_decompressor_close(); static ImageDecompressor* get_decompressor(const char * decompressor_name) ; static void decompress_resource(u1* compressed, u1* uncompressed, - u4 uncompressed_size, const ImageStrings* strings); + u8 uncompressed_size, const ImageStrings* strings, Endian* _endian); }; /** diff --git a/jdk/src/java.base/share/native/libjimage/imageFile.cpp b/jdk/src/java.base/share/native/libjimage/imageFile.cpp index 769ad18221b..d8b2a9d125a 100644 --- a/jdk/src/java.base/share/native/libjimage/imageFile.cpp +++ b/jdk/src/java.base/share/native/libjimage/imageFile.cpp @@ -41,7 +41,7 @@ #include "osSupport.hpp" // Map the full jimage, only with 64 bit addressing. -bool MemoryMapImage = sizeof(void *) == 8; +bool ImageFileReader::memory_map_image = sizeof(void *) == 8; #ifdef WIN32 const char FileSeparator = '\\'; @@ -144,142 +144,69 @@ void ImageLocation::clear_data() { } // ImageModuleData constructor maps out sub-tables for faster access. -ImageModuleData::ImageModuleData(const ImageFileReader* image_file, - const char* module_data_name) : +ImageModuleData::ImageModuleData(const ImageFileReader* image_file) : _image_file(image_file), - _endian(image_file->endian()), - _strings(image_file->get_strings()) { - // Retrieve the resource containing the module data for the image file. - ImageLocation location; - bool found = image_file->find_location(module_data_name, location); - if (found) { - u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED); - _data = new u1[(size_t)data_size]; - assert(_data != NULL && "allocation failed"); - _image_file->get_resource(location, _data); - // Map out the header. - _header = (Header*)_data; - // Get the package to module entry count. - u4 ptm_count = _header->ptm_count(_endian); - // Get the module to package entry count. - u4 mtp_count = _header->mtp_count(_endian); - // Compute the offset of the package to module perfect hash redirect. - u4 ptm_redirect_offset = sizeof(Header); - // Compute the offset of the package to module data. - u4 ptm_data_offset = ptm_redirect_offset + ptm_count * sizeof(s4); - // Compute the offset of the module to package perfect hash redirect. - u4 mtp_redirect_offset = ptm_data_offset + ptm_count * sizeof(PTMData); - // Compute the offset of the module to package data. - u4 mtp_data_offset = mtp_redirect_offset + mtp_count * sizeof(s4); - // Compute the offset of the module to package tables. - u4 mtp_packages_offset = mtp_data_offset + mtp_count * sizeof(MTPData); - // Compute the address of the package to module perfect hash redirect. - _ptm_redirect = (s4*)(_data + ptm_redirect_offset); - // Compute the address of the package to module data. - _ptm_data = (PTMData*)(_data + ptm_data_offset); - // Compute the address of the module to package perfect hash redirect. - _mtp_redirect = (s4*)(_data + mtp_redirect_offset); - // Compute the address of the module to package data. - _mtp_data = (MTPData*)(_data + mtp_data_offset); - // Compute the address of the module to package tables. - _mtp_packages = (s4*)(_data + mtp_packages_offset); - } else { - // No module data present. - _data = NULL; - _header = NULL; - _ptm_redirect = NULL; - _ptm_data = NULL; - _mtp_redirect = NULL; - _mtp_data = NULL; - _mtp_packages = NULL; - } + _endian(image_file->endian()) { } // Release module data resource. ImageModuleData::~ImageModuleData() { - if (_data) { - delete[] _data; - } } -// Return the name of the module data resource. Ex. "./lib/modules/file.jimage" -// yields "file.jdata" -void ImageModuleData::module_data_name(char* buffer, const char* image_file_name) { - // Locate the last slash in the file name path. - const char* slash = strrchr(image_file_name, FileSeparator); - // Trim the path to name and extension. - const char* name = slash ? slash + 1 : (char *)image_file_name; - // Locate the extension period. - const char* dot = strrchr(name, '.'); - assert(dot && "missing extension on jimage name"); - // Trim to only base name. - int length = (int)(dot - name); - strncpy(buffer, name, length); - buffer[length] = '\0'; - // Append extension. - strcat(buffer, ".jdata"); -} // Return the module in which a package resides. Returns NULL if not found. const char* ImageModuleData::package_to_module(const char* package_name) { - // Test files may contain no module data. - if (_data != NULL) { - // Search the package to module table. - s4 index = ImageStrings::find(_endian, package_name, _ptm_redirect, - _header->ptm_count(_endian)); - // If entry is found. - if (index != ImageStrings::NOT_FOUND) { - // Retrieve the package to module entry. - PTMData* data = _ptm_data + index; - // Verify that it is the correct data. - if (strcmp(package_name, get_string(data->name_offset(_endian))) != 0) { - return NULL; - } - // Return the module name. - return get_string(data->module_name_offset(_endian)); - } + // replace all '/' by '.' + char* replaced = new char[(int) strlen(package_name) + 1]; + assert(replaced != NULL && "allocation failed"); + int i; + for (i = 0; package_name[i] != '\0'; i++) { + replaced[i] = package_name[i] == '/' ? '.' : package_name[i]; } - return NULL; -} + replaced[i] = '\0'; -// Returns all the package names in a module in a NULL terminated array. -// Returns NULL if module not found. -const char** ImageModuleData::module_to_packages(const char* module_name) { - // Test files may contain no module data. - if (_data != NULL) { - // Search the module to package table. - s4 index = ImageStrings::find(_endian, module_name, _mtp_redirect, - _header->mtp_count(_endian)); - // If entry is found. - if (index != ImageStrings::NOT_FOUND) { - // Retrieve the module to package entry. - MTPData* data = _mtp_data + index; - // Verify that it is the correct data. - if (strcmp(module_name, get_string(data->name_offset(_endian))) != 0) { - return NULL; - } - // Construct an array of all the package entries. - u4 count = data->package_count(_endian); - const char** packages = new const char*[count + 1]; - assert(packages != NULL && "allocation failed"); - s4 package_offset = data->package_offset(_endian); - for (u4 i = 0; i < count; i++) { - u4 package_name_offset = mtp_package(package_offset + i); - const char* package_name = get_string(package_name_offset); - packages[i] = package_name; - } - packages[count] = NULL; - return packages; - } + // build path /packages/ + const char* radical = "/packages/"; + char* path = new char[(int) strlen(radical) + (int) strlen(package_name) + 1]; + assert(path != NULL && "allocation failed"); + strcpy(path, radical); + strcat(path, replaced); + delete[] replaced; + + // retrieve package location + ImageLocation location; + bool found = _image_file->find_location(path, location); + if (!found) { + delete[] path; + return NULL; } - return NULL; + + // retrieve offsets to module name + int size = (int)location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED); + u1* content = new u1[size]; + assert(content != NULL && "allocation failed"); + _image_file->get_resource(location, content); + u1* ptr = content; + // sequence of sizeof(8) isEmpty|offset. Use the first module that is not empty. + u4 offset = 0; + for (i = 0; i < size; i+=8) { + u4 isEmpty = _endian->get(*((u4*)ptr)); + ptr += 4; + if (!isEmpty) { + offset = _endian->get(*((u4*)ptr)); + break; + } + ptr += 4; + } + delete[] content; + return _image_file->get_strings().get(offset); } // Manage a table of open image files. This table allows multiple access points // to share an open image. ImageFileReaderTable::ImageFileReaderTable() : _count(0), _max(_growth) { _table = new ImageFileReader*[_max]; - assert( _table != NULL && "allocation failed"); + assert(_table != NULL && "allocation failed"); } ImageFileReaderTable::~ImageFileReaderTable() { @@ -326,26 +253,34 @@ ImageFileReaderTable ImageFileReader::_reader_table; SimpleCriticalSection _reader_table_lock; +// Locate an image if file already open. +ImageFileReader* ImageFileReader::find_image(const char* name) { + // Lock out _reader_table. + SimpleCriticalSectionLock cs(&_reader_table_lock); + // Search for an exist image file. + for (u4 i = 0; i < _reader_table.count(); i++) { + // Retrieve table entry. + ImageFileReader* reader = _reader_table.get(i); + // If name matches, then reuse (bump up use count.) + assert(reader->name() != NULL && "reader->name must not be null"); + if (strcmp(reader->name(), name) == 0) { + reader->inc_use(); + return reader; + } + } + + return NULL; +} + // Open an image file, reuse structure if file already open. ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) { - { - // Lock out _reader_table. - SimpleCriticalSectionLock cs(&_reader_table_lock); - // Search for an exist image file. - for (u4 i = 0; i < _reader_table.count(); i++) { - // Retrieve table entry. - ImageFileReader* reader = _reader_table.get(i); - // If name matches, then reuse (bump up use count.) - assert(reader->name() != NULL && "reader->name must not be null"); - if (strcmp(reader->name(), name) == 0) { - reader->inc_use(); - return reader; - } - } - } // Unlock the mutex + ImageFileReader* reader = find_image(name); + if (reader != NULL) { + return reader; + } // Need a new image reader. - ImageFileReader* reader = new ImageFileReader(name, big_endian); + reader = new ImageFileReader(name, big_endian); if (reader == NULL || !reader->open()) { // Failed to open. delete reader; @@ -385,21 +320,21 @@ void ImageFileReader::close(ImageFileReader *reader) { } // Return an id for the specifed ImageFileReader. -u8 ImageFileReader::readerToID(ImageFileReader *reader) { +u8 ImageFileReader::reader_to_ID(ImageFileReader *reader) { // ID is just the cloaked reader address. return (u8)reader; } // Validate the image id. -bool ImageFileReader::idCheck(u8 id) { +bool ImageFileReader::id_check(u8 id) { // Make sure the ID is a managed (_reader_table) reader. SimpleCriticalSectionLock cs(&_reader_table_lock); return _reader_table.contains((ImageFileReader*)id); } // Return an id for the specifed ImageFileReader. -ImageFileReader* ImageFileReader::idToReader(u8 id) { - assert(idCheck(id) && "invalid image id"); +ImageFileReader* ImageFileReader::id_to_reader(u8 id) { + assert(id_check(id) && "invalid image id"); return (ImageFileReader*)id; } @@ -429,8 +364,6 @@ ImageFileReader::~ImageFileReader() { // Open image file for read access. bool ImageFileReader::open() { - char buffer[IMAGE_MAX_PATH]; - // If file exists open for reading. _fd = osSupport::openReadOnly(_name); if (_fd == -1) { @@ -454,19 +387,17 @@ bool ImageFileReader::open() { if (_file_size < _index_size) { return false; } - // Determine how much of the image is memory mapped. - size_t map_size = (size_t)(MemoryMapImage ? _file_size : _index_size); // Memory map image (minimally the index.) - _index_data = (u1*)osSupport::map_memory(_fd, _name, 0, map_size); + _index_data = (u1*)osSupport::map_memory(_fd, _name, 0, (size_t)map_size()); assert(_index_data && "image file not memory mapped"); // Retrieve length of index perfect hash table. u4 length = table_length(); // Compute offset of the perfect hash table redirect table. u4 redirect_table_offset = (u4)header_size; // Compute offset of index attribute offsets. - u4 offsets_table_offset = redirect_table_offset + length * sizeof(s4); + u4 offsets_table_offset = redirect_table_offset + length * (u4)sizeof(s4); // Compute offset of index location attribute data. - u4 location_bytes_offset = offsets_table_offset + length * sizeof(u4); + u4 location_bytes_offset = offsets_table_offset + length * (u4)sizeof(u4); // Compute offset of index string table. u4 string_bytes_offset = location_bytes_offset + locations_size(); // Compute address of the perfect hash table redirect table. @@ -479,8 +410,7 @@ bool ImageFileReader::open() { _string_bytes = _index_data + string_bytes_offset; // Initialize the module data - ImageModuleData::module_data_name(buffer, _name); - module_data = new ImageModuleData(this, buffer); + module_data = new ImageModuleData(this); // Successful open (if memory allocation succeeded). return module_data != NULL; } @@ -660,10 +590,10 @@ void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_dat if (compressed_size != 0) { u1* compressed_data; // If not memory mapped read in bytes. - if (!MemoryMapImage) { + if (!memory_map_image) { // Allocate buffer for compression. - compressed_data = new u1[(u4)compressed_size]; - assert (compressed_data != NULL && "allocation failed"); + compressed_data = new u1[(size_t)compressed_size]; + assert(compressed_data != NULL && "allocation failed"); // Read bytes from offset beyond the image index. bool is_read = read_at(compressed_data, compressed_size, _index_size + offset); assert(is_read && "error reading from image or short read"); @@ -673,10 +603,10 @@ void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_dat // Get image string table. const ImageStrings strings = get_strings(); // Decompress resource. - ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, (u4)uncompressed_size, - &strings); + ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, uncompressed_size, + &strings, _endian); // If not memory mapped then release temporary buffer. - if (!MemoryMapImage) { + if (!memory_map_image) { delete[] compressed_data; } } else { diff --git a/jdk/src/java.base/share/native/libjimage/imageFile.hpp b/jdk/src/java.base/share/native/libjimage/imageFile.hpp index 9cb7eb41a8d..9e02d87460c 100644 --- a/jdk/src/java.base/share/native/libjimage/imageFile.hpp +++ b/jdk/src/java.base/share/native/libjimage/imageFile.hpp @@ -302,102 +302,18 @@ public: } }; -// -// NOTE: needs revision. -// Each loader requires set of module meta data to identify which modules and -// packages are managed by that loader. Currently, there is one image file per -// builtin loader, so only one module meta data resource per file. -// -// Each element in the module meta data is a native endian 4 byte integer. Note -// that entries with zero offsets for string table entries should be ignored ( -// padding for hash table lookup.) -// -// Format: -// Count of package to module entries -// Count of module to package entries -// Perfect Hash redirect table[Count of package to module entries] -// Package to module entries[Count of package to module entries] -// Offset to package name in string table -// Offset to module name in string table -// Perfect Hash redirect table[Count of module to package entries] -// Module to package entries[Count of module to package entries] -// Offset to module name in string table -// Count of packages in module -// Offset to first package in packages table -// Packages[] -// Offset to package name in string table // // Manage the image module meta data. class ImageModuleData { - class Header { - private: - u4 _ptm_count; // Count of package to module entries - u4 _mtp_count; // Count of module to package entries - public: - inline u4 ptm_count(Endian* endian) const { return endian->get(_ptm_count); } - inline u4 mtp_count(Endian* endian) const { return endian->get(_mtp_count); } - }; - - // Hashtable entry - class HashData { - private: - u4 _name_offset; // Name offset in string table - public: - inline s4 name_offset(Endian* endian) const { return endian->get(_name_offset); } - }; - - // Package to module hashtable entry - class PTMData : public HashData { - private: - u4 _module_name_offset; // Module name offset in string table - public: - inline s4 module_name_offset(Endian* endian) const { return endian->get(_module_name_offset); } - }; - - // Module to package hashtable entry - class MTPData : public HashData { - private: - u4 _package_count; // Number of packages in module - u4 _package_offset; // Offset in package list - public: - inline u4 package_count(Endian* endian) const { return endian->get(_package_count); } - inline u4 package_offset(Endian* endian) const { return endian->get(_package_offset); } - }; - const ImageFileReader* _image_file; // Source image file - Endian* _endian; // Endian handler - ImageStrings _strings; // Image file strings - u1* _data; // Module data resource data - u8 _data_size; // Size of resource data - Header* _header; // Module data header - s4* _ptm_redirect; // Package to module hashtable redirect - PTMData* _ptm_data; // Package to module data - s4* _mtp_redirect; // Module to packages hashtable redirect - MTPData* _mtp_data; // Module to packages data - s4* _mtp_packages; // Package data (name offsets) - - // Return a string from the string table. - inline const char* get_string(u4 offset) { - return _strings.get(offset); - } - - inline u4 mtp_package(u4 index) { - return _endian->get(_mtp_packages[index]); - } + Endian* _endian; // Endian handler public: - ImageModuleData(const ImageFileReader* image_file, const char* module_data_name); + ImageModuleData(const ImageFileReader* image_file); ~ImageModuleData(); - // Return the name of the module data resource. - static void module_data_name(char* buffer, const char* image_file_name); - // Return the module in which a package resides. Returns NULL if not found. const char* package_to_module(const char* package_name); - - // Returns all the package names in a module in a NULL terminated array. - // Returns NULL if module not found. - const char** module_to_packages(const char* module_name); }; // Image file header, starting at offset 0. @@ -491,6 +407,9 @@ private: // multiple uses (ex. loader.) static ImageFileReaderTable _reader_table; + // true if image should be fully memory mapped. + static bool memory_map_image; + char* _name; // Name of image s4 _use; // Use count int _fd; // File descriptor @@ -526,6 +445,9 @@ public: MINOR_VERSION = 0 }; + // Locate an image if file already open. + static ImageFileReader* find_image(const char* name); + // Open an image file, reuse structure if file already open. static ImageFileReader* open(const char* name, bool big_endian = Endian::is_big_endian()); @@ -533,13 +455,13 @@ public: static void close(ImageFileReader *reader); // Return an id for the specifed ImageFileReader. - static u8 readerToID(ImageFileReader *reader); + static u8 reader_to_ID(ImageFileReader *reader); // Validate the image id. - static bool idCheck(u8 id); + static bool id_check(u8 id); // Return an id for the specifed ImageFileReader. - static ImageFileReader* idToReader(u8 id); + static ImageFileReader* id_to_reader(u8 id); // Open image file for read access. bool open(); @@ -562,6 +484,11 @@ public: return _file_size; } + // Retrieve the size of the mapped image. + inline u8 map_size() const { + return (u8)(memory_map_image ? _file_size : _index_size); + } + // Return first address of index data. inline u1* get_index_address() const { return _index_data; diff --git a/jdk/src/java.base/share/native/libjimage/jimage.cpp b/jdk/src/java.base/share/native/libjimage/jimage.cpp index 4ed00d2aee5..4816a173be9 100644 --- a/jdk/src/java.base/share/native/libjimage/jimage.cpp +++ b/jdk/src/java.base/share/native/libjimage/jimage.cpp @@ -48,7 +48,7 @@ * * Ex. * jint error; - * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error); + * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error); * if (image == NULL) { * tty->print_cr("JImage failed to open: %d", error); * ... diff --git a/jdk/src/java.base/share/native/libjimage/jimage.hpp b/jdk/src/java.base/share/native/libjimage/jimage.hpp index 0650f23e9a6..d215e30c2ab 100644 --- a/jdk/src/java.base/share/native/libjimage/jimage.hpp +++ b/jdk/src/java.base/share/native/libjimage/jimage.hpp @@ -62,7 +62,7 @@ typedef jlong JImageLocationRef; * * Ex. * jint error; - * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules/bootmodules.jimage", &error); + * JImageFile* jimage = (*JImageOpen)(JAVA_HOME "lib/modules", &error); * if (image == NULL) { * tty->print_cr("JImage failed to open: %d", error); * ... diff --git a/jdk/src/java.base/share/native/libjli/args.c b/jdk/src/java.base/share/native/libjli/args.c index e275ccf3101..268046cd693 100644 --- a/jdk/src/java.base/share/native/libjli/args.c +++ b/jdk/src/java.base/share/native/libjli/args.c @@ -105,9 +105,15 @@ static void checkArg(const char *arg) { if (*arg++ == '-') { expectingNoDashArg = JNI_FALSE; if (JLI_StrCmp(arg, "cp") == 0 || - JLI_StrCmp(arg, "classpath") == 0) { + JLI_StrCmp(arg, "classpath") == 0 || + JLI_StrCmp(arg, "addmods") == 0 || + JLI_StrCmp(arg, "limitmods") == 0 || + JLI_StrCmp(arg, "mp") == 0 || + JLI_StrCmp(arg, "modulepath") == 0 || + JLI_StrCmp(arg, "upgrademodulepath") == 0) { expectingNoDashArg = JNI_TRUE; - } else if (JLI_StrCmp(arg, "jar") == 0) { + } else if (JLI_StrCmp(arg, "jar") == 0 || + JLI_StrCmp(arg, "m") == 0) { // This is tricky, we do expect NoDashArg // But that is considered main class to stop expansion expectingNoDashArg = JNI_FALSE; diff --git a/jdk/src/java.base/share/native/libjli/emessages.h b/jdk/src/java.base/share/native/libjli/emessages.h index 75b646f9d8c..9e3a7554eee 100644 --- a/jdk/src/java.base/share/native/libjli/emessages.h +++ b/jdk/src/java.base/share/native/libjli/emessages.h @@ -41,6 +41,10 @@ #define ARG_ERROR1 "Error: %s requires class path specification" #define ARG_ERROR2 "Error: %s requires jar file specification" #define ARG_ERROR3 "Error: The -J option should not be followed by a space." +#define ARG_ERROR4 "Error: %s requires module path specification" +#define ARG_ERROR5 "Error: %s requires module id" +#define ARG_ERROR6 "Error: %s requires modules to be specified" +#define ARG_ERROR7 "Error: %s can only be specified once" #define JVM_ERROR1 "Error: Could not create the Java Virtual Machine.\n" GEN_ERROR #define JVM_ERROR2 "Error: Could not detach main thread.\n" JNI_ERROR diff --git a/jdk/src/java.base/share/native/libjli/java.c b/jdk/src/java.base/share/native/libjli/java.c index 41e0e21f14b..9fd3ffd5c1c 100644 --- a/jdk/src/java.base/share/native/libjli/java.c +++ b/jdk/src/java.base/share/native/libjli/java.c @@ -69,10 +69,12 @@ static jboolean showVersion = JNI_FALSE; /* print but continue */ static jboolean printUsage = JNI_FALSE; /* print and exit*/ static jboolean printXUsage = JNI_FALSE; /* print and exit*/ static char *showSettings = NULL; /* print but continue */ +static char *listModules = NULL; static const char *_program_name; static const char *_launcher_name; static jboolean _is_java_args = JNI_FALSE; +static jboolean _have_classpath = JNI_FALSE; static const char *_fVersion; static jboolean _wc_enabled = JNI_FALSE; static jint _ergo_policy = DEFAULT_POLICY; @@ -96,6 +98,14 @@ static int numOptions, maxOptions; * Prototypes for functions internal to launcher. */ static void SetClassPath(const char *s); +static void SetModulePath(const char *s); +static void SetUpgradeModulePath(const char *s); +static void SetMainModule(const char *s); +static void SetAddModulesProp(const char *mods); +static void SetLimitModulesProp(const char *mods); +static void SetAddReadsProp(const jint n, const char *s); +static void SetAddExportsProp(const jint n, const char *s); +static void SetPatchProp(const jint n, const char *s); static void SelectVersion(int argc, char **argv, char **main_class); static void SetJvmEnvironment(int argc, char **argv); static jboolean ParseArguments(int *pargc, char ***pargv, @@ -114,6 +124,7 @@ static void SetApplicationClassPath(const char**); static void PrintJavaVersion(JNIEnv *env, jboolean extraLF); static void PrintUsage(JNIEnv* env, jboolean doXUsage); static void ShowSettings(JNIEnv* env, char *optString); +static void ListModules(JNIEnv* env, char *optString); static void SetPaths(int argc, char **argv); @@ -193,7 +204,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ { int mode = LM_UNKNOWN; char *what = NULL; - char *cpath = 0; char *main_class = NULL; int ret; InvocationFunctions ifn; @@ -270,11 +280,10 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ } } else { /* Set default CLASSPATH */ - cpath = getenv("CLASSPATH"); - if (cpath == NULL) { - cpath = "."; + char* cpath = getenv("CLASSPATH"); + if (cpath != NULL) { + SetClassPath(cpath); } - SetClassPath(cpath); } /* Parse command line options; if the return value of @@ -382,6 +391,12 @@ JavaMain(void * _args) CHECK_EXCEPTION_LEAVE(1); } + if (listModules != NULL) { + ListModules(env, listModules); + CHECK_EXCEPTION_LEAVE(1); + LEAVE(); + } + if (printVersion || showVersion) { PrintJavaVersion(env, showVersion); CHECK_EXCEPTION_LEAVE(0); @@ -520,7 +535,12 @@ CheckJvmType(int *pargc, char ***argv, jboolean speculative) { } } else { if (JLI_StrCmp(arg, "-classpath") == 0 || - JLI_StrCmp(arg, "-cp") == 0) { + JLI_StrCmp(arg, "-cp") == 0 || + JLI_StrCmp(arg, "-modulepath") == 0 || + JLI_StrCmp(arg, "-mp") == 0 || + JLI_StrCmp(arg, "-upgrademodulepath") == 0 || + JLI_StrCmp(arg, "-addmods") == 0 || + JLI_StrCmp(arg, "-limitmods") == 0) { newArgv[newArgvIdx++] = arg; argi++; if (argi < argc) { @@ -841,6 +861,105 @@ SetClassPath(const char *s) AddOption(def, NULL); if (s != orig) JLI_MemFree((char *) s); + _have_classpath = JNI_TRUE; +} + +static void +SetModulePath(const char *s) +{ + char *def; + const char *orig = s; + static const char format[] = "-Djdk.module.path=%s"; + if (s == NULL) + return; + s = JLI_WildcardExpandClasspath(s); + def = JLI_MemAlloc(sizeof(format) + - 2 /* strlen("%s") */ + + JLI_StrLen(s)); + sprintf(def, format, s); + AddOption(def, NULL); + if (s != orig) + JLI_MemFree((char *) s); +} + +static void +SetUpgradeModulePath(const char *s) +{ + char *def; + const char *orig = s; + static const char format[] = "-Djdk.upgrade.module.path=%s"; + if (s == NULL) + return; + s = JLI_WildcardExpandClasspath(s); + def = JLI_MemAlloc(sizeof(format) + - 2 /* strlen("%s") */ + + JLI_StrLen(s)); + sprintf(def, format, s); + AddOption(def, NULL); + if (s != orig) + JLI_MemFree((char *) s); +} + +static void +SetMainModule(const char *s) +{ + static const char format[] = "-Djdk.module.main=%s"; + char* slash = JLI_StrChr(s, '/'); + size_t s_len, def_len; + char *def; + + /* value may be or / */ + if (slash == NULL) { + s_len = JLI_StrLen(s); + } else { + s_len = (size_t) (slash - s); + } + def_len = sizeof(format) + - 2 /* strlen("%s") */ + + s_len; + def = JLI_MemAlloc(def_len); + JLI_Snprintf(def, def_len, format, s); + AddOption(def, NULL); +} + +static void +SetAddModulesProp(const char *mods) { + size_t buflen = JLI_StrLen(mods) + 40; + char *prop = (char *)JLI_MemAlloc(buflen); + JLI_Snprintf(prop, buflen, "-Djdk.launcher.addmods=%s", mods); + AddOption(prop, NULL); +} + +static void +SetLimitModulesProp(const char *mods) { + size_t buflen = JLI_StrLen(mods) + 40; + char *prop = (char *)JLI_MemAlloc(buflen); + JLI_Snprintf(prop, buflen, "-Djdk.launcher.limitmods=%s", mods); + AddOption(prop, NULL); +} + +static void +SetAddReadsProp(const jint n, const char *s) { + size_t buflen = JLI_StrLen(s) + 40; + char *prop = (char *)JLI_MemAlloc(buflen); + JLI_Snprintf(prop, buflen, "-Djdk.launcher.addreads.%d=%s", n, s); + AddOption(prop, NULL); +} + +static void +SetAddExportsProp(const jint n, const char *s) { + size_t buflen = JLI_StrLen(s) + 40; + char *prop = (char *)JLI_MemAlloc(buflen); + JLI_Snprintf(prop, buflen, "-Djdk.launcher.addexports.%d=%s", n, s); + AddOption(prop, NULL); +} + +static void +SetPatchProp(const jint n, const char *s) { + size_t buflen = JLI_StrLen(s) + 40; + char *prop = (char *)JLI_MemAlloc(buflen); + JLI_Snprintf(prop, buflen, "-Djdk.launcher.patch.%d=%s", n, s); + AddOption(prop, NULL); } /* @@ -1030,9 +1149,45 @@ ParseArguments(int *pargc, char ***pargv, SetClassPath(*argv); mode = LM_CLASS; argv++; --argc; + } else if (JLI_StrCmp(arg, "-modulepath") == 0 || JLI_StrCmp(arg, "-mp") == 0) { + ARG_CHECK (argc, ARG_ERROR4, arg); + SetModulePath(*argv); + argv++; --argc; + } else if (JLI_StrCmp(arg, "-upgrademodulepath") == 0) { + ARG_CHECK (argc, ARG_ERROR4, arg); + SetUpgradeModulePath(*argv); + argv++; --argc; } else if (JLI_StrCmp(arg, "-jar") == 0) { ARG_CHECK (argc, ARG_ERROR2, arg); mode = LM_JAR; + } else if (JLI_StrCmp(arg, "-m") == 0) { + ARG_CHECK (argc, ARG_ERROR5, arg); + SetMainModule(*argv); + mode = LM_MODULE; + } else if (JLI_StrCmp(arg, "-addmods") == 0) { + ARG_CHECK (argc, ARG_ERROR6, arg); + SetAddModulesProp(*argv); + argv++; --argc; + } else if (JLI_StrCmp(arg, "-limitmods") == 0) { + ARG_CHECK (argc, ARG_ERROR6, arg); + SetLimitModulesProp(*argv); + argv++; --argc; + } else if (JLI_StrCmp(arg, "-listmods") == 0 || + JLI_StrCCmp(arg, "-listmods:") == 0) { + listModules = arg; + return JNI_TRUE; + } else if (JLI_StrCCmp(arg, "-XaddReads:") == 0) { + static jint n; + char *value = arg + 11; + SetAddReadsProp(n++, value); + } else if (JLI_StrCCmp(arg, "-XaddExports:") == 0) { + static jint n; + char *value = arg + 13; + SetAddExportsProp(n++, value); + } else if (JLI_StrCCmp(arg, "-Xpatch:") == 0) { + static jint n; + char *value = arg + 8; + SetPatchProp(n++, value); } else if (JLI_StrCmp(arg, "-help") == 0 || JLI_StrCmp(arg, "-h") == 0 || JLI_StrCmp(arg, "-?") == 0) { @@ -1051,10 +1206,13 @@ ParseArguments(int *pargc, char ***pargv, * In the latter case, any SUBOPT value not recognized will default to "all" */ } else if (JLI_StrCmp(arg, "-XshowSettings") == 0 || - JLI_StrCCmp(arg, "-XshowSettings:") == 0) { + JLI_StrCCmp(arg, "-XshowSettings:") == 0) { showSettings = arg; } else if (JLI_StrCmp(arg, "-Xdiag") == 0) { AddOption("-Dsun.java.launcher.diag=true", NULL); + AddOption("-Djdk.launcher.traceResolver=true", NULL); + } else if (JLI_StrCmp(arg, "-Xdiag:resolver") == 0) { + AddOption("-Djdk.launcher.traceResolver=true", NULL); /* * The following case provide backward compatibility with old-style * command line options. @@ -1099,6 +1257,10 @@ ParseArguments(int *pargc, char ***pargv, } else if (RemovableOption(arg)) { ; /* Do not pass option to vm. */ } else { + /* java.class.path set on the command line */ + if (JLI_StrCCmp(arg, "-Djava.class.path=") == 0) { + _have_classpath = JNI_TRUE; + } AddOption(arg, NULL); } } @@ -1110,8 +1272,11 @@ ParseArguments(int *pargc, char ***pargv, if (*pwhat == NULL) { *pret = 1; } else if (mode == LM_UNKNOWN) { - /* default to LM_CLASS if -jar and -cp option are + /* default to LM_CLASS if -m, -jar and -cp options are * not specified */ + if (!_have_classpath) { + SetClassPath("."); + } mode = LM_CLASS; } @@ -1503,6 +1668,24 @@ ShowSettings(JNIEnv *env, char *optString) ServerClassMachine()); } +/** + * List modules supported by the runtime + */ +static void +ListModules(JNIEnv *env, char *optString) +{ + jmethodID listModulesID; + jstring joptString; + jclass cls = GetLauncherHelperClass(env); + NULL_CHECK(cls); + NULL_CHECK(listModulesID = (*env)->GetStaticMethodID(env, cls, + "listModules", "(ZLjava/lang/String;)V")); + NULL_CHECK(joptString = (*env)->NewStringUTF(env, optString)); + (*env)->CallStaticVoidMethod(env, cls, listModulesID, + USE_STDERR, + joptString); +} + /* * Prints default usage or the Xusage message, see sun.launcher.LauncherHelper.java */ diff --git a/jdk/src/java.base/share/native/libjli/java.h b/jdk/src/java.base/share/native/libjli/java.h index f6156fbdb90..cf9d37ecc8b 100644 --- a/jdk/src/java.base/share/native/libjli/java.h +++ b/jdk/src/java.base/share/native/libjli/java.h @@ -223,7 +223,8 @@ int JNICALL JavaMain(void * args); /* entry point */ enum LaunchMode { // cf. sun.launcher.LauncherHelper LM_UNKNOWN = 0, LM_CLASS, - LM_JAR + LM_JAR, + LM_MODULE }; static const char *launchModeNames[] diff --git a/jdk/src/java.base/share/native/libzip/zip_util.c b/jdk/src/java.base/share/native/libzip/zip_util.c index 9ae765b6a55..4837fc81c66 100644 --- a/jdk/src/java.base/share/native/libzip/zip_util.c +++ b/jdk/src/java.base/share/native/libzip/zip_util.c @@ -1408,7 +1408,7 @@ InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) case Z_OK: break; case Z_STREAM_END: - if (count != 0 || strm.total_out != entry->size) { + if (count != 0 || strm.total_out != (uInt)entry->size) { *msg = "inflateFully: Unexpected end of stream"; inflateEnd(&strm); return JNI_FALSE; @@ -1528,7 +1528,7 @@ ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pm case Z_OK: break; case Z_STREAM_END: - if (strm.total_out != outLen) { + if (strm.total_out != (uInt)outLen) { *pmsg = "INFLATER_inflateFully: Unexpected end of stream"; inflateEnd(&strm); return JNI_FALSE; diff --git a/jdk/src/java.base/solaris/classes/module-info.java.extra b/jdk/src/java.base/solaris/classes/module-info.java.extra new file mode 100644 index 00000000000..1e46f7c8cc7 --- /dev/null +++ b/jdk/src/java.base/solaris/classes/module-info.java.extra @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +exports sun.nio.ch to jdk.crypto.ucrypto; +exports sun.security.action to jdk.crypto.ucrypto; +exports sun.security.internal.spec to jdk.crypto.ucrypto; +exports sun.security.jca to jdk.crypto.ucrypto; +exports sun.security.rsa to jdk.crypto.ucrypto; +exports sun.security.util to jdk.crypto.ucrypto; diff --git a/jdk/src/java.base/windows/classes/module-info.java.extra b/jdk/src/java.base/windows/classes/module-info.java.extra new file mode 100644 index 00000000000..1e4a3a6ccb9 --- /dev/null +++ b/jdk/src/java.base/windows/classes/module-info.java.extra @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +exports sun.security.rsa to jdk.crypto.mscapi; +exports sun.security.internal.spec to jdk.crypto.mscapi; +exports sun.security.util to jdk.crypto.mscapi; diff --git a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c index 8075d046763..eeb6456ae6a 100644 --- a/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c +++ b/jdk/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,6 @@ * questions. */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - #include #include #include @@ -77,21 +73,6 @@ static jfieldID backupResult_bytesTransferred; static jfieldID backupResult_context; -/** - * Win32 APIs not available in Windows XP - */ -typedef HANDLE (WINAPI* FindFirstStream_Proc)(LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD); -typedef BOOL (WINAPI* FindNextStream_Proc)(HANDLE, LPVOID); - -typedef BOOLEAN (WINAPI* CreateSymbolicLinkProc) (LPCWSTR, LPCWSTR, DWORD); -typedef BOOL (WINAPI* GetFinalPathNameByHandleProc) (HANDLE, LPWSTR, DWORD, DWORD); - -static FindFirstStream_Proc FindFirstStream_func; -static FindNextStream_Proc FindNextStream_func; - -static CreateSymbolicLinkProc CreateSymbolicLink_func; -static GetFinalPathNameByHandleProc GetFinalPathNameByHandle_func; - static void throwWindowsException(JNIEnv* env, DWORD lastError) { jobject x = JNU_NewObjectByName(env, "sun/nio/fs/WindowsException", "(I)V", lastError); @@ -108,7 +89,6 @@ JNIEXPORT void JNICALL Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) { jclass clazz; - HMODULE h; clazz = (*env)->FindClass(env, "sun/nio/fs/WindowsNativeDispatcher$FirstFile"); CHECK_NULL(clazz); @@ -175,24 +155,6 @@ Java_sun_nio_fs_WindowsNativeDispatcher_initIDs(JNIEnv* env, jclass this) CHECK_NULL(backupResult_bytesTransferred); backupResult_context = (*env)->GetFieldID(env, clazz, "context", "J"); CHECK_NULL(backupResult_context); - - // get handle to kernel32 - if (GetModuleHandleExW((GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT), - (LPCWSTR)&CreateFileW, &h) != 0) - { - // requires Windows Server 2003 or newer - FindFirstStream_func = - (FindFirstStream_Proc)GetProcAddress(h, "FindFirstStreamW"); - FindNextStream_func = - (FindNextStream_Proc)GetProcAddress(h, "FindNextStreamW"); - - // requires Windows Vista or newer - CreateSymbolicLink_func = - (CreateSymbolicLinkProc)GetProcAddress(h, "CreateSymbolicLinkW"); - GetFinalPathNameByHandle_func = - (GetFinalPathNameByHandleProc)GetProcAddress(h, "GetFinalPathNameByHandleW"); - } } JNIEXPORT jlong JNICALL @@ -404,12 +366,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindFirstStream0(JNIEnv* env, jclass thi LPCWSTR lpFileName = jlong_to_ptr(address); HANDLE handle; - if (FindFirstStream_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return; - } - - handle = (*FindFirstStream_func)(lpFileName, FindStreamInfoStandard, &data, 0); + handle = FindFirstStreamW(lpFileName, FindStreamInfoStandard, &data, 0); if (handle != INVALID_HANDLE_VALUE) { jstring name = (*env)->NewString(env, data.cStreamName, (jsize)wcslen(data.cStreamName)); if (name == NULL) @@ -433,12 +390,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_FindNextStream(JNIEnv* env, jclass this, WIN32_FIND_STREAM_DATA data; HANDLE h = (HANDLE)jlong_to_ptr(handle); - if (FindNextStream_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return NULL; - } - - if ((*FindNextStream_func)(h, &data) != 0) { + if (FindNextStreamW(h, &data) != 0) { return (*env)->NewString(env, data.cStreamName, (jsize)wcslen(data.cStreamName)); } else { if (GetLastError() != ERROR_HANDLE_EOF) @@ -1087,13 +1039,8 @@ Java_sun_nio_fs_WindowsNativeDispatcher_CreateSymbolicLink0(JNIEnv* env, LPCWSTR link = jlong_to_ptr(linkAddress); LPCWSTR target = jlong_to_ptr(targetAddress); - if (CreateSymbolicLink_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return; - } - /* On Windows 64-bit this appears to succeed even when there is insufficient privileges */ - if ((*CreateSymbolicLink_func)(link, target, (DWORD)flags) == 0) + if (CreateSymbolicLinkW(link, target, (DWORD)flags) == 0) throwWindowsException(env, GetLastError()); } @@ -1155,12 +1102,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, HANDLE h = (HANDLE)jlong_to_ptr(handle); DWORD len; - if (GetFinalPathNameByHandle_func == NULL) { - JNU_ThrowInternalError(env, "Should not get here"); - return NULL; - } - - len = (*GetFinalPathNameByHandle_func)(h, path, MAX_PATH, 0); + len = GetFinalPathNameByHandleW(h, path, MAX_PATH, 0); if (len > 0) { if (len < MAX_PATH) { rv = (*env)->NewString(env, (const jchar *)path, (jsize)len); @@ -1168,7 +1110,7 @@ Java_sun_nio_fs_WindowsNativeDispatcher_GetFinalPathNameByHandle(JNIEnv* env, len += 1; /* return length does not include terminator */ lpBuf = (WCHAR*)malloc(len * sizeof(WCHAR)); if (lpBuf != NULL) { - len = (*GetFinalPathNameByHandle_func)(h, lpBuf, len, 0); + len = GetFinalPathNameByHandleW(h, lpBuf, len, 0); if (len > 0) { rv = (*env)->NewString(env, (const jchar *)lpBuf, (jsize)len); } else { diff --git a/jdk/src/java.compact1/share/classes/module-info.java b/jdk/src/java.compact1/share/classes/module-info.java new file mode 100644 index 00000000000..8c604682cd4 --- /dev/null +++ b/jdk/src/java.compact1/share/classes/module-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.compact1 { + requires public java.logging; + requires public java.scripting; +} + diff --git a/jdk/src/java.compact2/share/classes/module-info.java b/jdk/src/java.compact2/share/classes/module-info.java new file mode 100644 index 00000000000..31a738dcd8b --- /dev/null +++ b/jdk/src/java.compact2/share/classes/module-info.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.compact2 { + requires public java.compact1; + requires public java.rmi; + requires public java.sql; + requires public java.xml; +} + diff --git a/jdk/src/java.compact3/share/classes/module-info.java b/jdk/src/java.compact3/share/classes/module-info.java new file mode 100644 index 00000000000..aff5c522263 --- /dev/null +++ b/jdk/src/java.compact3/share/classes/module-info.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.compact3 { + requires public java.compact2; + requires public java.compiler; + requires public java.httpclient; + requires public java.instrument; + requires public java.management; + requires public java.naming; + requires public java.prefs; + requires public java.security.jgss; + requires public java.security.sasl; + requires public java.sql.rowset; + requires public java.xml.crypto; +} + diff --git a/jdk/src/java.datatransfer/share/classes/module-info.java b/jdk/src/java.datatransfer/share/classes/module-info.java new file mode 100644 index 00000000000..6c5c3a1cc8f --- /dev/null +++ b/jdk/src/java.datatransfer/share/classes/module-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.datatransfer { + exports java.awt.datatransfer; + exports sun.datatransfer to java.desktop; + uses sun.datatransfer.DesktopDatatransferService; +} diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java index ef5ca43cf23..4a72d0fd371 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java @@ -40,6 +40,7 @@ import apple.laf.JRSUIState.TitleBarHeightState; import com.apple.laf.AquaUtils.RecyclableSingleton; import com.apple.laf.AquaInternalFrameBorderMetrics; +import java.awt.geom.AffineTransform; public class AquaInternalFrameBorder implements Border, UIResource { private static final int kCloseButton = 0; @@ -309,18 +310,40 @@ public class AquaInternalFrameBorder implements Border, UIResource { return isInsideYButtonArea(i, y) && x >= startX && x <= endX; } - protected void paintTitleIcon(final Graphics g, final JInternalFrame frame, final int x, final int y) { - Icon icon = frame.getFrameIcon(); - if (icon == null) icon = UIManager.getIcon("InternalFrame.icon"); - if (icon == null) return; + protected void paintTitleIcon(final Graphics g, final JInternalFrame frame, + final int x, final int y) { - // Resize to 16x16 if necessary. - if (icon instanceof ImageIcon && (icon.getIconWidth() > sMaxIconWidth || icon.getIconHeight() > sMaxIconHeight)) { - final Image img = ((ImageIcon)icon).getImage(); - ((ImageIcon)icon).setImage(img.getScaledInstance(sMaxIconWidth, sMaxIconHeight, Image.SCALE_SMOOTH)); + Icon icon = frame.getFrameIcon(); + if (icon == null) { + icon = UIManager.getIcon("InternalFrame.icon"); } - icon.paintIcon(frame, g, x, y); + if (icon == null) { + return; + } + + if (icon.getIconWidth() > sMaxIconWidth + || icon.getIconHeight() > sMaxIconHeight) { + final Graphics2D g2 = (Graphics2D) g; + final AffineTransform savedAT = g2.getTransform(); + double xScaleFactor = (double) sMaxIconWidth / icon.getIconWidth(); + double yScaleFactor = (double) sMaxIconHeight / icon.getIconHeight(); + + //Coordinates are after a translation hence relative origin shifts + g2.translate(x, y); + + //scaling factor is needed to scale while maintaining aspect ratio + double scaleMaintainAspectRatio = Math.min(xScaleFactor, yScaleFactor); + + //minimum value is taken to set to a maximum Icon Dimension + g2.scale(scaleMaintainAspectRatio, scaleMaintainAspectRatio); + + icon.paintIcon(frame, g2, 0, 0); + g2.setTransform(savedAT); + + } else { + icon.paintIcon(frame, g, x, y); + } } protected int getIconWidth(final JInternalFrame frame) { @@ -330,9 +353,7 @@ public class AquaInternalFrameBorder implements Border, UIResource { if (icon == null) { icon = UIManager.getIcon("InternalFrame.icon"); } - - if (icon != null && icon instanceof ImageIcon) { - // Resize to 16x16 if necessary. + if (icon != null) { width = Math.min(icon.getIconWidth(), sMaxIconWidth); } @@ -346,9 +367,7 @@ public class AquaInternalFrameBorder implements Border, UIResource { if (icon == null) { icon = UIManager.getIcon("InternalFrame.icon"); } - - if (icon != null && icon instanceof ImageIcon) { - // Resize to 16x16 if necessary. + if (icon != null) { height = Math.min(icon.getIconHeight(), sMaxIconHeight); } diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java index 2dec5c895eb..35b87aac27e 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java @@ -128,14 +128,17 @@ public class AquaTableHeaderUI extends BasicTableHeaderUI { // Modify the table "border" to draw smaller, and with the titles in the right position // and sort indicators, just like an NSSave/Open panel. final AquaTableHeaderBorder cellBorder = AquaTableHeaderBorder.getListHeaderBorder(); - final boolean thisColumnSelected = localTable.getColumnModel().getColumn(column).getModelIndex() == sortColumn; + cellBorder.setSortOrder(AquaTableHeaderBorder.SORT_NONE); - cellBorder.setSelected(thisColumnSelected); - if (thisColumnSelected) { - cellBorder.setSortOrder(sortOrder); - } else { - cellBorder.setSortOrder(AquaTableHeaderBorder.SORT_NONE); + if (localTable != null) { + final boolean thisColumnSelected = localTable.getColumnModel().getColumn(column).getModelIndex() == sortColumn; + + cellBorder.setSelected(thisColumnSelected); + if (thisColumnSelected) { + cellBorder.setSortOrder(sortOrder); + } } + setBorder(cellBorder); return this; } diff --git a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java index faa670345c7..67520fcc30b 100644 --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaUtils.java @@ -37,12 +37,13 @@ import javax.swing.*; import javax.swing.border.Border; import javax.swing.plaf.UIResource; +import jdk.internal.loader.ClassLoaders; + import sun.awt.AppContext; import sun.lwawt.macosx.CImage; import sun.lwawt.macosx.CImage.Creator; import sun.lwawt.macosx.CPlatformWindow; -import sun.misc.Launcher; import sun.reflect.misc.ReflectUtil; import sun.security.action.GetPropertyAction; import sun.swing.SwingUtilities2; @@ -364,7 +365,8 @@ final class AquaUtils { // special casing naughty applications, like InstallAnywhere // REGR: JButton: Myst IV: the buttons of 1.0.3 updater have redraw issue static boolean shouldUseOpaqueButtons() { - final ClassLoader launcherClassLoader = Launcher.getLauncher().getClassLoader(); + // can we use ClassLoader.getSystemClassLoader here? + final ClassLoader launcherClassLoader = ClassLoaders.appClassLoader(); if (classExists(launcherClassLoader, "com.installshield.wizard.platform.macosx.MacOSXUtils")) return true; return false; } diff --git a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index cc3d345eb9f..b4116a17f3a 100644 --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -51,8 +51,6 @@ import sun.lwawt.*; import sun.lwawt.LWWindowPeer.PeerType; import sun.security.action.GetBooleanAction; -import sun.util.CoreResourceBundleControl; - @SuppressWarnings("serial") // JDK implementation class final class NamedCursor extends Cursor { NamedCursor(String name) { @@ -84,9 +82,7 @@ public final class LWCToolkit extends LWToolkit { public ResourceBundle run() { ResourceBundle platformResources = null; try { - platformResources = - ResourceBundle.getBundle("sun.awt.resources.awtosx", - CoreResourceBundleControl.getRBControlInstance()); + platformResources = ResourceBundle.getBundle("sun.awt.resources.awtosx"); } catch (MissingResourceException e) { // No resource file; defaults will be used. } diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m index 07bb7fab938..9b8e370a938 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTEvent.m @@ -134,7 +134,7 @@ const keyTable[] = {0x3D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x3E, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x3F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, // the 'fn' key on PowerBooks - {0x40, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, + {0x40, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F17}, {0x41, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_DECIMAL}, {0x42, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x43, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_MULTIPLY}, @@ -149,8 +149,8 @@ const keyTable[] = {0x4C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_ENTER}, {0x4D, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, {0x4E, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_SUBTRACT}, - {0x4F, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, - {0x50, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, + {0x4F, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F18}, + {0x50, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F19}, {0x51, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_EQUALS}, {0x52, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD0}, {0x53, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD1}, @@ -160,7 +160,7 @@ const keyTable[] = {0x57, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD5}, {0x58, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD6}, {0x59, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD7}, - {0x5A, NO, KL_UNKNOWN, java_awt_event_KeyEvent_VK_UNDEFINED}, + {0x5A, NO, KL_STANDARD, java_awt_event_KeyEvent_VK_F20}, {0x5B, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD8}, {0x5C, YES, KL_NUMPAD, java_awt_event_KeyEvent_VK_NUMPAD9}, {0x5D, YES, KL_STANDARD, java_awt_event_KeyEvent_VK_BACK_SLASH}, // This is a combo yen/backslash on JIS keyboards. diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m index 805596cc118..8070995baa6 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTView.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -624,7 +624,8 @@ AWT_ASSERT_APPKIT_THREAD; { NSString *selectedText = [self accessibleSelectedText]; NSAttributedString *styledText = [[NSAttributedString alloc] initWithString:selectedText]; - NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length]) documentAttributes:nil]; + NSData *rtfdData = [styledText RTFDFromRange:NSMakeRange(0, [styledText length]) + documentAttributes:@{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType}]; [styledText release]; return rtfdData; } @@ -681,7 +682,7 @@ AWT_ASSERT_APPKIT_THREAD; if ([[pboard types] containsObject:NSRTFDPboardType]) { NSData *rtfdData = [pboard dataForType:NSRTFDPboardType]; - NSAttributedString *styledText = [[NSAttributedString alloc] initWithRTFD:rtfdData documentAttributes:nil]; + NSAttributedString *styledText = [[NSAttributedString alloc] initWithRTFD:rtfdData documentAttributes:NULL]; NSString *text = [styledText string]; [styledText release]; diff --git a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m index 8f1e269de8f..9d8326ade6d 100644 --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/LWCToolkit.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -743,9 +743,10 @@ Java_sun_lwawt_macosx_LWCToolkit_initAppkit JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) { OSXAPP_SetJavaVM(vm); - // We need to let Foundation know that this is a multithreaded application, if it isn't already. + // We need to let Foundation know that this is a multithreaded application, + // if it isn't already. if (![NSThread isMultiThreaded]) { - [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]; + [[[[NSThread alloc] init] autorelease] start]; } return JNI_VERSION_1_4; diff --git a/jdk/src/java.desktop/macosx/native/libosx/CFileManager.m b/jdk/src/java.desktop/macosx/native/libosx/CFileManager.m index f5e676ad490..52ca5f8eccf 100644 --- a/jdk/src/java.desktop/macosx/native/libosx/CFileManager.m +++ b/jdk/src/java.desktop/macosx/native/libosx/CFileManager.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,25 +213,23 @@ JNF_COCOA_EXIT(env); */ JNIEXPORT jboolean JNICALL Java_com_apple_eio_FileManager__1moveToTrash -(JNIEnv *env, jclass clz, jstring url) +(JNIEnv *env, jclass clz, jstring fileName) { - __block jboolean returnValue = JNI_FALSE; + __block BOOL returnValue = NO; JNF_COCOA_ENTER(env); - NSString *path = JNFNormalizedNSStringForPath(env, url); + NSString * path = JNFNormalizedNSStringForPath(env, fileName); + NSURL *url = [NSURL fileURLWithPath:path]; [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){ - NSInteger res = 0; - [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation - source:[path stringByDeletingLastPathComponent] - destination:nil - files:[NSArray arrayWithObject:[path lastPathComponent]] - tag:&res]; - returnValue = (res == 0); + + returnValue = [[NSFileManager defaultManager] trashItemAtURL:url + resultingItemURL:nil + error:nil]; }]; JNF_COCOA_EXIT(env); - return returnValue; + return returnValue ? JNI_TRUE: JNI_FALSE; } /* diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.print.PrintServiceLookup b/jdk/src/java.desktop/share/classes/META-INF/services/javax.print.PrintServiceLookup deleted file mode 100644 index bbeb657da4e..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.print.PrintServiceLookup +++ /dev/null @@ -1,2 +0,0 @@ -# Provider for Java Print Service -sun.print.PrintServiceLookupProvider diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.print.StreamPrintServiceFactory b/jdk/src/java.desktop/share/classes/META-INF/services/javax.print.StreamPrintServiceFactory deleted file mode 100644 index b1bf88d80c4..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.print.StreamPrintServiceFactory +++ /dev/null @@ -1,2 +0,0 @@ -# Provider for Java 2D Stream print services. -sun.print.PSStreamPrinterFactory diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiDeviceProvider b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiDeviceProvider deleted file mode 100644 index bffb952eb65..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiDeviceProvider +++ /dev/null @@ -1,5 +0,0 @@ -# Providers for midi devices -com.sun.media.sound.RealTimeSequencerProvider -com.sun.media.sound.MidiOutDeviceProvider -com.sun.media.sound.MidiInDeviceProvider -com.sun.media.sound.SoftProvider diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileReader b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileReader deleted file mode 100644 index 1d643a0e42e..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileReader +++ /dev/null @@ -1,2 +0,0 @@ -# Providers for midi sequences -com.sun.media.sound.StandardMidiFileReader diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileWriter b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileWriter deleted file mode 100644 index bb74df72e1a..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.MidiFileWriter +++ /dev/null @@ -1,2 +0,0 @@ -# Providers for Midi file writing -com.sun.media.sound.StandardMidiFileWriter diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.SoundbankReader b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.SoundbankReader deleted file mode 100644 index 03c3df8201e..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.midi.spi.SoundbankReader +++ /dev/null @@ -1,5 +0,0 @@ -# Providers for Soundbanks -com.sun.media.sound.SF2SoundbankReader -com.sun.media.sound.DLSSoundbankReader -com.sun.media.sound.AudioFileSoundbankReader -com.sun.media.sound.JARSoundbankReader diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader deleted file mode 100644 index f0536e70d0e..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileReader +++ /dev/null @@ -1,7 +0,0 @@ -# Providers for audio file reading -com.sun.media.sound.AuFileReader -com.sun.media.sound.AiffFileReader -com.sun.media.sound.WaveFileReader -com.sun.media.sound.WaveFloatFileReader -com.sun.media.sound.WaveExtensibleFileReader -com.sun.media.sound.SoftMidiAudioFileReader diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileWriter b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileWriter deleted file mode 100644 index 83ac2b98105..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.AudioFileWriter +++ /dev/null @@ -1,5 +0,0 @@ -# Providers for writing audio files -com.sun.media.sound.AuFileWriter -com.sun.media.sound.AiffFileWriter -com.sun.media.sound.WaveFileWriter -com.sun.media.sound.WaveFloatFileWriter diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider deleted file mode 100644 index a92a6020d50..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.FormatConversionProvider +++ /dev/null @@ -1,5 +0,0 @@ -# Providers for FormatConversion -com.sun.media.sound.AudioFloatFormatConverter -com.sun.media.sound.UlawCodec -com.sun.media.sound.AlawCodec -com.sun.media.sound.PCMtoPCMCodec diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.MixerProvider b/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.MixerProvider deleted file mode 100644 index 5414bee18fb..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/javax.sound.sampled.spi.MixerProvider +++ /dev/null @@ -1,3 +0,0 @@ -# last mixer is default mixer -com.sun.media.sound.PortMixerProvider -com.sun.media.sound.DirectAudioDeviceProvider diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/sun.datatransfer.DesktopDatatransferService b/jdk/src/java.desktop/share/classes/META-INF/services/sun.datatransfer.DesktopDatatransferService deleted file mode 100644 index 7d763de56a3..00000000000 --- a/jdk/src/java.desktop/share/classes/META-INF/services/sun.datatransfer.DesktopDatatransferService +++ /dev/null @@ -1 +0,0 @@ -sun.awt.datatransfer.DesktopDatatransferServiceImpl diff --git a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java index bc2e7529d4f..984bf8ad239 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java +++ b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/ConstructorFinder.java @@ -72,6 +72,9 @@ public final class ConstructorFinder extends AbstractFinder> { if (type.isInterface()) { throw new NoSuchMethodException("Interface does not contain constructors"); } + if (!FinderUtils.isExported(type)) { + throw new NoSuchMethodException("Class is not accessible"); + } if (Modifier.isAbstract(type.getModifiers())) { throw new NoSuchMethodException("Abstract class cannot be instantiated"); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java index eb8b5bba616..5a4766dfb25 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java +++ b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FieldFinder.java @@ -54,6 +54,9 @@ public final class FieldFinder { if (name == null) { throw new IllegalArgumentException("Field name is not set"); } + if (!FinderUtils.isExported(type)) { + throw new NoSuchFieldException("Field '" + name + "' is not accessible"); + } Field field = type.getField(name); if (!Modifier.isPublic(field.getModifiers())) { throw new NoSuchFieldException("Field '" + name + "' is not public"); diff --git a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FinderUtils.java b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FinderUtils.java new file mode 100644 index 00000000000..27da02ac7b9 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/FinderUtils.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.beans.finder; + +/** + * Defines utility methods for use by finders. + */ + +final class FinderUtils { + private FinderUtils() { } + + /** + * Returns true if the given class is an exported package. + */ + public static boolean isExported(Class c) { + String pn = packageName(c); + return c.getModule().isExported(pn); + } + + private static String packageName(Class c) { + if (c.isArray()) { + return packageName(c.getComponentType()); + } else { + String name = c.getName(); + int dot = name.lastIndexOf('.'); + if (dot == -1) return ""; + return name.substring(0, dot); + } + } +} diff --git a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java index a10a1e7d544..eafc216c0e5 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java +++ b/jdk/src/java.desktop/share/classes/com/sun/beans/finder/MethodFinder.java @@ -134,6 +134,10 @@ public final class MethodFinder extends AbstractFinder { */ public static Method findAccessibleMethod(Method method) throws NoSuchMethodException { Class type = method.getDeclaringClass(); + + if (!FinderUtils.isExported(type)) { + throw new NoSuchMethodException("Method '" + method.getName() + "' is not accessible"); + } if (Modifier.isPublic(type.getModifiers()) && isPackageAccessible(type)) { return method; } diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java index 5bb49a5bef7..46185618913 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFBaseJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,16 +86,16 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { /** * Whether to write abbreviated JPEG streams (default == false). - * A subclass which sets this to true should also + * A subclass which sets this to {@code true} should also * initialized {@link #JPEGStreamMetadata}. */ protected boolean writeAbbreviatedStream = false; /** * Stream metadata equivalent to a tables-only stream such as in - * the JPEGTables. Default value is null. + * the {@code JPEGTables}. Default value is {@code null}. * This should be set by any subclass which sets - * {@link writeAbbreviatedStream} to true. + * {@link writeAbbreviatedStream} to {@code true}. */ protected IIOMetadata JPEGStreamMetadata = null; @@ -108,15 +108,15 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { /** * Removes nonessential nodes from a JPEG native image metadata tree. * All nodes derived from JPEG marker segments other than DHT, DQT, - * SOF, SOS segments are removed unless pruneTables is - * true in which case the nodes derived from the DHT and + * SOF, SOS segments are removed unless {@code pruneTables} is + * {@code true} in which case the nodes derived from the DHT and * DQT marker segments are also removed. * * @param tree A javax_imageio_jpeg_image_1.0 tree. * @param pruneTables Whether to prune Huffman and quantization tables. - * @throws NullPointerException if tree is - * null. - * @throws IllegalArgumentException if tree is not the root + * @throws NullPointerException if {@code tree} is + * {@code null}. + * @throws IllegalArgumentException if {@code tree} is not the root * of a JPEG native image metadata tree. */ private static void pruneNodes(Node tree, boolean pruneTables) { @@ -182,8 +182,8 @@ public abstract class TIFFBaseJPEGCompressor extends TIFFCompressor { } /** - * A ByteArrayOutputStream which allows writing to an - * ImageOutputStream. + * A {@code ByteArrayOutputStream} which allows writing to an + * {@code ImageOutputStream}. */ private static class IIOByteArrayOutputStream extends ByteArrayOutputStream { IIOByteArrayOutputStream() { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java index 3138974ad00..14aa2540acb 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFColorConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,39 +31,39 @@ package com.sun.imageio.plugins.tiff; public abstract class TIFFColorConverter { /** - * Constructs an instance of a TIFFColorConverter. + * Constructs an instance of a {@code TIFFColorConverter}. */ public TIFFColorConverter() {} /** * Converts an RGB triple into the native color space of this * TIFFColorConverter, and stores the result in the first three - * entries of the result array. + * entries of the {@code result} array. * * @param r the red value. * @param g the green value. * @param b the blue value. - * @param result an array of floats containing three elements. - * @throws NullPointerException if result is - * null. + * @param result an array of {@code float}s containing three elements. + * @throws NullPointerException if {@code result} is + * {@code null}. * @throws ArrayIndexOutOfBoundsException if - * result.length < 3. + * {@code result.length < 3}. */ public abstract void fromRGB(float r, float g, float b, float[] result); /** * Converts a triple in the native color space of this * TIFFColorConverter into an RGB triple, and stores the result in - * the first three entries of the rgb array. + * the first three entries of the {@code rgb} array. * * @param x0 the value of channel 0. * @param x1 the value of channel 1. * @param x2 the value of channel 2. - * @param rgb an array of floats containing three elements. - * @throws NullPointerException if rgb is - * null. + * @param rgb an array of {@code float}s containing three elements. + * @throws NullPointerException if {@code rgb} is + * {@code null}. * @throws ArrayIndexOutOfBoundsException if - * rgb.length < 3. + * {@code rgb.length < 3}. */ public abstract void toRGB(float x0, float x1, float x2, float[] rgb); } diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java index cc72f85cea8..ce1b2a58fa1 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,13 @@ import javax.imageio.stream.ImageOutputStream; public abstract class TIFFCompressor { /** - * The ImageWriter calling this - * TIFFCompressor. + * The {@code ImageWriter} calling this + * {@code TIFFCompressor}. */ protected ImageWriter writer; /** - * The IIOMetadata object containing metadata for the + * The {@code IIOMetadata} object containing metadata for the * current image. */ protected IIOMetadata metadata; @@ -63,7 +63,7 @@ public abstract class TIFFCompressor { protected boolean isCompressionLossless; /** - * The ImageOutputStream to be written. + * The {@code ImageOutputStream} to be written. */ protected ImageOutputStream stream; @@ -75,26 +75,26 @@ public abstract class TIFFCompressor { * to provide the implementation of the compression algorithm of an * unsupported compression type. * - *

        The parameters compressionTagValue and - * isCompressionLossless are provided to accomodate + *

        The parameters {@code compressionTagValue} and + * {@code isCompressionLossless} are provided to accomodate * compression types which are unknown. A compression type is * "known" if it is either among those already supported by the * TIFF writer (see {@link TIFFImageWriteParam}), or is listed in * the TIFF 6.0 specification but not supported. If the compression - * type is unknown, the compressionTagValue and - * isCompressionLossless parameters are ignored.

        + * type is unknown, the {@code compressionTagValue} and + * {@code isCompressionLossless} parameters are ignored.

        * * @param compressionType The name of the compression type. * @param compressionTagValue The value to be assigned to the TIFF * Compression tag in the TIFF image metadata; ignored if - * compressionType is a known type. + * {@code compressionType} is a known type. * @param isCompressionLossless Whether the compression is lossless; - * ignored if compressionType is a known type. + * ignored if {@code compressionType} is a known type. * - * @throws NullPointerException if compressionType is - * null. - * @throws IllegalArgumentException if compressionTagValue is - * less 1. + * @throws NullPointerException if {@code compressionType} is + * {@code null}. + * @throws IllegalArgumentException if {@code compressionTagValue} is + * less {@code 1}. */ public TIFFCompressor(String compressionType, int compressionTagValue, @@ -163,9 +163,9 @@ public abstract class TIFFCompressor { } /** - * Sets the ImageOutputStream to be written. + * Sets the {@code ImageOutputStream} to be written. * - * @param stream an ImageOutputStream to be written. + * @param stream an {@code ImageOutputStream} to be written. * * @see #getStream */ @@ -174,9 +174,9 @@ public abstract class TIFFCompressor { } /** - * Returns the ImageOutputStream that will be written. + * Returns the {@code ImageOutputStream} that will be written. * - * @return an ImageOutputStream. + * @return an {@code ImageOutputStream}. * * @see #setStream(ImageOutputStream) */ @@ -185,9 +185,9 @@ public abstract class TIFFCompressor { } /** - * Sets the value of the writer field. + * Sets the value of the {@code writer} field. * - * @param writer the current ImageWriter. + * @param writer the current {@code ImageWriter}. * * @see #getWriter() */ @@ -196,9 +196,9 @@ public abstract class TIFFCompressor { } /** - * Returns the current ImageWriter. + * Returns the current {@code ImageWriter}. * - * @return an ImageWriter. + * @return an {@code ImageWriter}. * * @see #setWriter(ImageWriter) */ @@ -207,9 +207,9 @@ public abstract class TIFFCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() @@ -219,9 +219,9 @@ public abstract class TIFFCompressor { } /** - * Returns the current IIOMetadata object. + * Returns the current {@code IIOMetadata} object. * - * @return the IIOMetadata object for the image being + * @return the {@code IIOMetadata} object for the image being * written. * * @see #setMetadata(IIOMetadata) @@ -232,15 +232,15 @@ public abstract class TIFFCompressor { /** * Encodes the supplied image data, writing to the currently set - * ImageOutputStream. + * {@code ImageOutputStream}. * - * @param b an array of bytes containing the packed + * @param b an array of {@code byte}s containing the packed * but uncompressed image data. * @param off the starting offset of the data to be written in the - * array b. + * array {@code b}. * @param width the width of the rectangle of pixels to be written. * @param height the height of the rectangle of pixels to be written. - * @param bitsPerSample an array of ints indicting + * @param bitsPerSample an array of {@code int}s indicting * the number of bits used to represent each image sample within * a pixel. * @param scanlineStride the number of bytes separating each @@ -249,7 +249,7 @@ public abstract class TIFFCompressor { * @return the number of bytes written. * * @throws IOException if the supplied data cannot be encoded by - * this TIFFCompressor, or if any I/O error occurs + * this {@code TIFFCompressor}, or if any I/O error occurs * during writing. */ public abstract int encode(byte[] b, int off, diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java index fdc29f26016..bdd31218e03 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -81,7 +81,7 @@ import com.sun.imageio.plugins.common.SimpleCMYKColorSpace; * *

        Decompressors may be written with various levels of complexity. * The most complex decompressors will override the - * decode method, and will perform all the work of + * {@code decode} method, and will perform all the work of * decoding, subsampling, offsetting, clipping, and format conversion. * This approach may be the most efficient, since it is possible to * avoid the use of extra image buffers, and it may be possible to @@ -89,35 +89,35 @@ import com.sun.imageio.plugins.common.SimpleCMYKColorSpace; * the destination. * *

        Less ambitious decompressors may override the - * decodeRaw method, which is responsible for + * {@code decodeRaw} method, which is responsible for * decompressing the entire tile or strip into a byte array (or other * appropriate datatype). The default implementation of - * decode will perform all necessary setup of buffers, - * call decodeRaw to perform the actual decoding, perform + * {@code decode} will perform all necessary setup of buffers, + * call {@code decodeRaw} to perform the actual decoding, perform * subsampling, and copy the results into the final destination image. * Where possible, it will pass the real image buffer to - * decodeRaw in order to avoid making an extra copy. + * {@code decodeRaw} in order to avoid making an extra copy. * *

        Slightly more ambitious decompressors may override - * decodeRaw, but avoid writing pixels that will be + * {@code decodeRaw}, but avoid writing pixels that will be * discarded in the subsampling phase. */ public abstract class TIFFDecompressor { /** - * The ImageReader calling this - * TIFFDecompressor. + * The {@code ImageReader} calling this + * {@code TIFFDecompressor}. */ protected ImageReader reader; /** - * The IIOMetadata object containing metadata for the + * The {@code IIOMetadata} object containing metadata for the * current image. */ protected IIOMetadata metadata; /** - * The value of the PhotometricInterpretation tag. + * The value of the {@code PhotometricInterpretation} tag. * Legal values are {@link * BaselineTIFFTagSet#PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO }, * {@link @@ -135,7 +135,7 @@ public abstract class TIFFDecompressor { protected int photometricInterpretation; /** - * The value of the Compression tag. Legal values are + * The value of the {@code Compression} tag. Legal values are * {@link BaselineTIFFTagSet#COMPRESSION_NONE}, {@link * BaselineTIFFTagSet#COMPRESSION_CCITT_RLE}, {@link * BaselineTIFFTagSet#COMPRESSION_CCITT_T_4}, {@link @@ -151,23 +151,23 @@ public abstract class TIFFDecompressor { protected int compression; /** - * true if the image is encoded using separate planes. + * {@code true} if the image is encoded using separate planes. */ protected boolean planar; /** - * The value of the SamplesPerPixel tag. + * The value of the {@code SamplesPerPixel} tag. */ protected int samplesPerPixel; /** - * The value of the BitsPerSample tag. + * The value of the {@code BitsPerSample} tag. * */ protected int[] bitsPerSample; /** - * The value of the SampleFormat tag. Legal values + * The value of the {@code SampleFormat} tag. Legal values * are {@link BaselineTIFFTagSet#SAMPLE_FORMAT_UNSIGNED_INTEGER}, * {@link BaselineTIFFTagSet#SAMPLE_FORMAT_SIGNED_INTEGER}, {@link * BaselineTIFFTagSet#SAMPLE_FORMAT_FLOATING_POINT}, {@link @@ -178,7 +178,7 @@ public abstract class TIFFDecompressor { new int[] {BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER}; /** - * The value of the ExtraSamples tag. Legal values + * The value of the {@code ExtraSamples} tag. Legal values * are {@link BaselineTIFFTagSet#EXTRA_SAMPLES_UNSPECIFIED}, * {@link BaselineTIFFTagSet#EXTRA_SAMPLES_ASSOCIATED_ALPHA}, * {@link BaselineTIFFTagSet#EXTRA_SAMPLES_UNASSOCIATED_ALPHA}, @@ -187,7 +187,7 @@ public abstract class TIFFDecompressor { protected int[] extraSamples; /** - * The value of the ColorMap tag. + * The value of the {@code ColorMap} tag. * */ protected char[] colorMap; @@ -195,20 +195,20 @@ public abstract class TIFFDecompressor { // Region of input stream containing the data /** - * The ImageInputStream containing the TIFF source + * The {@code ImageInputStream} containing the TIFF source * data. */ protected ImageInputStream stream; /** - * The offset in the source ImageInputStream of the + * The offset in the source {@code ImageInputStream} of the * start of the data to be decompressed. */ protected long offset; /** * The number of bytes of data from the source - * ImageInputStream to be decompressed. + * {@code ImageInputStream} to be decompressed. */ protected int byteCount; @@ -244,15 +244,15 @@ public abstract class TIFFDecompressor { // Subsampling to be performed /** - * The source X offset used, along with dstXOffset - * and subsampleX, to map between horizontal source + * The source X offset used, along with {@code dstXOffset} + * and {@code subsampleX}, to map between horizontal source * and destination pixel coordinates. */ protected int sourceXOffset; /** * The horizontal destination offset used, along with - * sourceXOffset and subsampleX, to map + * {@code sourceXOffset} and {@code subsampleX}, to map * between horizontal source and destination pixel coordinates. * See the comment for {@link #sourceXOffset sourceXOffset} for * the mapping equations. @@ -260,15 +260,15 @@ public abstract class TIFFDecompressor { protected int dstXOffset; /** - * The source Y offset used, along with dstYOffset - * and subsampleY, to map between vertical source and + * The source Y offset used, along with {@code dstYOffset} + * and {@code subsampleY}, to map between vertical source and * destination pixel coordinates. */ protected int sourceYOffset; /** * The vertical destination offset used, along with - * sourceYOffset and subsampleY, to map + * {@code sourceYOffset} and {@code subsampleY}, to map * between horizontal source and destination pixel coordinates. * See the comment for {@link #sourceYOffset sourceYOffset} for * the mapping equations. @@ -305,7 +305,7 @@ public abstract class TIFFDecompressor { // Destination for decodeRaw /** - * A BufferedImage for the decodeRaw + * A {@code BufferedImage} for the {@code decodeRaw} * method to write into. */ protected BufferedImage rawImage; @@ -345,15 +345,15 @@ public abstract class TIFFDecompressor { * The X coordinate of the upper-left source pixel that will * actually be copied into the destination image, taking into * account all subsampling, offsetting, and clipping. That is, - * the pixel at (activeSrcMinX, - * activeSrcMinY) is to be copied into the - * destination pixel at (dstMinX, - * dstMinY). + * the pixel at ({@code activeSrcMinX}, + * {@code activeSrcMinY}) is to be copied into the + * destination pixel at ({@code dstMinX}, + * {@code dstMinY}). * *

        The pixels in the source region to be copied are - * those with X coordinates of the form activeSrcMinX + - * k*subsampleX, where k is an integer such - * that 0 ≤ k < dstWidth. + * those with X coordinates of the form {@code activeSrcMinX + + * k*subsampleX}, where {@code k} is an integer such + * that {@code 0 ≤ k < dstWidth}. */ protected int activeSrcMinX; @@ -363,9 +363,9 @@ public abstract class TIFFDecompressor { * all subsampling, offsetting, and clipping. * *

        The pixels in the source region to be copied are - * those with Y coordinates of the form activeSrcMinY + - * k*subsampleY, where k is an integer such - * that 0 ≤ k < dstHeight. + * those with Y coordinates of the form {@code activeSrcMinY + + * k*subsampleY}, where {@code k} is an integer such + * that {@code 0 ≤ k < dstHeight}. */ protected int activeSrcMinY; @@ -375,7 +375,7 @@ public abstract class TIFFDecompressor { * susbampling, offsetting, and clipping. * *

        The active source width will always be equal to - * (dstWidth - 1)*subsampleX + 1. + * {@code (dstWidth - 1)*subsampleX + 1}. */ protected int activeSrcWidth; @@ -385,13 +385,13 @@ public abstract class TIFFDecompressor { * susbampling, offsetting, and clipping. * *

        The active source height will always be equal to - * (dstHeight - 1)*subsampleY + 1. + * {@code (dstHeight - 1)*subsampleY + 1}. */ protected int activeSrcHeight; /** - * A TIFFColorConverter object describing the color space of - * the encoded pixel data, or null. + * A {@code TIFFColorConverter} object describing the color space of + * the encoded pixel data, or {@code null}. */ protected TIFFColorConverter colorConverter; @@ -420,13 +420,13 @@ public abstract class TIFFDecompressor { // to exactly those dest pixels that are present in the source region. /** - * Create a PixelInterleavedSampleModel for use in creating - * an ImageTypeSpecifier. Its dimensions will be 1x1 and + * Create a {@code PixelInterleavedSampleModel} for use in creating + * an {@code ImageTypeSpecifier}. Its dimensions will be 1x1 and * it will have ascending band offsets as {0, 1, 2, ..., numBands}. * * @param dataType The data type (DataBuffer.TYPE_*). * @param numBands The number of bands. - * @return A PixelInterleavedSampleModel. + * @return A {@code PixelInterleavedSampleModel}. */ static SampleModel createInterleavedSM(int dataType, int numBands) { @@ -443,8 +443,8 @@ public abstract class TIFFDecompressor { } /** - * Create a ComponentColorModel for use in creating - * an ImageTypeSpecifier. + * Create a {@code ComponentColorModel} for use in creating + * an {@code ImageTypeSpecifier}. */ // This code was copied from javax.imageio.ImageTypeSpecifier. static ColorModel createComponentCM(ColorSpace colorSpace, @@ -518,8 +518,8 @@ public abstract class TIFFDecompressor { } /** - * Return the number of bits occupied by dataType - * which must be one of the DataBuffer TYPEs. + * Return the number of bits occupied by {@code dataType} + * which must be one of the {@code DataBuffer} {@code TYPE}s. */ private static int getDataTypeSize(int dataType) throws IIOException { int dataTypeSize = 0; @@ -578,7 +578,7 @@ public abstract class TIFFDecompressor { } /** - * Determines whether the DataBuffer is filled without + * Determines whether the {@code DataBuffer} is filled without * any interspersed padding bits. */ private static boolean isDataBufferBitContiguous(SampleModel sm) @@ -678,8 +678,8 @@ public abstract class TIFFDecompressor { } /** - * Reformats bit-discontiguous data into the DataBuffer - * of the supplied WritableRaster. + * Reformats bit-discontiguous data into the {@code DataBuffer} + * of the supplied {@code WritableRaster}. */ private static void reformatDiscontiguousData(byte[] buf, int stride, @@ -715,21 +715,21 @@ public abstract class TIFFDecompressor { /** * A utility method that returns an - * ImageTypeSpecifier suitable for decoding an image + * {@code ImageTypeSpecifier} suitable for decoding an image * with the given parameters. * * @param photometricInterpretation the value of the - * PhotometricInterpretation field. - * @param compression the value of the Compression field. + * {@code PhotometricInterpretation} field. + * @param compression the value of the {@code Compression} field. * @param samplesPerPixel the value of the - * SamplesPerPixel field. - * @param bitsPerSample the value of the BitsPerSample field. - * @param sampleFormat the value of the SampleFormat field. - * @param extraSamples the value of the ExtraSamples field. - * @param colorMap the value of the ColorMap field. + * {@code SamplesPerPixel} field. + * @param bitsPerSample the value of the {@code BitsPerSample} field. + * @param sampleFormat the value of the {@code SampleFormat} field. + * @param extraSamples the value of the {@code ExtraSamples} field. + * @param colorMap the value of the {@code ColorMap} field. * - * @return a suitable ImageTypeSpecifier, or - * null if it is not possible to create one. + * @return a suitable {@code ImageTypeSpecifier}, or + * {@code null} if it is not possible to create one. */ public static ImageTypeSpecifier getRawImageTypeSpecifier(int photometricInterpretation, @@ -1216,26 +1216,26 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the reader field. + * Sets the value of the {@code reader} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param reader the current ImageReader. + * @param reader the current {@code ImageReader}. */ public void setReader(ImageReader reader) { this.reader = reader; } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being read. */ public void setMetadata(IIOMetadata metadata) { @@ -1243,10 +1243,10 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the photometricInterpretation + * Sets the value of the {@code photometricInterpretation} * field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1258,9 +1258,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the compression field. + * Sets the value of the {@code compression} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1271,13 +1271,13 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the planar field. + * Sets the value of the {@code planar} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param planar true if the image to be decoded is + * @param planar {@code true} if the image to be decoded is * stored in planar format. */ public void setPlanar(boolean planar) { @@ -1285,9 +1285,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the samplesPerPixel field. + * Sets the value of the {@code samplesPerPixel} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1299,9 +1299,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the bitsPerSample field. + * Sets the value of the {@code bitsPerSample} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1314,9 +1314,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the sampleFormat field. + * Sets the value of the {@code sampleFormat} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1330,9 +1330,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the extraSamples field. + * Sets the value of the {@code extraSamples} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1346,14 +1346,14 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the colorMap field. + * Sets the value of the {@code colorMap} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * * @param colorMap the color map to apply to the source data, - * as an array of chars. + * as an array of {@code char}s. */ public void setColorMap(char[] colorMap) { this.colorMap = colorMap == null ? @@ -1361,22 +1361,22 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the stream field. + * Sets the value of the {@code stream} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param stream the ImageInputStream to be read. + * @param stream the {@code ImageInputStream} to be read. */ public void setStream(ImageInputStream stream) { this.stream = stream; } /** - * Sets the value of the offset field. + * Sets the value of the {@code offset} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1388,9 +1388,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the byteCount field. + * Sets the value of the {@code byteCount} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1403,9 +1403,9 @@ public abstract class TIFFDecompressor { // Region of the file image represented in the stream /** - * Sets the value of the srcMinX field. + * Sets the value of the {@code srcMinX} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1418,9 +1418,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the srcMinY field. + * Sets the value of the {@code srcMinY} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1433,9 +1433,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the srcWidth field. + * Sets the value of the {@code srcWidth} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1447,9 +1447,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the srcHeight field. + * Sets the value of the {@code srcHeight} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1463,9 +1463,9 @@ public abstract class TIFFDecompressor { // First source pixel to be read /** - * Sets the value of the sourceXOffset field. + * Sets the value of the {@code sourceXOffset} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1477,9 +1477,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstXOffset field. + * Sets the value of the {@code dstXOffset} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1491,9 +1491,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the sourceYOffset. + * Sets the value of the {@code sourceYOffset}. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1505,9 +1505,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstYOffset field. + * Sets the value of the {@code dstYOffset} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1521,15 +1521,15 @@ public abstract class TIFFDecompressor { // Subsampling to be performed /** - * Sets the value of the subsampleX field. + * Sets the value of the {@code subsampleX} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * * @param subsampleX the horizontal subsampling factor. * - * @throws IllegalArgumentException if subsampleX is + * @throws IllegalArgumentException if {@code subsampleX} is * less than or equal to 0. */ public void setSubsampleX(int subsampleX) { @@ -1540,15 +1540,15 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the subsampleY field. + * Sets the value of the {@code subsampleY} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * * @param subsampleY the vertical subsampling factor. * - * @throws IllegalArgumentException if subsampleY is + * @throws IllegalArgumentException if {@code subsampleY} is * less than or equal to 0. */ public void setSubsampleY(int subsampleY) { @@ -1561,13 +1561,13 @@ public abstract class TIFFDecompressor { // Band subsetting/rearrangement /** - * Sets the value of the sourceBands field. + * Sets the value of the {@code sourceBands} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param sourceBands an array of ints + * @param sourceBands an array of {@code int}s * specifying the source bands to be read. */ public void setSourceBands(int[] sourceBands) { @@ -1576,13 +1576,13 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the destinationBands field. + * Sets the value of the {@code destinationBands} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param destinationBands an array of ints + * @param destinationBands an array of {@code int}s * specifying the destination bands to be written. */ public void setDestinationBands(int[] destinationBands) { @@ -1593,22 +1593,22 @@ public abstract class TIFFDecompressor { // Destination image and region /** - * Sets the value of the image field. + * Sets the value of the {@code image} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * - * @param image the destination BufferedImage. + * @param image the destination {@code BufferedImage}. */ public void setImage(BufferedImage image) { this.image = image; } /** - * Sets the value of the dstMinX field. + * Sets the value of the {@code dstMinX} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1620,9 +1620,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstMinY field. + * Sets the value of the {@code dstMinY} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1634,9 +1634,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstWidth field. + * Sets the value of the {@code dstWidth} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1647,9 +1647,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the dstHeight field. + * Sets the value of the {@code dstHeight} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1662,9 +1662,9 @@ public abstract class TIFFDecompressor { // Active source region /** - * Sets the value of the activeSrcMinX field. + * Sets the value of the {@code activeSrcMinX} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1676,9 +1676,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the activeSrcMinY field. + * Sets the value of the {@code activeSrcMinY} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1690,9 +1690,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the activeSrcWidth field. + * Sets the value of the {@code activeSrcWidth} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1703,9 +1703,9 @@ public abstract class TIFFDecompressor { } /** - * Sets the value of the activeSrcHeight field. + * Sets the value of the {@code activeSrcHeight} field. * - *

        If this method is called, the beginDecoding + *

        If this method is called, the {@code beginDecoding} * method must be called prior to calling any of the decode * methods. * @@ -1716,23 +1716,23 @@ public abstract class TIFFDecompressor { } /** - * Sets the TIFFColorConverter object describing the color + * Sets the {@code TIFFColorConverter} object describing the color * space of the encoded data in the input stream. If no - * TIFFColorConverter is set, no conversion will be performed. + * {@code TIFFColorConverter} is set, no conversion will be performed. * - * @param colorConverter a TIFFColorConverter object, or - * null. + * @param colorConverter a {@code TIFFColorConverter} object, or + * {@code null}. */ public void setColorConverter(TIFFColorConverter colorConverter) { this.colorConverter = colorConverter; } /** - * Returns an ImageTypeSpecifier describing an image + * Returns an {@code ImageTypeSpecifier} describing an image * whose underlying data array has the same format as the raw * source pixel data. * - * @return an ImageTypeSpecifier. + * @return an {@code ImageTypeSpecifier}. */ public ImageTypeSpecifier getRawImageType() { ImageTypeSpecifier its = @@ -1747,18 +1747,18 @@ public abstract class TIFFDecompressor { } /** - * Creates a BufferedImage whose underlying data + * Creates a {@code BufferedImage} whose underlying data * array will be suitable for holding the raw decoded output of - * the decodeRaw method. + * the {@code decodeRaw} method. * *

        The default implementation calls - * getRawImageType, and calls the resulting - * ImageTypeSpecifier's - * createBufferedImage method. + * {@code getRawImageType}, and calls the resulting + * {@code ImageTypeSpecifier}'s + * {@code createBufferedImage} method. * - * @return a BufferedImage whose underlying data + * @return a {@code BufferedImage} whose underlying data * array has the same format as the raw source pixel data, or - * null if it is not possible to create such an + * {@code null} if it is not possible to create such an * image. */ public BufferedImage createRawImage() { @@ -1811,22 +1811,22 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided byte - * array b, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * bytes. + * Decodes the source data into the provided {@code byte} + * array {@code b}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code byte}s. * - * @param b a byte array to be written. - * @param dstOffset the starting offset in b to be + * @param b a {@code byte} array to be written. + * @param dstOffset the starting offset in {@code b} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of bytes to + * @param scanlineStride the number of {@code byte}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public abstract void decodeRaw(byte[] b, int dstOffset, @@ -1834,25 +1834,25 @@ public abstract class TIFFDecompressor { int scanlineStride) throws IOException; /** - * Decodes the source data into the provided short - * array s, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * shorts + * Decodes the source data into the provided {@code short} + * array {@code s}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code short}s * - *

        The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into s. + *

        The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code s}. * - * @param s a short array to be written. - * @param dstOffset the starting offset in s to be + * @param s a {@code short} array to be written. + * @param dstOffset the starting offset in {@code s} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of shorts to + * @param scanlineStride the number of {@code short}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(short[] s, int dstOffset, @@ -1891,25 +1891,25 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided int - * array i, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * ints. + * Decodes the source data into the provided {@code int} + * array {@code i}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code int}s. * - *

        The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into i. + *

        The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code i}. * - * @param i an int array to be written. - * @param dstOffset the starting offset in i to be + * @param i an {@code int} array to be written. + * @param dstOffset the starting offset in {@code i} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of ints to + * @param scanlineStride the number of {@code int}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(int[] i, int dstOffset, @@ -1953,25 +1953,25 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided float - * array f, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * floats. + * Decodes the source data into the provided {@code float} + * array {@code f}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code float}s. * - *

        The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into f. + *

        The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code f}. * - * @param f a float array to be written. - * @param dstOffset the starting offset in f to be + * @param f a {@code float} array to be written. + * @param dstOffset the starting offset in {@code f} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of floats to + * @param scanlineStride the number of {@code float}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(float[] f, int dstOffset, @@ -2017,25 +2017,25 @@ public abstract class TIFFDecompressor { } /** - * Decodes the source data into the provided double - * array f, starting at the offset given by - * dstOffset. Each pixel occupies - * bitsPerPixel bits, with no padding between pixels. - * Scanlines are separated by scanlineStride - * doubles. + * Decodes the source data into the provided {@code double} + * array {@code f}, starting at the offset given by + * {@code dstOffset}. Each pixel occupies + * {@code bitsPerPixel} bits, with no padding between pixels. + * Scanlines are separated by {@code scanlineStride} + * {@code double}s. * - *

        The default implementation calls decodeRaw(byte[] b, - * ...) and copies the resulting data into f. + *

        The default implementation calls {@code decodeRaw(byte[] b, + * ...)} and copies the resulting data into {@code f}. * - * @param f a double array to be written. - * @param dstOffset the starting offset in f to be + * @param f a {@code double} array to be written. + * @param dstOffset the starting offset in {@code f} to be * written. * @param bitsPerPixel the number of bits for each pixel. - * @param scanlineStride the number of doubles to + * @param scanlineStride the number of {@code double}s to * advance between that starting pixels of each scanline. * * @throws IOException if an error occurs reading from the source - * ImageInputStream. + * {@code ImageInputStream}. */ public void decodeRaw(double[] d, int dstOffset, @@ -2104,16 +2104,16 @@ public abstract class TIFFDecompressor { /** * This routine is called prior to a sequence of calls to the - * decode method, in order to allow any necessary + * {@code decode} method, in order to allow any necessary * tables or other structures to be initialized based on metadata * values. This routine is guaranteed to be called any time the * metadata values have changed. * *

        The default implementation computes tables used by the - * decode method to rescale components to different + * {@code decode} method to rescale components to different * bit depths. Thus, if this method is overridden, it is - * important for the subclass method to call super(), - * unless it overrides decode as well. + * important for the subclass method to call {@code super()}, + * unless it overrides {@code decode} as well. */ public void beginDecoding() { // Note: This method assumes that sourceBands, destinationBands, @@ -2242,35 +2242,35 @@ public abstract class TIFFDecompressor { /** * Decodes the input bit stream (located in the - * ImageInputStream stream, at offset - * offset, and continuing for byteCount - * bytes) into the output BufferedImage - * image. + * {@code ImageInputStream} {@code stream}, at offset + * {@code offset}, and continuing for {@code byteCount} + * bytes) into the output {@code BufferedImage} + * {@code image}. * *

        The default implementation analyzes the destination image * to determine if it is suitable as the destination for the - * decodeRaw method. If not, a suitable image is - * created. Next, decodeRaw is called to perform the + * {@code decodeRaw} method. If not, a suitable image is + * created. Next, {@code decodeRaw} is called to perform the * actual decoding, and the results are copied into the * destination image if necessary. Subsampling and offsetting are * performed automatically. * *

        The precise responsibilities of this routine are as * follows. The input bit stream is defined by the instance - * variables stream, offset, and - * byteCount. These bits contain the data for the - * region of the source image defined by srcMinX, - * srcMinY, srcWidth, and - * srcHeight. + * variables {@code stream}, {@code offset}, and + * {@code byteCount}. These bits contain the data for the + * region of the source image defined by {@code srcMinX}, + * {@code srcMinY}, {@code srcWidth}, and + * {@code srcHeight}. * *

        The source data is required to be subsampling, starting at - * the sourceXOffsetth column and including - * every subsampleXth pixel thereafter (and similarly - * for sourceYOffset and - * subsampleY). + * the {@code sourceXOffset}th column and including + * every {@code subsampleX}th pixel thereafter (and similarly + * for {@code sourceYOffset} and + * {@code subsampleY}). * *

        Pixels are copied into the destination with an addition shift of - * (dstXOffset, dstYOffset). The complete + * ({@code dstXOffset}, {@code dstYOffset}). The complete * set of formulas relating the source and destination coordinate spaces * are: * @@ -2279,9 +2279,9 @@ public abstract class TIFFDecompressor { * dy = (sy - sourceYOffset)/subsampleY + dstYOffset; * * - * Only source pixels such that (sx - sourceXOffset) % - * subsampleX == 0 and (sy - sourceYOffset) % - * subsampleY == 0 are copied. + * Only source pixels such that {@code (sx - sourceXOffset) % + * subsampleX == 0} and {@code (sy - sourceYOffset) % + * subsampleY == 0} are copied. * *

        The inverse mapping, from destination to source coordinates, * is one-to-one: @@ -2292,9 +2292,9 @@ public abstract class TIFFDecompressor { * * *

        The region of the destination image to be updated is given - * by the instance variables dstMinX, - * dstMinY, dstWidth, and - * dstHeight. + * by the instance variables {@code dstMinX}, + * {@code dstMinY}, {@code dstWidth}, and + * {@code dstHeight}. * *

        It is possible that not all of the source data being read * will contribute to the destination image. For example, the @@ -2303,32 +2303,32 @@ public abstract class TIFFDecompressor { * convenience, the bounds of the active source region (that is, * the region of the strip or tile being read that actually * contributes to the destination image, taking clipping into - * account) are available as activeSrcMinX, - * activeSrcMinY, activeSrcWidth and - * activeSrcHeight. Thus, the source pixel at - * (activeSrcMinX, activeSrcMinY) will - * map to the destination pixel (dstMinX, - * dstMinY). + * account) are available as {@code activeSrcMinX}, + * {@code activeSrcMinY}, {@code activeSrcWidth} and + * {@code activeSrcHeight}. Thus, the source pixel at + * ({@code activeSrcMinX}, {@code activeSrcMinY}) will + * map to the destination pixel ({@code dstMinX}, + * {@code dstMinY}). * *

        The sequence of source bands given by - * sourceBands are to be copied into the sequence of + * {@code sourceBands} are to be copied into the sequence of * bands in the destination given by - * destinationBands. + * {@code destinationBands}. * *

        Some standard tag information is provided the instance - * variables photometricInterpretation, - * compression, samplesPerPixel, - * bitsPerSample, sampleFormat, - * extraSamples, and colorMap. + * variables {@code photometricInterpretation}, + * {@code compression}, {@code samplesPerPixel}, + * {@code bitsPerSample}, {@code sampleFormat}, + * {@code extraSamples}, and {@code colorMap}. * *

        In practice, unless there is a significant performance * advantage to be gained by overriding this routine, most users * will prefer to use the default implementation of this routine, - * and instead override the decodeRaw and/or - * getRawImageType methods. + * and instead override the {@code decodeRaw} and/or + * {@code getRawImageType} methods. * * @exception IOException if an error occurs in - * decodeRaw. + * {@code decodeRaw}. */ public void decode() throws IOException { byte[] byteData = null; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java index b3e202cb2cd..3541ce110db 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFExifJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,7 @@ import javax.imageio.metadata.IIOMetadata; import javax.imageio.plugins.tiff.BaselineTIFFTagSet; /** - * A TIFFCompressor for the JPEG variant of Exif. + * A {@code TIFFCompressor} for the JPEG variant of Exif. */ public class TIFFExifJPEGCompressor extends TIFFBaseJPEGCompressor { public TIFFExifJPEGCompressor(ImageWriteParam param) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java index 9cbf49eb84b..5c126acab53 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFaxCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -232,12 +232,12 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * *

        The implementation in this class also sets local options * from the FILL_ORDER field if it exists.

        * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() @@ -253,8 +253,8 @@ abstract class TIFFFaxCompressor extends TIFFCompressor { } /** - * Return min of maxOffset or offset of first pixel - * different from pixel at bitOffset. + * Return min of {@code maxOffset} or offset of first pixel + * different from pixel at {@code bitOffset}. */ public int nextState(byte[] data, int base, diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java index ced248f9d7e..994d10d7810 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFFieldNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,12 +34,12 @@ import javax.imageio.plugins.tiff.TIFFTag; import javax.imageio.plugins.tiff.TIFFTagSet; /** - * The Node representation of a TIFFField + * The {@code Node} representation of a {@code TIFFField} * wherein the child node is procedural rather than buffered. */ public class TIFFFieldNode extends IIOMetadataNode { private static String getNodeName(TIFFField f) { - return f.getData() instanceof TIFFDirectory ? + return (f.hasDirectory() || f.getData() instanceof TIFFDirectory) ? "TIFFIFD" : "TIFFField"; } @@ -52,7 +52,8 @@ public class TIFFFieldNode extends IIOMetadataNode { public TIFFFieldNode(TIFFField field) { super(getNodeName(field)); - isIFD = field.getData() instanceof TIFFDirectory; + isIFD = field.hasDirectory() || + field.getData() instanceof TIFFDirectory; this.field = field; @@ -68,7 +69,8 @@ public class TIFFFieldNode extends IIOMetadataNode { setAttribute("parentTagName", tagName); } - TIFFDirectory dir = (TIFFDirectory)field.getData(); + TIFFDirectory dir = field.hasDirectory() ? + field.getDirectory() : (TIFFDirectory)field.getData(); TIFFTagSet[] tagSets = dir.getTagSets(); if(tagSets != null) { StringBuilder tagSetNames = new StringBuilder(); @@ -90,7 +92,8 @@ public class TIFFFieldNode extends IIOMetadataNode { if(isInitialized) return; if(isIFD) { - TIFFDirectory dir = (TIFFDirectory)field.getData(); + TIFFDirectory dir = field.hasDirectory() ? + field.getDirectory() : (TIFFDirectory)field.getData(); TIFFField[] fields = dir.getTIFFFields(); if(fields != null) { TIFFTagSet[] tagSets = dir.getTagSets(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java index c60a98c793b..46d1419ee4c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFIFD.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,7 +153,7 @@ public class TIFFIFD extends TIFFDirectory { } /** - * Returns an Iterator over the TIFF fields. The + * Returns an {@code Iterator} over the TIFF fields. The * traversal is in the order of increasing tag number. */ // Note: the sort is guaranteed for low fields by the use of an @@ -164,7 +164,7 @@ public class TIFFIFD extends TIFFDirectory { } /** - * Read the value of a field. The data parameter should be + * Read the value of a field. The {@code data} parameter should be * an array of length 1 of Object. * * @param stream the input stream @@ -762,8 +762,8 @@ public class TIFFIFD extends TIFFDirectory { } /** - * Returns a TIFFIFD wherein all fields from the - * BaselineTIFFTagSet are copied by value and all other + * Returns a {@code TIFFIFD} wherein all fields from the + * {@code BaselineTIFFTagSet} are copied by value and all other * fields copied by reference. */ public TIFFIFD getShallowClone() { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java index decebe16f0c..933c2da5a6c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1620,8 +1620,8 @@ public class TIFFImageMetadata extends IIOMetadata { } /** - * Returns a TIFFImageMetadata wherein all fields in the - * root IFD from the BaselineTIFFTagSet are copied by value + * Returns a {@code TIFFImageMetadata} wherein all fields in the + * root IFD from the {@code BaselineTIFFTagSet} are copied by value * and all other fields copied by reference. */ public TIFFImageMetadata getShallowClone() { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java index 47356e0d6a2..317027351fc 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,7 @@ public class TIFFImageReader extends ImageReader { // Metadata for image at 'currIndex', or null. private TIFFImageMetadata imageMetadata = null; - // A List of Longs indicating the stream + // A {@code List} of {@code Long}s indicating the stream // positions of the start of the IFD for each image. Entries // are added as needed. private List imageStartPosition = new ArrayList(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java index 21dc5cb7eb4..c30f7ec70f9 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriteParam.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,11 +122,11 @@ import javax.imageio.ImageWriteParam; * quality value is passed directly to the JPEG writer plug-in which * interprets it in the usual way.

        * - *

        The canWriteTiles and - * canWriteCompressed methods will return - * true; the canOffsetTiles and - * canWriteProgressive methods will return - * false.

        + *

        The {@code canWriteTiles} and + * {@code canWriteCompressed} methods will return + * {@code true}; the {@code canOffsetTiles} and + * {@code canWriteProgressive} methods will return + * {@code false}.

        * *

        If tiles are being written, then each of their dimensions will be * rounded to the nearest multiple of 16 per the TIFF specification. If @@ -140,10 +140,10 @@ import javax.imageio.ImageWriteParam; public class TIFFImageWriteParam extends ImageWriteParam { /** - * Constructs a TIFFImageWriteParam instance - * for a given Locale. + * Constructs a {@code TIFFImageWriteParam} instance + * for a given {@code Locale}. * - * @param locale the Locale for which messages + * @param locale the {@code Locale} for which messages * should be localized. */ public TIFFImageWriteParam(Locale locale) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java index ea819e9e968..d0d5c3e5ce0 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,11 +221,11 @@ public class TIFFImageWriter extends ImageWriter { * relative to a given tile grid layout specified by its X offset * and tile width. * - *

        If tileWidth < 0, the results of this method - * are undefined. If tileWidth == 0, an - * ArithmeticException will be thrown. + *

        If {@code tileWidth < 0}, the results of this method + * are undefined. If {@code tileWidth == 0}, an + * {@code ArithmeticException} will be thrown. * - * @throws ArithmeticException If tileWidth == 0. + * @throws ArithmeticException If {@code tileWidth == 0}. */ public static int XToTileX(int x, int tileGridXOffset, int tileWidth) { x -= tileGridXOffset; @@ -240,11 +240,11 @@ public class TIFFImageWriter extends ImageWriter { * relative to a given tile grid layout specified by its Y offset * and tile height. * - *

        If tileHeight < 0, the results of this method - * are undefined. If tileHeight == 0, an - * ArithmeticException will be thrown. + *

        If {@code tileHeight < 0}, the results of this method + * are undefined. If {@code tileHeight == 0}, an + * {@code ArithmeticException} will be thrown. * - * @throws ArithmeticException If tileHeight == 0. + * @throws ArithmeticException If {@code tileHeight == 0}. */ public static int YToTileY(int y, int tileGridYOffset, int tileHeight) { y -= tileGridYOffset; @@ -424,17 +424,17 @@ public class TIFFImageWriter extends ImageWriter { } /** - * Converts a standard javax_imageio_1.0 tree to a - * TIFFImageMetadata object. + * Converts a standard {@code javax_imageio_1.0} tree to a + * {@code TIFFImageMetadata} object. * * @param inData The metadata object. - * @return a TIFFImageMetadata or null if - * the standard tree derived from the input object is null. - * @throws IllegalArgumentException if inData is - * null. - * @throws IllegalArgumentException if inData does not support + * @return a {@code TIFFImageMetadata} or {@code null} if + * the standard tree derived from the input object is {@code null}. + * @throws IllegalArgumentException if {@code inData} is + * {@code null}. + * @throws IllegalArgumentException if {@code inData} does not support * the standard metadata format. - * @throws IIOInvalidTreeException if inData generates an + * @throws IIOInvalidTreeException if {@code inData} generates an * invalid standard metadata tree. */ private TIFFImageMetadata convertStandardImageMetadata(IIOMetadata inData) @@ -463,15 +463,15 @@ public class TIFFImageWriter extends ImageWriter { /** * Converts a native - * javax_imageio_tiff_image_1.0 tree to a - * TIFFImageMetadata object. + * {@code javax_imageio_tiff_image_1.0} tree to a + * {@code TIFFImageMetadata} object. * * @param inData The metadata object. - * @return a TIFFImageMetadata or null if - * the native tree derived from the input object is null. - * @throws IllegalArgumentException if inData is - * null or does not support the native metadata format. - * @throws IIOInvalidTreeException if inData generates an + * @return a {@code TIFFImageMetadata} or {@code null} if + * the native tree derived from the input object is {@code null}. + * @throws IllegalArgumentException if {@code inData} is + * {@code null} or does not support the native metadata format. + * @throws IIOInvalidTreeException if {@code inData} generates an * invalid native metadata tree. */ private TIFFImageMetadata convertNativeImageMetadata(IIOMetadata inData) @@ -504,8 +504,8 @@ public class TIFFImageWriter extends ImageWriter { * as needed. The destination image dimensions are provided as parameters * because these might differ from those of the source due to subsampling. * - * @param cm The ColorModel of the image being written. - * @param sm The SampleModel of the image being written. + * @param cm The {@code ColorModel} of the image being written. + * @param sm The {@code SampleModel} of the image being written. * @param destWidth The width of the written image after subsampling. * @param destHeight The height of the written image after subsampling. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java index a631a3a926c..7b6cfcf5b28 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFJPEGCompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,14 +102,14 @@ public class TIFFJPEGCompressor extends TIFFBaseJPEGCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * *

        The implementation in this class also adds the TIFF fields * JPEGTables, YCbCrSubSampling, YCbCrPositioning, and * ReferenceBlackWhite superseding any prior settings of those * fields.

        * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java index d53a275955f..cbf3b504f63 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -245,7 +245,7 @@ class TIFFLZWDecompressor extends TIFFDecompressor { } /** - * Append newString to the end of oldString. + * Append {@code newString} to the end of {@code oldString}. */ public byte[] composeString(byte oldString[], byte newString) { int length = oldString.length; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java index 92656697d2c..2a61535cff3 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFLZWUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -188,7 +188,7 @@ class TIFFLZWUtil { } /** - * Append newString to the end of oldString. + * Append {@code newString} to the end of {@code oldString}. */ public byte[] composeString(byte oldString[], byte newString) { int length = oldString.length; diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java index 657bd28861b..6ffc1f0acb7 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFNullDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,16 +34,16 @@ public class TIFFNullDecompressor extends TIFFDecompressor { */ private boolean isReadActiveOnly = false; - /** The original value of srcMinX. */ + /** The original value of {@code srcMinX}. */ private int originalSrcMinX; - /** The original value of srcMinY. */ + /** The original value of {@code srcMinY}. */ private int originalSrcMinY; - /** The original value of srcWidth. */ + /** The original value of {@code srcWidth}. */ private int originalSrcWidth; - /** The original value of srcHeight. */ + /** The original value of {@code srcHeight}. */ private int originalSrcHeight; public TIFFNullDecompressor() {} diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java index 264657ddb2a..2837754ddb2 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFOldJPEGDecompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,7 @@ import javax.imageio.plugins.tiff.BaselineTIFFTagSet; import javax.imageio.plugins.tiff.TIFFField; /** - * TIFFDecompressor for "Old JPEG" compression. + * {@code TIFFDecompressor} for "Old JPEG" compression. */ public class TIFFOldJPEGDecompressor extends TIFFJPEGDecompressor { diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java index cebfdfb2221..523f9eaa574 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRLECompressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,8 +42,8 @@ public class TIFFRLECompressor extends TIFFFaxCompressor { * CCITT RLE (Run Lenth Encoding). * * @param data The row of data to compress. - * @param rowOffset Starting index in data. - * @param colOffset Bit offset within first data[rowOffset]. + * @param rowOffset Starting index in {@code data}. + * @param colOffset Bit offset within first {@code data[rowOffset]}. * @param rowLength Number of bits in the row. * @param compData The compressed data. * diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java index 98a336f8c8f..77e0c9a109c 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFRenderedImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,15 +85,15 @@ public class TIFFRenderedImage implements RenderedImage { } /** - * Creates a copy of param. The source subsampling and + * Creates a copy of {@code param}. The source subsampling and * and bands settings and the destination bands and offset settings - * are copied. If param is a TIFFImageReadParam - * then the TIFFDecompressor and - * TIFFColorConverter settings are also copied; otherwise - * they are explicitly set to null. + * are copied. If {@code param} is a {@code TIFFImageReadParam} + * then the {@code TIFFDecompressor} and + * {@code TIFFColorConverter} settings are also copied; otherwise + * they are explicitly set to {@code null}. * * @param param the parameters to be copied. - * @param copyTagSets whether the TIFFTagSet settings + * @param copyTagSets whether the {@code TIFFTagSet} settings * should be copied if set. * @return copied parameters. */ diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java index fa2652ef902..55088e34dfe 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT4Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,13 +41,13 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { } /** - * Sets the value of the metadata field. + * Sets the value of the {@code metadata} field. * *

        The implementation in this class also sets local options * from the T4_OPTIONS field if it exists, and if it doesn't, adds * it with default values.

        * - * @param metadata the IIOMetadata object for the + * @param metadata the {@code IIOMetadata} object for the * image being written. * * @see #getMetadata() @@ -86,7 +86,7 @@ public class TIFFT4Compressor extends TIFFFaxCompressor { * @param isEOLAligned Whether EOL bit sequences should be padded. * @param data The row of data to compress. * @param lineStride Byte step between the same sample in different rows. - * @param colOffset Bit offset within first data[rowOffset]. + * @param colOffset Bit offset within first {@code data[rowOffset]}. * @param width Number of bits in the row. * @param height Number of rows in the buffer. * @param compData The compressed data. diff --git a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java index 964bba05032..517c23bde54 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFT6Compressor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public class TIFFT6Compressor extends TIFFFaxCompressor { * * @param data The row of data to compress. * @param lineStride Byte step between the same sample in different rows. - * @param colOffset Bit offset within first data[rowOffset]. + * @param colOffset Bit offset within first {@code data[rowOffset]}. * @param width Number of bits in the row. * @param height Number of rows in the buffer. * @param compData The compressed data. diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java index 8c9dc3c78be..c0ac8bf6d40 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,11 +26,11 @@ package com.sun.media.sound; import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFileFormat.Type; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; @@ -49,11 +49,6 @@ public final class AiffFileReader extends SunFileReader { throws UnsupportedAudioFileException, IOException { DataInputStream dis = new DataInputStream(stream); - // assumes a stream at the beginning of the file which has already - // passed the magic number test... - // leaves the input stream at the beginning of the audio data - int fileRead = 0; - int dataLength = 0; AudioFormat format = null; // Read the magic number @@ -65,9 +60,9 @@ public final class AiffFileReader extends SunFileReader { throw new UnsupportedAudioFileException("not an AIFF file"); } + int frameLength = 0; int length = dis.readInt(); int iffType = dis.readInt(); - fileRead += 12; int totallength; if(length <= 0 ) { @@ -91,7 +86,6 @@ public final class AiffFileReader extends SunFileReader { // Read the chunk name int chunkName = dis.readInt(); int chunkLen = dis.readInt(); - fileRead += 8; int chunkRead = 0; @@ -112,7 +106,13 @@ public final class AiffFileReader extends SunFileReader { if (channels <= 0) { throw new UnsupportedAudioFileException("Invalid number of channels"); } - dis.readInt(); // numSampleFrames + frameLength = dis.readInt(); // numSampleFrames + if (frameLength < 0) { + // AiffFileFormat uses int, unlike AIS which uses long + //TODO this (negative) value should be passed as long to AIS + frameLength = AudioSystem.NOT_SPECIFIED; + } + int sampleSizeInBits = dis.readUnsignedShort(); if (sampleSizeInBits < 1 || sampleSizeInBits > 32) { throw new UnsupportedAudioFileException("Invalid AIFF/COMM sampleSize"); @@ -149,38 +149,17 @@ public final class AiffFileReader extends SunFileReader { break; case AiffFileFormat.SSND_MAGIC: // Data chunk. - // we are getting *weird* numbers for chunkLen sometimes; - // this really should be the size of the data chunk.... - int dataOffset = dis.readInt(); - int blocksize = dis.readInt(); + int dataOffset = dis.readInt(); // for now unused in javasound + int blocksize = dis.readInt(); // for now unused in javasound chunkRead += 8; - - // okay, now we are done reading the header. we need to set the size - // of the data segment. we know that sometimes the value we get for - // the chunksize is absurd. this is the best i can think of:if the - // value seems okay, use it. otherwise, we get our value of - // length by assuming that everything left is the data segment; - // its length should be our original length (for all AIFF data chunks) - // minus what we've read so far. - // $$kk: we should be able to get length for the data chunk right after - // we find "SSND." however, some aiff files give *weird* numbers. what - // is going on?? - - if (chunkLen < length) { - dataLength = chunkLen - chunkRead; - } else { - // $$kk: 11.03.98: this seems dangerous! - dataLength = length - (fileRead + chunkRead); - } ssndFound = true; break; } // switch - fileRead += chunkRead; // skip the remainder of this chunk if (!ssndFound) { int toSkip = chunkLen - chunkRead; if (toSkip > 0) { - fileRead += dis.skipBytes(toSkip); + dis.skipBytes(toSkip); } } } // while @@ -188,36 +167,12 @@ public final class AiffFileReader extends SunFileReader { if (format == null) { throw new UnsupportedAudioFileException("missing COMM chunk"); } - AudioFileFormat.Type type = aifc?AudioFileFormat.Type.AIFC:AudioFileFormat.Type.AIFF; + Type type = aifc ? Type.AIFC : Type.AIFF; - return new AiffFileFormat(type, totallength, format, dataLength / format.getFrameSize()); + return new AiffFileFormat(type, totallength, format, frameLength); } // HELPER METHODS - /** write_ieee_extended(DataOutputStream dos, double f) throws IOException { - * Extended precision IEEE floating-point conversion routine. - * @argument DataOutputStream - * @argument double - * @return void - * @exception IOException - */ - private void write_ieee_extended(DataOutputStream dos, double f) throws IOException { - - int exponent = 16398; - double highMantissa = f; - - // For now write the integer portion of f - // $$jb: 03.30.99: stay in synch with JMF on this!!!! - while (highMantissa < 44000) { - highMantissa *= 2; - exponent--; - } - dos.writeShort(exponent); - dos.writeInt( ((int) highMantissa) << 16); - dos.writeInt(0); // low Mantissa - } - - /** * read_ieee_extended * Extended precision IEEE floating-point conversion routine. diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java index 0a4788df804..9b5ebac2f6b 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java @@ -59,7 +59,6 @@ public final class AiffFileWriter extends SunFileWriter { super(new AudioFileFormat.Type[]{AudioFileFormat.Type.AIFF}); } - // METHODS TO IMPLEMENT AudioFileWriter @Override @@ -83,7 +82,6 @@ public final class AiffFileWriter extends SunFileWriter { return new AudioFileFormat.Type[0]; } - @Override public int write(AudioInputStream stream, AudioFileFormat.Type fileType, OutputStream out) throws IOException { Objects.requireNonNull(stream); @@ -102,11 +100,9 @@ public final class AiffFileWriter extends SunFileWriter { throw new IOException("stream length not specified"); } - int bytesWritten = writeAiffFile(stream, aiffFileFormat, out); - return bytesWritten; + return writeAiffFile(stream, aiffFileFormat, out); } - @Override public int write(AudioInputStream stream, AudioFileFormat.Type fileType, File out) throws IOException { Objects.requireNonNull(stream); @@ -129,12 +125,15 @@ public final class AiffFileWriter extends SunFileWriter { // $$kk: 10.22.99: jan: please either implement this or throw an exception! // $$fb: 2001-07-13: done. Fixes Bug 4479981 - int ssndBlockSize = (aiffFileFormat.getFormat().getChannels() * aiffFileFormat.getFormat().getSampleSizeInBits()); + int channels = aiffFileFormat.getFormat().getChannels(); + int sampleSize = aiffFileFormat.getFormat().getSampleSizeInBits(); + int ssndBlockSize = channels * ((sampleSize + 7) / 8); int aiffLength=bytesWritten; int ssndChunkSize=aiffLength-aiffFileFormat.getHeaderSize()+16; long dataSize=ssndChunkSize-16; - int numFrames=(int) (dataSize*8/ssndBlockSize); + //TODO possibly incorrect round + int numFrames = (int) (dataSize / ssndBlockSize); RandomAccessFile raf=new RandomAccessFile(out, "rw"); // skip FORM magic @@ -173,12 +172,7 @@ public final class AiffFileWriter extends SunFileWriter { AudioFormat streamFormat = stream.getFormat(); AudioFormat.Encoding streamEncoding = streamFormat.getEncoding(); - - float sampleRate; int sampleSizeInBits; - int channels; - int frameSize; - float frameRate; int fileSize; boolean convert8to16 = false; @@ -235,7 +229,6 @@ public final class AiffFileWriter extends SunFileWriter { return fileFormat; } - private int writeAiffFile(InputStream in, AiffFileFormat aiffFileFormat, OutputStream out) throws IOException { int bytesRead = 0; @@ -275,25 +268,20 @@ public final class AiffFileWriter extends SunFileWriter { AudioFormat.Encoding encoding = null; //$$fb a little bit nicer handling of constants - - //int headerSize = 54; int headerSize = aiffFileFormat.getHeaderSize(); - //int fverChunkSize = 0; int fverChunkSize = aiffFileFormat.getFverChunkSize(); - //int commChunkSize = 26; int commChunkSize = aiffFileFormat.getCommChunkSize(); int aiffLength = -1; int ssndChunkSize = -1; - //int ssndOffset = headerSize - 16; int ssndOffset = aiffFileFormat.getSsndChunkOffset(); short channels = (short) format.getChannels(); short sampleSize = (short) format.getSampleSizeInBits(); - int ssndBlockSize = (channels * sampleSize); - int numFrames = aiffFileFormat.getFrameLength(); - long dataSize = -1; + int ssndBlockSize = channels * ((sampleSize + 7) / 8); + int numFrames = aiffFileFormat.getFrameLength(); + long dataSize = -1; if( numFrames != AudioSystem.NOT_SPECIFIED) { - dataSize = (long) numFrames * ssndBlockSize / 8; + dataSize = (long) numFrames * ssndBlockSize; ssndChunkSize = (int)dataSize + 16; aiffLength = (int)dataSize+headerSize; } @@ -403,9 +391,6 @@ public final class AiffFileWriter extends SunFileWriter { } - - - // HELPER METHODS private static final int DOUBLE_MANTISSA_LENGTH = 52; @@ -452,6 +437,4 @@ public final class AiffFileWriter extends SunFileWriter { dos.writeShort(extendedBits79To64); dos.writeLong(extendedBits63To0); } - - } diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java index 30c49810771..a5f024a2592 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JARSoundbankReader.java @@ -88,7 +88,8 @@ public final class JARSoundbankReader extends SoundbankReader { try { Class c = Class.forName(line.trim(), false, ucl); if (Soundbank.class.isAssignableFrom(c)) { - Object o = ReflectUtil.newInstance(c); + ReflectUtil.checkPackageAccess(c); + Object o = c.newInstance(); soundbanks.add((Soundbank) o); } } catch (ClassNotFoundException ignored) { diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java index 240c6d27c58..9085c58b530 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveExtensibleFileReader.java @@ -255,16 +255,17 @@ public final class WaveExtensibleFileReader extends SunFileReader { public AudioInputStream getAudioInputStream(final InputStream stream) throws UnsupportedAudioFileException, IOException { - AudioFileFormat format = getAudioFileFormat(stream); + final AudioFileFormat format = getAudioFileFormat(stream); // we've got everything, the stream is supported and it is at the // beginning of the header, so find the data chunk again and return an // AudioInputStream - RIFFReader riffiterator = new RIFFReader(stream); + final RIFFReader riffiterator = new RIFFReader(stream); while (riffiterator.hasNextChunk()) { RIFFReader chunk = riffiterator.nextChunk(); if (chunk.getFormat().equals("data")) { - return new AudioInputStream(chunk, format.getFormat(), chunk - .getSize()); + final AudioFormat af = format.getFormat(); + final long length = chunk.getSize() / af.getFrameSize(); + return new AudioInputStream(chunk, af, length); } } throw new UnsupportedAudioFileException(); diff --git a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java index afecd0e34be..6639cf040e8 100644 --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/WaveFloatFileReader.java @@ -95,16 +95,17 @@ public final class WaveFloatFileReader extends SunFileReader { public AudioInputStream getAudioInputStream(final InputStream stream) throws UnsupportedAudioFileException, IOException { - AudioFileFormat format = getAudioFileFormat(stream); + final AudioFileFormat format = getAudioFileFormat(stream); // we've got everything, the stream is supported and it is at the // beginning of the header, so find the data chunk again and return an // AudioInputStream - RIFFReader riffiterator = new RIFFReader(stream); + final RIFFReader riffiterator = new RIFFReader(stream); while (riffiterator.hasNextChunk()) { RIFFReader chunk = riffiterator.nextChunk(); if (chunk.getFormat().equals("data")) { - return new AudioInputStream(chunk, format.getFormat(), - chunk.getSize()); + final AudioFormat af = format.getFormat(); + final long length = chunk.getSize() / af.getFrameSize(); + return new AudioInputStream(chunk, af, length); } } throw new UnsupportedAudioFileException(); diff --git a/jdk/src/java.desktop/share/classes/java/awt/Component.java b/jdk/src/java.desktop/share/classes/java/awt/Component.java index 663c5f909be..a01b9065c36 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java @@ -8696,6 +8696,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * the Swing package private method {@code compWriteObjectNotify}. */ private void doSwingSerialization() { + @SuppressWarnings("deprecation") Package swingPackage = Package.getPackage("javax.swing"); // For Swing serialization to correctly work Swing needs to // be notified before Component does it's serialization. This diff --git a/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java b/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java index d23e672779c..9b04496f65b 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/jdk/src/java.desktop/share/classes/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -231,7 +231,9 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy // Before all the checks below we first see if it's an FTP provider or a focus cycle root. // If it's the case just go down cycle (if it's set to "implicit"). Component comp = getComponentDownCycle(aComponent, FORWARD_TRAVERSAL); - if (comp != null) { + // Check if aComponent is focus-cycle-root's default Component, i.e. + // focus cycle root & focus-cycle-root's default Component is same. + if (comp != null && comp != aComponent) { return comp; } diff --git a/jdk/src/java.desktop/share/classes/java/awt/Toolkit.java b/jdk/src/java.desktop/share/classes/java/awt/Toolkit.java index 663a6c72a1b..9e7646fd320 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Toolkit.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Toolkit.java @@ -56,7 +56,6 @@ import sun.awt.AppContext; import sun.awt.HeadlessToolkit; import sun.awt.PeerEvent; import sun.awt.SunToolkit; -import sun.util.CoreResourceBundleControl; import java.security.AccessController; import java.security.PrivilegedAction; @@ -464,7 +463,8 @@ public abstract class Toolkit { */ private static void fallbackToLoadClassForAT(String atName) { try { - Class.forName(atName, false, ClassLoader.getSystemClassLoader()).newInstance(); + Class c = Class.forName(atName, false, ClassLoader.getSystemClassLoader()); + c.newInstance(); } catch (ClassNotFoundException e) { newAWTError(e, "Assistive Technology not found: " + atName); } catch (InstantiationException e) { @@ -1373,9 +1373,7 @@ public abstract class Toolkit { new java.security.PrivilegedAction() { public Void run() { try { - resources = - ResourceBundle.getBundle("sun.awt.resources.awt", - CoreResourceBundleControl.getRBControlInstance()); + resources = ResourceBundle.getBundle("sun.awt.resources.awt"); } catch (MissingResourceException e) { // No resource file; defaults will be used. } diff --git a/jdk/src/java.desktop/share/classes/java/awt/Window.java b/jdk/src/java.desktop/share/classes/java/awt/Window.java index 7ac8023acdd..5894ad303b7 100644 --- a/jdk/src/java.desktop/share/classes/java/awt/Window.java +++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java @@ -2797,7 +2797,12 @@ public class Window extends Container implements Accessible { */ @Deprecated public void applyResourceBundle(String rbName) { - applyResourceBundle(ResourceBundle.getBundle(rbName)); + // Use the unnamed module from the TCCL or system class loader. + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + applyResourceBundle(ResourceBundle.getBundle(rbName, cl.getUnnamedModule())); } /* diff --git a/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java b/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java index 6f1427fe54a..1ab720f7555 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java +++ b/jdk/src/java.desktop/share/classes/java/beans/EventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -526,8 +526,11 @@ public class EventHandler implements InvocationHandler { * @throws NullPointerException if {@code listenerInterface} is null * @throws NullPointerException if {@code target} is null * @throws NullPointerException if {@code action} is null - * + * @throws IllegalArgumentException if creating a Proxy for + * {@code listenerInterface} fails for any of the restrictions + * specified by {@link Proxy#newProxyInstance} * @see #create(Class, Object, String, String) + * @see Proxy#newProxyInstance */ public static T create(Class listenerInterface, Object target, String action) @@ -584,8 +587,11 @@ public class EventHandler implements InvocationHandler { * @throws NullPointerException if {@code listenerInterface} is null * @throws NullPointerException if {@code target} is null * @throws NullPointerException if {@code action} is null - * + * @throws IllegalArgumentException if creating a Proxy for + * {@code listenerInterface} fails for any of the restrictions + * specified by {@link Proxy#newProxyInstance} * @see #create(Class, Object, String, String, String) + * @see Proxy#newProxyInstance */ public static T create(Class listenerInterface, Object target, String action, @@ -675,8 +681,11 @@ public class EventHandler implements InvocationHandler { * @throws NullPointerException if {@code listenerInterface} is null * @throws NullPointerException if {@code target} is null * @throws NullPointerException if {@code action} is null - * + * @throws IllegalArgumentException if creating a Proxy for + * {@code listenerInterface} fails for any of the restrictions + * specified by {@link Proxy#newProxyInstance} * @see EventHandler + * @see Proxy#newProxyInstance */ public static T create(Class listenerInterface, Object target, String action, diff --git a/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java b/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java index ddef0cffad5..ba2cbcd2dc9 100644 --- a/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java +++ b/jdk/src/java.desktop/share/classes/java/beans/SimpleBeanInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,8 @@ package java.beans; import java.awt.Image; import java.awt.Toolkit; -import java.io.InputStream; +import java.awt.image.ImageProducer; +import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; @@ -171,19 +172,24 @@ public class SimpleBeanInfo implements BeanInfo { } /** - * This is a utility method to help in loading icon images. - * It takes the name of a resource file associated with the - * current object's class file and loads an image object - * from that file. Typically images will be GIFs. + * This is a utility method to help in loading icon images. It takes the + * name of a resource file associated with the current object's class file + * and loads an image object from that file. Typically images will be GIFs. * - * @param resourceName A pathname relative to the directory - * holding the class file of the current class. For example, - * "wombat.gif". - * @return an image object. May be null if the load failed. + * @param resourceName A pathname relative to the directory holding the + * class file of the current class. For example, "wombat.gif". + * @return an image object or null if the resource is not found or the + * resource could not be loaded as an Image */ public Image loadImage(final String resourceName) { - try (InputStream in = getClass().getResourceAsStream(resourceName)) { - return Toolkit.getDefaultToolkit().createImage(in.readAllBytes()); + try { + final URL url = getClass().getResource(resourceName); + if (url != null) { + final ImageProducer ip = (ImageProducer) url.getContent(); + if (ip != null) { + return Toolkit.getDefaultToolkit().createImage(ip); + } + } } catch (final Exception ignored) { } return null; diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java b/jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java index f9c29cd59dc..5f39ea935fa 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageReader.java @@ -2452,31 +2452,16 @@ public abstract class ImageReader { locale = Locale.getDefault(); } - /** - * If an applet supplies an implementation of ImageReader and - * resource bundles, then the resource bundle will need to be - * accessed via the applet class loader. So first try the context - * class loader to locate the resource bundle. - * If that throws MissingResourceException, then try the - * system class loader. + /* + * Only the plugin knows the messages that are provided, so we + * can always locate the resource bundles from the same loader + * as that for the plugin code itself. */ - ClassLoader loader = - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public ClassLoader run() { - return Thread.currentThread().getContextClassLoader(); - } - }); - ResourceBundle bundle = null; try { - bundle = ResourceBundle.getBundle(baseName, locale, loader); + bundle = ResourceBundle.getBundle(baseName, locale, this.getClass().getModule()); } catch (MissingResourceException mre) { - try { - bundle = ResourceBundle.getBundle(baseName, locale); - } catch (MissingResourceException mre1) { - throw new IllegalArgumentException("Bundle not found!"); - } + throw new IllegalArgumentException("Bundle not found!"); } String warning = null; diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/ImageWriter.java b/jdk/src/java.desktop/share/classes/javax/imageio/ImageWriter.java index d9b0694f5e1..a9a681ce05f 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/ImageWriter.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/ImageWriter.java @@ -1954,31 +1954,16 @@ public abstract class ImageWriter implements ImageTranscoder { locale = Locale.getDefault(); } - /** - * If an applet supplies an implementation of ImageWriter and - * resource bundles, then the resource bundle will need to be - * accessed via the applet class loader. So first try the context - * class loader to locate the resource bundle. - * If that throws MissingResourceException, then try the - * system class loader. + /* + * Only the plugin knows the messages that are provided, so we + * can always locate the resource bundles from the same loader + * as that for the plugin code itself. */ - ClassLoader loader = - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public ClassLoader run() { - return Thread.currentThread().getContextClassLoader(); - } - }); - ResourceBundle bundle = null; try { - bundle = ResourceBundle.getBundle(baseName, locale, loader); + bundle = ResourceBundle.getBundle(baseName, locale, this.getClass().getModule()); } catch (MissingResourceException mre) { - try { - bundle = ResourceBundle.getBundle(baseName, locale); - } catch (MissingResourceException mre1) { - throw new IllegalArgumentException("Bundle not found!"); - } + throw new IllegalArgumentException("Bundle not found!"); } String warning = null; diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java index 14646f1a05b..76e28bc9743 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java @@ -26,7 +26,11 @@ package javax.imageio.metadata; import org.w3c.dom.Node; + import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.security.AccessController; +import java.security.PrivilegedAction; /** * An abstract class to be extended by objects that represent metadata @@ -395,45 +399,11 @@ public abstract class IIOMetadata { throw new IllegalArgumentException("Unsupported format name"); } try { - Class cls = null; - final Object o = this; - - // firstly we try to use classloader used for loading - // the IIOMetadata implemantation for this plugin. - ClassLoader loader = - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public ClassLoader run() { - return o.getClass().getClassLoader(); - } - }); - - try { - cls = Class.forName(formatClassName, true, - loader); - } catch (ClassNotFoundException e) { - // we failed to load IIOMetadataFormat class by - // using IIOMetadata classloader.Next try is to - // use thread context classloader. - loader = - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public ClassLoader run() { - return Thread.currentThread().getContextClassLoader(); - } - }); - try { - cls = Class.forName(formatClassName, true, - loader); - } catch (ClassNotFoundException e1) { - // finally we try to use system classloader in case - // if we failed to load IIOMetadataFormat implementation - // class above. - cls = Class.forName(formatClassName, true, - ClassLoader.getSystemClassLoader()); - } - } - + final String className = formatClassName; + // Try to load from the module of the IIOMetadata implementation + // for this plugin since the IIOMetadataImpl is part of the plugin + PrivilegedAction> pa = () -> { return getMetadataFormatClass(className); }; + Class cls = AccessController.doPrivileged(pa); Method meth = cls.getMethod("getInstance"); return (IIOMetadataFormat) meth.invoke(null); } catch (Exception e) { @@ -442,7 +412,24 @@ public abstract class IIOMetadata { ex.initCause(e); throw ex; } + } + private Class getMetadataFormatClass(String formatClassName) { + Module thisModule = IIOMetadata.class.getModule(); + Module targetModule = this.getClass().getModule(); + Class c = Class.forName(targetModule, formatClassName); + if (thisModule.equals(targetModule) || c == null) { + return c; + } + if (thisModule.isNamed()) { + int i = formatClassName.lastIndexOf("."); + String pn = i > 0 ? formatClassName.substring(0, i) : ""; + if (!targetModule.isExported(pn, thisModule)) { + throw new IllegalStateException("Class " + formatClassName + + " in named module must be exported to java.desktop module."); + } + } + return c; } /** diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java index 736decceb80..797ecc56180 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java @@ -43,6 +43,12 @@ import javax.imageio.ImageTypeSpecifier; * returns an instance of the class. Commonly, an implementation will * construct only a single instance and cache it for future * invocations of {@code getInstance}. + *

        In the event that the plugin is provided as part of a named module, + * that module must export the package containing the implementation class + * to the

        java.desktop
        module via a qualified export. + * An unqualified export is not recommended unless also needed for + * some other reason. Failing to export the package will result in + * access failure at runtime. * *

        The structures that may be described by this class are a subset * of those expressible using XML document type definitions (DTDs), diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java index bec11ebf65c..82df5907abc 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java @@ -956,34 +956,17 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { } /** - * If an applet supplies an implementation of IIOMetadataFormat and - * resource bundles, then the resource bundle will need to be - * accessed via the applet class loader. So first try the context - * class loader to locate the resource bundle. - * If that throws MissingResourceException, then try the - * system class loader. + * Per the class documentation, resource bundles, including localized ones + * are intended to be delivered by the subclasser - ie supplier of the + * metadataformat. For the standard format and all standard plugins that + * is the JDK. For 3rd party plugins that they will supply their own. + * This includes plugins bundled with applets/applications. + * In all cases this means it is sufficient to search for those resource + * in the module that is providing the MetadataFormatImpl subclass. */ - ClassLoader loader = - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public ClassLoader run() { - return Thread.currentThread().getContextClassLoader(); - } - }); - - ResourceBundle bundle = null; - try { - bundle = ResourceBundle.getBundle(resourceBaseName, - locale, loader); - } catch (MissingResourceException mre) { - try { - bundle = ResourceBundle.getBundle(resourceBaseName, locale); - } catch (MissingResourceException mre1) { - return null; - } - } - try { + ResourceBundle bundle = ResourceBundle.getBundle(resourceBaseName, locale, + this.getClass().getModule()); return bundle.getString(key); } catch (MissingResourceException e) { return null; diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java index d434acf8ab3..d1dbd3cf4fb 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/BaselineTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2175,9 +2175,9 @@ public class BaselineTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of a BaselineTIFFTagSet. + * Returns a shared instance of a {@code BaselineTIFFTagSet}. * - * @return a BaselineTIFFTagSet instance. + * @return a {@code BaselineTIFFTagSet} instance. */ public synchronized static BaselineTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java index d37a1330d12..03198c45c51 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifGPSTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,7 @@ public class ExifGPSTagSet extends TIFFTagSet { /** * A value to be used with the "GPSVersionID" tag to indicate GPS version * 2.2. The value equals the US-ASCII encoding of the byte array - * {'2', '2', '0', '0'}. + * {@code {'2', '2', '0', '0'}}. * * @see #TAG_GPS_VERSION_ID */ @@ -711,9 +711,9 @@ public class ExifGPSTagSet extends TIFFTagSet { } /** - * Returns a shared instance of an ExifGPSTagSet. + * Returns a shared instance of an {@code ExifGPSTagSet}. * - * @return an ExifGPSTagSet instance. + * @return an {@code ExifGPSTagSet} instance. */ public synchronized static ExifGPSTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java index b2a52790f0b..7089c653fbe 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifInteroperabilityTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -88,9 +88,9 @@ public class ExifInteroperabilityTagSet extends TIFFTagSet { /** * Returns the shared instance of - * ExifInteroperabilityTagSet. + * {@code ExifInteroperabilityTagSet}. * - * @return the ExifInteroperabilityTagSet instance. + * @return the {@code ExifInteroperabilityTagSet} instance. */ public synchronized static ExifInteroperabilityTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java index 29647711fc4..108e1a16852 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifParentTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,9 +80,9 @@ public class ExifParentTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of an ExifParentTIFFTagSet. + * Returns a shared instance of an {@code ExifParentTIFFTagSet}. * - * @return an ExifParentTIFFTagSet instance. + * @return an {@code ExifParentTIFFTagSet} instance. */ public synchronized static ExifParentTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java index 5867a0ffef5..c5be97c88c2 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/ExifTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ import java.util.List; * standard for annotating images used by most digital camera * manufacturers. The Exif specification may be found at * - * http://www.exif.org/Exif2-2.PDF + * {@code http://www.exif.org/Exif2-2.PDF} * . * *

        The definitions of the data types referenced by the field @@ -67,7 +67,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { /** * A value to be used with the "ExifVersion" tag to indicate Exif version * 2.1. The value equals the US-ASCII encoding of the byte array - * {'0', '2', '1', '0'}. + * {@code {'0', '2', '1', '0'}}. * * @see #TAG_EXIF_VERSION */ @@ -78,7 +78,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { /** * A value to be used with the "ExifVersion" tag to indicate Exif version * 2.2. The value equals the US-ASCII encoding of the byte array - * {'0', '2', '2', '0'}. + * {@code {'0', '2', '2', '0'}}. * * @see #TAG_EXIF_VERSION */ @@ -94,7 +94,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { /** * A tag indicating the color space information (type SHORT). The - * legal values are given by the COLOR_SPACE_* + * legal values are given by the {@code COLOR_SPACE_*} * constants. * * @see #COLOR_SPACE_SRGB @@ -1256,7 +1256,7 @@ public class ExifTIFFTagSet extends TIFFTagSet { static class ExifVersion extends TIFFTag { public ExifVersion() { - super("Exifversion", + super("ExifVersion", TAG_EXIF_VERSION, 1 << TIFFTag.TIFF_UNDEFINED, 4); @@ -1992,9 +1992,9 @@ public class ExifTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of an ExifTIFFTagSet. + * Returns a shared instance of an {@code ExifTIFFTagSet}. * - * @return an ExifTIFFTagSet instance. + * @return an {@code ExifTIFFTagSet} instance. */ public synchronized static ExifTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java index fa9733cd3f0..8a3043da122 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/FaxTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,9 +131,9 @@ public class FaxTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of a FaxTIFFTagSet. + * Returns a shared instance of a {@code FaxTIFFTagSet}. * - * @return a FaxTIFFTagSet instance. + * @return a {@code FaxTIFFTagSet} instance. */ public synchronized static FaxTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java index c478f7c03e7..28ee56abd3c 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/GeoTIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ import java.util.List; * standard for annotating georeferenced or geocoded raster imagery. * The GeoTIFF specification may be found at - * http://www.remotesensing.org/geotiff/spec/geotiffhome.html + * {@code http://www.remotesensing.org/geotiff/spec/geotiffhome.html} * . This class does not handle the GeoKeys referenced * from a GeoKeyDirectoryTag as those are not TIFF tags per se. * @@ -63,7 +63,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { /** A tag used to store the GeoKey directory. */ public static final int TAG_GEO_KEY_DIRECTORY = 34735; - /** A tag used to store all double-values GeoKeys. */ + /** A tag used to store all {@code double}-values GeoKeys. */ public static final int TAG_GEO_DOUBLE_PARAMS = 34736; /** A tag used to store all ASCII-values GeoKeys. */ @@ -97,7 +97,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { static class GeoKeyDirectory extends TIFFTag { public GeoKeyDirectory() { - super("GeoKeyDirectory", + super("GeoKeyDirectoryTag", TAG_GEO_KEY_DIRECTORY, 1 << TIFFTag.TIFF_SHORT); } @@ -105,7 +105,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { static class GeoDoubleParams extends TIFFTag { public GeoDoubleParams() { - super("GeoDoubleParams", + super("GeoDoubleParamsTag", TAG_GEO_DOUBLE_PARAMS, 1 << TIFFTag.TIFF_DOUBLE); } @@ -113,7 +113,7 @@ public class GeoTIFFTagSet extends TIFFTagSet { static class GeoAsciiParams extends TIFFTag { public GeoAsciiParams() { - super("GeoAsciiParams", + super("GeoAsciiParamsTag", TAG_GEO_ASCII_PARAMS, 1 << TIFFTag.TIFF_ASCII); } @@ -137,9 +137,9 @@ public class GeoTIFFTagSet extends TIFFTagSet { } /** - * Returns a shared instance of a GeoTIFFTagSet. + * Returns a shared instance of a {@code GeoTIFFTagSet}. * - * @return a GeoTIFFTagSet instance. + * @return a {@code GeoTIFFTagSet} instance. */ public synchronized static GeoTIFFTagSet getInstance() { if (theInstance == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java index ea13664767c..f3e5577716a 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFDirectory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,58 +41,58 @@ import com.sun.imageio.plugins.tiff.TIFFImageMetadata; * image metadata. A TIFF image metadata tree represents an Image File * Directory (IFD) from a TIFF 6.0 stream. An IFD consists of a number of * IFD Entries each of which associates an identifying tag number with - * a compatible value. A TIFFDirectory instance corresponds + * a compatible value. A {@code TIFFDirectory} instance corresponds * to an IFD and contains a set of {@link TIFFField}s each of which * corresponds to an IFD Entry in the IFD. * - *

        When reading, a TIFFDirectory may be created by passing + *

        When reading, a {@code TIFFDirectory} may be created by passing * the value returned by {@link javax.imageio.ImageReader#getImageMetadata * ImageReader.getImageMetadata()} to {@link #createFromMetadata * createFromMetadata()}. The {@link TIFFField}s in the directory may then * be obtained using the accessor methods provided in this class.

        * *

        When writing, an {@link IIOMetadata} object for use by one of the - * write() methods of {@link javax.imageio.ImageWriter} may be - * created from a TIFFDirectory by {@link #getAsMetadata()}. - * The TIFFDirectory itself may be created by construction or - * from the IIOMetadata object returned by + * {@code write()} methods of {@link javax.imageio.ImageWriter} may be + * created from a {@code TIFFDirectory} by {@link #getAsMetadata()}. + * The {@code TIFFDirectory} itself may be created by construction or + * from the {@code IIOMetadata} object returned by * {@link javax.imageio.ImageWriter#getDefaultImageMetadata - * ImageWriter.getDefaultImageMetadata()}. The TIFFFields in the + * ImageWriter.getDefaultImageMetadata()}. The {@code TIFFField}s in the * directory may be set using the mutator methods provided in this class.

        * - *

        A TIFFDirectory is aware of the tag numbers in the + *

        A {@code TIFFDirectory} is aware of the tag numbers in the * group of {@link TIFFTagSet}s associated with it. When - * a TIFFDirectory is created from a native image metadata + * a {@code TIFFDirectory} is created from a native image metadata * object, these tag sets are derived from the tagSets attribute * of the TIFFIFD node.

        * - *

        A TIFFDirectory might also have a parent {@link TIFFTag}. + *

        A {@code TIFFDirectory} might also have a parent {@link TIFFTag}. * This will occur if the directory represents an IFD other than the root * IFD of the image. The parent tag is the tag of the IFD Entry which is a - * pointer to the IFD represented by this TIFFDirectory. The - * {@link TIFFTag#isIFDPointer} method of this parent TIFFTag - * must return true. When a TIFFDirectory is + * pointer to the IFD represented by this {@code TIFFDirectory}. The + * {@link TIFFTag#isIFDPointer} method of this parent {@code TIFFTag} + * must return {@code true}. When a {@code TIFFDirectory} is * created from a native image metadata object, the parent tag set is set * from the parentTagName attribute of the corresponding - * TIFFIFD node. Note that a TIFFDirectory instance - * which has a non-null parent tag will be contained in the - * data field of a TIFFField instance which has a tag field + * TIFFIFD node. Note that a {@code TIFFDirectory} instance + * which has a non-{@code null} parent tag will be contained in the + * data field of a {@code TIFFField} instance which has a tag field * equal to the contained directory's parent tag.

        * - *

        As an example consider an Exif image. The TIFFDirectory + *

        As an example consider an Exif image. The {@code TIFFDirectory} * instance corresponding to the Exif IFD in the Exif stream would have parent * tag {@link ExifParentTIFFTagSet#TAG_EXIF_IFD_POINTER TAG_EXIF_IFD_POINTER} * and would include {@link ExifTIFFTagSet} in its group of known tag sets. - * The TIFFDirectory corresponding to this Exif IFD will be - * contained in the data field of a TIFFField which will in turn - * be contained in the TIFFDirectory corresponding to the primary - * IFD of the Exif image which will itself have a null-valued + * The {@code TIFFDirectory} corresponding to this Exif IFD will be + * contained in the data field of a {@code TIFFField} which will in turn + * be contained in the {@code TIFFDirectory} corresponding to the primary + * IFD of the Exif image which will itself have a {@code null}-valued * parent tag.

        * *

        Note that this implementation is not synchronized. If multiple - * threads use a TIFFDirectory instance concurrently, and at + * threads use a {@code TIFFDirectory} instance concurrently, and at * least one of the threads modifies the directory, for example, by adding - * or removing TIFFFields or TIFFTagSets, it + * or removing {@code TIFFField}s or {@code TIFFTagSet}s, it * must be synchronized externally.

        * * @since 9 @@ -107,10 +107,10 @@ public class TIFFDirectory implements Cloneable { private static final int MAX_LOW_FIELD_TAG_NUM = BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE; - /** The TIFFTagSets associated with this directory. */ + /** The {@code TIFFTagSets} associated with this directory. */ private List tagSets; - /** The parent TIFFTag of this directory. */ + /** The parent {@code TIFFTag} of this directory. */ private TIFFTag parentTag; /** @@ -123,13 +123,13 @@ public class TIFFDirectory implements Cloneable { private int numLowFields = 0; /** - * A mapping of Integer tag numbers to TIFFFields + * A mapping of {@code Integer} tag numbers to {@code TIFFField}s * for fields which are not low tag numbered. */ private Map highFields = new TreeMap(); /** - * Creates a TIFFDirectory instance from the contents of + * Creates a {@code TIFFDirectory} instance from the contents of * an image metadata object. The supplied object must support an image * metadata format supported by the TIFF {@link javax.imageio.ImageWriter} * plug-in. This will usually be either the TIFF native image metadata @@ -139,12 +139,12 @@ public class TIFFDirectory implements Cloneable { * @param tiffImageMetadata A metadata object which supports a compatible * image metadata format. * - * @return A TIFFDirectory populated from the contents of + * @return A {@code TIFFDirectory} populated from the contents of * the supplied metadata object. * - * @throws NullPointerException if tiffImageMetadata - * is null. - * @throws IllegalArgumentException if tiffImageMetadata + * @throws NullPointerException if {@code tiffImageMetadata} + * is {@code null}. + * @throws IllegalArgumentException if {@code tiffImageMetadata} * does not support a compatible image metadata format. * @throws IIOInvalidTreeException if the supplied metadata object * cannot be parsed. @@ -204,7 +204,7 @@ public class TIFFDirectory implements Cloneable { } /** - * Converts a TIFFDirectory to a TIFFIFD. + * Converts a {@code TIFFDirectory} to a {@code TIFFIFD}. */ private static TIFFIFD getDirectoryAsIFD(TIFFDirectory dir) { if(dir instanceof TIFFIFD) { @@ -219,27 +219,39 @@ public class TIFFDirectory implements Cloneable { TIFFField f = fields[i]; TIFFTag tag = f.getTag(); if(tag.isIFDPointer()) { - TIFFDirectory subIFD = - getDirectoryAsIFD((TIFFDirectory)f.getData()); - f = new TIFFField(tag, f.getType(), (long)f.getCount(), subIFD); + TIFFDirectory subDir = null; + if (f.hasDirectory()) { + subDir = f.getDirectory(); + } else if (f.getData() instanceof TIFFDirectory) { + subDir = (TIFFDirectory)f.getData(); + } + if (subDir != null) { + TIFFDirectory subIFD = getDirectoryAsIFD(subDir); + f = new TIFFField(tag, f.getType(), (long)f.getCount(), + subIFD); + } else { + f = null; + } + } + if (f != null) { + ifd.addTIFFField(f); } - ifd.addTIFFField(f); } return ifd; } /** - * Constructs a TIFFDirectory which is aware of a given + * Constructs a {@code TIFFDirectory} which is aware of a given * group of {@link TIFFTagSet}s. An optional parent {@link TIFFTag} * may also be specified. * - * @param tagSets The TIFFTagSets associated with this + * @param tagSets The {@code TIFFTagSets} associated with this * directory. - * @param parentTag The parent TIFFTag of this directory; - * may be null. - * @throws NullPointerException if tagSets is - * null. + * @param parentTag The parent {@code TIFFTag} of this directory; + * may be {@code null}. + * @throws NullPointerException if {@code tagSets} is + * {@code null}. */ public TIFFDirectory(TIFFTagSet[] tagSets, TIFFTag parentTag) { if(tagSets == null) { @@ -256,8 +268,8 @@ public class TIFFDirectory implements Cloneable { /** * Returns the {@link TIFFTagSet}s of which this directory is aware. * - * @return The TIFFTagSets associated with this - * TIFFDirectory. + * @return The {@code TIFFTagSet}s associated with this + * {@code TIFFDirectory}. */ public TIFFTagSet[] getTagSets() { return tagSets.toArray(new TIFFTagSet[tagSets.size()]); @@ -267,9 +279,9 @@ public class TIFFDirectory implements Cloneable { * Adds an element to the group of {@link TIFFTagSet}s of which this * directory is aware. * - * @param tagSet The TIFFTagSet to add. - * @throws NullPointerException if tagSet is - * null. + * @param tagSet The {@code TIFFTagSet} to add. + * @throws NullPointerException if {@code tagSet} is + * {@code null}. */ public void addTagSet(TIFFTagSet tagSet) { if(tagSet == null) { @@ -285,9 +297,9 @@ public class TIFFDirectory implements Cloneable { * Removes an element from the group of {@link TIFFTagSet}s of which this * directory is aware. * - * @param tagSet The TIFFTagSet to remove. - * @throws NullPointerException if tagSet is - * null. + * @param tagSet The {@code TIFFTagSet} to remove. + * @throws NullPointerException if {@code tagSet} is + * {@code null}. */ public void removeTagSet(TIFFTagSet tagSet) { if(tagSet == null) { @@ -301,10 +313,10 @@ public class TIFFDirectory implements Cloneable { /** * Returns the parent {@link TIFFTag} of this directory if one - * has been defined or null otherwise. + * has been defined or {@code null} otherwise. * - * @return The parent TIFFTag of this - * TIFFDiectory or null. + * @return The parent {@code TIFFTag} of this + * {@code TIFFDiectory} or {@code null}. */ public TIFFTag getParentTag() { return parentTag; @@ -312,12 +324,12 @@ public class TIFFDirectory implements Cloneable { /** * Returns the {@link TIFFTag} which has tag number equal to - * tagNumber or null if no such tag + * {@code tagNumber} or {@code null} if no such tag * exists in the {@link TIFFTagSet}s associated with this * directory. * * @param tagNumber The tag number of interest. - * @return The corresponding TIFFTag or null. + * @return The corresponding {@code TIFFTag} or {@code null}. */ public TIFFTag getTag(int tagNumber) { return TIFFIFD.getTag(tagNumber, tagSets); @@ -326,8 +338,8 @@ public class TIFFDirectory implements Cloneable { /** * Returns the number of {@link TIFFField}s in this directory. * - * @return The number of TIFFFields in this - * TIFFDirectory. + * @return The number of {@code TIFFField}s in this + * {@code TIFFDirectory}. */ public int getNumTIFFFields() { return numLowFields + highFields.size(); @@ -339,7 +351,7 @@ public class TIFFDirectory implements Cloneable { * * @param tagNumber The tag number. * @return Whether a {@link TIFFTag} with tag number equal to - * tagNumber is present in this TIFFDirectory. + * {@code tagNumber} is present in this {@code TIFFDirectory}. */ public boolean containsTIFFField(int tagNumber) { return (tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM && @@ -351,7 +363,7 @@ public class TIFFDirectory implements Cloneable { * Adds a TIFF field to the directory. * * @param f The field to add. - * @throws NullPointerException if f is null. + * @throws NullPointerException if {@code f} is {@code null}. */ public void addTIFFField(TIFFField f) { if(f == null) { @@ -372,8 +384,8 @@ public class TIFFDirectory implements Cloneable { * Retrieves a TIFF field from the directory. * * @param tagNumber The tag number of the tag associated with the field. - * @return A TIFFField with the requested tag number of - * null if no such field is present. + * @return A {@code TIFFField} with the requested tag number of + * {@code null} if no such field is present. */ public TIFFField getTIFFField(int tagNumber) { TIFFField f; @@ -444,7 +456,7 @@ public class TIFFDirectory implements Cloneable { * Converts the directory to a metadata object. * * @return A metadata instance initialized from the contents of this - * TIFFDirectory. + * {@code TIFFDirectory}. */ public IIOMetadata getAsMetadata() { return new TIFFImageMetadata(getDirectoryAsIFD(this)); @@ -453,7 +465,7 @@ public class TIFFDirectory implements Cloneable { /** * Clones the directory and all the fields contained therein. * - * @return A clone of this TIFFDirectory. + * @return A clone of this {@code TIFFDirectory}. * @throws CloneNotSupportedException if the instance cannot be cloned. */ @Override diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java index 7afc44520f9..336f81550b7 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * *

        A field in a TIFF Image File Directory (IFD) is defined as a * tag number accompanied by a sequence of values of identical data type. - * TIFF 6.0 defines 12 data types; a 13th type IFD is + * TIFF 6.0 defines 12 data types; a 13th type {@code IFD} is * defined in TIFF Tech Note 1 of TIFF Specification Supplement 1. These * TIFF data types are referred to by Java constants and mapped internally * onto Java language data types and type names as follows: @@ -68,10 +68,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_BYTE} * * - * byte + * {@code byte} * * - * "Byte" + * {@code "Byte"} * * * @@ -83,10 +83,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_ASCII} * * - * String + * {@code String} * * - * "Ascii" + * {@code "Ascii"} * * * @@ -98,10 +98,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SHORT} * * - * char + * {@code char} * * - * "Short" + * {@code "Short"} * * * @@ -113,10 +113,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_LONG} * * - * long + * {@code long} * * - * "Long" + * {@code "Long"} * * * @@ -128,10 +128,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_RATIONAL} * * - * long[2] {numerator, denominator} + * {@code long[2]} {numerator, denominator} * * - * "Rational" + * {@code "Rational"} * * * @@ -143,10 +143,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SBYTE} * * - * byte + * {@code byte} * * - * "SByte" + * {@code "SByte"} * * * @@ -158,10 +158,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_UNDEFINED} * * - * byte + * {@code byte} * * - * "Undefined" + * {@code "Undefined"} * * * @@ -173,10 +173,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SSHORT} * * - * short + * {@code short} * * - * "SShort" + * {@code "SShort"} * * * @@ -188,10 +188,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SLONG} * * - * int + * {@code int} * * - * "SLong" + * {@code "SLong"} * * * @@ -203,10 +203,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_SRATIONAL} * * - * int[2] {numerator, denominator} + * {@code int[2]} {numerator, denominator} * * - * "SRational" + * {@code "SRational"} * * * @@ -218,10 +218,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_FLOAT} * * - * float + * {@code float} * * - * "Float" + * {@code "Float"} * * * @@ -233,10 +233,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_DOUBLE} * * - * double + * {@code double} * * - * "Double" + * {@code "Double"} * * * @@ -248,10 +248,10 @@ import com.sun.imageio.plugins.tiff.TIFFIFD; * {@link TIFFTag#TIFF_IFD_POINTER} * * - * long + * {@code long} * * - * "IFDPointer" + * {@code "IFDPointer"} * * * @@ -411,19 +411,19 @@ public class TIFFField implements Cloneable { } /** - * Creates a TIFFField from a TIFF native image + * Creates a {@code TIFFField} from a TIFF native image * metadata node. If the value of the "tagNumber" attribute - * of the node is not found in tagSet then a new - * TIFFTag with name TIFFTag.UNKNOWN_TAG_NAME + * of the node is not found in {@code tagSet} then a new + * {@code TIFFTag} with name {@code TIFFTag.UNKNOWN_TAG_NAME} * will be created and assigned to the field. * - * @param tagSet The TIFFTagSet to which the - * TIFFTag of the field belongs. - * @param node A native TIFF image metadata TIFFField node. - * @throws NullPointerException if node is - * null. + * @param tagSet The {@code TIFFTagSet} to which the + * {@code TIFFTag} of the field belongs. + * @param node A native TIFF image metadata {@code TIFFField} node. + * @throws NullPointerException if {@code node} is + * {@code null}. * @throws IllegalArgumentException if the name of the node is not - * "TIFFField". + * {@code "TIFFField"}. * @return A new {@code TIFFField}. */ public static TIFFField createFromMetadataNode(TIFFTagSet tagSet, @@ -487,14 +487,14 @@ public class TIFFField implements Cloneable { } /** - * Constructs a TIFFField with arbitrary data. The - * type parameter must be a value for which + * Constructs a {@code TIFFField} with arbitrary data. The + * {@code type} parameter must be a value for which * {@link TIFFTag#isDataTypeOK tag.isDataTypeOK()} - * returns true. The data parameter must + * returns {@code true}. The {@code data} parameter must * be an array of a Java type appropriate for the type of the TIFF * field. * - *

        Note that the value (data) of the TIFFField + *

        Note that the value (data) of the {@code TIFFField} * will always be the actual field value regardless of the number of * bytes required for that value. This is the case despite the fact * that the TIFF IFD Entry corresponding to the field may @@ -503,24 +503,29 @@ public class TIFFField implements Cloneable { * value fits into 4 bytes). In other words, the value of the * field will already have been read from the TIFF stream. (An exception * to this case may occur when the field represents the contents of a - * non-baseline IFD. In that case the data will be a long[] - * containing the offset to the IFD and the TIFFDirectory + * non-baseline IFD. In that case the data will be a {@code long[]} + * containing the offset to the IFD and the {@code TIFFDirectory} * returned by {@link #getDirectory()} will be its contents.) * * @param tag The tag to associated with this field. - * @param type One of the TIFFTag.TIFF_* constants + * @param type One of the {@code TIFFTag.TIFF_*} constants * indicating the data type of the field as written to the TIFF stream. * @param count The number of data values. * @param data The actual data content of the field. * - * @throws NullPointerException if tag == null. - * @throws IllegalArgumentException if type is not - * one of the TIFFTag.TIFF_* data type constants. - * @throws IllegalArgumentException if type is an unacceptable - * data type for the supplied TIFFTag. - * @throws IllegalArgumentException if count < 0. - * @throws NullPointerException if data == null. - * @throws IllegalArgumentException if data is an instance of + * @throws NullPointerException if {@code tag == null}. + * @throws IllegalArgumentException if {@code type} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. + * @throws IllegalArgumentException if {@code type} is an unacceptable + * data type for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code count < 0}. + * @throws IllegalArgumentException if {@code count < 1} + * and {@code type} is {@code TIFF_RATIONAL} or + * {@code TIFF_SRATIONAL}. + * @throws IllegalArgumentException if {@code count ≠ 1} + * and {@code type} is {@code TIFF_IFD_POINTER}. + * @throws NullPointerException if {@code data == null}. + * @throws IllegalArgumentException if {@code data} is an instance of * a class incompatible with the specified type. * @throws IllegalArgumentException if the size of the data array is wrong. */ @@ -534,6 +539,14 @@ public class TIFFField implements Cloneable { + " for " + tag.getName() + " tag"); } else if(count < 0) { throw new IllegalArgumentException("count < 0!"); + } else if((type == TIFFTag.TIFF_RATIONAL + || type == TIFFTag.TIFF_SRATIONAL) + && count < 1) { + throw new IllegalArgumentException + ("Type is TIFF_RATIONAL or TIFF_SRATIONAL and count < 1"); + } else if (type == TIFFTag.TIFF_IFD_POINTER && count != 1) { + throw new IllegalArgumentException + ("Type is TIFF_IFD_POINTER count != 1"); } else if(data == null) { throw new NullPointerException("data == null!"); } @@ -612,15 +625,15 @@ public class TIFFField implements Cloneable { * parameters and the created array. * * @param tag The tag to associated with this field. - * @param type One of the TIFFTag.TIFF_* constants + * @param type One of the {@code TIFFTag.TIFF_*} constants * indicating the data type of the field as written to the TIFF stream. * @param count The number of data values. - * @throws NullPointerException if tag == null. - * @throws IllegalArgumentException if type is not - * one of the TIFFTag.TIFF_* data type constants. - * @throws IllegalArgumentException if type is an unacceptable - * data type for the supplied TIFFTag. - * @throws IllegalArgumentException if count < 0. + * @throws NullPointerException if {@code tag == null}. + * @throws IllegalArgumentException if {@code type} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. + * @throws IllegalArgumentException if {@code type} is an unacceptable + * data type for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code count < 0}. * @see #TIFFField(TIFFTag,int,int,Object) */ public TIFFField(TIFFTag tag, int type, int count) { @@ -628,20 +641,20 @@ public class TIFFField implements Cloneable { } /** - * Constructs a TIFFField with a single non-negative integral + * Constructs a {@code TIFFField} with a single non-negative integral * value. * The field will have type * {@link TIFFTag#TIFF_SHORT TIFF_SHORT} if - * val < 65536 and type + * {@code val < 65536} and type * {@link TIFFTag#TIFF_LONG TIFF_LONG} otherwise. The count * of the field will be unity. * * @param tag The tag to associate with this field. * @param value The value to associate with this field. - * @throws NullPointerException if tag == null. + * @throws NullPointerException if {@code tag == null}. * @throws IllegalArgumentException if the derived type is unacceptable - * for the supplied TIFFTag. - * @throws IllegalArgumentException if value < 0. + * for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code value < 0}. */ public TIFFField(TIFFTag tag, int value) { if(tag == null) { @@ -677,24 +690,24 @@ public class TIFFField implements Cloneable { } /** - * Constructs a TIFFField with an IFD offset and contents. + * Constructs a {@code TIFFField} with an IFD offset and contents. * The offset will be stored as the data of this field as - * long[] {offset}. The directory will not be cloned. The count + * {@code long[] {offset}}. The directory will not be cloned. The count * of the field will be unity. * * @param tag The tag to associated with this field. - * @param type One of the constants TIFFTag.TIFF_LONG or - * TIFFTag.TIFF_IFD_POINTER. + * @param type One of the constants {@code TIFFTag.TIFF_LONG} or + * {@code TIFFTag.TIFF_IFD_POINTER}. * @param offset The IFD offset. * @param dir The directory. * - * @throws NullPointerException if tag == null. - * @throws IllegalArgumentException if type is neither - * TIFFTag.TIFF_LONG nor TIFFTag.TIFF_IFD_POINTER. - * @throws IllegalArgumentException if type is an unacceptable - * data type for the supplied TIFFTag. - * @throws IllegalArgumentException if offset is non-positive. - * @throws NullPointerException if dir == null. + * @throws NullPointerException if {@code tag == null}. + * @throws IllegalArgumentException if {@code type} is neither + * {@code TIFFTag.TIFF_LONG} nor {@code TIFFTag.TIFF_IFD_POINTER}. + * @throws IllegalArgumentException if {@code type} is an unacceptable + * data type for the supplied {@code TIFFTag}. + * @throws IllegalArgumentException if {@code offset} is non-positive. + * @throws NullPointerException if {@code dir == null}. * * @see #TIFFField(TIFFTag,int,int,Object) */ @@ -715,14 +728,14 @@ public class TIFFField implements Cloneable { /** * Retrieves the tag associated with this field. * - * @return The associated TIFFTag. + * @return The associated {@code TIFFTag}. */ public TIFFTag getTag() { return tag; } /** - * Retrieves the tag number in the range [0, 65535]. + * Retrieves the tag number in the range {@code [0, 65535]}. * * @return The tag number. */ @@ -732,7 +745,7 @@ public class TIFFField implements Cloneable { /** * Returns the type of the data stored in the field. For a TIFF 6.0 - * stream, the value will equal one of the TIFFTag.TIFF_* + * stream, the value will equal one of the {@code TIFFTag.TIFF_*} * constants. For future revisions of TIFF, higher values are possible. * * @return The data type of the field value. @@ -744,11 +757,11 @@ public class TIFFField implements Cloneable { /** * Returns the name of the supplied data type constant. * - * @param dataType One of the TIFFTag.TIFF_* constants + * @param dataType One of the {@code TIFFTag.TIFF_*} constants * indicating the data type of the field as written to the TIFF stream. * @return The type name corresponding to the supplied type constant. - * @throws IllegalArgumentException if dataType is not - * one of the TIFFTag.TIFF_* data type constants. + * @throws IllegalArgumentException if {@code dataType} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. */ public static String getTypeName(int dataType) { if (dataType < TIFFTag.MIN_DATATYPE || @@ -761,11 +774,11 @@ public class TIFFField implements Cloneable { /** * Returns the data type constant corresponding to the supplied data - * type name. If the name is unknown -1 will be returned. + * type name. If the name is unknown {@code -1} will be returned. * * @param typeName The type name. - * @return One of the TIFFTag.TIFF_* constants or - * -1 if the name is not recognized. + * @return One of the {@code TIFFTag.TIFF_*} constants or + * {@code -1} if the name is not recognized. */ public static int getTypeByName(String typeName) { for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) { @@ -780,14 +793,14 @@ public class TIFFField implements Cloneable { /** * Creates an array appropriate for the indicated data type. * - * @param dataType One of the TIFFTag.TIFF_* data type + * @param dataType One of the {@code TIFFTag.TIFF_*} data type * constants. * @param count The number of values in the array. * @return An array appropriate for the specified data type. * - * @throws IllegalArgumentException if dataType is not - * one of the TIFFTag.TIFF_* data type constants. - * @throws IllegalArgumentException if count < 0. + * @throws IllegalArgumentException if {@code dataType} is not + * one of the {@code TIFFTag.TIFF_*} data type constants. + * @throws IllegalArgumentException if {@code count < 0}. */ public static Object createArrayForType(int dataType, int count) { if(count < 0) { @@ -823,15 +836,15 @@ public class TIFFField implements Cloneable { } /** - * Returns the TIFFField as a node named either + * Returns the {@code TIFFField} as a node named either * "TIFFField" or "TIFFIFD" as described in the * TIFF native image metadata specification. The node will be named * "TIFFIFD" if and only if the field's data object is an * instance of {@link TIFFDirectory} or equivalently * {@link TIFFTag#isIFDPointer getTag.isIFDPointer()} returns - * true. + * {@code true}. * - * @return a Node named "TIFFField" or + * @return a {@code Node} named "TIFFField" or * "TIFFIFD". */ public Node getAsNativeNode() { @@ -850,8 +863,8 @@ public class TIFFField implements Cloneable { /** * Returns the number of data items present in the field. For - * TIFFTag.TIFF_ASCII fields, the value returned is the - * number of Strings, not the total length of the + * {@code TIFFTag.TIFF_ASCII} fields, the value returned is the + * number of {@code String}s, not the total length of the * data as in the file representation. * * @return The number of data items present in the field. @@ -871,17 +884,17 @@ public class TIFFField implements Cloneable { /** * Returns the data as an uninterpreted array of - * bytes. The type of the field must be one of - * TIFFTag.TIFF_BYTE, TIFF_SBYTE, or - * TIFF_UNDEFINED. + * {@code byte}s. The type of the field must be one of + * {@code TIFFTag.TIFF_BYTE}, {@code TIFF_SBYTE}, or + * {@code TIFF_UNDEFINED}. * - *

        For data in TIFFTag.TIFF_BYTE format, the application + *

        For data in {@code TIFFTag.TIFF_BYTE} format, the application * must take care when promoting the data to longer integral types * to avoid sign extension. * * @throws ClassCastException if the field is not of type - * TIFF_BYTE, TIFF_SBYTE, or - * TIFF_UNDEFINED. + * {@code TIFF_BYTE}, {@code TIFF_SBYTE}, or + * {@code TIFF_UNDEFINED}. * @return The data as an uninterpreted array of bytes. */ public byte[] getAsBytes() { @@ -889,11 +902,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SHORT data as an array of - * chars (unsigned 16-bit integers). + * Returns {@code TIFFTag.TIFF_SHORT} data as an array of + * {@code char}s (unsigned 16-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_SHORT. + * {@code TIFF_SHORT}. * @return The data as an array of {@code char}s. */ public char[] getAsChars() { @@ -901,11 +914,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SSHORT data as an array of - * shorts (signed 16-bit integers). + * Returns {@code TIFFTag.TIFF_SSHORT} data as an array of + * {@code short}s (signed 16-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_SSHORT. + * {@code TIFF_SSHORT}. * @return The data as an array of {@code short}s. */ public short[] getAsShorts() { @@ -913,12 +926,12 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SLONG data as an array of - * ints (signed 32-bit integers). + * Returns {@code TIFFTag.TIFF_SLONG} data as an array of + * {@code int}s (signed 32-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_SHORT, TIFF_SSHORT, or - * TIFF_SLONG. + * {@code TIFF_SHORT}, {@code TIFF_SSHORT}, or + * {@code TIFF_SLONG}. * @return The data as an array of {@code int}s. */ public int[] getAsInts() { @@ -944,12 +957,12 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_LONG or - * TIFF_IFD_POINTER data as an array of - * longs (signed 64-bit integers). + * Returns {@code TIFFTag.TIFF_LONG} or + * {@code TIFF_IFD_POINTER} data as an array of + * {@code long}s (signed 64-bit integers). * * @throws ClassCastException if the field is not of type - * TIFF_LONG or TIFF_IFD_POINTER. + * {@code TIFF_LONG} or {@code TIFF_IFD_POINTER}. * @return The data as an array of {@code long}s. */ public long[] getAsLongs() { @@ -957,11 +970,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_FLOAT data as an array of - * floats (32-bit floating-point values). + * Returns {@code TIFFTag.TIFF_FLOAT} data as an array of + * {@code float}s (32-bit floating-point values). * * @throws ClassCastException if the field is not of type - * TIFF_FLOAT. + * {@code TIFF_FLOAT}. * @return The data as an array of {@code float}s. */ public float[] getAsFloats() { @@ -969,11 +982,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_DOUBLE data as an array of - * doubles (64-bit floating-point values). + * Returns {@code TIFFTag.TIFF_DOUBLE} data as an array of + * {@code double}s (64-bit floating-point values). * * @throws ClassCastException if the field is not of type - * TIFF_DOUBLE. + * {@code TIFF_DOUBLE}. * @return The data as an array of {@code double}s. */ public double[] getAsDoubles() { @@ -981,11 +994,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_SRATIONAL data as an array of - * 2-element arrays of ints. + * Returns {@code TIFFTag.TIFF_SRATIONAL} data as an array of + * 2-element arrays of {@code int}s. * * @throws ClassCastException if the field is not of type - * TIFF_SRATIONAL. + * {@code TIFF_SRATIONAL}. * @return The data as an array of signed rationals. */ public int[][] getAsSRationals() { @@ -993,11 +1006,11 @@ public class TIFFField implements Cloneable { } /** - * Returns TIFFTag.TIFF_RATIONAL data as an array of - * 2-element arrays of longs. + * Returns {@code TIFFTag.TIFF_RATIONAL} data as an array of + * 2-element arrays of {@code long}s. * * @throws ClassCastException if the field is not of type - * TIFF_RATIONAL. + * {@code TIFF_RATIONAL}. * @return The data as an array of unsigned rationals. */ public long[][] getAsRationals() { @@ -1005,30 +1018,30 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as an int. + * Returns data in any format as an {@code int}. * - *

        TIFFTag.TIFF_BYTE values are treated as unsigned; that + *

        {@code TIFFTag.TIFF_BYTE} values are treated as unsigned; that * is, no sign extension will take place and the returned value - * will be in the range [0, 255]. TIFF_SBYTE data + * will be in the range [0, 255]. {@code TIFF_SBYTE} data * will be returned in the range [-128, 127]. * - *

        A TIFF_UNDEFINED value is treated as though - * it were a TIFF_BYTE. + *

        A {@code TIFF_UNDEFINED} value is treated as though + * it were a {@code TIFF_BYTE}. * - *

        Data in TIFF_SLONG, TIFF_LONG, - * TIFF_FLOAT, TIFF_DOUBLE or - * TIFF_IFD_POINTER format are simply cast to - * int and may suffer from truncation. + *

        Data in {@code TIFF_SLONG}, {@code TIFF_LONG}, + * {@code TIFF_FLOAT}, {@code TIFF_DOUBLE} or + * {@code TIFF_IFD_POINTER} format are simply cast to + * {@code int} and may suffer from truncation. * - *

        Data in TIFF_SRATIONAL or - * TIFF_RATIONAL format are evaluated by dividing the + *

        Data in {@code TIFF_SRATIONAL} or + * {@code TIFF_RATIONAL} format are evaluated by dividing the * numerator into the denominator using double-precision - * arithmetic and then casting to int. Loss of + * arithmetic and then casting to {@code int}. Loss of * precision and truncation may occur. * - *

        Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method, with the result - * case to int. + *

        Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method, with the result + * case to {@code int}. * * @param index The index of the data. * @return The data at the given index as an {@code int}. @@ -1068,17 +1081,17 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as a long. + * Returns data in any format as a {@code long}. * - *

        TIFFTag.TIFF_BYTE and TIFF_UNDEFINED data + *

        {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data * are treated as unsigned; that is, no sign extension will take * place and the returned value will be in the range [0, 255]. - * TIFF_SBYTE data will be returned in the range + * {@code TIFF_SBYTE} data will be returned in the range * [-128, 127]. * - *

        Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method, with the result - * cast to long. + *

        Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method, with the result + * cast to {@code long}. * * @param index The index of the data. * @return The data at the given index as a {@code long}. @@ -1114,27 +1127,27 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as a float. + * Returns data in any format as a {@code float}. * - *

        TIFFTag.TIFF_BYTE and TIFF_UNDEFINED data + *

        {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data * are treated as unsigned; that is, no sign extension will take * place and the returned value will be in the range [0, 255]. - * TIFF_SBYTE data will be returned in the range + * {@code TIFF_SBYTE} data will be returned in the range * [-128, 127]. * - *

        Data in TIFF_SLONG, TIFF_LONG, - * TIFF_DOUBLE, or TIFF_IFD_POINTER format are - * simply cast to float and may suffer from + *

        Data in {@code TIFF_SLONG}, {@code TIFF_LONG}, + * {@code TIFF_DOUBLE}, or {@code TIFF_IFD_POINTER} format are + * simply cast to {@code float} and may suffer from * truncation. * - *

        Data in TIFF_SRATIONAL or - * TIFF_RATIONAL format are evaluated by dividing the + *

        Data in {@code TIFF_SRATIONAL} or + * {@code TIFF_RATIONAL} format are evaluated by dividing the * numerator into the denominator using double-precision - * arithmetic and then casting to float. + * arithmetic and then casting to {@code float}. * - *

        Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method, with the result - * cast to float. + *

        Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method, with the result + * cast to {@code float}. * * @param index The index of the data. * @return The data at the given index as a {@code float}. @@ -1174,21 +1187,21 @@ public class TIFFField implements Cloneable { } /** - * Returns data in any format as a double. + * Returns data in any format as a {@code double}. * - *

        TIFFTag.TIFF_BYTE and TIFF_UNDEFINED data + *

        {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data * are treated as unsigned; that is, no sign extension will take * place and the returned value will be in the range [0, 255]. - * TIFF_SBYTE data will be returned in the range + * {@code TIFF_SBYTE} data will be returned in the range * [-128, 127]. * - *

        Data in TIFF_SRATIONAL or - * TIFF_RATIONAL format are evaluated by dividing the + *

        Data in {@code TIFF_SRATIONAL} or + * {@code TIFF_RATIONAL} format are evaluated by dividing the * numerator into the denominator using double-precision * arithmetic. * - *

        Data in TIFF_ASCII format will be parsed as by - * the Double.parseDouble method. + *

        Data in {@code TIFF_ASCII} format will be parsed as by + * the {@code Double.parseDouble} method. * * @param index The index of the data. * @return The data at the given index as a {@code double}. @@ -1228,11 +1241,11 @@ public class TIFFField implements Cloneable { } /** - * Returns a TIFFTag.TIFF_ASCII value as a - * String. + * Returns a {@code TIFFTag.TIFF_ASCII} value as a + * {@code String}. * * @throws ClassCastException if the field is not of type - * TIFF_ASCII. + * {@code TIFF_ASCII}. * * @param index The index of the data. * @return The data at the given index as a {@code String}. @@ -1242,13 +1255,13 @@ public class TIFFField implements Cloneable { } /** - * Returns a TIFFTag.TIFF_SRATIONAL data item as a - * two-element array of ints. + * Returns a {@code TIFFTag.TIFF_SRATIONAL} data item as a + * two-element array of {@code int}s. * * @param index The index of the data. * @return The data at the given index as a signed rational. * @throws ClassCastException if the field is not of type - * TIFF_SRATIONAL. + * {@code TIFF_SRATIONAL}. */ public int[] getAsSRational(int index) { return ((int[][])data)[index]; @@ -1261,7 +1274,7 @@ public class TIFFField implements Cloneable { * @param index The index of the data. * @return The data at the given index as an unsigned rational. * @throws ClassCastException if the field is not of type - * TIFF_RATIONAL. + * {@code TIFF_RATIONAL}. */ public long[] getAsRational(int index) { return ((long[][])data)[index]; @@ -1269,11 +1282,11 @@ public class TIFFField implements Cloneable { /** - * Returns a String containing a human-readable + * Returns a {@code String} containing a human-readable * version of the data item. Data of type - * TIFFTag.TIFF_RATIONAL or TIFF_SRATIONAL are + * {@code TIFFTag.TIFF_RATIONAL} or {@code TIFF_SRATIONAL} are * represented as a pair of integers separated by a - * '/' character. + * {@code '/'} character. * * @param index The index of the data. * @return The data at the given index as a {@code String}. @@ -1342,7 +1355,7 @@ public class TIFFField implements Cloneable { } /** - * Returns whether the field has a TIFFDirectory. + * Returns whether the field has a {@code TIFFDirectory}. * * @return true if and only if getDirectory() returns non-null. */ @@ -1351,8 +1364,8 @@ public class TIFFField implements Cloneable { } /** - * Returns the associated TIFFDirectory, if available. If no - * directory is set, then null will be returned. + * Returns the associated {@code TIFFDirectory}, if available. If no + * directory is set, then {@code null} will be returned. * * @return the TIFFDirectory instance or null. */ @@ -1363,7 +1376,7 @@ public class TIFFField implements Cloneable { /** * Clones the field and all the information contained therein. * - * @return A clone of this TIFFField. + * @return A clone of this {@code TIFFField}. * @throws CloneNotSupportedException if the instance cannot be cloned. */ @Override diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java index 27f633c7cfd..9c120d094ef 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFImageReadParam.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,11 +39,11 @@ import javax.imageio.ImageReadParam; * be provided by this interface. * *

        Additional TIFF tags must be organized into - * TIFFTagSets. A TIFFTagSet may be + * {@code TIFFTagSet}s. A {@code TIFFTagSet} may be * provided to the reader by means of the - * addAllowedTagSet method. By default, the tag sets - * BaselineTIFFTagSet, FaxTIFFTagSet, - * ExifParentTIFFTagSet, and GeoTIFFTagSet + * {@code addAllowedTagSet} method. By default, the tag sets + * {@code BaselineTIFFTagSet}, {@code FaxTIFFTagSet}, + * {@code ExifParentTIFFTagSet}, and {@code GeoTIFFTagSet} * are included. * * @since 9 @@ -53,10 +53,10 @@ public class TIFFImageReadParam extends ImageReadParam { private List allowedTagSets = new ArrayList(4); /** - * Constructs a TIFFImageReadParam. Tags defined by - * the TIFFTagSets BaselineTIFFTagSet, - * FaxTIFFTagSet, ExifParentTIFFTagSet, and - * GeoTIFFTagSet will be supported. + * Constructs a {@code TIFFImageReadParam}. Tags defined by + * the {@code TIFFTagSet}s {@code BaselineTIFFTagSet}, + * {@code FaxTIFFTagSet}, {@code ExifParentTIFFTagSet}, and + * {@code GeoTIFFTagSet} will be supported. * * @see BaselineTIFFTagSet * @see FaxTIFFTagSet @@ -71,13 +71,13 @@ public class TIFFImageReadParam extends ImageReadParam { } /** - * Adds a TIFFTagSet object to the list of allowed + * Adds a {@code TIFFTagSet} object to the list of allowed * tag sets. * - * @param tagSet a TIFFTagSet. + * @param tagSet a {@code TIFFTagSet}. * - * @throws IllegalArgumentException if tagSet is - * null. + * @throws IllegalArgumentException if {@code tagSet} is + * {@code null}. */ public void addAllowedTagSet(TIFFTagSet tagSet) { if (tagSet == null) { @@ -87,15 +87,15 @@ public class TIFFImageReadParam extends ImageReadParam { } /** - * Removes a TIFFTagSet object from the list of - * allowed tag sets. Removal is based on the equals - * method of the TIFFTagSet, which is normally + * Removes a {@code TIFFTagSet} object from the list of + * allowed tag sets. Removal is based on the {@code equals} + * method of the {@code TIFFTagSet}, which is normally * defined as reference equality. * - * @param tagSet a TIFFTagSet. + * @param tagSet a {@code TIFFTagSet}. * - * @throws IllegalArgumentException if tagSet is - * null. + * @throws IllegalArgumentException if {@code tagSet} is + * {@code null}. */ public void removeAllowedTagSet(TIFFTagSet tagSet) { if (tagSet == null) { @@ -105,10 +105,10 @@ public class TIFFImageReadParam extends ImageReadParam { } /** - * Returns a List containing the allowed - * TIFFTagSet objects. + * Returns a {@code List} containing the allowed + * {@code TIFFTagSet} objects. * - * @return a List of TIFFTagSets. + * @return a {@code List} of {@code TIFFTagSet}s. */ public List getAllowedTagSets() { return allowedTagSets; diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java index 68542c4078d..c312bd55419 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -105,7 +105,7 @@ public class TIFFTag { * The name assigned to a tag with an unknown tag number. Such * a tag may be created for example when reading an IFD and a * tag number is encountered which is not in any of the - * TIFFTagSets known to the reader. + * {@code TIFFTagSet}s known to the reader. */ public static final String UNKNOWN_TAG_NAME = "UnknownTag"; @@ -141,12 +141,12 @@ public class TIFFTag { private SortedMap valueNames = null; /** - * Constructs a TIFFTag with a given name, tag number, set + * Constructs a {@code TIFFTag} with a given name, tag number, set * of legal data types, and value count. A negative value count signifies * that either an arbitrary number of values is legal or the required count * is determined by the values of other fields in the IFD. A non-negative * count specifies the number of values which an associated field must - * contain. The tag will have no associated TIFFTagSet. + * contain. The tag will have no associated {@code TIFFTagSet}. * *

        If there are mnemonic names to be associated with the legal * data values for the tag, {@link #addValueName(int, String) @@ -183,18 +183,18 @@ public class TIFFTag { } /** - * Constructs a TIFFTag with a given name, tag number and - * TIFFTagSet to which it refers. The legal data types are + * Constructs a {@code TIFFTag} with a given name, tag number and + * {@code TIFFTagSet} to which it refers. The legal data types are * set to include {@link #TIFF_LONG} and {@link #TIFF_IFD_POINTER} and the - * value count is unity. The TIFFTagSet will - * represent the set of TIFFTags which appear in the IFD - * pointed to. A TIFFTag represents an IFD pointer if and - * only if tagSet is non-null or the data - * type TIFF_IFD_POINTER is legal. + * value count is unity. The {@code TIFFTagSet} will + * represent the set of {@code TIFFTag}s which appear in the IFD + * pointed to. A {@code TIFFTag} represents an IFD pointer if and + * only if {@code tagSet} is non-{@code null} or the data + * type {@code TIFF_IFD_POINTER} is legal. * * @param name the name of the tag. * @param number the number used to represent the tag. - * @param tagSet the TIFFTagSet to which this tag belongs. + * @param tagSet the {@code TIFFTagSet} to which this tag belongs. * @throws NullPointerException if name or tagSet is null. * @throws IllegalArgumentException if number is negative. * @@ -210,9 +210,9 @@ public class TIFFTag { } /** - * Constructs a TIFFTag with a given name, tag number, + * Constructs a {@code TIFFTag} with a given name, tag number, * and set of legal data types. The value count of the tag will be - * undefined and it will have no associated TIFFTagSet. + * undefined and it will have no associated {@code TIFFTagSet}. * * @param name the name of the tag. * @param number the number used to represent the tag. @@ -236,9 +236,9 @@ public class TIFFTag { * * @return the number of bytes used to store the given data type. * - * @throws IllegalArgumentException if datatype is - * less than MIN_DATATYPE or greater than - * MAX_DATATYPE. + * @throws IllegalArgumentException if {@code datatype} is + * less than {@code MIN_DATATYPE} or greater than + * {@code MAX_DATATYPE}. */ public static int getSizeOfType(int dataType) { if (dataType < MIN_DATATYPE ||dataType > MAX_DATATYPE) { @@ -251,7 +251,7 @@ public class TIFFTag { /** * Returns the name of the tag, as it will appear in image metadata. * - * @return the tag name, as a String. + * @return the tag name, as a {@code String}. */ public String getName() { return name; @@ -260,7 +260,7 @@ public class TIFFTag { /** * Returns the integer used to represent the tag. * - * @return the tag number, as an int. + * @return the tag number, as an {@code int}. */ public int getNumber() { return number; @@ -276,7 +276,7 @@ public class TIFFTag { * (1 << TIFFTag.TIFF_SHORT) | (1 << TIFFTag.TIFF_LONG) * * - * @return an int containing a bitmask encoding the + * @return an {@code int} containing a bitmask encoding the * set of valid data types. */ public int getDataTypes() { @@ -285,11 +285,11 @@ public class TIFFTag { /** * Returns the value count of this tag. If this value is positive, it - * represents the required number of values for a TIFFField + * represents the required number of values for a {@code TIFFField} * which has this tag. If the value is negative, the count is undefined. * In the latter case the count may be derived, e.g., the number of values - * of the BitsPerSample field is SamplesPerPixel, - * or it may be variable as in the case of most US-ASCII + * of the {@code BitsPerSample} field is {@code SamplesPerPixel}, + * or it may be variable as in the case of most {@code US-ASCII} * fields. * * @return the value count of this tag. @@ -299,18 +299,18 @@ public class TIFFTag { } /** - * Returns true if the given data type + * Returns {@code true} if the given data type * may be used for the data associated with this tag. * * @param dataType the data type to be queried, one of - * TIFF_BYTE, TIFF_SHORT, etc. + * {@code TIFF_BYTE}, {@code TIFF_SHORT}, etc. * - * @return a boolean indicating whether the given + * @return a {@code boolean} indicating whether the given * data type may be used with this tag. * - * @throws IllegalArgumentException if datatype is - * less than MIN_DATATYPE or greater than - * MAX_DATATYPE. + * @throws IllegalArgumentException if {@code datatype} is + * less than {@code MIN_DATATYPE} or greater than + * {@code MAX_DATATYPE}. */ public boolean isDataTypeOK(int dataType) { if (dataType < MIN_DATATYPE || dataType > MAX_DATATYPE) { @@ -320,38 +320,38 @@ public class TIFFTag { } /** - * Returns the TIFFTagSet of which this tag is a part. + * Returns the {@code TIFFTagSet} of which this tag is a part. * - * @return the containing TIFFTagSet. + * @return the containing {@code TIFFTagSet}. */ public TIFFTagSet getTagSet() { return tagSet; } /** - * Returns true if this tag is used to point to an IFD - * structure containing additional tags. A TIFFTag represents - * an IFD pointer if and only if its TIFFTagSet is - * non-null or the data type TIFF_IFD_POINTER is + * Returns {@code true} if this tag is used to point to an IFD + * structure containing additional tags. A {@code TIFFTag} represents + * an IFD pointer if and only if its {@code TIFFTagSet} is + * non-{@code null} or the data type {@code TIFF_IFD_POINTER} is * legal. This condition will be satisfied if and only if either - * getTagSet() != null or - * isDataTypeOK(TIFF_IFD_POINTER) == true. + * {@code getTagSet() != null} or + * {@code isDataTypeOK(TIFF_IFD_POINTER) == true}. * *

        Many TIFF extensions use the IFD mechanism in order to limit the * number of new tags that may appear in the root IFD.

        * - * @return true if this tag points to an IFD. + * @return {@code true} if this tag points to an IFD. */ public boolean isIFDPointer() { return tagSet != null || isDataTypeOK(TIFF_IFD_POINTER); } /** - * Returns true if there are mnemonic names associated with + * Returns {@code true} if there are mnemonic names associated with * the set of legal values for the data associated with this tag. Mnemonic * names apply only to tags which have integral data type. * - * @return true if mnemonic value names are available. + * @return {@code true} if mnemonic value names are available. */ public boolean hasValueNames() { return valueNames != null; @@ -373,14 +373,14 @@ public class TIFFTag { /** * Returns the mnemonic name associated with a particular value - * that this tag's data may take on, or null if + * that this tag's data may take on, or {@code null} if * no name is present. Mnemonic names apply only to tags which have * integral data type. * * @param value the data value. * * @return the mnemonic name associated with the value, as a - * String. + * {@code String}. */ public String getValueName(int value) { if (valueNames == null) { diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java index 8082fba86b8..793bafce1b7 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFTagSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,7 @@ import java.util.TreeSet; * specification itself). * *

        This class and its subclasses are responsible for mapping - * between raw tag numbers and TIFFTag objects, which + * between raw tag numbers and {@code TIFFTag} objects, which * contain additional information about each tag, such as the tag's * name, legal data types, and mnemonic names for some or all of ts * data values. @@ -59,15 +59,15 @@ public class TIFFTagSet { private TIFFTagSet() {} /** - * Constructs a TIFFTagSet, given a List - * of TIFFTag objects. + * Constructs a {@code TIFFTagSet}, given a {@code List} + * of {@code TIFFTag} objects. * - * @param tags a List object containing - * TIFFTag objects to be added to this tag set. + * @param tags a {@code List} object containing + * {@code TIFFTag} objects to be added to this tag set. * - * @throws IllegalArgumentException if tags is - * null, or contains objects that are not instances - * of the TIFFTag class. + * @throws IllegalArgumentException if {@code tags} is + * {@code null}, or contains objects that are not instances + * of the {@code TIFFTag} class. */ public TIFFTagSet(List tags) { if (tags == null) { @@ -88,29 +88,29 @@ public class TIFFTagSet { } /** - * Returns the TIFFTag from this set that is - * associated with the given tag number, or null if + * Returns the {@code TIFFTag} from this set that is + * associated with the given tag number, or {@code null} if * no tag exists for that number. * * @param tagNumber the number of the tag to be retrieved. * - * @return the numbered TIFFTag, or null. + * @return the numbered {@code TIFFTag}, or {@code null}. */ public TIFFTag getTag(int tagNumber) { return allowedTagsByNumber.get(Integer.valueOf(tagNumber)); } /** - * Returns the TIFFTag having the given tag name, or - * null if the named tag does not belong to this tag set. + * Returns the {@code TIFFTag} having the given tag name, or + * {@code null} if the named tag does not belong to this tag set. * * @param tagName the name of the tag to be retrieved, as a - * String. + * {@code String}. * - * @return the named TIFFTag, or null. + * @return the named {@code TIFFTag}, or {@code null}. * - * @throws IllegalArgumentException if tagName is - * null. + * @throws IllegalArgumentException if {@code tagName} is + * {@code null}. */ public TIFFTag getTag(String tagName) { if (tagName == null) { @@ -123,7 +123,7 @@ public class TIFFTagSet { * Retrieves an unmodifiable numerically increasing set of tag numbers. * *

        The returned object is unmodifiable and contains the tag - * numbers of all TIFFTags in this TIFFTagSet + * numbers of all {@code TIFFTag}s in this {@code TIFFTagSet} * sorted into ascending order according to * {@link Integer#compareTo(Object)}.

        * @@ -145,7 +145,7 @@ public class TIFFTagSet { * Retrieves an unmodifiable lexicographically increasing set of tag names. * *

        The returned object is unmodifiable and contains the tag - * names of all TIFFTags in this TIFFTagSet + * names of all {@code TIFFTag}s in this {@code TIFFTagSet} * sorted into ascending order according to * {@link String#compareTo(Object)}.

        * diff --git a/jdk/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java b/jdk/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java index 7b433f9fe4f..d46711aedc7 100644 --- a/jdk/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java +++ b/jdk/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java @@ -28,6 +28,9 @@ package javax.imageio.spi; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Iterator; import javax.imageio.ImageReader; @@ -587,8 +590,10 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider { throw new IllegalArgumentException("Unsupported format name"); } try { - Class cls = Class.forName(formatClassName, true, - ClassLoader.getSystemClassLoader()); + // Try to load from the same location as the module of the SPI + final String className = formatClassName; + PrivilegedAction> pa = () -> { return getMetadataFormatClass(className); }; + Class cls = AccessController.doPrivileged(pa); Method meth = cls.getMethod("getInstance"); return (IIOMetadataFormat) meth.invoke(null); } catch (Exception e) { @@ -598,4 +603,22 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider { throw ex; } } + + private Class getMetadataFormatClass(String formatClassName) { + Module thisModule = ImageReaderWriterSpi.class.getModule(); + Module targetModule = this.getClass().getModule(); + Class c = Class.forName(targetModule, formatClassName); + if (thisModule.equals(targetModule) || c == null) { + return c; + } + if (thisModule.isNamed()) { + int i = formatClassName.lastIndexOf("."); + String pn = i > 0 ? formatClassName.substring(0, i) : ""; + if (!targetModule.isExported(pn, thisModule)) { + throw new IllegalStateException("Class " + formatClassName + + " in named module must be exported to java.desktop module."); + } + } + return c; + } } diff --git a/jdk/src/java.desktop/share/classes/javax/print/ServiceUI.java b/jdk/src/java.desktop/share/classes/javax/print/ServiceUI.java index 520d508c3b5..fede6e1b85c 100644 --- a/jdk/src/java.desktop/share/classes/javax/print/ServiceUI.java +++ b/jdk/src/java.desktop/share/classes/javax/print/ServiceUI.java @@ -193,36 +193,48 @@ public class ServiceUI { getLocalGraphicsEnvironment().getDefaultScreenDevice(). getDefaultConfiguration().getBounds() : gc.getBounds(); + x += gcBounds.x; + y += gcBounds.y; ServiceDialog dialog; if (owner instanceof Frame) { dialog = new ServiceDialog(gc, - x + gcBounds.x, - y + gcBounds.y, + x, + y, services, defaultIndex, flavor, attributes, (Frame)owner); } else { dialog = new ServiceDialog(gc, - x + gcBounds.x, - y + gcBounds.y, + x, + y, services, defaultIndex, flavor, attributes, (Dialog)owner); } Rectangle dlgBounds = dialog.getBounds(); - // get union of all GC bounds - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice[] gs = ge.getScreenDevices(); - for (int j=0; j gcBounds.x + gcBounds.width) { + if ((gcBounds.x + gcBounds.width - dlgBounds.width) > gcBounds.x) { + x = (gcBounds.x + gcBounds.width) - dlgBounds.width; + } else { + x = gcBounds.x; + } + } + if (dlgBounds.y + dlgBounds.height > gcBounds.y + gcBounds.height) { + if ((gcBounds.y + gcBounds.height - dlgBounds.height) > gcBounds.y) { + y = (gcBounds.y + gcBounds.height) - dlgBounds.height; + } else { + y = gcBounds.y; + } + } + dialog.setBounds(x, y, dlgBounds.width, dlgBounds.height); } dialog.show(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java b/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java index 18f30579f4e..74778d50267 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/DefaultDesktopManager.java @@ -191,12 +191,6 @@ public class DefaultDesktopManager implements DesktopManager, java.io.Serializab JLayeredPane.putLayer(desktopIcon, layer); } - // If we are maximized we already have the normal bounds recorded - // don't try to re-record them, otherwise we incorrectly set the - // normal bounds to maximized state. - if (!f.isMaximum()) { - f.setNormalBounds(f.getBounds()); - } if (findNext) { if (d.selectFrame(true) == null) { // The icon is the last frame. diff --git a/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java b/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java index d529f6976a7..1955407b75a 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/UIDefaults.java @@ -30,13 +30,15 @@ import javax.swing.plaf.ComponentUI; import javax.swing.border.*; import javax.swing.event.SwingPropertyChangeSupport; +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; import java.lang.reflect.*; import java.util.HashMap; import java.util.Map; import java.util.Enumeration; import java.util.Hashtable; import java.util.ResourceBundle; -import java.util.ResourceBundle.Control; import java.util.Locale; import java.util.Vector; import java.util.MissingResourceException; @@ -52,7 +54,6 @@ import java.security.PrivilegedAction; import sun.reflect.misc.MethodUtil; import sun.reflect.misc.ReflectUtil; import sun.swing.SwingUtilities2; -import sun.util.CoreResourceBundleControl; /** * A table of defaults for Swing components. Applications can set/get @@ -302,12 +303,12 @@ public class UIDefaults extends Hashtable for (int i=resourceBundles.size()-1; i >= 0; i--) { String bundleName = resourceBundles.get(i); try { - Control c = CoreResourceBundleControl.getRBControlInstance(bundleName); ResourceBundle b; - if (c != null) { - b = ResourceBundle.getBundle(bundleName, l, c); + if (isDesktopResourceBundle(bundleName)) { + // load resource bundle from java.desktop module + b = ResourceBundle.getBundle(bundleName, l, UIDefaults.class.getModule()); } else { - b = ResourceBundle.getBundle(bundleName, l); + b = ResourceBundle.getBundle(bundleName, l, ClassLoader.getSystemClassLoader()); } Enumeration keys = b.getKeys(); @@ -329,6 +330,30 @@ public class UIDefaults extends Hashtable return values; } + /* + * Test if the specified baseName of the ROOT locale is in java.desktop module. + * JDK always defines the resource bundle of the ROOT locale. + */ + private static boolean isDesktopResourceBundle(String baseName) { + Module thisModule = UIDefaults.class.getModule(); + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + Class c = Class.forName(thisModule, baseName); + if (c != null) { + return true; + } else { + String resourceName = baseName.replace('.', '/') + ".properties"; + try (InputStream in = thisModule.getResourceAsStream(resourceName)) { + return in != null; + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + } + }); + } + /** * Sets the value of key to value for all locales. * If key is a string and the new value isn't @@ -767,7 +792,13 @@ public class UIDefaults extends Hashtable m = uiClass.getMethod("createUI", new Class[]{JComponent.class}); put(uiClass, m); } - uiObject = MethodUtil.invoke(m, null, new Object[]{target}); + + if (uiClass.getModule() == ComponentUI.class.getModule()) { + // uiClass is a system LAF if it's in java.desktop module + uiObject = m.invoke(null, new Object[]{target}); + } else { + uiObject = MethodUtil.invoke(m, null, new Object[]{target}); + } } catch (NoSuchMethodException e) { getUIError("static createUI() method not found in " + uiClass); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java index bbc35bf9c1d..e573cf6f6af 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/filechooser/FileSystemView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -583,6 +583,69 @@ public abstract class FileSystemView { } } + /** + * Returns an array of files representing the values to show by default in + * the file chooser selector. + * + * @return an array of {@code File} objects. + * @throws SecurityException if the caller does not have necessary + * permissions + * @since 9 + */ + public File[] getChooserComboBoxFiles() { + return (File[]) ShellFolder.get("fileChooserComboBoxFolders"); + } + + /** + * Returns whether the specified file denotes a shell interpreted link which + * can be obtained by the {@link #getLinkLocation(File)}. + * + * @param file a file + * @return whether this is a link + * @throws NullPointerException if {@code file} equals {@code null} + * @throws SecurityException if the caller does not have necessary + * permissions + * @see #getLinkLocation(File) + * @since 9 + */ + public boolean isLink(File file) { + if (file == null) { + throw new NullPointerException("file is null"); + } + try { + return ShellFolder.getShellFolder(file).isLink(); + } catch (FileNotFoundException e) { + return false; + } + } + + /** + * Returns the regular file referenced by the specified link file if + * the specified file is a shell interpreted link. + * Returns {@code null} if the specified file is not + * a shell interpreted link. + * + * @param file a file + * @return the linked file or {@code null}. + * @throws FileNotFoundException if the linked file does not exist + * @throws NullPointerException if {@code file} equals {@code null} + * @throws SecurityException if the caller does not have necessary + * permissions + * @since 9 + */ + public File getLinkLocation(File file) throws FileNotFoundException { + if (file == null) { + throw new NullPointerException("file is null"); + } + ShellFolder shellFolder; + try { + shellFolder = ShellFolder.getShellFolder(file); + } catch (FileNotFoundException e) { + return null; + } + return shellFolder.isLink() ? shellFolder.getLinkLocation() : null; + } + /** * Throws {@code FileNotFoundException} if file not found or current thread was interrupted */ diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java index a9b0b80e444..2a3df571977 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicScrollPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -962,18 +962,13 @@ public class BasicScrollPaneUI int orientation = SwingConstants.VERTICAL; // find which scrollbar to scroll, or return if none - if (toScroll == null || !toScroll.isVisible()) { + if (toScroll == null || !toScroll.isVisible() + || e.isShiftDown()) { toScroll = scrollpane.getHorizontalScrollBar(); if (toScroll == null || !toScroll.isVisible()) { return; } orientation = SwingConstants.HORIZONTAL; - } else if(e.isShiftDown()){ - JScrollBar hScroll = scrollpane.getHorizontalScrollBar(); - if (hScroll != null && hScroll.isVisible()) { - toScroll = hScroll; - orientation = SwingConstants.HORIZONTAL; - } } e.consume(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java index b22941c8f6f..f7b370eb35b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthDesktopPaneUI.java @@ -362,9 +362,6 @@ public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements setWasIcon(f, Boolean.TRUE); } - if (!f.isMaximum()) { - f.setNormalBounds(f.getBounds()); - } c.remove(f); c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); try { diff --git a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java index 904172fa049..16272ffa819 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthTableHeaderUI.java @@ -230,9 +230,10 @@ public class SynthTableHeaderUI extends BasicTableHeaderUI boolean hasRollover = (column == getRolloverColumn()); if (isSelected || hasRollover || hasFocus) { + boolean enabled = (table == null)? true : table.isEnabled(); SynthLookAndFeel.setSelectedUI((SynthLabelUI)SynthLookAndFeel. getUIOfType(getUI(), SynthLabelUI.class), - isSelected, hasFocus, table.isEnabled(), + isSelected, hasFocus, enabled, hasRollover); } else { SynthLookAndFeel.resetSelectedUI(); diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java b/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java index ee9cda6e85f..12cc4b3f95c 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/DefaultFormatter.java @@ -31,7 +31,6 @@ import java.io.Serializable; import java.lang.reflect.*; import java.text.ParseException; import javax.swing.*; -import javax.swing.text.*; /** * DefaultFormatter formats arbitrary objects. Formatting is done diff --git a/jdk/src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java b/jdk/src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java index 205fda25a09..c40bdfc592b 100644 --- a/jdk/src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java +++ b/jdk/src/java.desktop/share/classes/javax/swing/text/html/ObjectView.java @@ -24,7 +24,6 @@ */ package javax.swing.text.html; -import java.util.Enumeration; import java.awt.*; import javax.swing.*; import javax.swing.text.*; diff --git a/jdk/src/java.desktop/share/classes/module-info.java b/jdk/src/java.desktop/share/classes/module-info.java new file mode 100644 index 00000000000..78af9bf8826 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/module-info.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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. + */ + +module java.desktop { + requires public java.datatransfer; + requires public java.xml; + requires java.prefs; + + exports java.applet; + exports java.awt; + exports java.awt.color; + exports java.awt.dnd; + exports java.awt.event; + exports java.awt.font; + exports java.awt.geom; + exports java.awt.im; + exports java.awt.im.spi; + exports java.awt.image; + exports java.awt.image.renderable; + exports java.awt.print; + exports java.beans; + exports java.beans.beancontext; + exports javax.accessibility; + exports javax.imageio; + exports javax.imageio.event; + exports javax.imageio.metadata; + exports javax.imageio.plugins.bmp; + exports javax.imageio.plugins.jpeg; + exports javax.imageio.plugins.tiff; + exports javax.imageio.spi; + exports javax.imageio.stream; + exports javax.print; + exports javax.print.attribute; + exports javax.print.attribute.standard; + exports javax.print.event; + exports javax.sound.midi; + exports javax.sound.midi.spi; + exports javax.sound.sampled; + exports javax.sound.sampled.spi; + exports javax.swing; + exports javax.swing.border; + exports javax.swing.colorchooser; + exports javax.swing.event; + exports javax.swing.filechooser; + exports javax.swing.plaf; + exports javax.swing.plaf.basic; + exports javax.swing.plaf.metal; + exports javax.swing.plaf.multi; + exports javax.swing.plaf.nimbus; + exports javax.swing.plaf.synth; + exports javax.swing.table; + exports javax.swing.text; + exports javax.swing.text.html; + exports javax.swing.text.html.parser; + exports javax.swing.text.rtf; + exports javax.swing.tree; + exports javax.swing.undo; + + // qualified exports may be inserted at build time + // see make/GensrcModuleInfo.gmk + exports sun.awt to + jdk.accessibility; + + uses java.awt.im.spi.InputMethodDescriptor; + uses javax.accessibility.AccessibilityProvider; + uses javax.imageio.spi.ImageInputStreamSpi; + uses javax.imageio.spi.ImageOutputStreamSpi; + uses javax.imageio.spi.ImageReaderSpi; + uses javax.imageio.spi.ImageTranscoderSpi; + uses javax.imageio.spi.ImageWriterSpi; + uses javax.print.PrintServiceLookup; + uses javax.print.StreamPrintServiceFactory; + uses javax.sound.midi.spi.MidiDeviceProvider; + uses javax.sound.midi.spi.MidiFileReader; + uses javax.sound.midi.spi.MidiFileWriter; + uses javax.sound.midi.spi.SoundbankReader; + uses javax.sound.sampled.spi.AudioFileReader; + uses javax.sound.sampled.spi.AudioFileWriter; + uses javax.sound.sampled.spi.FormatConversionProvider; + uses javax.sound.sampled.spi.MixerProvider; + + provides sun.datatransfer.DesktopDatatransferService with sun.awt.datatransfer.DesktopDatatransferServiceImpl; + provides java.net.ContentHandlerFactory with sun.awt.www.content.MultimediaContentHandlers; + provides javax.print.PrintServiceLookup with sun.print.PrintServiceLookupProvider; + provides javax.print.StreamPrintServiceFactory with sun.print.PSStreamPrinterFactory; + provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiInDeviceProvider; + provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.MidiOutDeviceProvider; + provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.RealTimeSequencerProvider; + provides javax.sound.midi.spi.MidiDeviceProvider with com.sun.media.sound.SoftProvider; + provides javax.sound.midi.spi.MidiFileReader with com.sun.media.sound.StandardMidiFileReader; + provides javax.sound.midi.spi.MidiFileWriter with com.sun.media.sound.StandardMidiFileWriter; + provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.AudioFileSoundbankReader; + provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.DLSSoundbankReader; + provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.JARSoundbankReader; + provides javax.sound.midi.spi.SoundbankReader with com.sun.media.sound.SF2SoundbankReader; + provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AiffFileReader; + provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.AuFileReader; + provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.SoftMidiAudioFileReader; + provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFileReader; + provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveFloatFileReader; + provides javax.sound.sampled.spi.AudioFileReader with com.sun.media.sound.WaveExtensibleFileReader; + provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AiffFileWriter; + provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.AuFileWriter; + provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFileWriter; + provides javax.sound.sampled.spi.AudioFileWriter with com.sun.media.sound.WaveFloatFileWriter; + provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AlawCodec; + provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.AudioFloatFormatConverter; + provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.PCMtoPCMCodec; + provides javax.sound.sampled.spi.FormatConversionProvider with com.sun.media.sound.UlawCodec; + provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.DirectAudioDeviceProvider; + provides javax.sound.sampled.spi.MixerProvider with com.sun.media.sound.PortMixerProvider; +} + diff --git a/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java b/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java index 192c0c84f2e..9faf3b39440 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java @@ -43,7 +43,6 @@ import java.lang.reflect.*; import sun.awt.AWTSecurityManager; import sun.awt.AppContext; import sun.awt.AWTPermissions; -import sun.security.provider.*; import sun.security.util.SecurityConstants; diff --git a/jdk/src/java.desktop/share/classes/sun/applet/Main.java b/jdk/src/java.desktop/share/classes/sun/applet/Main.java index 681fb81c6db..086b1113614 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/Main.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/Main.java @@ -30,8 +30,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.net.MalformedURLException; import java.util.Enumeration; @@ -75,7 +73,6 @@ public class Main { /** * Member variables set according to options passed in to AppletViewer. */ - private boolean debugFlag = false; private boolean helpFlag = false; private String encoding = null; private boolean noSecurityFlag = false; @@ -136,14 +133,6 @@ public class Main { return 1; } - if (debugFlag) { - // START A DEBUG SESSION - // Given the current architecture, we will end up decoding the - // arguments again, but at least we are guaranteed to have - // arguments which are valid. - return invokeDebugger(args); - } - // INSTALL THE SECURITY MANAGER (if necessary) if (!noSecurityFlag && (System.getSecurityManager() == null)) init(); @@ -191,9 +180,6 @@ public class Main { throw new ParseException(lookup("main.err.dupoption", arg)); encoding = args[++i]; return 2; - } else if ("-debug".equals(arg)) { - debugFlag = true; - return 1; } else if ("-Xnosecurity".equals(arg)) { // This is an undocumented (and, in the future, unsupported) // flag which prevents AppletViewer from installing its own @@ -267,68 +253,6 @@ public class Main { return u; } - /** - * Invoke the debugger with the arguments passed in to appletviewer. - * - * @param args The arguments passed into the debugger. - * @return {@code 0} if the debugger is invoked successfully, - * {@code 1} otherwise. - */ - private int invokeDebugger(String [] args) { - // CONSTRUCT THE COMMAND LINE - String [] newArgs = new String[args.length + 1]; - int current = 0; - - // Add a -classpath argument that prevents - // the debugger from launching appletviewer with the default of - // ".". appletviewer's classpath should never contain valid - // classes since they will result in security exceptions. - // Ideally, the classpath should be set to "", but the VM won't - // allow an empty classpath, so a phony directory name is used. - String phonyDir = System.getProperty("java.home") + - File.separator + "phony"; - newArgs[current++] = "-Djava.class.path=" + phonyDir; - - // Appletviewer's main class is the debuggee - newArgs[current++] = "sun.applet.Main"; - - // Append all the of the original appletviewer arguments, - // leaving out the "-debug" option. - for (int i = 0; i < args.length; i++) { - if (!("-debug".equals(args[i]))) { - newArgs[current++] = args[i]; - } - } - - // LAUNCH THE DEBUGGER - // Reflection is used for two reasons: - // 1) The debugger classes are on classpath and thus must be loaded - // by the application class loader. (Currently, appletviewer are - // loaded through the boot class path out of rt.jar.) - // 2) Reflection removes any build dependency between appletviewer - // and jdb. - try { - Class c = Class.forName("com.sun.tools.example.debug.tty.TTY", true, - ClassLoader.getSystemClassLoader()); - Method m = c.getDeclaredMethod("main", - new Class[] { String[].class }); - m.invoke(null, new Object[] { newArgs }); - } catch (ClassNotFoundException cnfe) { - System.err.println(lookup("main.debug.cantfinddebug")); - return 1; - } catch (NoSuchMethodException nsme) { - System.err.println(lookup("main.debug.cantfindmain")); - return 1; - } catch (InvocationTargetException ite) { - System.err.println(lookup("main.debug.exceptionindebug")); - return 1; - } catch (IllegalAccessException iae) { - System.err.println(lookup("main.debug.cantaccess")); - return 1; - } - return 0; - } - private void init() { // GET APPLETVIEWER USER-SPECIFIC PROPERTIES Properties avProps = getAVProps(); diff --git a/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java b/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java index f05729b972e..2b2bf2de74f 100644 --- a/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java +++ b/jdk/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java @@ -74,7 +74,7 @@ public class MsgAppletViewer extends ListResourceBundle { {"appletviewer.parse.warning.embed.requireswidth", "Warning: tag requires width attribute."}, {"appletviewer.parse.warning.appnotLongersupported", "Warning: tag no longer supported, use instead:"}, {"appletviewer.deprecated", "AppletViewer is deprecated."}, - {"appletviewer.usage", "Usage: appletviewer url(s)\n\nwhere include:\n -debug Start the applet viewer in the Java debugger\n -encoding Specify character encoding used by HTML files\n -J Pass argument to the java interpreter\n\nThe -J option is non-standard and subject to change without notice."}, + {"appletviewer.usage", "Usage: appletviewer url(s)\n\nwhere include:\n -encoding Specify character encoding used by HTML files\n -J Pass argument to the java interpreter\n\nThe -J option is non-standard and subject to change without notice."}, {"appletviewer.main.err.unsupportedopt", "Unsupported option: {0}"}, {"appletviewer.main.err.unrecognizedarg", "Unrecognized argument: {0}"}, {"appletviewer.main.err.dupoption", "Duplicate use of option: {0}"}, diff --git a/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java b/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java index 1e054b9de81..c034dbebd44 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/ExtendedKeyCodes.java @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ package sun.awt; import java.util.Collections; diff --git a/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java b/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java index 39ba273ec54..3aadaa63c82 100644 --- a/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java +++ b/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/TransferableProxy.java @@ -208,9 +208,11 @@ final class ClassLoaderObjectInputStream extends ObjectInputStream { classObjs[i] = cl; } try { - return Proxy.getProxyClass(hasNonPublicInterface ? - nonPublicLoader : classLoader, - classObjs); + @SuppressWarnings("deprecation") + Class proxyClass = Proxy.getProxyClass(hasNonPublicInterface ? + nonPublicLoader : classLoader, + classObjs); + return proxyClass; } catch (IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java new file mode 100644 index 00000000000..fc067b0070d --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContext.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.java2d; + +import java.lang.ref.Reference; + +/** + * ReentrantContext is a base class to hold thread-local data supporting + * reentrancy in either a ThreadLocal or a ConcurrentLinkedQueue + * + * @see ReentrantContextProvider + */ +public class ReentrantContext { + // usage stored as a byte + byte usage = ReentrantContextProvider.USAGE_TL_INACTIVE; + /* + * Reference to this instance (hard, soft or weak). + * @see ReentrantContextProvider#refType + */ + Reference reference = null; +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java new file mode 100644 index 00000000000..92132aabcc4 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProvider.java @@ -0,0 +1,169 @@ +/* + * 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.java2d; + +import java.lang.ref.Reference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +/** + * This abstract ReentrantContextProvider helper class manages the creation, + * storage, and retrieval of concrete ReentrantContext instances which can be + * subclassed to hold cached contextual data. + * + * It supports reentrancy as every call to acquire() provides a new unique context + * instance that must later be returned for reuse by a call to release(ctx) + * (typically in a try/finally block). + * + * It has a couple of abstract implementations which store references in a queue + * and/or thread-local storage. + * The Providers can be configured to hold ReentrantContext instances in memory + * using hard, soft or weak references. + * + * The acquire() and release() methods are used to retrieve and return the contexts. + * + * The {@code newContext()} method remains abstract in all implementations and + * must be provided by the module to create a new subclass of ReentrantContext + * with the appropriate contextual data in it. + * + * Sample Usage: + * - create a subclass ReentrantContextImpl to hold the thread state: + * + * static final class ReentrantContextImpl extends ReentrantContext { + * // specific cached data + * } + * + * - create the appropriate ReentrantContextProvider: + * + * private static final ReentrantContextProvider contextProvider = + * new ReentrantContextProviderTL(ReentrantContextProvider.REF_WEAK) + * { + * @Override + * protected ReentrantContextImpl newContext() { + * return new ReentrantContextImpl(); + * } + * }; + * ... + * void someMethod() { + * ReentrantContextImpl ctx = contextProvider.acquire(); + * try { + * // use the context + * } finally { + * contextProvider.release(ctx); + * } + * } + * + * @param ReentrantContext subclass + * + * @see ReentrantContext + */ +public abstract class ReentrantContextProvider +{ + // thread-local storage: inactive + static final byte USAGE_TL_INACTIVE = 0; + // thread-local storage: in use + static final byte USAGE_TL_IN_USE = 1; + // CLQ storage + static final byte USAGE_CLQ = 2; + + // hard reference + public static final int REF_HARD = 0; + // soft reference + public static final int REF_SOFT = 1; + // weak reference + public static final int REF_WEAK = 2; + + /* members */ + // internal reference type + private final int refType; + + /** + * Create a new ReentrantContext provider using the given reference type + * among hard, soft or weak + * + * @param refType reference type + */ + protected ReentrantContextProvider(final int refType) { + this.refType = refType; + } + + /** + * Create a new ReentrantContext instance + * + * @return new ReentrantContext instance + */ + protected abstract K newContext(); + + /** + * Give a ReentrantContext instance for the current thread + * + * @return ReentrantContext instance + */ + public abstract K acquire(); + + /** + * Restore the given ReentrantContext instance for reuse + * + * @param ctx ReentrantContext instance + */ + public abstract void release(K ctx); + + @SuppressWarnings("unchecked") + protected final Reference getOrCreateReference(final K ctx) { + if (ctx.reference == null) { + // Create the reference: + switch (refType) { + case REF_HARD: + ctx.reference = new HardReference(ctx); + break; + case REF_SOFT: + ctx.reference = new SoftReference(ctx); + break; + default: + case REF_WEAK: + ctx.reference = new WeakReference(ctx); + break; + } + } + return (Reference) ctx.reference; + } + + /* Missing HardReference implementation */ + static final class HardReference extends WeakReference { + // kept strong reference: + private final V strongRef; + + HardReference(final V referent) { + // no referent needed for the parent WeakReference: + super(null); + this.strongRef = referent; + } + + @Override + public V get() { + return strongRef; + } + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java new file mode 100644 index 00000000000..22978cef888 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderCLQ.java @@ -0,0 +1,89 @@ +/* + * 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.java2d; + +import java.lang.ref.Reference; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * This ReentrantContextProvider implementation uses one ConcurrentLinkedQueue + * to store all ReentrantContext instances (thread and its child contexts) + * + * Note: this implementation keeps less contexts in memory depending on the + * concurrent active threads in contrary to a ThreadLocal provider. However, + * it is slower in highly concurrent workloads. + * + * @param ReentrantContext subclass + */ +public abstract class ReentrantContextProviderCLQ + extends ReentrantContextProvider +{ + // ReentrantContext queue to store all contexts + private final ConcurrentLinkedQueue> ctxQueue + = new ConcurrentLinkedQueue>(); + + /** + * Create a new ReentrantContext provider using the given reference type + * among hard, soft or weak based using a ConcurrentLinkedQueue storage + * + * @param refType reference type + */ + public ReentrantContextProviderCLQ(final int refType) { + super(refType); + } + + /** + * Give a ReentrantContext instance for the current thread + * + * @return ReentrantContext instance + */ + @Override + public final K acquire() { + K ctx = null; + // Drain queue if all referent are null: + Reference ref = null; + while ((ctx == null) && ((ref = ctxQueue.poll()) != null)) { + ctx = ref.get(); + } + if (ctx == null) { + // create a new ReentrantContext if none is available + ctx = newContext(); + ctx.usage = USAGE_CLQ; + } + return ctx; + } + + /** + * Restore the given ReentrantContext instance for reuse + * + * @param ctx ReentrantContext instance + */ + @Override + public final void release(final K ctx) { + if (ctx.usage == USAGE_CLQ) { + ctxQueue.offer(getOrCreateReference(ctx)); + } + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java new file mode 100644 index 00000000000..14dcb84d6d5 --- /dev/null +++ b/jdk/src/java.desktop/share/classes/sun/java2d/ReentrantContextProviderTL.java @@ -0,0 +1,123 @@ +/* + * 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.java2d; + +import java.lang.ref.Reference; + +/** +* This ReentrantContextProvider implementation uses a ThreadLocal to hold + * the first ReentrantContext per thread and a ReentrantContextProviderCLQ to + * store child ReentrantContext instances needed during recursion. + * + * Note: this implementation may keep up to one context in memory per thread. + * Child contexts for recursive uses are stored in the queue using a WEAK + * reference by default unless specified in the 2 argument constructor. + * + * @param ReentrantContext subclass + */ +public abstract class ReentrantContextProviderTL + extends ReentrantContextProvider +{ + // Thread-local storage: + private final ThreadLocal> ctxTL + = new ThreadLocal>(); + + // ReentrantContext CLQ provider for child contexts: + private final ReentrantContextProviderCLQ ctxProviderCLQ; + + /** + * Create a new ReentrantContext provider using the given reference type + * among hard, soft or weak. + * It uses weak reference for the child contexts. + * + * @param refType reference type + */ + public ReentrantContextProviderTL(final int refType) { + this(refType, REF_WEAK); + } + + /** + * Create a new ReentrantContext provider using the given reference types + * among hard, soft or weak + * + * @param refTypeTL reference type used by ThreadLocal + * @param refTypeCLQ reference type used by ReentrantContextProviderCLQ + */ + public ReentrantContextProviderTL(final int refTypeTL, final int refTypeCLQ) + { + super(refTypeTL); + + final ReentrantContextProviderTL parent = this; + + this.ctxProviderCLQ = new ReentrantContextProviderCLQ(refTypeCLQ) { + @Override + protected K newContext() { + return parent.newContext(); + } + }; + } + + /** + * Give a ReentrantContext instance for the current thread + * + * @return ReentrantContext instance + */ + @Override + public final K acquire() { + K ctx = null; + final Reference ref = ctxTL.get(); + if (ref != null) { + ctx = ref.get(); + } + if (ctx == null) { + // create a new ReentrantContext if none is available + ctx = newContext(); + // update thread local reference: + ctxTL.set(getOrCreateReference(ctx)); + } + // Check reentrance: + if (ctx.usage == USAGE_TL_INACTIVE) { + ctx.usage = USAGE_TL_IN_USE; + } else { + // get or create another ReentrantContext from CLQ provider: + ctx = ctxProviderCLQ.acquire(); + } + return ctx; + } + + /** + * Restore the given ReentrantContext instance for reuse + * + * @param ctx ReentrantContext instance + */ + @Override + public final void release(final K ctx) { + if (ctx.usage == USAGE_TL_IN_USE) { + ctx.usage = USAGE_TL_INACTIVE; + } else { + ctxProviderCLQ.release(ctx); + } + } +} diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java index 226a3d2e30d..6e8da24453e 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/ByteArrayCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,7 +126,7 @@ final class ByteArrayCache implements MarlinConst { } if (doChecks) { - check(array, 0, array.length, value); + check(array, fromIndex, toIndex, value); } } @@ -135,9 +135,10 @@ final class ByteArrayCache implements MarlinConst { { if (doChecks) { // check zero on full array: - for (int i = fromIndex; i < toIndex; i++) { + for (int i = 0; i < array.length; i++) { if (array[i] != value) { - logException("Invalid array value at " + i + "\n" + logException("Invalid value at: " + i + " = " + array[i] + + " from: " + fromIndex + " to: " + toIndex + "\n" + Arrays.toString(array), new Throwable()); // ensure array is correctly filled: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java index 06d7f351e28..681c75d4ceb 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/FloatArrayCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -127,7 +127,7 @@ final class FloatArrayCache implements MarlinConst { } if (doChecks) { - check(array, 0, array.length, value); + check(array, fromIndex, toIndex, value); } } @@ -136,9 +136,10 @@ final class FloatArrayCache implements MarlinConst { { if (doChecks) { // check zero on full array: - for (int i = fromIndex; i < toIndex; i++) { + for (int i = 0; i < array.length; i++) { if (array[i] != value) { - logException("Invalid array value at " + i + "\n" + logException("Invalid value at: " + i + " = " + array[i] + + " from: " + fromIndex + " to: " + toIndex + "\n" + Arrays.toString(array), new Throwable()); // ensure array is correctly filled: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java index 11c5aae84f6..af4d0b69529 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/IntArrayCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,7 +126,7 @@ final class IntArrayCache implements MarlinConst { } if (doChecks) { - check(array, 0, array.length, value); + check(array, fromIndex, toIndex, value); } } @@ -135,9 +135,10 @@ final class IntArrayCache implements MarlinConst { { if (doChecks) { // check zero on full array: - for (int i = fromIndex; i < toIndex; i++) { + for (int i = 0; i < array.length; i++) { if (array[i] != value) { - logException("Invalid array value at " + i + "\n" + logException("Invalid value at: " + i + " = " + array[i] + + " from: " + fromIndex + " to: " + toIndex + "\n" + Arrays.toString(array), new Throwable()); // ensure array is correctly filled: diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java index 18cb441c571..40afc7fe9a6 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -590,8 +590,8 @@ public final class MarlinCache implements MarlinConst { alphaRow[to + 1] = 0; } if (doChecks) { - IntArrayCache.check(blkFlags, 0, blkFlags.length, 0); - IntArrayCache.check(alphaRow, 0, alphaRow.length, 0); + IntArrayCache.check(blkFlags, blkW, blkE, 0); + IntArrayCache.check(alphaRow, from, px1 - bboxX0, 0); } if (doMonitors) { diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java index f7b5f7c43a8..e01a5e77f9c 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/MarlinRenderingEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,11 +30,12 @@ import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Path2D; import java.awt.geom.PathIterator; -import java.lang.ref.Reference; import java.security.AccessController; -import java.util.concurrent.ConcurrentLinkedQueue; import static sun.java2d.marlin.MarlinUtils.logInfo; import sun.awt.geom.PathConsumer2D; +import sun.java2d.ReentrantContextProvider; +import sun.java2d.ReentrantContextProviderCLQ; +import sun.java2d.ReentrantContextProviderTL; import sun.java2d.pipe.AATileGenerator; import sun.java2d.pipe.Region; import sun.java2d.pipe.RenderingEngine; @@ -882,46 +883,50 @@ public class MarlinRenderingEngine extends RenderingEngine // use ThreadLocal or ConcurrentLinkedQueue to get one RendererContext private static final boolean useThreadLocal; - // hard reference - static final int REF_HARD = 0; - // soft reference - static final int REF_SOFT = 1; - // weak reference - static final int REF_WEAK = 2; - // reference type stored in either TL or CLQ static final int REF_TYPE; // Per-thread RendererContext - private static final ThreadLocal rdrCtxThreadLocal; - // RendererContext queue when ThreadLocal is disabled - private static final ConcurrentLinkedQueue rdrCtxQueue; + private static final ReentrantContextProvider rdrCtxProvider; // Static initializer to use TL or CLQ mode static { - // CLQ mode by default: useThreadLocal = MarlinProperties.isUseThreadLocal(); - rdrCtxThreadLocal = (useThreadLocal) ? new ThreadLocal() - : null; - rdrCtxQueue = (!useThreadLocal) ? new ConcurrentLinkedQueue() - : null; // Soft reference by default: - String refType = AccessController.doPrivileged( + final String refType = AccessController.doPrivileged( new GetPropertyAction("sun.java2d.renderer.useRef", "soft")); switch (refType) { default: case "soft": - REF_TYPE = REF_SOFT; + REF_TYPE = ReentrantContextProvider.REF_SOFT; break; case "weak": - REF_TYPE = REF_WEAK; + REF_TYPE = ReentrantContextProvider.REF_WEAK; break; case "hard": - REF_TYPE = REF_HARD; + REF_TYPE = ReentrantContextProvider.REF_HARD; break; } + + if (useThreadLocal) { + rdrCtxProvider = new ReentrantContextProviderTL(REF_TYPE) + { + @Override + protected RendererContext newContext() { + return RendererContext.createContext(); + } + }; + } else { + rdrCtxProvider = new ReentrantContextProviderCLQ(REF_TYPE) + { + @Override + protected RendererContext newContext() { + return RendererContext.createContext(); + } + }; + } } private static boolean settingsLogged = !enableLogs; @@ -936,13 +941,13 @@ public class MarlinRenderingEngine extends RenderingEngine String refType; switch (REF_TYPE) { default: - case REF_HARD: + case ReentrantContextProvider.REF_HARD: refType = "hard"; break; - case REF_SOFT: + case ReentrantContextProvider.REF_SOFT: refType = "soft"; break; - case REF_WEAK: + case ReentrantContextProvider.REF_WEAK: refType = "weak"; break; } @@ -1025,22 +1030,7 @@ public class MarlinRenderingEngine extends RenderingEngine */ @SuppressWarnings({"unchecked"}) static RendererContext getRendererContext() { - RendererContext rdrCtx = null; - final Object ref = (useThreadLocal) ? rdrCtxThreadLocal.get() - : rdrCtxQueue.poll(); - if (ref != null) { - // resolve reference: - rdrCtx = (REF_TYPE == REF_HARD) ? ((RendererContext) ref) - : ((Reference) ref).get(); - } - // create a new RendererContext if none is available - if (rdrCtx == null) { - rdrCtx = RendererContext.createContext(); - if (useThreadLocal) { - // update thread local reference: - rdrCtxThreadLocal.set(rdrCtx.reference); - } - } + final RendererContext rdrCtx = rdrCtxProvider.acquire(); if (doMonitors) { RendererContext.stats.mon_pre_getAATileGenerator.start(); } @@ -1057,8 +1047,6 @@ public class MarlinRenderingEngine extends RenderingEngine if (doMonitors) { RendererContext.stats.mon_pre_getAATileGenerator.stop(); } - if (!useThreadLocal) { - rdrCtxQueue.offer(rdrCtx.reference); - } + rdrCtxProvider.release(rdrCtx); } } diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java index 043db8adeba..f9b5e081785 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java @@ -148,8 +148,8 @@ final class Renderer implements PathConsumer2D, MarlinConst { ////////////////////////////////////////////////////////////////////////////// // EDGE LIST ////////////////////////////////////////////////////////////////////////////// - private float edgeMinY = Float.POSITIVE_INFINITY; - private float edgeMaxY = Float.NEGATIVE_INFINITY; + private int edgeMinY = Integer.MAX_VALUE; + private int edgeMaxY = Integer.MIN_VALUE; private float edgeMinX = Float.POSITIVE_INFINITY; private float edgeMaxX = Float.NEGATIVE_INFINITY; @@ -357,18 +357,21 @@ final class Renderer implements PathConsumer2D, MarlinConst { } return; } - // edge min/max X/Y are in subpixel space (inclusive) - if (y1 < edgeMinY) { - edgeMinY = y1; + + // edge min/max X/Y are in subpixel space (inclusive) within bounds: + // note: Use integer crossings to ensure consistent range within + // edgeBuckets / edgeBucketCounts arrays in case of NaN values (int = 0) + if (firstCrossing < edgeMinY) { + edgeMinY = firstCrossing; } - if (y2 > edgeMaxY) { - edgeMaxY = y2; + if (lastCrossing > edgeMaxY) { + edgeMaxY = lastCrossing; } // Use double-precision for improved accuracy: final double x1d = x1; final double y1d = y1; - final double slope = (x2 - x1d) / (y2 - y1d); + final double slope = (x1d - x2) / (y1d - y2); if (slope >= 0.0) { // <==> x1 < x2 if (x1 < edgeMinX) { @@ -504,7 +507,7 @@ final class Renderer implements PathConsumer2D, MarlinConst { private float x0, y0; // Position of most recent 'moveTo' command - private float pix_sx0, pix_sy0; + private float sx0, sy0; // per-thread renderer context final RendererContext rdrCtx; @@ -570,8 +573,8 @@ final class Renderer implements PathConsumer2D, MarlinConst { edgeBucketCounts = rdrCtx.getIntArray(edgeBucketsLength); } - edgeMinY = Float.POSITIVE_INFINITY; - edgeMaxY = Float.NEGATIVE_INFINITY; + edgeMinY = Integer.MAX_VALUE; + edgeMaxY = Integer.MIN_VALUE; edgeMinX = Float.POSITIVE_INFINITY; edgeMaxX = Float.NEGATIVE_INFINITY; @@ -628,7 +631,7 @@ final class Renderer implements PathConsumer2D, MarlinConst { blkFlags = blkFlags_initial; } - if (edgeMinY != Float.POSITIVE_INFINITY) { + if (edgeMinY != Integer.MAX_VALUE) { // if context is maked as DIRTY: if (rdrCtx.dirty) { // may happen if an exception if thrown in the pipeline processing: @@ -688,16 +691,18 @@ final class Renderer implements PathConsumer2D, MarlinConst { @Override public void moveTo(float pix_x0, float pix_y0) { closePath(); - this.pix_sx0 = pix_x0; - this.pix_sy0 = pix_y0; - this.y0 = tosubpixy(pix_y0); - this.x0 = tosubpixx(pix_x0); + final float sx = tosubpixx(pix_x0); + final float sy = tosubpixy(pix_y0); + this.sx0 = sx; + this.sy0 = sy; + this.x0 = sx; + this.y0 = sy; } @Override public void lineTo(float pix_x1, float pix_y1) { - float x1 = tosubpixx(pix_x1); - float y1 = tosubpixy(pix_y1); + final float x1 = tosubpixx(pix_x1); + final float y1 = tosubpixy(pix_y1); addLine(x0, y0, x1, y1); x0 = x1; y0 = y1; @@ -729,8 +734,9 @@ final class Renderer implements PathConsumer2D, MarlinConst { @Override public void closePath() { - // lineTo expects its input in pixel coordinates. - lineTo(pix_sx0, pix_sy0); + addLine(x0, y0, sx0, sy0); + x0 = sx0; + y0 = sy0; } @Override @@ -1396,7 +1402,7 @@ final class Renderer implements PathConsumer2D, MarlinConst { if (doMonitors) { RendererContext.stats.mon_rdr_endRendering.start(); } - if (edgeMinY == Float.POSITIVE_INFINITY) { + if (edgeMinY == Integer.MAX_VALUE) { return false; // undefined edges bounds } @@ -1407,11 +1413,10 @@ final class Renderer implements PathConsumer2D, MarlinConst { final int spminX = FloatMath.max(FloatMath.ceil_int(edgeMinX - 0.5f), boundsMinX); final int spmaxX = FloatMath.min(FloatMath.ceil_int(edgeMaxX - 0.5f), boundsMaxX - 1); - // y1 (and y2) are already biased by -0.5 in tosubpixy(): - final int spminY = FloatMath.max(FloatMath.ceil_int(edgeMinY), _boundsMinY); - int maxY = FloatMath.ceil_int(edgeMaxY); - + // edge Min/Max Y are already rounded to subpixels within bounds: + final int spminY = edgeMinY; final int spmaxY; + int maxY = edgeMaxY; if (maxY <= _boundsMaxY - 1) { spmaxY = maxY; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java index f9524c88870..60de2c31570 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,10 @@ package sun.java2d.marlin; import java.awt.geom.Path2D; -import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.concurrent.atomic.AtomicInteger; +import sun.java2d.ReentrantContext; +import sun.java2d.ReentrantContextProvider; import static sun.java2d.marlin.ArrayCache.*; import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator; import static sun.java2d.marlin.MarlinUtils.logInfo; @@ -36,7 +37,7 @@ import static sun.java2d.marlin.MarlinUtils.logInfo; /** * This class is a renderer context dedicated to a single thread */ -final class RendererContext implements MarlinConst { +final class RendererContext extends ReentrantContext implements MarlinConst { // RendererContext creation counter private static final AtomicInteger contextCount = new AtomicInteger(1); @@ -45,7 +46,7 @@ final class RendererContext implements MarlinConst { ? RendererStats.getInstance(): null; private static final boolean USE_CACHE_HARD_REF = doStats - || (MarlinRenderingEngine.REF_TYPE == MarlinRenderingEngine.REF_WEAK); + || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK); /** * Create a new renderer context @@ -55,6 +56,7 @@ final class RendererContext implements MarlinConst { static RendererContext createContext() { final RendererContext newCtx = new RendererContext("ctx" + Integer.toString(contextCount.getAndIncrement())); + if (RendererContext.stats != null) { RendererContext.stats.allContexts.add(newCtx); } @@ -63,11 +65,6 @@ final class RendererContext implements MarlinConst { // context name (debugging purposes) final String name; - /* - * Reference to this instance (hard, soft or weak). - * @see MarlinRenderingEngine#REF_TYPE - */ - final Object reference; // Smallest object used as Cleaner's parent reference final Object cleanerObj = new Object(); // dirty flag indicating an exception occured during pipeline in pathTo() @@ -101,7 +98,7 @@ final class RendererContext implements MarlinConst { /** * Constructor * - * @param name + * @param name context name (debugging) */ RendererContext(final String name) { if (logCreateContext) { @@ -124,20 +121,6 @@ final class RendererContext implements MarlinConst { stroker = new Stroker(this); dasher = new Dasher(this); - - // Create the reference to this instance (hard, soft or weak): - switch (MarlinRenderingEngine.REF_TYPE) { - default: - case MarlinRenderingEngine.REF_HARD: - reference = this; - break; - case MarlinRenderingEngine.REF_SOFT: - reference = new SoftReference(this); - break; - case MarlinRenderingEngine.REF_WEAK: - reference = new WeakReference(this); - break; - } } /** diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java index 94b0e2f1e59..1d144169376 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/marlin/Version.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,7 @@ package sun.java2d.marlin; public final class Version { - private static final String version = "marlin-0.7.3-Unsafe-OpenJDK"; + private static final String version = "marlin-0.7.3.2-Unsafe-OpenJDK"; public static String getVersion() { return version; diff --git a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java index e071b967a02..3046ff69c60 100644 --- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java +++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,11 @@ import java.awt.BasicStroke; import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.Rectangle2D; +import java.util.concurrent.ConcurrentLinkedQueue; import sun.awt.SunHints; +import sun.java2d.ReentrantContext; +import sun.java2d.ReentrantContextProvider; +import sun.java2d.ReentrantContextProviderTL; import sun.java2d.SunGraphics2D; /** @@ -38,28 +42,31 @@ import sun.java2d.SunGraphics2D; * This class sets up the Generator and computes the alpha tiles * and then passes them on to a CompositePipe object for painting. */ -public class AAShapePipe +public final class AAShapePipe implements ShapeDrawPipe, ParallelogramPipe { - static RenderingEngine renderengine = RenderingEngine.getInstance(); + static final RenderingEngine renderengine = RenderingEngine.getInstance(); // Per-thread TileState (~1K very small so do not use any Weak Reference) - private static final ThreadLocal tileStateThreadLocal = - new ThreadLocal() { - @Override - protected TileState initialValue() { - return new TileState(); - } - }; + private static final ReentrantContextProvider tileStateProvider = + new ReentrantContextProviderTL( + ReentrantContextProvider.REF_HARD) + { + @Override + protected TileState newContext() { + return new TileState(); + } + }; - CompositePipe outpipe; + final CompositePipe outpipe; public AAShapePipe(CompositePipe pipe) { outpipe = pipe; } + @Override public void draw(SunGraphics2D sg, Shape s) { - BasicStroke bs; + final BasicStroke bs; if (sg.stroke instanceof BasicStroke) { bs = (BasicStroke) sg.stroke; @@ -71,10 +78,12 @@ public class AAShapePipe renderPath(sg, s, bs); } + @Override public void fill(SunGraphics2D sg, Shape s) { renderPath(sg, s, null); } + @Override public void fillParallelogram(SunGraphics2D sg, double ux1, double uy1, double ux2, double uy2, @@ -82,21 +91,23 @@ public class AAShapePipe double dx1, double dy1, double dx2, double dy2) { - Region clip = sg.getCompClip(); - final TileState ts = tileStateThreadLocal.get(); - final int[] abox = ts.abox; + final TileState ts = tileStateProvider.acquire(); + try { + final int[] abox = ts.abox; - AATileGenerator aatg = - renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, - clip, abox); - if (aatg == null) { - // Nothing to render - return; + final AATileGenerator aatg = + renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0, + sg.getCompClip(), abox); + if (aatg != null) { + renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), + aatg, abox, ts); + } + } finally { + tileStateProvider.release(ts); } - - renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts); } + @Override public void drawParallelogram(SunGraphics2D sg, double ux1, double uy1, double ux2, double uy2, @@ -105,52 +116,61 @@ public class AAShapePipe double dx2, double dy2, double lw1, double lw2) { - Region clip = sg.getCompClip(); - final TileState ts = tileStateThreadLocal.get(); - final int[] abox = ts.abox; + final TileState ts = tileStateProvider.acquire(); + try { + final int[] abox = ts.abox; - AATileGenerator aatg = - renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, lw2, - clip, abox); - if (aatg == null) { - // Nothing to render - return; + final AATileGenerator aatg = + renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, + lw2, sg.getCompClip(), abox); + if (aatg != null) { + // Note that bbox is of the original shape, not the wide path. + // This is appropriate for handing to Paint methods... + renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), + aatg, abox, ts); + } + } finally { + tileStateProvider.release(ts); } - - // Note that bbox is of the original shape, not the wide path. - // This is appropriate for handing to Paint methods... - renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts); } public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) { - boolean adjust = (bs != null && + final boolean adjust = (bs != null && sg.strokeHint != SunHints.INTVAL_STROKE_PURE); - boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED); + final boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED); - Region clip = sg.getCompClip(); - final TileState ts = tileStateThreadLocal.get(); - final int[] abox = ts.abox; + final TileState ts = tileStateProvider.acquire(); + try { + final int[] abox = ts.abox; - AATileGenerator aatg = - renderengine.getAATileGenerator(s, sg.transform, clip, - bs, thin, adjust, abox); - if (aatg == null) { - // Nothing to render - return; + final AATileGenerator aatg = + renderengine.getAATileGenerator(s, sg.transform, sg.getCompClip(), + bs, thin, adjust, abox); + if (aatg != null) { + renderTiles(sg, s, aatg, abox, ts); + } + } finally { + tileStateProvider.release(ts); } - - renderTiles(sg, s, aatg, abox, ts); } public void renderTiles(SunGraphics2D sg, Shape s, - AATileGenerator aatg, int abox[], TileState ts) + final AATileGenerator aatg, + final int[] abox, final TileState ts) { Object context = null; try { + // reentrance: outpipe may also use AAShapePipe: context = outpipe.startSequence(sg, s, ts.computeDevBox(abox), abox); + // copy of int[] abox as local variables for performance: + final int x0 = abox[0]; + final int y0 = abox[1]; + final int x1 = abox[2]; + final int y1 = abox[3]; + final int tw = aatg.getTileWidth(); final int th = aatg.getTileHeight(); @@ -158,16 +178,15 @@ public class AAShapePipe final byte[] alpha = ts.getAlphaTile(tw * th); byte[] atile; - for (int y = abox[1]; y < abox[3]; y += th) { - int h = Math.min(th, abox[3] - y); + for (int y = y0; y < y1; y += th) { + final int h = Math.min(th, y1 - y); - for (int x = abox[0]; x < abox[2]; x += tw) { - int w = Math.min(tw, abox[2] - x); + for (int x = x0; x < x1; x += tw) { + final int w = Math.min(tw, x1 - x); - int a = aatg.getTypicalAlpha(); - if (a == 0x00 || - outpipe.needTile(context, x, y, w, h) == false) - { + final int a = aatg.getTypicalAlpha(); + + if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) { aatg.nextTile(); outpipe.skipTile(context, x, y); continue; @@ -180,8 +199,7 @@ public class AAShapePipe aatg.getAlpha(alpha, 0, tw); } - outpipe.renderPathTile(context, atile, 0, tw, - x, y, w, h); + outpipe.renderPathTile(context, atile, 0, tw, x, y, w, h); } } } finally { @@ -193,7 +211,7 @@ public class AAShapePipe } // Tile state used by AAShapePipe - static final class TileState { + static final class TileState extends ReentrantContext { // cached tile (32 x 32 tile by default) private byte[] theTile = new byte[32 * 32]; // dirty aabox array @@ -240,5 +258,4 @@ public class AAShapePipe return box; } } - } diff --git a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 1ffb6a18e1d..7ba84ab1630 100644 --- a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -791,12 +791,15 @@ public abstract class RasterPrinterJob extends PrinterJob { return page; } - final GraphicsConfiguration gc = - GraphicsEnvironment.getLocalGraphicsEnvironment(). - getDefaultScreenDevice().getDefaultConfiguration(); - Rectangle bounds = gc.getBounds(); - int x = bounds.x+bounds.width/3; - int y = bounds.y+bounds.height/3; + GraphicsConfiguration grCfg = null; + Window w = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); + if (w != null) { + grCfg = w.getGraphicsConfiguration(); + } else { + grCfg = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + } + final GraphicsConfiguration gc = grCfg; PrintService service = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { @@ -814,9 +817,39 @@ public abstract class RasterPrinterJob extends PrinterJob { return null; } + // we position the dialog a little beyond the upper-left corner of the window + // which is consistent with the NATIVE page dialog + Rectangle gcBounds = gc.getBounds(); + int x = gcBounds.x+50; + int y = gcBounds.y+50; ServiceDialog pageDialog = new ServiceDialog(gc, x, y, service, DocFlavor.SERVICE_FORMATTED.PAGEABLE, attributes, (Frame)null); + Rectangle dlgBounds = pageDialog.getBounds(); + + // if portion of dialog is not within the gc boundary + if (!gcBounds.contains(dlgBounds)) { + // check if dialog exceed window bounds at left or bottom + // Then position the dialog by moving it by the amount it exceeds + // the window bounds + // If it results in dialog moving beyond the window bounds at top/left + // then position it at window top/left + if (dlgBounds.x + dlgBounds.width > gcBounds.x + gcBounds.width) { + if ((gcBounds.x + gcBounds.width - dlgBounds.width) > gcBounds.x) { + x = (gcBounds.x + gcBounds.width) - dlgBounds.width; + } else { + x = gcBounds.x; + } + } + if (dlgBounds.y + dlgBounds.height > gcBounds.y + gcBounds.height) { + if ((gcBounds.y + gcBounds.height - dlgBounds.height) > gcBounds.y) { + y = (gcBounds.y + gcBounds.height) - dlgBounds.height; + } else { + y = gcBounds.y; + } + } + pageDialog.setBounds(x, y, dlgBounds.width, dlgBounds.height); + } pageDialog.show(); if (pageDialog.getStatus() == ServiceDialog.APPROVE) { @@ -893,9 +926,15 @@ public abstract class RasterPrinterJob extends PrinterJob { * We raise privilege when we put up the dialog, to avoid * the "warning applet window" banner. */ - final GraphicsConfiguration gc = - GraphicsEnvironment.getLocalGraphicsEnvironment(). - getDefaultScreenDevice().getDefaultConfiguration(); + GraphicsConfiguration grCfg = null; + Window w = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); + if (w != null) { + grCfg = w.getGraphicsConfiguration(); + } else { + grCfg = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + } + final GraphicsConfiguration gc = grCfg; PrintService service = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { @@ -940,9 +979,10 @@ public abstract class RasterPrinterJob extends PrinterJob { } } - Rectangle bounds = gc.getBounds(); - int x = bounds.x+bounds.width/3; - int y = bounds.y+bounds.height/3; + // we position the dialog a little beyond the upper-left corner of the window + // which is consistent with the NATIVE print dialog + int x = 50; + int y = 50; PrintService newService; // temporarily add an attribute pointing back to this job. PrinterJobWrapper jobWrapper = new PrinterJobWrapper(this); diff --git a/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java b/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java index 8e71a80a0e9..dbae176dd7e 100644 --- a/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java +++ b/jdk/src/java.desktop/unix/classes/sun/java2d/x11/XSurfaceData.java @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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.java2d.x11; import java.awt.image.*; diff --git a/jdk/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java b/jdk/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java index f84f855cce3..d602b3c712a 100644 --- a/jdk/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java +++ b/jdk/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java @@ -52,6 +52,7 @@ public class CUPSPrinter { private boolean initialized; private static native String getCupsServer(); private static native int getCupsPort(); + private static native String getCupsDefaultPrinter(); private static native boolean canConnect(String server, int port); private static native boolean initIDs(); // These functions need to be synchronized as @@ -266,6 +267,15 @@ public class CUPSPrinter { * Returns 2 values - index 0 is printer name, index 1 is the uri. */ static String[] getDefaultPrinter() { + // Try to get user/lpoptions-defined printer name from CUPS + // if not user-set, then go for server default destination + String printerInfo[] = new String[2]; + printerInfo[0] = getCupsDefaultPrinter(); + + if (printerInfo[0] != null) { + printerInfo[1] = null; + return printerInfo.clone(); + } try { URL url = new URL("http", getServer(), getPort(), ""); final HttpURLConnection urlConnection = @@ -301,7 +311,7 @@ public class CUPSPrinter { attCl)) { HashMap defaultMap = null; - String[] printerInfo = new String[2]; + InputStream is = urlConnection.getInputStream(); HashMap[] responseMap = IPPPrintService.readIPPResponse( is); diff --git a/jdk/src/java.desktop/unix/native/common/awt/CUPSfuncs.c b/jdk/src/java.desktop/unix/native/common/awt/CUPSfuncs.c index a530a47fb84..7ba8652b478 100644 --- a/jdk/src/java.desktop/unix/native/common/awt/CUPSfuncs.c +++ b/jdk/src/java.desktop/unix/native/common/awt/CUPSfuncs.c @@ -43,6 +43,10 @@ typedef int (*fn_ippPort)(void); typedef http_t* (*fn_httpConnect)(const char *, int); typedef void (*fn_httpClose)(http_t *); typedef char* (*fn_cupsGetPPD)(const char *); +typedef cups_dest_t* (*fn_cupsGetDest)(const char *name, + const char *instance, int num_dests, cups_dest_t *dests); +typedef int (*fn_cupsGetDests)(cups_dest_t **dests); +typedef void (*fn_cupsFreeDests)(int num_dests, cups_dest_t *dests); typedef ppd_file_t* (*fn_ppdOpenFile)(const char *); typedef void (*fn_ppdClose)(ppd_file_t *); typedef ppd_option_t* (*fn_ppdFindOption)(ppd_file_t *, const char *); @@ -53,6 +57,9 @@ fn_ippPort j2d_ippPort; fn_httpConnect j2d_httpConnect; fn_httpClose j2d_httpClose; fn_cupsGetPPD j2d_cupsGetPPD; +fn_cupsGetDest j2d_cupsGetDest; +fn_cupsGetDests j2d_cupsGetDests; +fn_cupsFreeDests j2d_cupsFreeDests; fn_ppdOpenFile j2d_ppdOpenFile; fn_ppdClose j2d_ppdClose; fn_ppdFindOption j2d_ppdFindOption; @@ -106,6 +113,24 @@ Java_sun_print_CUPSPrinter_initIDs(JNIEnv *env, return JNI_FALSE; } + j2d_cupsGetDest = (fn_cupsGetDest)dlsym(handle, "cupsGetDest"); + if (j2d_cupsGetDest == NULL) { + dlclose(handle); + return JNI_FALSE; + } + + j2d_cupsGetDests = (fn_cupsGetDests)dlsym(handle, "cupsGetDests"); + if (j2d_cupsGetDests == NULL) { + dlclose(handle); + return JNI_FALSE; + } + + j2d_cupsFreeDests = (fn_cupsFreeDests)dlsym(handle, "cupsFreeDests"); + if (j2d_cupsFreeDests == NULL) { + dlclose(handle); + return JNI_FALSE; + } + j2d_ppdOpenFile = (fn_ppdOpenFile)dlsym(handle, "ppdOpenFile"); if (j2d_ppdOpenFile == NULL) { dlclose(handle); @@ -169,6 +194,30 @@ Java_sun_print_CUPSPrinter_getCupsPort(JNIEnv *env, } +/* + * Gets CUPS default printer name. + * + */ +JNIEXPORT jstring JNICALL +Java_sun_print_CUPSPrinter_getCupsDefaultPrinter(JNIEnv *env, + jobject printObj) +{ + jstring cDefPrinter = NULL; + cups_dest_t *dests; + char *defaultPrinter = NULL; + int num_dests = j2d_cupsGetDests(&dests); + int i = 0; + cups_dest_t *dest = j2d_cupsGetDest(NULL, NULL, num_dests, dests); + if (dest != NULL) { + defaultPrinter = dest->name; + if (defaultPrinter != NULL) { + cDefPrinter = JNU_NewStringPlatform(env, defaultPrinter); + } + } + j2d_cupsFreeDests(num_dests, dests); + return cDefPrinter; +} + /* * Checks if connection can be made to the server. * diff --git a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java index 93dc53d4f27..8f4da91eef2 100644 --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DBlitLoops.java @@ -500,6 +500,7 @@ class D3DRTTSurfaceToSurfaceTransform extends TransformBlit { class D3DSurfaceToSwBlit extends Blit { private int typeval; + private WeakReference srcTmp; // REMIND: destination will actually be opaque/premultiplied... D3DSurfaceToSwBlit(SurfaceType dstType, int typeval) { @@ -509,11 +510,97 @@ class D3DSurfaceToSwBlit extends Blit { this.typeval = typeval; } + /* + * Clip value is ignored in D3D SurfaceToSw blit. + * Root Cause: The native interfaces to D3D use StretchRect API followed + * by custom copy of pixels from Surface to Sysmem. As a result, clipping + * in D3DSurfaceToSw works 'only' for Rect clips, provided, proper srcX, + * srcY, dstX, dstY, width and height are passed to native interfaces. + * Non rect clips (For example: Shape clips) are ignored completely. + * + * Solution: There are three solutions possible to fix this issue. + * 1. Convert the entire Surface to Sysmem and perform regular Blit. + * An optimized version of this is to take up the conversion only + * when Shape clips are needed. Existing native interface will suffice + * for supporting Rect clips. + * 2. With help of existing classes we could perform SwToSurface, + * SurfaceToSurface (implements clip) and SurfaceToSw (complete copy) + * in order. + * 3. Modify the native D3D interface to accept clip and perform same logic + * as the second approach but at native side. + * + * Upon multiple experiments, the first approach has been found to be + * faster than the others as it deploys 1-draw/copy operation for rect clip + * and 2-draw/copy operations for shape clip compared to 3-draws/copy + * operations deployed by the remaining approaches. + * + * complexClipBlit method helps to convert or copy the contents from + * D3DSurface onto Sysmem and perform a regular Blit with the clip + * information as required. This method is used when non-rectangular + * clip is needed. + */ + private synchronized void complexClipBlit(SurfaceData src, SurfaceData dst, + Composite comp, Region clip, + int sx, int sy, int dx, int dy, + int w, int h) { + SurfaceData cachedSrc = null; + if (srcTmp != null) { + // use cached intermediate surface, if available + cachedSrc = srcTmp.get(); + } + + // Type- indicates the pixel format of Sysmem based BufferedImage. + // Native d3d interfaces support on the fly conversion of pixels from + // d3d surface to destination sysmem memory of type IntARGB only. + final int type = BufferedImage.TYPE_INT_ARGB; + src = convertFrom(this, src, sx, sy, w, h, cachedSrc, type); + + // copy intermediate SW to destination SW using complex clip + final Blit performop = Blit.getFromCache(src.getSurfaceType(), + CompositeType.SrcNoEa, + dst.getSurfaceType()); + performop.Blit(src, dst, comp, clip, 0, 0, dx, dy, w, h); + + if (src != cachedSrc) { + // cache the intermediate surface + srcTmp = new WeakReference<>(src); + } + } + public void Blit(SurfaceData src, SurfaceData dst, Composite comp, Region clip, int sx, int sy, int dx, int dy, int w, int h) { + if (clip != null) { + clip = clip.getIntersectionXYWH(dx, dy, w, h); + // At the end this method will flush the RenderQueue, we should exit + // from it as soon as possible. + if (clip.isEmpty()) { + return; + } + + // Adjust final dst(x,y) and src(x,y) based on the clip. The + // logic is that, when clip limits drawing on the destination, + // corresponding pixels from the src should be skipped. + sx += clip.getLoX() - dx; + sy += clip.getLoY() - dy; + dx = clip.getLoX(); + dy = clip.getLoY(); + w = clip.getWidth(); + h = clip.getHeight(); + + // Check if the clip is Rectangular. For non-rectangular clips + // complexClipBlit will convert Surface To Sysmem and perform + // regular Blit. + if (!clip.isRectangular()) { + complexClipBlit(src, dst, comp, clip, + sx, sy, dx, dy, + w, h); + return; + } + } + D3DRenderQueue rq = D3DRenderQueue.getInstance(); rq.lock(); try { diff --git a/jdk/src/java.httpclient/share/classes/module-info.java b/jdk/src/java.httpclient/share/classes/module-info.java new file mode 100644 index 00000000000..eee3f326028 --- /dev/null +++ b/jdk/src/java.httpclient/share/classes/module-info.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module java.httpclient { + requires java.base; + exports java.net.http; +} + 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 c3a51970767..c0bb90b59b6 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,141 +25,155 @@ package java.lang.instrument; -import java.security.ProtectionDomain; +import java.lang.reflect.Module; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; /* * Copyright 2003 Wily Technology, Inc. */ /** - * An agent provides an implementation of this interface in order - * to transform class files. - * The transformation occurs before the class is defined by the JVM. + * A transformer of class files. An agent registers an implementation of this + * interface using the {@link Instrumentation#addTransformer addTransformer} + * method so that the transformer's {@link + * ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[]) + * transform} method is invoked when classes are loaded, + * {@link Instrumentation#redefineClasses redefined}, or + * {@link Instrumentation#retransformClasses retransformed}. The implementation + * should override one of the {@code transform} methods defined here. + * Transformers are invoked before the class is defined by the Java virtual + * machine. + * + *

        + * There are two kinds of transformers, determined by the canRetransform + * parameter of + * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)}: + *

          + *
        • retransformation capable transformers that were added with + * canRetransform as true + *
        • + *
        • retransformation incapable transformers that were added with + * canRetransform as false or where added with + * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer)} + *
        • + *
        + * + *

        + * Once a transformer has been registered with + * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean) + * addTransformer}, + * the transformer will be called for every new class definition and every class redefinition. + * Retransformation capable transformers will also be called on every class retransformation. + * The request for a new class definition is made with + * {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass} + * or its native equivalents. + * The request for a class redefinition is made with + * {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses} + * or its native equivalents. + * The request for a class retransformation is made with + * {@link java.lang.instrument.Instrumentation#retransformClasses Instrumentation.retransformClasses} + * or its native equivalents. + * The transformer is called during the processing of the request, before the class file bytes + * have been verified or applied. + * When there are multiple transformers, transformations are composed by chaining the + * transform calls. + * That is, the byte array returned by one call to transform becomes the input + * (via the classfileBuffer parameter) to the next call. + * + *

        + * Transformations are applied in the following order: + *

          + *
        • Retransformation incapable transformers + *
        • + *
        • Retransformation incapable native transformers + *
        • + *
        • Retransformation capable transformers + *
        • + *
        • Retransformation capable native transformers + *
        • + *
        + * + *

        + * For retransformations, the retransformation incapable transformers are not + * called, instead the result of the previous transformation is reused. + * In all other cases, this method is called. + * Within each of these groupings, transformers are called in the order registered. + * Native transformers are provided by the ClassFileLoadHook event + * in the Java Virtual Machine Tool Interface). + * + *

        + * The input (via the classfileBuffer parameter) to the first + * transformer is: + *

          + *
        • for new class definition, + * the bytes passed to ClassLoader.defineClass + *
        • + *
        • for class redefinition, + * definitions.getDefinitionClassFile() where + * definitions is the parameter to + * {@link java.lang.instrument.Instrumentation#redefineClasses + * Instrumentation.redefineClasses} + *
        • + *
        • for class retransformation, + * the bytes passed to the new class definition or, if redefined, + * the last redefinition, with all transformations made by retransformation + * incapable transformers reapplied automatically and unaltered; + * for details see + * {@link java.lang.instrument.Instrumentation#retransformClasses + * Instrumentation.retransformClasses} + *
        • + *
        + * + *

        + * If the implementing method determines that no transformations are needed, + * it should return null. + * Otherwise, it should create a new byte[] array, + * copy the input classfileBuffer into it, + * along with all desired transformations, and return the new array. + * The input classfileBuffer must not be modified. + * + *

        + * In the retransform and redefine cases, + * the transformer must support the redefinition semantics: + * if a class that the transformer changed during initial definition is later + * retransformed or redefined, the + * transformer must insure that the second class output class file is a legal + * redefinition of the first output class file. + * + *

        + * If the transformer throws an exception (which it doesn't catch), + * subsequent transformers will still be called and the load, redefine + * or retransform will still be attempted. + * Thus, throwing an exception has the same effect as returning null. + * To prevent unexpected behavior when unchecked exceptions are generated + * in transformer code, a transformer can catch Throwable. + * If the transformer believes the classFileBuffer does not + * represent a validly formatted class file, it should throw + * an IllegalClassFormatException; + * while this has the same effect as returning null. it facilitates the + * logging or debugging of format corruptions. + * *

        * Note the term class file is used as defined in section 3.1 of - * The Java™ Virtual Machine Specification, - * to mean a sequence - * of bytes in class file format, whether or not they reside in a file. + * The Java™ Virtual Machine Specification, to mean a + * sequence of bytes in class file format, whether or not they reside in a + * file. * * @see java.lang.instrument.Instrumentation - * @see java.lang.instrument.Instrumentation#addTransformer - * @see java.lang.instrument.Instrumentation#removeTransformer * @since 1.5 */ public interface ClassFileTransformer { + /** - * The implementation of this method may transform the supplied class file and - * return a new replacement class file. + * Transforms the given class file and returns a new replacement class file. + * This method is invoked when the {@link Module Module} bearing {@link + * ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[]) + * transform} is not overridden. * - *

        - * There are two kinds of transformers, determined by the canRetransform - * parameter of - * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean)}: - *

          - *
        • retransformation capable transformers that were added with - * canRetransform as true - *
        • - *
        • retransformation incapable transformers that were added with - * canRetransform as false or where added with - * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer)} - *
        • - *
        - * - *

        - * Once a transformer has been registered with - * {@link java.lang.instrument.Instrumentation#addTransformer(ClassFileTransformer,boolean) - * addTransformer}, - * the transformer will be called for every new class definition and every class redefinition. - * Retransformation capable transformers will also be called on every class retransformation. - * The request for a new class definition is made with - * {@link java.lang.ClassLoader#defineClass ClassLoader.defineClass} - * or its native equivalents. - * The request for a class redefinition is made with - * {@link java.lang.instrument.Instrumentation#redefineClasses Instrumentation.redefineClasses} - * or its native equivalents. - * The request for a class retransformation is made with - * {@link java.lang.instrument.Instrumentation#retransformClasses Instrumentation.retransformClasses} - * or its native equivalents. - * The transformer is called during the processing of the request, before the class file bytes - * have been verified or applied. - * When there are multiple transformers, transformations are composed by chaining the - * transform calls. - * That is, the byte array returned by one call to transform becomes the input - * (via the classfileBuffer parameter) to the next call. - * - *

        - * Transformations are applied in the following order: - *

          - *
        • Retransformation incapable transformers - *
        • - *
        • Retransformation incapable native transformers - *
        • - *
        • Retransformation capable transformers - *
        • - *
        • Retransformation capable native transformers - *
        • - *
        - * - *

        - * For retransformations, the retransformation incapable transformers are not - * called, instead the result of the previous transformation is reused. - * In all other cases, this method is called. - * Within each of these groupings, transformers are called in the order registered. - * Native transformers are provided by the ClassFileLoadHook event - * in the Java Virtual Machine Tool Interface). - * - *

        - * The input (via the classfileBuffer parameter) to the first - * transformer is: - *

          - *
        • for new class definition, - * the bytes passed to ClassLoader.defineClass - *
        • - *
        • for class redefinition, - * definitions.getDefinitionClassFile() where - * definitions is the parameter to - * {@link java.lang.instrument.Instrumentation#redefineClasses - * Instrumentation.redefineClasses} - *
        • - *
        • for class retransformation, - * the bytes passed to the new class definition or, if redefined, - * the last redefinition, with all transformations made by retransformation - * incapable transformers reapplied automatically and unaltered; - * for details see - * {@link java.lang.instrument.Instrumentation#retransformClasses - * Instrumentation.retransformClasses} - *
        • - *
        - * - *

        - * If the implementing method determines that no transformations are needed, - * it should return null. - * Otherwise, it should create a new byte[] array, - * copy the input classfileBuffer into it, - * along with all desired transformations, and return the new array. - * The input classfileBuffer must not be modified. - * - *

        - * In the retransform and redefine cases, - * the transformer must support the redefinition semantics: - * if a class that the transformer changed during initial definition is later - * retransformed or redefined, the - * transformer must insure that the second class output class file is a legal - * redefinition of the first output class file. - * - *

        - * If the transformer throws an exception (which it doesn't catch), - * subsequent transformers will still be called and the load, redefine - * or retransform will still be attempted. - * Thus, throwing an exception has the same effect as returning null. - * To prevent unexpected behavior when unchecked exceptions are generated - * in transformer code, a transformer can catch Throwable. - * If the transformer believes the classFileBuffer does not - * represent a validly formatted class file, it should throw - * an IllegalClassFormatException; - * while this has the same effect as returning null. it facilitates the - * logging or debugging of format corruptions. + * @implSpec The default implementation returns null. * * @param loader the defining loader of the class to be transformed, * may be null if the bootstrap loader @@ -169,20 +183,67 @@ public interface ClassFileTransformer { * For example, "java/util/List". * @param classBeingRedefined if this is triggered by a redefine or retransform, * the class being redefined or retransformed; - * if this is a class load, null + * if this is a class load, {@code null} * @param protectionDomain the protection domain of the class being defined or redefined * @param classfileBuffer the input byte buffer in class file format - must not be modified * - * @throws IllegalClassFormatException if the input does not represent a well-formed class file - * @return a well-formed class file buffer (the result of the transform), - or null if no transform is performed. - * @see Instrumentation#redefineClasses + * @throws IllegalClassFormatException + * if the input does not represent a well-formed class file + * @return a well-formed class file buffer (the result of the transform), + * or {@code null} if no transform is performed */ - byte[] + default byte[] transform( ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) - throws IllegalClassFormatException; + throws IllegalClassFormatException { + return null; + } + + + /** + * Transforms the given class file and returns a new replacement class file. + * + * @implSpec The default implementation of this method invokes the + * {@link #transform(ClassLoader,String,Class,ProtectionDomain,byte[]) transform} + * method with the {@link Module#getClassLoader() ClassLoader} for the module. + * + * @param module the module of the class to be transformed + * @param className the name of the class in the internal form of fully + * qualified class and interface names as defined in + * The Java Virtual Machine Specification. + * For example, "java/util/List". + * @param classBeingRedefined if this is triggered by a redefine or retransform, + * the class being redefined or retransformed; + * if this is a class load, {@code null} + * @param protectionDomain the protection domain of the class being defined or redefined + * @param classfileBuffer the input byte buffer in class file format - must not be modified + * + * @throws IllegalClassFormatException + * if the input does not represent a well-formed class file + * @return a well-formed class file buffer (the result of the transform), + * or {@code null} if no transform is performed + * + * @since 9 + */ + default byte[] + transform( Module module, + String className, + Class classBeingRedefined, + ProtectionDomain protectionDomain, + byte[] classfileBuffer) + throws IllegalClassFormatException { + + PrivilegedAction pa = module::getClassLoader; + ClassLoader loader = AccessController.doPrivileged(pa); + + // invoke the legacy transform method + return transform(loader, + className, + classBeingRedefined, + protectionDomain, + classfileBuffer); + } } 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 bedb780680f..44b0aa3c853 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,9 +25,9 @@ package java.lang.instrument; -import java.io.File; -import java.io.IOException; -import java.util.jar.JarFile; +import java.lang.reflect.Module; +import java.security.ProtectionDomain; +import java.util.jar.JarFile; /* * Copyright 2003 Wily Technology, Inc. @@ -74,9 +74,8 @@ public interface Instrumentation { * The transformer is called when classes are loaded, when they are * {@linkplain #redefineClasses redefined}. and if canRetransform is true, * when they are {@linkplain #retransformClasses retransformed}. - * See {@link java.lang.instrument.ClassFileTransformer#transform - * ClassFileTransformer.transform} for the order - * of transform calls. + * {@link ClassFileTransformer} defines the order of transform calls. + * * If a transformer throws * an exception during execution, the JVM will still call the other registered * transformers in order. The same transformer may be added more than once, @@ -163,18 +162,16 @@ public interface Instrumentation { * *

      • for each transformer that was added with canRetransform * false, the bytes returned by - * {@link java.lang.instrument.ClassFileTransformer#transform transform} - * during the last class load or redefine are + * {@link ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[]) + * transform} during the last class load or redefine are * reused as the output of the transformation; note that this is * equivalent to reapplying the previous transformation, unaltered; - * except that - * {@link java.lang.instrument.ClassFileTransformer#transform transform} - * is not called + * except that {@code transform} method is not called. *
      • *
      • for each transformer that was added with canRetransform * true, the - * {@link java.lang.instrument.ClassFileTransformer#transform transform} - * method is called in these transformers + * {@link ClassFileTransformer#transform(Module,String,Class,ProtectionDomain,byte[]) + * transform} method is called in these transformers *
      • *
      • the transformed class file bytes are installed as the new * definition of the class @@ -182,10 +179,9 @@ public interface Instrumentation { * *

        * - * The order of transformation is described in the - * {@link java.lang.instrument.ClassFileTransformer#transform transform} method. - * This same order is used in the automatic reapplication of retransformation - * incapable transforms. + * The order of transformation is described in {@link ClassFileTransformer}. + * This same order is used in the automatic reapplication of + * retransformation incapable transforms. *

        * * The initial class file bytes represent the bytes passed to @@ -662,4 +658,21 @@ public interface Instrumentation { */ void setNativeMethodPrefix(ClassFileTransformer transformer, String prefix); + + /** + * Updates a module to read another module. + * + * Agents that instrument code in named modules may need to arrange for the + * modules to read other modules. This method is equivalent to code in {@code + * module} calling {@link Module#addReads(Module) addReads} to read {@code + * other}. + * + * @param module the module to update + * @param other the module to read + * @throws NullPointerException if either module is {@code null} + * + * @since 9 + * @see Module#canRead(Module) + */ + void addModuleReads(Module module, Module other); } diff --git a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html index 6c6e380b0f4..9b1b02ea06f 100644 --- a/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html +++ b/jdk/src/java.instrument/share/classes/java/lang/instrument/package.html @@ -1,5 +1,5 @@ + + + + MultiResolutionTrayIconTest + + + + +To run test please push "Start" (if system tray is not supported, push "Pass"). + +Two tray icons will appear (note: sometimes they can go to the tray icons pool). + +Please check if both of them have correct size and +the same colouring (white rectagle in a blue mount). In this case please push "Pass". + +Otherwise (if the 2nd red-white small icon appears) please push "Fail". + + + diff --git a/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java new file mode 100644 index 00000000000..f6f069b0ed8 --- /dev/null +++ b/jdk/test/java/awt/image/multiresolution/MultiResolutionTrayIconTest/MultiResolutionTrayIconTest.java @@ -0,0 +1,116 @@ +/* + * 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 8150176 + @ignore 8150176 + @summary Check if correct resolution variant is used for tray icon. + @author a.stepanov + @run applet/manual=yesno MultiResolutionTrayIconTest.html +*/ + + +import java.applet.Applet; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; + + +public class MultiResolutionTrayIconTest extends Applet { + + private SystemTray tray; + private TrayIcon icon, iconMRI; + + public void init() { this.setLayout(new BorderLayout()); } + + public void start() { + + boolean trayIsSupported = SystemTray.isSupported(); + Button b = new Button("Start"); + if (trayIsSupported) { + + prepareIcons(); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { doTest(); } + }); + } else { + b.setLabel("not supported"); + b.setEnabled(false); + System.out.println("system tray is not supported"); + } + add(b, BorderLayout.CENTER); + + validate(); + setVisible(true); + } + + private BufferedImage generateImage(int w, int h, Color c) { + + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + Graphics g = img.getGraphics(); + g.setColor(c); + g.fillRect(0, 0, w, h); + g.setColor(Color.WHITE); + int r = (Math.min(w, h) >= 8) ? 3 : 1; + g.fillRect(r, r, w - 2 * r, h - 2 * r); + return img; + } + + private void prepareIcons() { + + tray = SystemTray.getSystemTray(); + Dimension d = tray.getTrayIconSize(); + int w = d.width, h = d.height; + + BufferedImage img = generateImage(w, h, Color.BLUE); + // use wrong icon size for "nok" + BufferedImage nok = generateImage(w / 2 + 2, h / 2 + 2, Color.RED); + BaseMultiResolutionImage mri = + new BaseMultiResolutionImage(new BufferedImage[] {nok, img}); + icon = new TrayIcon(img); + iconMRI = new TrayIcon(mri); + } + + private void doTest() { + + if (tray.getTrayIcons().length > 0) { return; } // icons were added already + try { + tray.add(icon); + tray.add(iconMRI); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public void stop() { + + // check for null, just in case + if (tray != null) { + tray.remove(icon); + tray.remove(iconMRI); + } + } +} diff --git a/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java new file mode 100644 index 00000000000..c16e58076c1 --- /dev/null +++ b/jdk/test/java/awt/patchlib/java.desktop/java/awt/Helper.java @@ -0,0 +1,31 @@ +/* + * 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 java.awt; +import java.lang.reflect.Module; +public class Helper { + private Helper() { } + public static void addExports(String pn, Module target) { + java.awt.Component.class.getModule().addExports(pn, target); + } +} diff --git a/jdk/test/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java b/jdk/test/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java new file mode 100644 index 00000000000..013de39b8a1 --- /dev/null +++ b/jdk/test/java/awt/print/PrinterJob/MultiMonPrintDlgTest.java @@ -0,0 +1,125 @@ +/* + * 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. + */ +import java.awt.Button; +import java.awt.Component; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.KeyboardFocusManager; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.JOptionPane; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 8138749 + * @summary PrinterJob.printDialog() does not support multi-mon, + * always displayed on primary + * @run main/manual MultiMonPrintDlgTest + */ +public class MultiMonPrintDlgTest implements ActionListener { + + Frame primaryFrame = null; + Frame secFrame = null; + GraphicsDevice gd[] = GraphicsEnvironment.getLocalGraphicsEnvironment(). + getScreenDevices(); + + public MultiMonPrintDlgTest() throws Exception { + if (gd.length <= 1) { + System.out.println("This test should be run only on dual-monitor systems. Aborted!!"); + return; + } + + String[] instructions = + { + " This test should be running on a dual-monitor setup.", + "A frame will be created on each of the 2 monitor. ", + "Click the Print button on the frame displayed in the non-default monitor.", + "Please verify that page dialog followed by print dialog ", + " is displayed in the same screen", + "where the frame is located ie, in the non-default monitor.", + }; + + SwingUtilities.invokeAndWait(() -> { + JOptionPane.showMessageDialog( + (Component) null, + instructions, + "information", JOptionPane.INFORMATION_MESSAGE); + }); + GraphicsDevice defDev = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); + int x = 0; + Frame f = null; + for (x = 0; x < gd.length; x ++) { + if (gd[x] != defDev) { + secFrame = new Frame("Screen " + x + " - secondary", gd[x].getDefaultConfiguration()); + f = secFrame; + } else { + primaryFrame = new Frame("Screen " + x + " - primary", gd[x].getDefaultConfiguration()); + f = primaryFrame; + } + Button b = new Button("Print"); + b.addActionListener(this); + f.add("South", b); + f.addWindowListener (new WindowAdapter() { + public void windowClosing(WindowEvent we) { + ((Window) we.getSource()).dispose(); + } + }); + f.setSize(200, 200); + f.setVisible(true); + } + } + + public void actionPerformed (ActionEvent ae) { + try { + javax.print.attribute.PrintRequestAttributeSet prSet = + new javax.print.attribute.HashPrintRequestAttributeSet(); + java.awt.print.PrinterJob.getPrinterJob().pageDialog(prSet); + Window w = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); + int dialogButton = JOptionPane.showConfirmDialog (w, + "Did the pageDialog shown in non-default monitor?", + null, JOptionPane.YES_NO_OPTION); + if(dialogButton == JOptionPane.NO_OPTION) { + throw new RuntimeException("PageDialog is shown in wrong monitor"); + } + java.awt.print.PrinterJob.getPrinterJob().printDialog(prSet); + dialogButton = JOptionPane.showConfirmDialog (w, + "Did the printDialog shown in non-default monitor?", + null, JOptionPane.YES_NO_OPTION); + if(dialogButton == JOptionPane.NO_OPTION) { + throw new RuntimeException("PrintDialog is shown in wrong monitor"); + } + } finally { + primaryFrame.dispose(); + secFrame.dispose(); + } + } + + public static void main (String args[]) throws Exception { + MultiMonPrintDlgTest test = new MultiMonPrintDlgTest(); + } +} diff --git a/jdk/test/java/awt/regtesthelpers/Util.java b/jdk/test/java/awt/regtesthelpers/Util.java index 2b2a8fb2555..62feee23489 100644 --- a/jdk/test/java/awt/regtesthelpers/Util.java +++ b/jdk/test/java/awt/regtesthelpers/Util.java @@ -212,22 +212,6 @@ public final class Util { robot.waitForIdle(); } - public static Field getField(final Class klass, final String fieldName) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Field run() { - try { - Field field = klass.getDeclaredField(fieldName); - assert (field != null); - field.setAccessible(true); - return field; - } catch (SecurityException se) { - throw new RuntimeException("Error: unexpected exception caught!", se); - } catch (NoSuchFieldException nsfe) { - throw new RuntimeException("Error: unexpected exception caught!", nsfe); - } - } - }); - } /* * Waits for a notification and for a boolean condition to become true. @@ -461,6 +445,10 @@ public final class Util { try { final Class _clazz = clazz; + Method m_addExports = Class.forName("java.awt.Helper").getDeclaredMethod("addExports", String.class, java.lang.reflect.Module.class); + // No MToolkit anymore: nothing to do about it. + // We may be called from non-X11 system, and this permission cannot be delegated to a test. + m_addExports.invoke(null, "sun.awt.X11", Util.class.getModule()); Method m_getWMID = (Method)AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { @@ -478,6 +466,10 @@ public final class Util { } }); return ((Integer)m_getWMID.invoke(null, new Object[] {})).intValue(); + } catch (ClassNotFoundException cnfe) { + cnfe.printStackTrace(); + } catch (NoSuchMethodException nsme) { + nsme.printStackTrace(); } catch (IllegalAccessException iae) { iae.printStackTrace(); } catch (InvocationTargetException ite) { diff --git a/jdk/test/java/awt/regtesthelpers/UtilInternal.java b/jdk/test/java/awt/regtesthelpers/UtilInternal.java index ef12684fb10..d7f0e1e61ce 100644 --- a/jdk/test/java/awt/regtesthelpers/UtilInternal.java +++ b/jdk/test/java/awt/regtesthelpers/UtilInternal.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -33,7 +33,6 @@ import java.awt.Frame; import sun.awt.AWTAccessor; - /** Class with static methods using internal/proprietary API by necessity. */ @@ -50,6 +49,8 @@ public final class UtilInternal { .getPeer(embedder); System.out.println("frame's peer = " + frame_peer); if ("sun.awt.windows.WToolkit".equals(tk.getClass().getName())) { + java.awt.Helper.addExports("sun.awt.windows", UtilInternal.class.getModule()); + Class comp_peer_class = Class.forName("sun.awt.windows.WComponentPeer"); System.out.println("comp peer class = " + comp_peer_class); @@ -63,8 +64,8 @@ public final class UtilInternal { Constructor constructor = clazz.getConstructor (new Class [] {Long.TYPE}); return (Frame) constructor.newInstance (new Object[] {hwnd}); } else if ("sun.awt.X11.XToolkit".equals(tk.getClass().getName())) { + java.awt.Helper.addExports("sun.awt.X11", UtilInternal.class.getModule()); Class x_base_window_class = Class.forName("sun.awt.X11.XBaseWindow"); - System.out.println("x_base_window_class = " + x_base_window_class); Method get_window = x_base_window_class.getMethod("getWindow", new Class[0]); System.out.println("get_window = " + get_window); long window = (Long) get_window.invoke(frame_peer, new Object[0]); diff --git a/jdk/test/java/awt/xembed/server/TesterClient.java b/jdk/test/java/awt/xembed/server/TesterClient.java index 22991f33931..535e65bb45d 100644 --- a/jdk/test/java/awt/xembed/server/TesterClient.java +++ b/jdk/test/java/awt/xembed/server/TesterClient.java @@ -32,6 +32,8 @@ public class TesterClient { public static void main(String[] args) throws Throwable { // First parameter is the name of the test, second is the window, the rest are rectangles Class cl = Class.forName("sun.awt.X11.XEmbedServerTester"); + cl.getModule().addExports("sun.awt.X11",TesterClient.class.getModule()); + test = cl.getMethod(args[0], new Class[0]); long window = Long.parseLong(args[1]); Rectangle r[] = new Rectangle[(args.length-2)/4]; diff --git a/jdk/test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java b/jdk/test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java index b6e5b86b18b..b6e794690d1 100644 --- a/jdk/test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java +++ b/jdk/test/java/beans/XMLEncoder/sun_swing_PrintColorUIResource.java @@ -25,8 +25,8 @@ * @test * @bug 6589532 * @summary Tests PrintColorUIResource value encoding - * @author Sergey Malenkov * @modules java.desktop/sun.swing + * @author Sergey Malenkov */ import java.awt.Color; diff --git a/jdk/test/java/lang/Class/Foo.java b/jdk/test/java/lang/Class/Foo.java new file mode 100644 index 00000000000..bc8df3df09d --- /dev/null +++ b/jdk/test/java/lang/Class/Foo.java @@ -0,0 +1,27 @@ +/* + * 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 foo; + +// Loaded by a custom class loader in GetPackageTest +public class Foo { +} diff --git a/jdk/test/java/lang/Class/GetModuleTest.java b/jdk/test/java/lang/Class/GetModuleTest.java new file mode 100644 index 00000000000..566721c890f --- /dev/null +++ b/jdk/test/java/lang/Class/GetModuleTest.java @@ -0,0 +1,153 @@ +/** + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Exercise Class#getModule + * @modules java.base/jdk.internal.org.objectweb.asm + * java.desktop + * @run testng GetModuleTest + */ + +import java.awt.Component; +import java.lang.reflect.Field; +import java.lang.reflect.Module; + +import jdk.internal.org.objectweb.asm.ClassWriter; +import static jdk.internal.org.objectweb.asm.Opcodes.*; +import sun.misc.Unsafe; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class GetModuleTest { + + static final Unsafe U; + static { + try { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + U = (Unsafe) theUnsafe.get(null); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + private static final Module TEST_MODULE = GetModuleTest.class.getModule(); + + + @DataProvider(name = "testclasses") + public Object[][] testClasses() { + return new Object[][] { + + // unnamed module + + { GetModuleTest.class, null }, + { GetModuleTest[].class, null }, + { GetModuleTest[][].class, null }, + + // should return named module + + { int.class, "java.base" }, + { int[].class, "java.base" }, + { int[][].class, "java.base" }, + { void.class, "java.base" }, + + { Object.class, "java.base" }, + { Object[].class, "java.base" }, + { Object[][].class, "java.base" }, + { Component.class, "java.desktop" }, + { Component[].class, "java.desktop" }, + { Component[][].class, "java.desktop" }, + }; + } + + @Test(dataProvider = "testclasses") + public void testGetModule(Class type, String expected) { + Module m = type.getModule(); + assertNotNull(m); + if (expected == null) { + assertTrue(m == TEST_MODULE); + } else { + assertEquals(m.getName(), expected); + } + } + + + @DataProvider(name = "hostclasses") + public Object[][] hostClasses() { + return new Object[][] { + + { GetModuleTest.class, null }, + { GetModuleTest[].class, null }, + { Object.class, null }, + { Object[].class, null }, + { Component.class, null }, + { Component[].class, null }, + + }; + } + + /** + * Exercise Class::getModule on VM anonymous classes + */ + @Test(dataProvider = "hostclasses") + public void testGetModuleOnVMAnonymousClass(Class hostClass, String ignore) { + + // choose a class name in the same package as the host class + String prefix = packageName(hostClass); + if (prefix.length() > 0) + prefix = prefix.replace('.', '/') + "/"; + String className = prefix + "Anon"; + + // create the class + String superName = "java/lang/Object"; + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + + ClassWriter.COMPUTE_FRAMES); + cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, + className, null, superName, null); + byte[] classBytes = cw.toByteArray(); + int cpPoolSize = constantPoolSize(classBytes); + Class anonClass + = U.defineAnonymousClass(hostClass, classBytes, new Object[cpPoolSize]); + + assertTrue(anonClass.getModule() == hostClass.getModule()); + } + + private static String packageName(Class c) { + if (c.isArray()) { + return packageName(c.getComponentType()); + } else { + String name = c.getName(); + int dot = name.lastIndexOf('.'); + if (dot == -1) return ""; + return name.substring(0, dot); + } + } + + private static int constantPoolSize(byte[] classFile) { + return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF); + } + +} diff --git a/jdk/test/java/lang/Class/GetPackageTest.java b/jdk/test/java/lang/Class/GetPackageTest.java new file mode 100644 index 00000000000..d1ffea75ecb --- /dev/null +++ b/jdk/test/java/lang/Class/GetPackageTest.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Basic test for Class.getPackage + * @compile Foo.java + * @run testng GetPackageTest + */ + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Properties; + +import static org.testng.Assert.*; + +public class GetPackageTest { + private static Class fooClass; // definePackage is not called for Foo class + + @BeforeTest + public static void loadFooClass() throws ClassNotFoundException { + TestClassLoader loader = new TestClassLoader(); + fooClass = loader.loadClass("foo.Foo"); + assertEquals(fooClass.getClassLoader(), loader); + } + + @DataProvider(name = "testclasses") + public Object[][] testClasses() { + return new Object[][] { + // primitive type, void, array types + { int.class, null }, + { long[].class, null }, + { Object[][].class, null }, + { void.class, null }, + + // unnamed package + { GetPackageTest.class, "" }, + + // named package + { fooClass, "foo" }, + { Object.class, "java.lang" }, + { Properties.class, "java.util" }, + { BigInteger.class, "java.math" }, + { Test.class, "org.testng.annotations" }, + }; + } + + @Test(dataProvider = "testClasses") + public void testGetPackage(Class type, String expected) { + Package p = type.getPackage(); + if (expected == null) { + assertTrue(p == null); + } else { + assertEquals(p.getName(), expected); + } + } + + static class TestClassLoader extends ClassLoader { + public TestClassLoader() { + super(); + } + + public TestClassLoader(ClassLoader parent) { + super(parent); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + Path p = Paths.get(System.getProperty("test.classes", ".")); + + try { + byte[] bb = Files.readAllBytes(p.resolve("foo/Foo.class")); + return defineClass(name, bb, 0, bb.length); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + @Override + protected Class loadClass(String cn, boolean resolve) throws ClassNotFoundException { + if (!cn.equals("foo.Foo")) + return super.loadClass(cn, resolve); + return findClass(cn); + } + + } +} + + diff --git a/jdk/test/java/lang/Class/forName/modules/TestDriver.java b/jdk/test/java/lang/Class/forName/modules/TestDriver.java new file mode 100644 index 00000000000..690849b7c2a --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/TestDriver.java @@ -0,0 +1,172 @@ +/* + * 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.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.stream.Stream; + +import jdk.testlibrary.FileUtils; +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import static org.testng.Assert.assertTrue; + +/** + * @test + * @bug 8087335 + * @summary Tests for Class.forName(Module,String) + * @library /lib/testlibrary + * @modules jdk.compiler + * @build TestDriver CompilerUtils jdk.testlibrary.ProcessTools jdk.testlibrary.FileUtils TestMain TestLayer + * @run testng TestDriver + */ + +public class TestDriver { + + private static final String TEST_SRC = + Paths.get(System.getProperty("test.src")).toString(); + private static final String TEST_CLASSES = + Paths.get(System.getProperty("test.classes")).toString(); + + private static final Path MOD_SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MOD_DEST_DIR = Paths.get("mods"); + + private static final String[] modules = new String[] {"m1", "m2", "m3"}; + + /** + * Compiles all modules used by the test. + */ + @BeforeClass + public void setup() throws Exception { + assertTrue(CompilerUtils.compile( + MOD_SRC_DIR, MOD_DEST_DIR, + "-modulesourcepath", + MOD_SRC_DIR.toString())); + + copyDirectories(MOD_DEST_DIR.resolve("m1"), Paths.get("mods1")); + copyDirectories(MOD_DEST_DIR.resolve("m2"), Paths.get("mods2")); + } + + @Test + public void test() throws Exception { + String[] options = new String[] { + "-cp", TEST_CLASSES, + "-mp", MOD_DEST_DIR.toString(), + "-addmods", String.join(",", modules), + "-m", "m2/p2.test.Main" + }; + runTest(options); + } + + @Test + public void testUnnamedModule() throws Exception { + String[] options = new String[] { + "-cp", TEST_CLASSES, + "-mp", MOD_DEST_DIR.toString(), + "-addmods", String.join(",", modules), + "TestMain" + }; + runTest(options); + } + + @Test + public void testLayer() throws Exception { + String[] options = new String[] { + "-cp", TEST_CLASSES, + "TestLayer" + }; + + runTest(options); + } + + @Test + public void testDeniedClassLoaderAccess() throws Exception { + String[] options = new String[] { + "-mp", MOD_DEST_DIR.toString(), + "-addmods", String.join(",", modules), + "-m", "m3/p3.NoGetClassLoaderAccess" + }; + assertTrue(executeTestJava(options) + .outputTo(System.out) + .errorTo(System.err) + .getExitValue() == 0); + } + + @Test + public void testDeniedAccess() throws Exception { + Path policyFile = Paths.get(TEST_SRC, "policy.denied"); + + String[] options = new String[] { + "-Djava.security.manager", + "-Djava.security.policy=" + policyFile.toString(), + "-mp", MOD_DEST_DIR.toString(), + "-addmods", String.join(",", modules), + "-m", "m3/p3.NoAccess" + }; + assertTrue(executeTestJava(options) + .outputTo(System.out) + .errorTo(System.err) + .getExitValue() == 0); + } + + private String[] runWithSecurityManager(String[] options) { + Path policyFile = Paths.get(TEST_SRC, "policy"); + Stream opts = Stream.concat(Stream.of("-Djava.security.manager", + "-Djava.security.policy=" + policyFile.toString()), + Arrays.stream(options)); + return opts.toArray(String[]::new); + } + + private void runTest(String[] options) throws Exception { + assertTrue(executeTestJava(options) + .outputTo(System.out) + .errorTo(System.err) + .getExitValue() == 0); + + assertTrue(executeTestJava(runWithSecurityManager(options)) + .outputTo(System.out) + .errorTo(System.err) + .getExitValue() == 0); + } + + private void copyDirectories(Path source, Path dest) throws IOException { + if (Files.exists(dest)) + FileUtils.deleteFileTreeWithRetry(dest); + Files.walk(source, Integer.MAX_VALUE) + .filter(Files::isRegularFile) + .forEach(p -> { + try { + Path to = dest.resolve(source.relativize(p)); + Files.createDirectories(to.getParent()); + Files.copy(p, to); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/TestLayer.java b/jdk/test/java/lang/Class/forName/modules/TestLayer.java new file mode 100644 index 00000000000..8a01cb18b51 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/TestLayer.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; + +public class TestLayer { + private static final Path MODS_DIR = Paths.get("mods"); + private static final Set modules = Set.of("m1", "m2"); + + public static void main(String[] args) throws Exception { + // disable security manager until Class.forName is called. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + System.setSecurityManager(null); + } + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = parent.resolveRequiresAndUses(ModuleFinder.empty(), + finder, + modules); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + + if (sm != null) { + System.setSecurityManager(sm); + } + + // find exported and non-exported class from a named module + findClass(m1, "p1.A"); + findClass(m1, "p1.internal.B"); + findClass(m2, "p2.C"); + + // find class from unnamed module + ClassLoader ld = TestLayer.class.getClassLoader(); + findClass(ld.getUnnamedModule(), "TestDriver"); + + // check if clinit should not be initialized + // compile without module-path; so use reflection + Class c = Class.forName(m1, "p1.Initializer"); + Method m = c.getMethod("isInited"); + Boolean isClinited = (Boolean) m.invoke(null); + if (isClinited.booleanValue()) { + throw new RuntimeException("clinit should not be invoked"); + } + } + + static Class findClass(Module module, String cn) { + Class c = Class.forName(module, cn); + if (c == null) { + throw new RuntimeException(cn + " not found in " + module); + } + if (c.getModule() != module) { + throw new RuntimeException(c.getModule() + " != " + module); + } + return c; + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/TestMain.java b/jdk/test/java/lang/Class/forName/modules/TestMain.java new file mode 100644 index 00000000000..0da5136622c --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/TestMain.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +import java.lang.reflect.Layer; +import java.lang.reflect.Method; +import java.lang.reflect.Module; + +public class TestMain { + public static void main(String[] args) throws Exception { + Layer boot = Layer.boot(); + Module m1 = boot.findModule("m1").get(); + Module m2 = boot.findModule("m2").get(); + + // find exported and non-exported class from a named module + findClass(m1, "p1.A"); + findClass(m1, "p1.internal.B"); + findClass(m2, "p2.C"); + + // find class from unnamed module + ClassLoader loader = TestMain.class.getClassLoader(); + findClass(loader.getUnnamedModule(), "TestDriver"); + + // check if clinit should not be initialized + // compile without module-path; so use reflection + Class c = Class.forName(m1, "p1.Initializer"); + Method m = c.getMethod("isInited"); + Boolean isClinited = (Boolean) m.invoke(null); + if (isClinited.booleanValue()) { + throw new RuntimeException("clinit should not be invoked"); + } + } + + static Class findClass(Module module, String cn) { + Class c = Class.forName(module, cn); + if (c == null) { + throw new RuntimeException(cn + " not found in " + module); + } + if (c.getModule() != module) { + throw new RuntimeException(c.getModule() + " != " + module); + } + return c; + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/policy b/jdk/test/java/lang/Class/forName/modules/policy new file mode 100644 index 00000000000..a95eccaab71 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/policy @@ -0,0 +1,7 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.lang.RuntimePermission "getBootLayer"; + permission java.lang.RuntimePermission "getClassLoader"; + permission java.io.FilePermission "mods/-", "read"; + permission java.util.PropertyPermission "user.dir", "read"; +}; diff --git a/jdk/test/java/lang/Class/forName/modules/policy.denied b/jdk/test/java/lang/Class/forName/modules/policy.denied new file mode 100644 index 00000000000..763f6152191 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/policy.denied @@ -0,0 +1,11 @@ +grant { + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.lang.RuntimePermission "getBootLayer"; + permission java.lang.RuntimePermission "getClassLoader"; + permission java.io.FilePermission "mods1", "read"; + permission java.io.FilePermission "mods2", "read"; + // only grant access to p1.* classes + // no access to p1.internal.* and p2.* classes + permission java.io.FilePermission "mods1/p1/*", "read"; + permission java.util.PropertyPermission "user.dir", "read"; +}; diff --git a/jdk/test/java/lang/Class/forName/modules/src/m1/module-info.java b/jdk/test/java/lang/Class/forName/modules/src/m1/module-info.java new file mode 100644 index 00000000000..47a2c4c1f77 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m1 { + exports p1; +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m1/p1/A.java b/jdk/test/java/lang/Class/forName/modules/src/m1/p1/A.java new file mode 100644 index 00000000000..444b8cc342c --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m1/p1/A.java @@ -0,0 +1,31 @@ +/* + * 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; + +public class A { + static { + Initializer.init(); + System.out.println("p1.A is initialzed"); + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m1/p1/Initializer.java b/jdk/test/java/lang/Class/forName/modules/src/m1/p1/Initializer.java new file mode 100644 index 00000000000..e8823ca9c7f --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m1/p1/Initializer.java @@ -0,0 +1,34 @@ +/* + * 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; + +public class Initializer { + private static boolean inited = false; + static synchronized void init() { + inited = true; + } + public static synchronized boolean isInited() { + return inited; + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m1/p1/internal/B.java b/jdk/test/java/lang/Class/forName/modules/src/m1/p1/internal/B.java new file mode 100644 index 00000000000..3454c062ff2 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m1/p1/internal/B.java @@ -0,0 +1,28 @@ +/* + * 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.internal; + +public class B { + public B() {} +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m2/module-info.java b/jdk/test/java/lang/Class/forName/modules/src/m2/module-info.java new file mode 100644 index 00000000000..e28b2202567 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + exports p2; +} diff --git a/langtools/test/tools/jdeps/VerboseFormat/use/unsafe/DontUseUnsafe.java b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/C.java similarity index 95% rename from langtools/test/tools/jdeps/VerboseFormat/use/unsafe/DontUseUnsafe.java rename to jdk/test/java/lang/Class/forName/modules/src/m2/p2/C.java index fac1e7ea590..e976c5c2e74 100644 --- a/langtools/test/tools/jdeps/VerboseFormat/use/unsafe/DontUseUnsafe.java +++ b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/C.java @@ -21,8 +21,7 @@ * questions. */ -package use.unsafe; - -public class DontUseUnsafe { +package p2; +public class C { } diff --git a/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java new file mode 100644 index 00000000000..83856c6d814 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m2/p2/test/Main.java @@ -0,0 +1,61 @@ +/* + * 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 p2.test; + +import java.lang.reflect.Layer; +import java.lang.reflect.Module; + +public class Main { + public static void main(String... args) throws Exception { + Layer boot = Layer.boot(); + Module m1 = boot.findModule("m1").get(); + Module m2 = Main.class.getModule(); + + // find exported and non-exported class from a named module + findClass(m1, "p1.A"); + findClass(m1, "p1.internal.B"); + findClass(m2, "p2.C"); + + // find class from unnamed module + ClassLoader loader = m2.getClassLoader(); + findClass(loader.getUnnamedModule(), "TestDriver"); + + try { + Class c = findClass(m1, "p1.internal.B"); + c.newInstance(); + throw new RuntimeException(c.getName() + " is not exported to m2"); + } catch (IllegalAccessException e) {} + } + + static Class findClass(Module module, String cn) { + Class c = Class.forName(module, cn); + if (c == null) { + throw new RuntimeException(cn + " not found in " + module); + } + if (c.getModule() != module) { + throw new RuntimeException(c.getModule() + " != " + module); + } + return c; + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m3/module-info.java b/jdk/test/java/lang/Class/forName/modules/src/m3/module-info.java new file mode 100644 index 00000000000..a92b756bbef --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m3/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m3 { +} 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 new file mode 100644 index 00000000000..902e92d7c00 --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java @@ -0,0 +1,114 @@ +/* + * 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 p3; + +import java.io.FilePermission; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.AccessControlException; +import java.security.Permission; +import java.util.Set; + +public class NoAccess { + private static final Module M3 = NoAccess.class.getModule(); + private static final Path MODS_DIR1 = Paths.get("mods1"); + private static final Path MODS_DIR2 = Paths.get("mods2"); + public static void main(String[] args) throws Exception { + // disable security manager until Class.forName is called. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + System.setSecurityManager(null); + } + + ModuleFinder finder = ModuleFinder.of(Paths.get("mods1"), Paths.get("mods2")); + + Layer bootLayer = Layer.boot(); + Configuration parent = bootLayer.configuration(); + + Configuration cf = parent.resolveRequiresAndUses(finder, + ModuleFinder.empty(), + Set.of("m1", "m2")); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl); + + if (sm != null) { + System.setSecurityManager(sm); + } + + Module m1 = bootLayer.findModule("m1").get(); + Module m2 = bootLayer.findModule("m2").get(); + Module m3 = bootLayer.findModule("m3").get(); + + findClass(m1, "p1.internal.B"); + findClass(m2, "p2.C"); + findClass(m3, "p3.internal.Foo"); + + // permissions granted + findClass(m1, "p1.A"); + findClass(m1, "p1.internal.B"); + findClass(m2, "p2.C"); + findClass(m3, "p3.internal.Foo"); + + + // m1 and m2 from a different layer + m1 = layer.findModule("m1").get(); + m2 = layer.findModule("m2").get(); + m3 = layer.findModule("m3").get(); + + findClass(m1, "p1.A"); + findClass(m3, "p3.internal.Foo"); + + // no permission + Path path = MODS_DIR1.resolve("p1").resolve("internal").resolve("B.class"); + findClass(m1, "p1.internal.B", new FilePermission(path.toString(), "read")); + path = MODS_DIR2.resolve("p2").resolve("C.class"); + findClass(m2, "p2.C", new FilePermission(path.toString(), "read")); + } + + static Class findClass(Module module, String cn) { + return findClass(module, cn, null); + } + + static Class findClass(Module module, String cn, Permission perm) { + try { + Class c = Class.forName(module, cn); + if (c == null) { + throw new RuntimeException(cn + " not found in " + module); + } + if (c.getModule() != module) { + throw new RuntimeException(c.getModule() + " != " + module); + } + return c; + } catch (AccessControlException e) { + if (e.getPermission().equals(perm)) + return null; + throw e; + } + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java new file mode 100644 index 00000000000..1c2ee70fcbc --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/NoGetClassLoaderAccess.java @@ -0,0 +1,69 @@ +/* + * 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 p3; + +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.security.AccessControlException; +import java.security.Permission; + +/** + * Verify RuntimePermission("getClassLoader") is needed to load + * a class in another module + */ +public class NoGetClassLoaderAccess { + private static final Module m3 = NoGetClassLoaderAccess.class.getModule(); + private static final Permission GET_CLASSLOADER_PERMISSION = new RuntimePermission("getClassLoader"); + + public static void main(String[] args) throws Exception { + Layer boot = Layer.boot(); + + System.setSecurityManager(new SecurityManager()); + Module m1 = boot.findModule("m1").get(); + Module m2 = boot.findModule("m2").get(); + findClass(m1, "p1.A"); + findClass(m1, "p1.internal.B"); + findClass(m2, "p2.C"); + findClass(m3, "p3.internal.Foo"); + } + + static Class findClass(Module module, String cn) { + try { + Class c = Class.forName(module, cn); + if (c == null) { + throw new RuntimeException(cn + " not found in " + module); + } + if (c.getModule() != module) { + throw new RuntimeException(c.getModule() + " != " + module); + } + return c; + } catch (AccessControlException e) { + if (module != m3) { + if (e.getPermission().equals(GET_CLASSLOADER_PERMISSION)) + return null; + } + throw e; + } + } +} diff --git a/jdk/test/java/lang/Class/forName/modules/src/m3/p3/internal/Foo.java b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/internal/Foo.java new file mode 100644 index 00000000000..c6693f1bafe --- /dev/null +++ b/jdk/test/java/lang/Class/forName/modules/src/m3/p3/internal/Foo.java @@ -0,0 +1,27 @@ +/* + * 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 p3.internal; + +public class Foo { +} diff --git a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java index 71ee0df8779..45a7b8e2259 100644 --- a/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java +++ b/jdk/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java @@ -23,7 +23,11 @@ import java.io.FilePermission; import java.io.IOException; +import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; +import java.lang.reflect.Module; +import java.lang.reflect.Modifier; +import java.lang.reflect.InaccessibleObjectException; import java.lang.reflect.ReflectPermission; import java.net.URI; import java.nio.file.FileSystem; @@ -47,6 +51,8 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; +import jdk.internal.module.Modules; + /** * @test * @bug 8065552 @@ -54,6 +60,7 @@ import java.util.stream.Stream; * set accessible if the right permission is granted; this test * loads all the classes in the BCL, get their declared fields, * and call setAccessible(false) followed by setAccessible(true); + * @modules java.base/jdk.internal.module * @run main/othervm FieldSetAccessibleTest UNSECURE * @run main/othervm FieldSetAccessibleTest SECURE * @@ -73,22 +80,47 @@ public class FieldSetAccessibleTest { // Test that all fields for any given class can be made accessibles - static void testSetFieldsAccessible(Class c) { + static void testSetFieldsAccessible(Class c, boolean expectException) { for (Field f : c.getDeclaredFields()) { fieldCount.incrementAndGet(); - f.setAccessible(false); - f.setAccessible(true); + boolean expect = expectException; + if ((c == Module.class || c == AccessibleObject.class) && + !Modifier.isPublic(f.getModifiers())) { + expect = true; + } + try { + f.setAccessible(false); + f.setAccessible(true); + if (expect) { + throw new RuntimeException( + String.format("Expected InaccessibleObjectException is not thrown " + + "for field %s in class %s%n", f.getName(), c.getName())); + } + } catch (InaccessibleObjectException expected) { + if (!expect) { + throw new RuntimeException(expected); + } + } } } // Performs a series of test on the given class. // At this time, we only call testSetFieldsAccessible(c) - public static boolean test(Class c) { - //System.out.println(c.getName()); + public static boolean test(Class c, boolean addExports) { + Module self = FieldSetAccessibleTest.class.getModule(); + Module target = c.getModule(); + String pn = c.getPackage().getName(); + boolean exported = self.canRead(target) && target.isExported(pn, self); + if (addExports && !exported) { + Modules.addExports(target, pn, self); + exported = true; + } + boolean expectException = !exported; + classCount.incrementAndGet(); // Call getDeclaredFields() and try to set their accessible flag. - testSetFieldsAccessible(c); + testSetFieldsAccessible(c, expectException); // add more tests here... @@ -154,17 +186,25 @@ public class FieldSetAccessibleTest { final long start = System.nanoTime(); boolean classFound = false; int index = 0; - for (String s: iterable) { + for (String s : iterable) { if (index == maxIndex) break; try { if (index < startIndex) continue; - if (test(s)) { + if (test(s, false)) { classFound = true; } } finally { index++; } } + + // Re-test with all packages exported + for (String s : iterable) { + test(s, true); + } + + classCount.set(classCount.get() / 2); + fieldCount.set(fieldCount.get() / 2); long elapsed = System.nanoTime() - start; long secs = elapsed / 1000_000_000; long millis = (elapsed % 1000_000_000) / 1000_000; @@ -187,17 +227,13 @@ public class FieldSetAccessibleTest { } } - static boolean test(String s) { + static boolean test(String s, boolean addExports) { try { - if (s.startsWith("WrapperGenerator")) { - System.out.println("Skipping "+ s); - return false; - } final Class c = Class.forName( s.replace('/', '.').substring(0, s.length() - 6), false, systemClassLoader); - return test(c); + return test(c, addExports); } catch (Exception t) { t.printStackTrace(System.err); failed.add(s); @@ -224,7 +260,7 @@ public class FieldSetAccessibleTest { .filter(x -> x.getNameCount() > 2) .map( x-> x.subpath(2, x.getNameCount())) .map( x -> x.toString()) - .filter(s -> s.endsWith(".class")); + .filter(s -> s.endsWith(".class") && !s.endsWith("module-info.class")); } @Override diff --git a/jdk/test/java/lang/Class/getPackageName/Basic.java b/jdk/test/java/lang/Class/getPackageName/Basic.java new file mode 100644 index 00000000000..e0c0bd17d3c --- /dev/null +++ b/jdk/test/java/lang/Class/getPackageName/Basic.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @compile Basic.java + * @run testng p.Basic + * @summary Basic test for java.lang.Class::getPackageName + */ + +package p; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.*; + +public class Basic { + + + // -- member classes -- + + static class Nested { + static class Foo { } + } + + Class getNestedClass1() { + return Nested.class; + } + Class getNestedClass2() { + return Nested.Foo.class; + } + + class Inner { + class Foo { } + } + + Class getInnerClass1() { + return Inner.class; + } + Class getInnerClass2() { + return Inner.Foo.class; + } + + // -- local and anonymous classes -- + + Class getLocalClass1() { + class Local { } + return Local.class; + } + + Class getLocalClass2() { + class Local { + class Foo { } + } + return Local.Foo.class; + } + + Class getLocalClass3() { + class Local { + final Class c; + Local() { + class Foo { } + this.c = Foo.class; + } + Class get() { + return c; + } + } + return new Local().get(); + } + + Class getAnonymousClass1() { + Runnable r = new Runnable() { public void run() { } }; + return r.getClass(); + } + + Class getAnonymousClass2() { + class Local { + Class get() { + Runnable r = new Runnable() { public void run() { } }; + return r.getClass(); + } + } + return new Local().get(); + } + + Class getAnonymousClass3() { + Runnable r = () -> { }; + return r.getClass(); + } + + Class getAnonymousClass4() { + class Local { + Class get() { + Runnable r = () -> { }; + return r.getClass(); + } + } + return new Local().get(); + } + + Class getAnonymousClass5() { + class Local { + final Class c; + Local() { + Runnable r = new Runnable() { public void run() { } }; + this.c = r.getClass(); + } + Class get() { + return c; + } + } + return new Local().get(); + } + + Class getAnonymousClass6() { + class Local { + final Class c; + Local() { + Runnable r = () -> { }; + this.c = r.getClass(); + } + Class get() { + return c; + } + } + return new Local().get(); + } + + static final String TEST_PACKAGE = Basic.class.getPackage().getName(); + + @DataProvider(name = "classes") + public Object[][] classes() { + return new Object[][] { + + { Basic.class, TEST_PACKAGE }, + { Basic[].class, null }, + { Basic[][].class, null }, + + { getNestedClass1(), TEST_PACKAGE }, + { getNestedClass2(), TEST_PACKAGE }, + { getInnerClass1(), TEST_PACKAGE }, + { getInnerClass2(), TEST_PACKAGE }, + + { getLocalClass1(), TEST_PACKAGE }, + { getLocalClass2(), TEST_PACKAGE }, + { getLocalClass3(), TEST_PACKAGE }, + + { getAnonymousClass1(), TEST_PACKAGE }, + { getAnonymousClass2(), TEST_PACKAGE }, + { getAnonymousClass3(), TEST_PACKAGE }, + { getAnonymousClass4(), TEST_PACKAGE }, + { getAnonymousClass5(), TEST_PACKAGE }, + { getAnonymousClass6(), TEST_PACKAGE }, + + { Object.class, "java.lang" }, + { Object[].class, null }, + { Object[][].class, null }, + + { int.class, null }, + { int[].class, null }, + { int[][].class, null }, + + { void.class, null }, + + }; + } + + @Test(dataProvider = "classes") + public void testPackageName(Class type, String expected) { + assertEquals(type.getPackageName(), expected); + } + +} diff --git a/jdk/test/java/lang/Class/getResource/Main.java b/jdk/test/java/lang/Class/getResource/Main.java new file mode 100644 index 00000000000..b1b45f3933e --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/Main.java @@ -0,0 +1,167 @@ +/* + * 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.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Basic test of Class getResource and getResourceAsStream when invoked from + * code in named modules. + */ + +public class Main { + + static final String NAME = "myresource"; + + public static void main(String[] args) throws IOException { + + // create m1/myresource containing "m1" + Path file = directoryFor("m1").resolve(NAME); + Files.write(file, "m1".getBytes("UTF-8")); + + // create m2/myresource containing "m2" + file = directoryFor("m2").resolve(NAME); + Files.write(file, "m2".getBytes("UTF-8")); + + // check that m3/myresource does not exist + assertTrue(Files.notExists(directoryFor("m3").resolve(NAME))); + + // invoke Class getResource from the unnamed module + URL url0 = Main.class.getResource("/" + NAME); + assertNull(url0); + + // invoke Class getResource from modules m1-m3 + URL url1 = p1.Main.getResource("/" + NAME); + URL url2 = p2.Main.getResource("/" + NAME); + URL url3 = p3.Main.getResource("/" + NAME); + assertNotNull(url1); + assertNotNull(url2); + assertNull(url3); + + // check contents of resurces at url1 and url2 + assertEquals(new String(readAll(url1), "UTF-8"), "m1"); + assertEquals(new String(readAll(url2), "UTF-8"), "m2"); + + // invoke Class getResourceAsStream from the unnamed module + InputStream in0 = Main.class.getResourceAsStream("/" + NAME); + assertNull(in0); + + // invoke Class getResourceAsStream from modules m1-m3 + try (InputStream in = p1.Main.getResourceAsStream("/" + NAME)) { + String s = new String(in.readAllBytes(), "UTF-8"); + assertEquals(s, "m1"); + } + try (InputStream in = p2.Main.getResourceAsStream("/" + NAME)) { + String s = new String(in.readAllBytes(), "UTF-8"); + assertEquals(s, "m2"); + } + InputStream in3 = p3.Main.getResourceAsStream("/" + NAME); + assertNull(in3); + + // invoke Module getResources on modules m1-m3 + InputStream in1 = p1.Main.class.getModule().getResourceAsStream("/" + NAME); + InputStream in2 = p2.Main.class.getModule().getResourceAsStream("/" + NAME); + in3 = p3.Main.class.getModule().getResourceAsStream("/" + NAME); + assertNotNull(in1); + assertNotNull(in2); + assertNull(in3); + + // check the content of in1 and in2 + String s1 = new String(in1.readAllBytes(), "UTF-8"); + String s2 = new String(in2.readAllBytes(), "UTF-8"); + assertEquals(s1, "m1"); + assertEquals(s2, "m2"); + + // SecurityManager case + System.setSecurityManager(new SecurityManager()); + + assertNull(Main.class.getResource("/" + NAME)); + assertNull(p1.Main.getResource("/" + NAME)); + assertNull(p2.Main.getResource("/" + NAME)); + assertNull(p3.Main.getResource("/" + NAME)); + + assertNull(Main.class.getResourceAsStream("/" + NAME)); + assertNull(p1.Main.getResourceAsStream("/" + NAME)); + assertNull(p2.Main.getResourceAsStream("/" + NAME)); + assertNull(p3.Main.getResourceAsStream("/" + NAME)); + + System.out.println("Success!"); + } + + /** + * Returns the directory for the given module (by name). + */ + static Path directoryFor(String name) { + Configuration cf = Layer.boot().configuration(); + ResolvedModule resolvedModule = cf.findModule(name).orElse(null); + if (resolvedModule == null) + throw new RuntimeException("not found: " + name); + Path dir = Paths.get(resolvedModule.reference().location().get()); + if (!Files.isDirectory(dir)) + throw new RuntimeException("not a directory: " + dir); + return dir; + } + + static byte[] readAll(URL url) throws IOException { + try (InputStream in = url.openStream()) { + return in.readAllBytes(); + } + } + + static void assertTrue(boolean condition) { + if (!condition) throw new RuntimeException(); + } + + static void assertNull(Object o) { + assertTrue(o == null); + } + + static void assertNotNull(Object o) { + assertTrue(o != null); + } + + static void assertEquals(Object actual, Object expected) { + if (expected == null) { + assertNull(actual); + } else { + assertTrue(expected.equals(actual)); + } + } + + static void assertNotEquals(Object actual, Object expected) { + if (expected == null) { + assertNotNull(actual); + } else { + assertTrue(!expected.equals(actual)); + } + } +} + diff --git a/jdk/test/java/lang/Class/getResource/ResourcesTest.java b/jdk/test/java/lang/Class/getResource/ResourcesTest.java new file mode 100644 index 00000000000..a78e3353f45 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/ResourcesTest.java @@ -0,0 +1,95 @@ +/* + * 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 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 ResourcesTest CompilerUtils jdk.testlibrary.* + * @run testng ResourcesTest + * @summary Driver for basic test of Class getResource and getResourceAsStream + */ + +@Test +public class ResourcesTest { + + 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 CLASSES_DIR = Paths.get("classes"); + private static final Path MODS_DIR = Paths.get("mods"); + + + /** + * Compiles the modules used by the test and the test Main + */ + @BeforeTest + public void compileAll() throws Exception { + boolean compiled; + + // javac -modulesource mods -d mods src/** + compiled = CompilerUtils + .compile(SRC_DIR, + MODS_DIR, + "-modulesourcepath", SRC_DIR.toString()); + assertTrue(compiled); + + // javac -mp mods -d classes Main.java + compiled = CompilerUtils + .compile(Paths.get(TEST_SRC, "Main.java"), + CLASSES_DIR, + "-mp", MODS_DIR.toString(), + "-addmods", "m1,m2,m3"); + assertTrue(compiled); + + } + + /** + * Run the test + */ + public void runTest() throws Exception { + + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "m1,m2,m3", + "-cp", CLASSES_DIR.toString(), + "Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + +} + diff --git a/jdk/test/java/lang/Class/getResource/src/m1/module-info.java b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java new file mode 100644 index 00000000000..47a2c4c1f77 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m1 { + exports p1; +} diff --git a/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java new file mode 100644 index 00000000000..afc13950f4c --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m1/p1/Main.java @@ -0,0 +1,39 @@ +/* + * 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.io.InputStream; +import java.net.URL; + +public class Main { + private Main() { } + + public static URL getResource(String name) { + return Main.class.getResource(name); + } + + public static InputStream getResourceAsStream(String name) { + return Main.class.getResourceAsStream(name); + } +} diff --git a/jdk/test/java/lang/Class/getResource/src/m2/module-info.java b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java new file mode 100644 index 00000000000..e28b2202567 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + exports p2; +} diff --git a/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java new file mode 100644 index 00000000000..51bdcf62cc5 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m2/p2/Main.java @@ -0,0 +1,39 @@ +/* + * 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 p2; + +import java.io.InputStream; +import java.net.URL; + +public class Main { + private Main() { } + + public static URL getResource(String name) { + return Main.class.getResource(name); + } + + public static InputStream getResourceAsStream(String name) { + return Main.class.getResourceAsStream(name); + } +} diff --git a/jdk/test/java/lang/Class/getResource/src/m3/module-info.java b/jdk/test/java/lang/Class/getResource/src/m3/module-info.java new file mode 100644 index 00000000000..f9754a0a870 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m3/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m3 { + exports p3; +} diff --git a/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java b/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java new file mode 100644 index 00000000000..08062e1d831 --- /dev/null +++ b/jdk/test/java/lang/Class/getResource/src/m3/p3/Main.java @@ -0,0 +1,39 @@ +/* + * 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 p3; + +import java.io.InputStream; +import java.net.URL; + +public class Main { + private Main() { } + + public static URL getResource(String name) { + return Main.class.getResource(name); + } + + public static InputStream getResourceAsStream(String name) { + return Main.class.getResourceAsStream(name); + } +} diff --git a/jdk/test/java/lang/ClassLoader/GetSystemPackage.java b/jdk/test/java/lang/ClassLoader/GetSystemPackage.java index 3e7d3261b98..fba5648f5f4 100644 --- a/jdk/test/java/lang/ClassLoader/GetSystemPackage.java +++ b/jdk/test/java/lang/ClassLoader/GetSystemPackage.java @@ -85,15 +85,15 @@ public class GetSystemPackage { buildJar("no-manifest.jar", null); runSubProcess("System package with manifest improperly resolved.", - "-Xbootclasspath/p:" + testClassesDir + "/manifest.jar", + "-Xbootclasspath/a:" + testClassesDir + "/manifest.jar", "GetSystemPackage", "system-manifest"); runSubProcess("System package from directory improperly resolved.", - "-Xbootclasspath/p:" + testClassesDir, "GetSystemPackage", + "-Xbootclasspath/a:" + testClassesDir, "GetSystemPackage", "system-no-manifest"); runSubProcess("System package with no manifest improperly resolved", - "-Xbootclasspath/p:" + testClassesDir + "/no-manifest.jar", + "-Xbootclasspath/a:" + testClassesDir + "/no-manifest.jar", "GetSystemPackage", "system-no-manifest"); runSubProcess("Classpath package with manifest improperly resolved", @@ -112,8 +112,6 @@ public class GetSystemPackage { testClassesDir + "/package2/Class2.class"); jar.addClassFile("GetSystemPackage.class", testClassesDir + "/GetSystemPackage.class"); - jar.addClassFile("GetSystemPackageClassLoader.class", - testClassesDir + "/GetSystemPackageClassLoader.class"); jar.build(); } @@ -128,9 +126,10 @@ public class GetSystemPackage { } private static void verifyPackage(boolean hasManifest, - boolean isSystemPackage) throws Exception + boolean isSystemPackage) + throws Exception { - Class c = Class.forName("package2.Class2"); + Class c = Class.forName("package2.Class2"); Package pkg = c.getPackage(); if (pkg == null || pkg != Package.getPackage("package2") || !"package2".equals(pkg.getName())) { @@ -148,14 +147,11 @@ public class GetSystemPackage { } if (!hasManifest && specificationTitle != null) { fail("Invalid manifest for package " + pkg.getName() + ": was " + - specificationTitle + " expected: null"); + specificationTitle + " expected: null"); } - // force the use of a classloader with no parent, then retrieve the - // package in a way that bypasses the classloader pkg maps - GetSystemPackageClassLoader classLoader = - new GetSystemPackageClassLoader(); - Package systemPkg = classLoader.getSystemPackage("package2"); + ClassLoader ld = c.getClassLoader(); + Package systemPkg = ld != null ? null : Package.getPackage("package2"); if (findPackage("java.lang") == null) { fail("java.lang not found via Package.getPackages()"); @@ -193,21 +189,6 @@ public class GetSystemPackage { } } -/* - * This classloader bypasses the system classloader to give as direct access - * to Package.getSystemPackage() as possible - */ -class GetSystemPackageClassLoader extends ClassLoader { - - public GetSystemPackageClassLoader() { - super(null); - } - - public Package getSystemPackage(String name) { - return super.getPackage(name); - } -} - /* * Helper class for building jar files */ diff --git a/jdk/test/java/lang/ClassLoader/findSystemClass/Loader.java b/jdk/test/java/lang/ClassLoader/findSystemClass/Loader.java index e141462a9ae..94f1726c6f1 100644 --- a/jdk/test/java/lang/ClassLoader/findSystemClass/Loader.java +++ b/jdk/test/java/lang/ClassLoader/findSystemClass/Loader.java @@ -44,7 +44,6 @@ * - Loadee.java (source for a class that refers to Loader) * - Loadee.classfile (to test findSystemClass) * - Loadee.resource (to test getSystemResource) - * - java/lang/Object.class (to test getSystemResources) * * The extension ".classfile" is so the class file is not seen by any loader * other than Loader. If you need to make any changes you will have to @@ -127,25 +126,6 @@ public class Loader extends ClassLoader { throw new Exception ("java.lang.ClassLoader.getSystemResource() test failed!"); } - - if ((tests & RESOURCES) == RESOURCES) { - report("getSystemResources()"); - java.util.Enumeration e = - getSystemResources("java/lang/Object.class"); - HashSet hs = new HashSet(); - while (e.hasMoreElements()) { - URL u = (URL)e.nextElement(); - if (u == null) - break; - System.out.println("url: " + u); - hs.add(u); - } - if (hs.size() != 2) { - throw - new Exception("java.lang.ClassLoader.getSystemResources()"+ - " did not find all resources"); - } - } } private static void report(String s) { diff --git a/jdk/test/java/lang/ClassLoader/getResource/GetResource.sh b/jdk/test/java/lang/ClassLoader/getResource/GetResource.sh index 2f178cd20b8..fc365dbd014 100644 --- a/jdk/test/java/lang/ClassLoader/getResource/GetResource.sh +++ b/jdk/test/java/lang/ClassLoader/getResource/GetResource.sh @@ -29,21 +29,12 @@ # # @run shell GetResource.sh -if [ "${TESTSRC}" = "" ] ; then - TESTSRC=`pwd` -fi -if [ "${TESTCLASSES}" = "" ] ; then - TESTCLASSES=`pwd` -fi - -if [ "${TESTJAVA}" = "" ] ; then - echo "TESTJAVA not set. Test cannot execute." - echo "FAILED!!!" - exit 1 -fi - -if [ "${COMPILEJAVA}" = "" ] ; then - COMPILEJAVA="${TESTJAVA}" +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" fi # set platform-specific variables @@ -96,12 +87,7 @@ setup "b" cd ${TESTCLASSES} DIR=`pwd` -# Expected -Xbootclasspath -# Location or -classpath -runTest "a" "-Xbootclasspath/p:a" -runTest "a" "-Xbootclasspath/p:a${PS}b" -runTest "b" "-Xbootclasspath/p:b" -runTest "b" "-Xbootclasspath/p:b${PS}a" +# Expected -classpath runTest "a" -cp a runTest "a" -cp "a${PS}b" runTest "b" -cp b @@ -109,16 +95,10 @@ runTest "b" -cp "b${PS}a" cd ${DIR}/a -runTest "a" "-Xbootclasspath/p:." -runTest "b" "-Xbootclasspath/p:../b" - # no -classpath runTest "a" -cp "${PS}" runTest "b" -cp "../b" -# Test empty path in bootclasspath not default to current working directory -runTest "b" "-Xbootclasspath/p:${PS}../b" - # Test empty path in classpath default to current working directory runTest "a" -cp "${PS}../b" diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java new file mode 100644 index 00000000000..a6436aff42e --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/Main.java @@ -0,0 +1,112 @@ +/* + * 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.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Basic test of ClassLoader getResource and getResourceAsStream when + * invoked from code in named modules. + */ + +public class Main { + + static final String NAME = "myresource"; + + public static void main(String[] args) throws IOException { + + // create m1/myresource containing "m1" + Path file = directoryFor("m1").resolve(NAME); + Files.write(file, "m1".getBytes("UTF-8")); + + // create m2/myresource containing "m2" + file = directoryFor("m2").resolve(NAME); + Files.write(file, "m2".getBytes("UTF-8")); + + // check that m3/myresource does not exist + assertTrue(Files.notExists(directoryFor("m3").resolve(NAME))); + + // invoke ClassLoader getResource from the unnamed module + assertNull(Main.class.getClassLoader().getResource("/" + NAME)); + + // invoke ClassLoader getResource from modules m1-m3 + // Resources in a named module are private to that module. + // ClassLoader.getResource should not find resource in named modules. + assertNull(p1.Main.getResourceInClassLoader("/" + NAME)); + assertNull(p2.Main.getResourceInClassLoader("/" + NAME)); + assertNull(p3.Main.getResourceInClassLoader("/" + NAME)); + + // invoke ClassLoader getResourceAsStream from the unnamed module + assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME)); + + // invoke ClassLoader getResourceAsStream from modules m1-m3 + // Resources in a named module are private to that module. + // ClassLoader.getResourceAsStream should not find resource in named modules. + assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME)); + assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME)); + assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME)); + + // SecurityManager case + System.setSecurityManager(new SecurityManager()); + + assertNull(Main.class.getClassLoader().getResource("/" + NAME)); + assertNull(p1.Main.getResourceInClassLoader("/" + NAME)); + assertNull(p2.Main.getResourceInClassLoader("/" + NAME)); + assertNull(p3.Main.getResourceInClassLoader("/" + NAME)); + + assertNull(Main.class.getClassLoader().getResourceAsStream("/" + NAME)); + assertNull(p1.Main.getResourceAsStreamInClassLoader("/" + NAME)); + assertNull(p2.Main.getResourceAsStreamInClassLoader("/" + NAME)); + assertNull(p3.Main.getResourceAsStreamInClassLoader("/" + NAME)); + + System.out.println("Success!"); + } + + /** + * Returns the directory for the given module (by name). + */ + static Path directoryFor(String mn) { + Configuration cf = Layer.boot().configuration(); + ResolvedModule resolvedModule = cf.findModule(mn).orElse(null); + if (resolvedModule == null) + throw new RuntimeException("not found: " + mn); + Path dir = Paths.get(resolvedModule.reference().location().get()); + if (!Files.isDirectory(dir)) + throw new RuntimeException("not a directory: " + dir); + return dir; + } + + static void assertTrue(boolean condition) { + if (!condition) throw new RuntimeException(); + } + + static void assertNull(Object o) { + assertTrue(o == null); + } +} + diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java new file mode 100644 index 00000000000..c6e1bcf764d --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/ResourcesTest.java @@ -0,0 +1,91 @@ +/* + * 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 static jdk.testlibrary.ProcessTools.executeTestJava; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * @test + * @bug 8087335 + * @library /lib/testlibrary + * @modules jdk.compiler + * @build ResourcesTest CompilerUtils jdk.testlibrary.* + * @run testng ResourcesTest + * @summary Driver for basic test of ClassLoader getResource and getResourceAsStream + */ + +@Test +public class ResourcesTest { + + 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 CLASSES_DIR = Paths.get("classes"); + private static final Path MODS_DIR = Paths.get("mods"); + + /** + * Compiles the modules used by the test and the test Main + */ + @BeforeTest + public void compileAll() throws Exception { + boolean compiled; + + // javac -modulesource mods -d mods src/** + compiled = CompilerUtils + .compile(SRC_DIR, + MODS_DIR, + "-modulesourcepath", SRC_DIR.toString()); + assertTrue(compiled); + + // javac -mp mods -d classes Main.java + compiled = CompilerUtils + .compile(Paths.get(TEST_SRC, "Main.java"), + CLASSES_DIR, + "-mp", MODS_DIR.toString(), + "-addmods", "m1,m2,m3"); + assertTrue(compiled); + } + + /** + * Run the test + */ + public void runTest() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "m1,m2,m3", + "-cp", CLASSES_DIR.toString(), + "Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } +} + diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java new file mode 100644 index 00000000000..47a2c4c1f77 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m1 { + exports p1; +} diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java new file mode 100644 index 00000000000..9e14eb0c226 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m1/p1/Main.java @@ -0,0 +1,39 @@ +/* + * 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.io.InputStream; +import java.net.URL; + +public class Main { + private Main() { } + + public static URL getResourceInClassLoader(String name) { + return Main.class.getClassLoader().getResource(name); + } + + public static InputStream getResourceAsStreamInClassLoader(String name) { + return Main.class.getClassLoader().getResourceAsStream(name); + } +} diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java new file mode 100644 index 00000000000..e28b2202567 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + exports p2; +} diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java new file mode 100644 index 00000000000..6f291a21969 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m2/p2/Main.java @@ -0,0 +1,39 @@ +/* + * 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 p2; + +import java.io.InputStream; +import java.net.URL; + +public class Main { + private Main() { } + + public static URL getResourceInClassLoader(String name) { + return Main.class.getClassLoader().getResource(name); + } + + public static InputStream getResourceAsStreamInClassLoader(String name) { + return Main.class.getClassLoader().getResourceAsStream(name); + } +} diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java new file mode 100644 index 00000000000..f9754a0a870 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m3 { + exports p3; +} diff --git a/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java new file mode 100644 index 00000000000..55a23b9efbe --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/getResource/modules/src/m3/p3/Main.java @@ -0,0 +1,39 @@ +/* + * 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 p3; + +import java.io.InputStream; +import java.net.URL; + +public class Main { + private Main() { } + + public static URL getResourceInClassLoader(String name) { + return Main.class.getClassLoader().getResource(name); + } + + public static InputStream getResourceAsStreamInClassLoader(String name) { + return Main.class.getClassLoader().getResourceAsStream(name); + } +} diff --git a/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java b/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java new file mode 100644 index 00000000000..d02c483ce38 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/platformClassLoader/DefinePlatformClass.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test java.* class defined by the platform class loader + * @build jdk.zipfs/java.fake.Fake + * @modules jdk.zipfs/java.fake + * @run main DefinePlatformClass + */ + +import java.fake.Fake; + +public class DefinePlatformClass { + public static void main(String... args) { + Fake fake = new Fake(); + fake.run(); + ClassLoader loader = fake.getClass().getClassLoader(); + if (loader != ClassLoader.getPlatformClassLoader()) { + throw new RuntimeException("unexpected class loader: " + loader); + } + } +} diff --git a/jdk/test/java/lang/ClassLoader/platformClassLoader/jdk.zipfs/java/fake/Fake.java b/jdk/test/java/lang/ClassLoader/platformClassLoader/jdk.zipfs/java/fake/Fake.java new file mode 100644 index 00000000000..67d7dc0bcc0 --- /dev/null +++ b/jdk/test/java/lang/ClassLoader/platformClassLoader/jdk.zipfs/java/fake/Fake.java @@ -0,0 +1,28 @@ +/* + * 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 java.fake; + +public class Fake { + public void run() {} +} diff --git a/jdk/test/java/lang/Package/Foo.java b/jdk/test/java/lang/Package/Foo.java new file mode 100644 index 00000000000..9243baed0fc --- /dev/null +++ b/jdk/test/java/lang/Package/Foo.java @@ -0,0 +1,34 @@ +/* + * 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 foo; + +public class Foo { + /** + * Returns all Packages visible to the class loader defining by + * this Foo class. Package.getPackages() is caller-sensitive. + */ + public static Package[] getPackages() { + return Package.getPackages(); + } +} + diff --git a/jdk/test/java/lang/Package/GetPackages.java b/jdk/test/java/lang/Package/GetPackages.java new file mode 100644 index 00000000000..3f0a4d92c28 --- /dev/null +++ b/jdk/test/java/lang/Package/GetPackages.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test Package object is local to each ClassLoader. + * There can be one Package object of "foo" name defined by + * different class loader. + * @compile Foo.java + * @run testng GetPackages + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.lang.reflect.*; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class GetPackages { + final TestClassLoader loader; + final Class fooClass; + /* + * Each TestClassLoader defines a "foo.Foo" class which has a unique + * Package object of "foo" regardless whether its ancestor class loader + * defines a package "foo" or not. + */ + GetPackages(TestClassLoader loader) throws ClassNotFoundException { + this.loader = loader; + this.fooClass = loader.loadClass("foo.Foo"); + } + + /* + * Check package "foo" defined locally in the TestClassLoader + * as well as its ancestors. + */ + void checkPackage() throws ClassNotFoundException { + // Name of an unnamed package is empty string + assertEquals(this.getClass().getPackage().getName(), ""); + + assertEquals(fooClass.getClassLoader(), loader); + + Package p = loader.getDefinedPackage("foo"); + assertEquals(p.getName(), "foo"); + assertEquals(p, loader.getPackage("foo")); + + if (loader.getParent() != null) { + Package p2 = ((TestClassLoader)loader.getParent()).getDefinedPackage("foo"); + assertTrue(p != p2); + } + + long count = Arrays.stream(loader.getDefinedPackages()) + .map(Package::getName) + .filter(pn -> pn.equals("foo")) + .count(); + assertEquals(count, 1); + } + + /* + * Check the number of package "foo" defined to this class loader and + * its ancestors + */ + Package[] getPackagesFromLoader() { + return loader.packagesInClassLoaderChain(); + } + + /* + * Package.getPackages is caller-sensitve. Call through Foo class + * to find all Packages visible to this TestClassLoader and its ancestors + */ + Package[] getPackagesFromFoo() throws Exception { + Method m = fooClass.getMethod("getPackages"); + return (Package[])m.invoke(null); + } + + private static long numFooPackages(Package[] pkgs) throws Exception { + return Arrays.stream(pkgs) + .filter(p -> p.getName().equals("foo")) + .count(); + } + + @DataProvider(name = "loaders") + public static Object[][] testLoaders() { + TestClassLoader loader1 = new TestClassLoader(null); + TestClassLoader loader2 = new TestClassLoader(loader1); + TestClassLoader loader3 = new TestClassLoader(loader2); + + // Verify the number of expected Package object of "foo" visible + // to the class loader + return new Object[][] { + { loader1, 1 }, + { loader2, 2 }, + { loader3, 3 } + }; + } + + @Test(dataProvider = "loaders") + public static void test(TestClassLoader loader, long expected) throws Exception { + GetPackages test = new GetPackages(loader); + // check package "foo" existence + test.checkPackage(); + + assertEquals(numFooPackages(test.getPackagesFromLoader()), expected); + assertEquals(numFooPackages(test.getPackagesFromFoo()), expected); + } +} + +class TestClassLoader extends ClassLoader { + public TestClassLoader() { + super(); + } + + public TestClassLoader(ClassLoader parent) { + super(parent); + } + + public Package getPackage(String pn) { + return super.getPackage(pn); + } + + public Package[] packagesInClassLoaderChain() { + return super.getPackages(); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + Path p = Paths.get(System.getProperty("test.classes", ".")); + + try { + byte[] bb = Files.readAllBytes(p.resolve("foo/Foo.class")); + return defineClass(name, bb, 0, bb.length); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + @Override + protected Class loadClass(String cn, boolean resolve) throws ClassNotFoundException { + if (!cn.equals("foo.Foo")) + return super.loadClass(cn, resolve); + return findClass(cn); + } +} diff --git a/jdk/test/java/lang/Package/annotation/PackageInfoTest.java b/jdk/test/java/lang/Package/annotation/PackageInfoTest.java new file mode 100644 index 00000000000..6e41390efa1 --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/PackageInfoTest.java @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Basic test of package-info in named module and duplicate + * package-info in unnamed module + * @modules java.compiler + * java.desktop + * jdk.compiler + * jdk.xml.dom + * @build jdk.xml.dom/org.w3c.dom.css.Fake + * jdk.xml.dom/org.w3c.dom.css.FakePackage + * @compile/module=jdk.xml.dom org/w3c/dom/css/package-info.java + * @compile package-info.java PackageInfoTest.java + * @run testng p.PackageInfoTest + */ + +package p; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.annotation.Annotation; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.css.CSSRule; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import static org.testng.Assert.*; + +public class PackageInfoTest { + @DataProvider(name = "jdkClasses") + public Object[][] jdkClasses() { + return new Object[][] { + { java.awt.Button.class, null }, + { java.lang.Object.class, null }, + { org.w3c.dom.css.CSSRule.class, null }, + { loadClass("org.w3c.dom.css.Fake"), loadClass("org.w3c.dom.css.FakePackage") }, + }; + } + + @Test(dataProvider = "jdkClasses") + public void testPackageInfo(Class type, Class annType) { + Package pkg = type.getPackage(); + assertTrue(pkg.isSealed()); + assertTrue(annType == null || pkg.getDeclaredAnnotations().length != 0); + if (annType != null) { + assertTrue(pkg.isAnnotationPresent(annType)); + } + } + + private Class loadClass(String name) { + return Class.forName(CSSRule.class.getModule(), name); + } + + @DataProvider(name = "classpathClasses") + public Object[][] cpClasses() throws IOException, ClassNotFoundException { + // these classes will be loaded from classpath in unnamed module + return new Object[][]{ + { p.PackageInfoTest.class, Deprecated.class } + }; + } + + @Test(dataProvider = "classpathClasses") + public void testClassPathPackage(Class type, Class annType) { + Package pkg = type.getPackage(); + assertTrue(pkg.isSealed() == false); + assertTrue(pkg.isAnnotationPresent(annType)); + } + + static final String[] otherClasses = new String[] { + "p/package-info.class", + "p/Duplicate.class", + "p/Bar.class" + }; + + @Test + public void testDuplicatePackage() throws Exception { + // a custom class loader loading another package p annotated with @Duplicate + Path classes = Paths.get(System.getProperty("test.classes", "."), "tmp"); + Files.createDirectories(classes); + URLClassLoader loader = new URLClassLoader(new URL[] { classes.toUri().toURL() }); + + // clean up before compiling classes + Arrays.stream(otherClasses) + .forEach(c -> { + try { + Files.deleteIfExists(classes.resolve(c)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + + Path src = Paths.get(System.getProperty("test.src", "."), "src", "p"); + compile(classes, + src.resolve("package-info.java"), + src.resolve("Duplicate.java"), + src.resolve("Bar.java")); + + // verify if classes are present + Arrays.stream(otherClasses) + .forEach(c -> { + if (Files.notExists(classes.resolve(c))) { + throw new RuntimeException(c + " not exist"); + } + }); + + Class c = Class.forName("p.Bar", true, loader); + assertTrue(c.getClassLoader() == loader); + assertTrue(this.getClass().getClassLoader() != loader); + + // package p defined by the custom class loader + Package pkg = c.getPackage(); + assertTrue(pkg.getName().equals("p")); + assertTrue(pkg.isSealed() == false); + + // package p defined by the application class loader + Package p = this.getClass().getPackage(); + assertTrue(p.getName().equals("p")); + assertTrue(p != pkg); + + Arrays.stream(pkg.getDeclaredAnnotations()) + .forEach(ann -> System.out.format("%s @%s%n", pkg.getName(), ann)); + + Arrays.stream(p.getDeclaredAnnotations()) + .forEach(ann -> System.out.format("%s @%s%n", p.getName(), ann)); + + // local package p defined by loader + Class ann = + (Class)Class.forName("p.Duplicate", false, loader); + assertTrue(pkg.isAnnotationPresent(ann)); + } + + private void compile(Path destDir, Path... files) throws IOException { + compile(null, destDir, files); + } + + private void compile(String option, Path destDir, Path... files) + throws IOException + { + System.err.println("compile..."); + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) { + Iterable fileObjects = + fm.getJavaFileObjectsFromPaths(Arrays.asList(files)); + + List options = new ArrayList<>(); + if (option != null) { + options.add(option); + } + if (destDir != null) { + options.add("-d"); + options.add(destDir.toString()); + } + options.add("-cp"); + options.add(System.getProperty("test.classes", ".")); + + JavaCompiler.CompilationTask task = + compiler.getTask(null, fm, null, options, null, fileObjects); + if (!task.call()) + throw new AssertionError("compilation failed"); + } + } + +} diff --git a/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/Fake.java b/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/Fake.java new file mode 100644 index 00000000000..88e5fb654bd --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/Fake.java @@ -0,0 +1,26 @@ +/* + * 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 org.w3c.dom.css; + +public class Fake {} diff --git a/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/FakePackage.java b/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/FakePackage.java new file mode 100644 index 00000000000..4323286115e --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/FakePackage.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.w3c.dom.css; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(value={PACKAGE}) +public @interface FakePackage { +} + diff --git a/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/package-info.java b/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/package-info.java new file mode 100644 index 00000000000..7d200df0f13 --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/jdk.xml.dom/org/w3c/dom/css/package-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +@FakePackage +package org.w3c.dom.css; diff --git a/jdk/test/java/lang/Package/annotation/package-info.java b/jdk/test/java/lang/Package/annotation/package-info.java new file mode 100644 index 00000000000..6b5931c642c --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/package-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +@Deprecated +package p; diff --git a/jdk/test/java/lang/Package/annotation/src/p/Bar.java b/jdk/test/java/lang/Package/annotation/src/p/Bar.java new file mode 100644 index 00000000000..0f23144f7b7 --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/src/p/Bar.java @@ -0,0 +1,26 @@ +/* + * 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 p; + +public class Bar {} diff --git a/jdk/test/java/lang/Package/annotation/src/p/Duplicate.java b/jdk/test/java/lang/Package/annotation/src/p/Duplicate.java new file mode 100644 index 00000000000..eacbd892282 --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/src/p/Duplicate.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +import java.lang.annotation.*; +import static java.lang.annotation.ElementType.*; + +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(value={PACKAGE}) +public @interface Duplicate { +} + diff --git a/jdk/test/java/lang/Package/annotation/src/p/package-info.java b/jdk/test/java/lang/Package/annotation/src/p/package-info.java new file mode 100644 index 00000000000..2975a181262 --- /dev/null +++ b/jdk/test/java/lang/Package/annotation/src/p/package-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +@Duplicate +package p; diff --git a/jdk/test/java/lang/SecurityManager/RestrictedPackages.java b/jdk/test/java/lang/SecurityManager/RestrictedPackages.java index 546df6b1661..56d0ed5ea13 100644 --- a/jdk/test/java/lang/SecurityManager/RestrictedPackages.java +++ b/jdk/test/java/lang/SecurityManager/RestrictedPackages.java @@ -77,6 +77,7 @@ final class RestrictedPackages { "jdk.internal.", "jdk.nashorn.internal.", "jdk.nashorn.tools.", + "jdk.rmi.rmic.", "jdk.tools.jimage.", "com.sun.activation.registries.", "com.sun.java.accessibility.util.internal." diff --git a/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.sh b/jdk/test/java/lang/SecurityManager/modules/CustomSecurityManager.sh similarity index 54% rename from jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.sh rename to jdk/test/java/lang/SecurityManager/modules/CustomSecurityManager.sh index eac0315e7e3..e722677fd3f 100644 --- a/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.sh +++ b/jdk/test/java/lang/SecurityManager/modules/CustomSecurityManager.sh @@ -1,7 +1,5 @@ -#! /bin/sh - # -# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -23,30 +21,46 @@ # questions. # +# @test +# @summary Basic test of -Djava.security.manager to a class in named module. + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC=`pwd` + TESTCLASSES=`pwd` +fi -# set platform-dependent variables OS=`uname -s` case "$OS" in - SunOS | Darwin | AIX ) - PATHSEP=":" - FILESEP="/" - ;; - Linux ) - PATHSEP=":" - FILESEP="/" + Windows*) + PS=";" ;; CYGWIN* ) - PATHSEP=";" - FILESEP="/" - ;; - Windows* ) - PATHSEP=";" - FILESEP="\\" + PS=";" ;; * ) - echo "Unrecognized system!" - exit 1; + PS=":" ;; esac -${TESTJAVA}${FILESEP}bin${FILESEP}java ${TESTVMOPTS} -Xbootclasspath/p:${TESTCLASSES} ADatagramSocket true +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java ${TESTVMOPTS}" + +mkdir -p mods +$JAVAC -d mods -modulesourcepath ${TESTSRC} `find ${TESTSRC}/m -name "*.java"` + +mkdir -p classes +$JAVAC -d classes ${TESTSRC}/Test.java + +$JAVA -cp classes -mp mods -addmods m \ + -Djava.security.manager \ + -Djava.security.policy=${TESTSRC}/test.policy Test +$JAVA -cp classes -mp mods -addmods m \ + -Djava.security.manager=p.CustomSecurityManager \ + -Djava.security.policy=${TESTSRC}/test.policy Test + +exit 0 diff --git a/jdk/test/java/lang/SecurityManager/modules/Test.java b/jdk/test/java/lang/SecurityManager/modules/Test.java new file mode 100644 index 00000000000..81cf617aa79 --- /dev/null +++ b/jdk/test/java/lang/SecurityManager/modules/Test.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +import java.lang.reflect.Module; + +public class Test { + public static void main(String... args) { + SecurityManager sm = System.getSecurityManager(); + Module module = sm.getClass().getModule(); + String s = System.getProperty("java.security.manager"); + String expected = s.isEmpty() ? "java.base" : "m"; + if (!module.isNamed() || !module.getName().equals(expected)) { + throw new RuntimeException(module + " expected module m instead"); + } + } +} diff --git a/jdk/test/java/lang/SecurityManager/modules/m/module-info.java b/jdk/test/java/lang/SecurityManager/modules/m/module-info.java new file mode 100644 index 00000000000..cf46bcc808e --- /dev/null +++ b/jdk/test/java/lang/SecurityManager/modules/m/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m { +} diff --git a/jdk/test/java/lang/SecurityManager/modules/m/p/CustomSecurityManager.java b/jdk/test/java/lang/SecurityManager/modules/m/p/CustomSecurityManager.java new file mode 100644 index 00000000000..bc6e22ddbca --- /dev/null +++ b/jdk/test/java/lang/SecurityManager/modules/m/p/CustomSecurityManager.java @@ -0,0 +1,29 @@ +/* + * 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 p; + +public class CustomSecurityManager extends SecurityManager { + public CustomSecurityManager() { + } +} diff --git a/jdk/test/java/lang/SecurityManager/modules/test.policy b/jdk/test/java/lang/SecurityManager/modules/test.policy new file mode 100644 index 00000000000..a3929e36b54 --- /dev/null +++ b/jdk/test/java/lang/SecurityManager/modules/test.policy @@ -0,0 +1,3 @@ +grant { + permission java.util.PropertyPermission "*", "read"; +}; diff --git a/jdk/test/java/lang/StackTraceElement/ModuleFrames.java b/jdk/test/java/lang/StackTraceElement/ModuleFrames.java new file mode 100644 index 00000000000..a3b66759a13 --- /dev/null +++ b/jdk/test/java/lang/StackTraceElement/ModuleFrames.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Stack trace should have module information + * @run testng ModuleFrames + */ + +import java.util.Arrays; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class ModuleFrames { + + @Test + public void testModuleName() { + try { + Integer.parseInt("a"); + } catch (NumberFormatException e) { + + StackTraceElement[] stack = e.getStackTrace(); + StackTraceElement topFrame = stack[0]; + StackTraceElement thisFrame = findFrame(this.getClass().getName(), stack); + + assertEquals(topFrame.getModuleName(), "java.base", + "Expected top frame to be in module java.base"); + + assertTrue(topFrame.toString().contains("java.base"), + "Expected toString of top frame to include java.base"); + + assertNull(thisFrame.getModuleName(), + "Expected frame for test not to have a module name"); + } + } + + private static StackTraceElement findFrame(String cn, StackTraceElement[] stack) { + return Arrays.stream(stack) + .filter(s -> s.getClassName().equals(cn)) + .findFirst() + .get(); + } +} diff --git a/jdk/test/java/lang/StackTraceElement/PublicConstructor.java b/jdk/test/java/lang/StackTraceElement/PublicConstructor.java index b83538e8e9c..b4ec9a4d47c 100644 --- a/jdk/test/java/lang/StackTraceElement/PublicConstructor.java +++ b/jdk/test/java/lang/StackTraceElement/PublicConstructor.java @@ -41,9 +41,25 @@ public class PublicConstructor { throw new RuntimeException("1"); if (ste.isNativeMethod()) throw new RuntimeException("2"); - StackTraceElement ste2 = new StackTraceElement("com.acme.Widget", - "frobnicate", "Widget.java", -2); - if (!ste2.isNativeMethod()) + StackTraceElement ste2 + = new StackTraceElement("jdk.module", + "9.0", + "com.acme.Widget", + "frobnicate", + "Widget.java", + 42); + if (!(ste2.getClassName().equals("com.acme.Widget") && + ste2.getModuleName().equals("jdk.module") && + ste2.getModuleVersion().equals("9.0") && + ste2.getFileName().equals("Widget.java") && + ste2.getMethodName().equals("frobnicate") && + ste2.getLineNumber() == 42)) throw new RuntimeException("3"); + if (ste2.isNativeMethod()) + throw new RuntimeException("4"); + StackTraceElement ste3 = new StackTraceElement("com.acme.Widget", + "frobnicate", "Widget.java", -2); + if (!ste3.isNativeMethod()) + throw new RuntimeException("5"); } } diff --git a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java index c6c46fb82d2..b5f8653bc1b 100644 --- a/jdk/test/java/lang/StackWalker/VerifyStackTrace.java +++ b/jdk/test/java/lang/StackWalker/VerifyStackTrace.java @@ -72,7 +72,7 @@ public class VerifyStackTrace { "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:158)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:188)\n" + "5: VerifyStackTrace$1.run(VerifyStackTrace.java:218)\n" + - "6: java.security.AccessController.doPrivileged(Native Method)\n" + + "6: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + "7: VerifyStackTrace.test(VerifyStackTrace.java:227)\n" + "8: VerifyStackTrace.main(VerifyStackTrace.java:182)\n"; @@ -101,12 +101,12 @@ public class VerifyStackTrace { "2: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:147)\n" + "3: VerifyStackTrace$Handle.run(VerifyStackTrace.java:160)\n" + "4: VerifyStackTrace.invoke(VerifyStackTrace.java:190)\n" + - "5: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + - "6: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + - "7: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + - "8: java.lang.reflect.Method.invoke(Method.java:520)\n" + + "5: sun.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + + "6: sun.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + + "7: sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + + "8: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + "9: VerifyStackTrace$1.run(VerifyStackTrace.java:220)\n" + - "10: java.security.AccessController.doPrivileged(Native Method)\n" + + "10: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + "11: VerifyStackTrace.test(VerifyStackTrace.java:229)\n" + "12: VerifyStackTrace.main(VerifyStackTrace.java:185)\n"; @@ -134,16 +134,16 @@ public class VerifyStackTrace { "1: VerifyStackTrace.lambda$test$1(VerifyStackTrace.java:213)\n" + "2: VerifyStackTrace$$Lambda$1/662441761.run(Unknown Source)\n" + "3: VerifyStackTrace$Handle.execute(VerifyStackTrace.java:149)\n" + - "4: java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(LambdaForm$DMH)\n" + - "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(LambdaForm$MH)\n" + + "4: java.lang.invoke.LambdaForm$DMH/2008017533.invokeVirtual_LL_V(java.base/LambdaForm$DMH)\n" + + "5: java.lang.invoke.LambdaForm$MH/1395089624.invoke_MT(java.base/LambdaForm$MH)\n" + "6: VerifyStackTrace$Handle.run(VerifyStackTrace.java:162)\n" + "7: VerifyStackTrace.invoke(VerifyStackTrace.java:192)\n" + - "8: sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n" + - "9: sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\n" + - "10: sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n" + - "11: java.lang.reflect.Method.invoke(Method.java:520)\n" + + "8: sun.reflect.NativeMethodAccessorImpl.invoke0(java.base/Native Method)\n" + + "9: sun.reflect.NativeMethodAccessorImpl.invoke(java.base/NativeMethodAccessorImpl.java:62)\n" + + "10: sun.reflect.DelegatingMethodAccessorImpl.invoke(java.base/DelegatingMethodAccessorImpl.java:43)\n" + + "11: java.lang.reflect.Method.invoke(java.base/Method.java:520)\n" + "12: VerifyStackTrace$1.run(VerifyStackTrace.java:222)\n" + - "13: java.security.AccessController.doPrivileged(Native Method)\n" + + "13: java.security.AccessController.doPrivileged(java.base/Native Method)\n" + "14: VerifyStackTrace.test(VerifyStackTrace.java:231)\n" + "15: VerifyStackTrace.main(VerifyStackTrace.java:188)\n"; @@ -202,6 +202,8 @@ public class VerifyStackTrace { // out before comparing. We also erase the hash-like names of // synthetic frames introduced by lambdas & method handles return produced.replaceAll(":[1-9][0-9]*\\)", ":00)") + .replaceAll("-internal/", "/").replaceAll("-ea/", "/") + .replaceAll("java.base@[0-9]+/", "java.base/") .replaceAll("/[0-9]+\\.run", "/xxxxxxxx.run") .replaceAll("/[0-9]+\\.invoke", "/xxxxxxxx.invoke") .replaceAll("\\$[0-9]+", "\\$??"); diff --git a/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java b/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java index 9afc5e7b559..b48610a91f2 100644 --- a/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java +++ b/jdk/test/java/lang/instrument/ATransformerManagementTestCase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ import java.io.*; import java.lang.instrument.*; +import java.lang.reflect.Module; import java.security.ProtectionDomain; import java.util.*; @@ -291,7 +292,25 @@ ATransformerManagementTestCase // The transform testing is triggered by redefine, ignore others if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this); - return super.transform( loader, + return super.transform( loader, + className, + classBeingRedefined, + protectionDomain, + classfileBuffer); + } + + public byte[] + transform( + Module module, + String className, + Class classBeingRedefined, + ProtectionDomain protectionDomain, + byte[] classfileBuffer) { + + // The transform testing is triggered by redefine, ignore others + if (classBeingRedefined != null) checkInTransformer(MyClassFileTransformer.this); + + return super.transform( module, className, classBeingRedefined, protectionDomain, diff --git a/jdk/test/java/lang/instrument/BootClassPath/Agent.java b/jdk/test/java/lang/instrument/BootClassPath/Agent.java index a233d4639cb..b072e5fae7d 100644 --- a/jdk/test/java/lang/instrument/BootClassPath/Agent.java +++ b/jdk/test/java/lang/instrument/BootClassPath/Agent.java @@ -33,10 +33,7 @@ import java.lang.instrument.Instrumentation; public class Agent { public static void premain(String options, Instrumentation ins) throws Exception { - String bootclasspath = System.getProperty("sun.boot.class.path"); - System.out.println("bootclasspath: " + bootclasspath); - - Class c = Class.forName("AgentSupport"); + Class c = Class.forName("AgentSupport"); ClassLoader cl = c.getClassLoader(); if (cl != null) { System.err.println("AgentSupport loaded by: " + cl); diff --git a/jdk/test/java/lang/instrument/MakeJAR2.sh b/jdk/test/java/lang/instrument/MakeJAR2.sh index 596a0d47ed1..ec76b820472 100644 --- a/jdk/test/java/lang/instrument/MakeJAR2.sh +++ b/jdk/test/java/lang/instrument/MakeJAR2.sh @@ -86,7 +86,8 @@ cd bootpath ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} bootreporter/*.java cd .. -${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -XDignore.symbol.file ${AGENT}.java asmlib/*.java +${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -XaddExports:java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED ${AGENT}.java asmlib/*.java ${JAVAC} ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -classpath .${PATHSEP}bootpath ${APP}.java echo "Manifest-Version: 1.0" > ${AGENT}.mf diff --git a/jdk/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java b/jdk/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java index ad1a725b966..b1146712f30 100644 --- a/jdk/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java +++ b/jdk/test/java/lang/instrument/RedefineClassWithNativeMethodAgent.java @@ -21,10 +21,12 @@ * questions. */ -import java.lang.instrument.*; -import java.net.*; -import java.util.*; -import java.io.*; +import java.io.InputStream; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Module; +import java.util.Timer; +import java.util.TimerTask; public class RedefineClassWithNativeMethodAgent { static Class clz; @@ -33,29 +35,20 @@ public class RedefineClassWithNativeMethodAgent { public static void premain(String agentArgs, final Instrumentation inst) throws Exception { String s = agentArgs.substring(0, agentArgs.indexOf(".class")); clz = Class.forName(s.replace('/', '.')); - ClassLoader loader = - RedefineClassWithNativeMethodAgent.class.getClassLoader(); - URL classURL = loader.getResource(agentArgs); - if (classURL == null) { + InputStream in; + Module m = clz.getModule(); + if (m != null) { + in = m.getResourceAsStream(agentArgs); + } else { + ClassLoader loader = + RedefineClassWithNativeMethodAgent.class.getClassLoader(); + in = loader.getResourceAsStream(agentArgs); + } + if (in == null) { throw new Exception("Cannot find class: " + agentArgs); } + byte[] buffer = in.readAllBytes(); - int redefineLength; - InputStream redefineStream; - - System.out.println("Reading test class from " + classURL); - if (classURL.getProtocol().equals("file")) { - File f = new File(classURL.getFile()); - redefineStream = new FileInputStream(f); - redefineLength = (int) f.length(); - } else { - URLConnection conn = classURL.openConnection(); - redefineStream = conn.getInputStream(); - redefineLength = conn.getContentLength(); - } - - final byte[] buffer = new byte[redefineLength]; - new BufferedInputStream(redefineStream).read(buffer); new Timer(true).schedule(new TimerTask() { public void run() { try { diff --git a/jdk/test/java/lang/instrument/RetransformAgent.java b/jdk/test/java/lang/instrument/RetransformAgent.java index 920fffbb0b1..19cd34e60a7 100644 --- a/jdk/test/java/lang/instrument/RetransformAgent.java +++ b/jdk/test/java/lang/instrument/RetransformAgent.java @@ -34,6 +34,7 @@ */ import java.lang.instrument.*; +import java.lang.reflect.Module; import java.security.ProtectionDomain; import java.io.*; import asmlib.*; @@ -67,12 +68,13 @@ class RetransformAgent { this.nname = nname; } - public byte[] transform(ClassLoader loader, + public byte[] transform(Module module, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { boolean redef = classBeingRedefined != null; + // System.err.println("hook " + trname + ": " + className + // (redef? " REDEF" : " LOAD")); if ((redef? onRedef : onLoad) && className != null && className.equals(cname)) { diff --git a/jdk/test/java/lang/instrument/SimpleIdentityTransformer.java b/jdk/test/java/lang/instrument/SimpleIdentityTransformer.java index cf4b987cbf2..d8fc0c07874 100644 --- a/jdk/test/java/lang/instrument/SimpleIdentityTransformer.java +++ b/jdk/test/java/lang/instrument/SimpleIdentityTransformer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ import java.lang.instrument.Instrumentation; import java.lang.instrument.ClassFileTransformer; +import java.lang.reflect.Module; import java.security.*; /* @@ -59,4 +60,16 @@ SimpleIdentityTransformer implements ClassFileTransformer { return newBuffer; } + public byte[] + transform( + Module module, + String className, + Class classBeingRedefined, + ProtectionDomain protectionDomain, + byte[] classfileBuffer) { + byte[] newBuffer = new byte[classfileBuffer.length]; + System.arraycopy(classfileBuffer, 0, newBuffer, 0, classfileBuffer.length); + + return newBuffer; + } } diff --git a/jdk/test/java/lang/invoke/AccessControlTest.java b/jdk/test/java/lang/invoke/AccessControlTest.java index 5e6fc14a0fb..57cec50b2ec 100644 --- a/jdk/test/java/lang/invoke/AccessControlTest.java +++ b/jdk/test/java/lang/invoke/AccessControlTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ package test.java.lang.invoke; import java.lang.invoke.*; import java.lang.reflect.*; +import java.lang.reflect.Modifier; import java.util.*; import org.testng.*; import org.testng.annotations.*; @@ -117,11 +118,13 @@ public class AccessControlTest { suffix = "/noaccess"; else if (lookupModes == PUBLIC) suffix = "/public"; - else if (lookupModes == (PUBLIC|PACKAGE)) + else if (lookupModes == (PUBLIC|MODULE)) + suffix = "/module"; + else if (lookupModes == (PUBLIC|MODULE|PACKAGE)) suffix = "/package"; - else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE)) + else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE)) suffix = "/private"; - else if (lookupModes == (PUBLIC|PACKAGE|PRIVATE|PROTECTED)) + else if (lookupModes == (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED)) suffix = ""; else suffix = "/#"+Integer.toHexString(lookupModes); @@ -147,16 +150,26 @@ public class AccessControlTest { *

      • [A6] If the new lookup class is not accessible to the old lookup class, * using the original access modes, * then no members, not even public members, will be accessible. - * [A7] (In all other cases, public members will continue to 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.) * * Other than the above cases, the new lookup will have the same - * access capabilities as the original. [A8] + * access capabilities as the original. [A10] *
        */ public LookupCase in(Class c2) { Class c1 = lookupClass(); int m1 = lookupModes(); int changed = 0; + // for the purposes of access control then treat classes in different unnamed + // modules as being in the same module. + boolean sameModule = (c1.getModule() == c2.getModule()) || + (!c1.getModule().isNamed() && !c2.getModule().isNamed()); boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() && packagePrefix(c1).equals(packagePrefix(c2))); boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2)); @@ -166,12 +179,20 @@ public class AccessControlTest { boolean accessible = sameClass; // [A6] if ((m1 & PACKAGE) != 0) accessible |= samePackage; if ((m1 & PUBLIC ) != 0) accessible |= (c2.getModifiers() & PUBLIC) != 0; + if (!sameModule) { + if (c1.getModule().isNamed()) { + accessible = false; // [A8] + } else { + // Different module; loose MODULE and lower access. + changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED); // [A7] + } + } if (!accessible) { // Different package and no access to c2; lose all access. - changed |= (PUBLIC|PACKAGE|PRIVATE|PROTECTED); // [A6] + changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED); // [A6] } if (!samePackage) { - // Different package; lose PACKAGE and lower access. + // Different package; loose PACKAGE and lower access. changed |= (PACKAGE|PRIVATE|PROTECTED); // [A4] } if (!sameTopLevel) { @@ -181,9 +202,9 @@ public class AccessControlTest { if (!sameClass) { changed |= (PROTECTED); // [A3] } else { - assert(changed == 0); // [A8] (no deprivation if same class) + assert(changed == 0); // [A10] (no deprivation if same class) } - if (accessible) assert((changed & PUBLIC) == 0); // [A7] + if (accessible) assert((changed & PUBLIC) == 0); // [A9] int m2 = m1 & ~changed; LookupCase l2 = new LookupCase(c2, m2); assert(l2.lookupClass() == c2); // [A1] @@ -206,6 +227,16 @@ public class AccessControlTest { public boolean willAccess(Method m) { 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()) + && (lookupModes & PUBLIC) != 0 + && (!c2.getModule().isNamed()) + && Modifier.isPublic(c2.getModifiers()) + && Modifier.isPublic(m.getModifiers())) + return true; + LookupCase lc = this.in(c2); int m1 = lc.lookupModes(); int m2 = fixMods(m.getModifiers()); @@ -227,9 +258,25 @@ public class AccessControlTest { /** Predict the success or failure of accessing this class. */ public boolean willAccessClass(Class c2, boolean load) { Class c1 = lookupClass(); - if (load && c1.getClassLoader() == null) { + 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()) + && (lookupModes & PUBLIC) != 0 + && (!c2.getModule().isNamed()) + && Modifier.isPublic(c2.getModifiers())) + return true; + LookupCase lc = this.in(c2); int m1 = lc.lookupModes(); boolean r = false; @@ -248,6 +295,11 @@ 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) { @@ -303,7 +355,7 @@ public class AccessControlTest { LookupCase expect = l1.in(c2); if (!expect.equals(l2)) System.out.println("*** expect "+l1+" => "+expect+" but got "+l2); - assertEquals(expect, l2); + assertEquals(l2, expect); } } @@ -420,6 +472,7 @@ public class AccessControlTest { } static Method targetMethod(Class targetClass, int targetAccess, MethodType methodType) { + assert targetAccess != MODULE; String methodName = accessName(targetAccess)+placeName(targetClass); if (verbosity >= 2) System.out.println(targetClass.getSimpleName()+"."+methodName+methodType); @@ -453,6 +506,7 @@ public class AccessControlTest { assert(false); return "?"; } + // MODULE not a test case at this time private static final int[] ACCESS_CASES = { PUBLIC, PACKAGE, PRIVATE, PROTECTED }; diff --git a/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java b/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java index 3e2467363be..5b439faad79 100644 --- a/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java +++ b/jdk/test/java/lang/invoke/CustomizedLambdaFormTest.java @@ -21,21 +21,25 @@ * questions. */ -package java.lang.invoke; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodType; /* @test * @summary Assertion in LambdaFormEditor.bindArgumentType is too strong * - * @run main/bootclasspath -esa java.lang.invoke.CustomizedLambdaFormTest + * @compile/module=java.base java/lang/invoke/MethodHandleHelper.java + * @run main/othervm -esa CustomizedLambdaFormTest */ + public class CustomizedLambdaFormTest { static void testExtendCustomizedBMH() throws Exception { // Construct BMH - MethodHandle mh = MethodHandles.Lookup.IMPL_LOOKUP.findVirtual(String.class, "concat", + MethodHandle mh = MethodHandleHelper.IMPL_LOOKUP.findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class)) .bindTo("a"); - mh.customize(); + MethodHandleHelper.customize(mh); mh.bindTo("b"); // Try to extend customized BMH } diff --git a/jdk/test/java/lang/invoke/MethodHandlesTest.java b/jdk/test/java/lang/invoke/MethodHandlesTest.java index 7b578a4bf3f..3370767940b 100644 --- a/jdk/test/java/lang/invoke/MethodHandlesTest.java +++ b/jdk/test/java/lang/invoke/MethodHandlesTest.java @@ -386,7 +386,7 @@ public class MethodHandlesTest { static final Lookup PACKAGE = PackageSibling.lookup(); // This lookup is good for public members and protected members of PubExample static final Lookup SUBCLASS = RemoteExample.lookup(); - // This lookup is good only for public members. + // This lookup is good only for public members in exported packages. static final Lookup PUBLIC = MethodHandles.publicLookup(); // Subject methods... @@ -634,10 +634,15 @@ public class MethodHandlesTest { public void testFindVirtualClone0() throws Throwable { // test some ad hoc system methods testFindVirtual(false, PUBLIC, Object.class, Object.class, "clone"); + + // ##### FIXME - disable tests for clone until we figure out how they should work with modules + + /* testFindVirtual(true, PUBLIC, Object[].class, Object.class, "clone"); testFindVirtual(true, PUBLIC, int[].class, Object.class, "clone"); for (Class cls : new Class[]{ boolean[].class, long[].class, float[].class, char[].class }) testFindVirtual(true, PUBLIC, cls, Object.class, "clone"); + */ } void testFindVirtual(Class defc, Class ret, String name, Class... params) throws Throwable { diff --git a/jdk/test/java/lang/invoke/VarargsArrayTest.java b/jdk/test/java/lang/invoke/VarargsArrayTest.java index a247fa5b434..98e069835a7 100644 --- a/jdk/test/java/lang/invoke/VarargsArrayTest.java +++ b/jdk/test/java/lang/invoke/VarargsArrayTest.java @@ -21,8 +21,10 @@ * questions. */ -package java.lang.invoke; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleHelper; +import java.lang.invoke.MethodType; import sun.invoke.util.Wrapper; import java.util.Arrays; import java.util.Collections; @@ -31,14 +33,16 @@ import com.oracle.testlibrary.jsr292.CodeCacheOverflowProcessor; /* @test * @summary unit tests for varargs array methods: MethodHandleInfo.varargsArray(int), * MethodHandleInfo.varargsArray(Class,int) & MethodHandleInfo.varargsList(int) + * @modules java.base/sun.invoke.util * @library /lib/testlibrary /lib/testlibrary/jsr292 - * @run main/bootclasspath java.lang.invoke.VarargsArrayTest + * @compile/module=java.base java/lang/invoke/MethodHandleHelper.java + * @run main/bootclasspath VarargsArrayTest * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250 - * java.lang.invoke.VarargsArrayTest + * VarargsArrayTest */ /* This might take a while and burn lots of metadata: - * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true java.lang.invoke.VarargsArrayTest + * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.EXHAUSTIVE=true VarargsArrayTest */ public class VarargsArrayTest { private static final Class CLASS = VarargsArrayTest.class; @@ -60,7 +64,7 @@ public class VarargsArrayTest { final int MIN = START_ARITY; final int MAX = MAX_ARITY-2; // 253+1 would cause parameter overflow with 'this' added for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, 17, MAX)) { - MethodHandle target = MethodHandleImpl.varargsArray(nargs); + MethodHandle target = MethodHandleHelper.varargsArray(nargs); Object[] args = new Object[nargs]; for (int i = 0; i < nargs; i++) args[i] = "#"+i; @@ -110,7 +114,7 @@ public class VarargsArrayTest { if (elemType == long.class || elemType == double.class) { MAX /= 2; MIN /= 2; } for (int nargs = MIN; nargs <= MAX; nargs = nextArgCount(nargs, density, MAX)) { Object[] args = makeTestArray(elemType, nargs); - MethodHandle varargsArray = MethodHandleImpl.varargsArray(arrayType, nargs); + MethodHandle varargsArray = MethodHandleHelper.varargsArray(arrayType, nargs); MethodType vaType = varargsArray.type(); assertEquals(arrayType, vaType.returnType()); if (nargs != 0) { diff --git a/jdk/test/java/lang/invoke/java.base/java/lang/invoke/MethodHandleHelper.java b/jdk/test/java/lang/invoke/java.base/java/lang/invoke/MethodHandleHelper.java new file mode 100644 index 00000000000..d85d6d116a7 --- /dev/null +++ b/jdk/test/java/lang/invoke/java.base/java/lang/invoke/MethodHandleHelper.java @@ -0,0 +1,52 @@ +/* + * 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 java.lang.invoke; + +import java.lang.invoke.MethodHandles.Lookup; + +/** + * Helper class to inject into java.lang.invoke that provides access to + * package-private methods in this package. + */ + +public class MethodHandleHelper { + + private MethodHandleHelper() { } + + public static final Lookup IMPL_LOOKUP = Lookup.IMPL_LOOKUP; + + public static void customize(MethodHandle mh) { + mh.customize(); + } + + public static MethodHandle varargsArray(int nargs) { + return MethodHandleImpl.varargsArray(nargs); + } + + public static MethodHandle varargsArray(Class arrayType, int nargs) { + return MethodHandleImpl.varargsArray(arrayType, nargs); + } + +} + diff --git a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java index a5917e589a1..83024e58c33 100644 --- a/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java +++ b/jdk/test/java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java @@ -54,8 +54,6 @@ public class LambdaAccessControlDoPrivilegedTest extends LUtils { scratch.clear(); scratch.add("public class Bar {"); scratch.add("public static void main(String... args) {"); - scratch.add("System.out.println(\"sun.boot.class.path\" + \"=\" +"); - scratch.add(" System.getProperty(\"sun.boot.class.path\", \"\"));"); scratch.add("System.setSecurityManager(new SecurityManager());"); scratch.add("DoPriv.main();"); scratch.add("}"); diff --git a/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java b/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java new file mode 100644 index 00000000000..d76513e17a7 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/ModuleAccessControlTest.java @@ -0,0 +1,81 @@ +/* + * 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, "-modulesourcepath", SRC_DIR.toString())); + } + } + + /** + * Launch the test + */ + @Test + public void runTest() throws Exception { + int exitValue = executeTestJava("-mp", 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/src/m1/module-info.java b/jdk/test/java/lang/invoke/modules/src/m1/module-info.java new file mode 100644 index 00000000000..175c7727611 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ +module m1 { + requires m2; + exports p1; +} 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 new file mode 100644 index 00000000000..3fd1a0eb43d --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m1/p1/Main.java @@ -0,0 +1,225 @@ +/* + * 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/invoke/modules/src/m1/p1/Type1.java b/jdk/test/java/lang/invoke/modules/src/m1/p1/Type1.java new file mode 100644 index 00000000000..341fdcdab52 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m1/p1/Type1.java @@ -0,0 +1,27 @@ +/* + * 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; + +public class Type1 { + public Type1() { } +} diff --git a/jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java b/jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java new file mode 100644 index 00000000000..bf62a785b99 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m1/p2/Type2.java @@ -0,0 +1,27 @@ +/* + * 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 p2; + +public class Type2 { + public Type2() { } +} diff --git a/jdk/test/java/lang/invoke/modules/src/m2/module-info.java b/jdk/test/java/lang/invoke/modules/src/m2/module-info.java new file mode 100644 index 00000000000..f26ae1c330d --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m2/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +module m2 { + exports q1; +} diff --git a/jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java b/jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java new file mode 100644 index 00000000000..b845ee3a6e1 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m2/q1/Type1.java @@ -0,0 +1,27 @@ +/* + * 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 q1; + +public class Type1 { + public Type1() { } +} diff --git a/jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java b/jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java new file mode 100644 index 00000000000..ecc30c42074 --- /dev/null +++ b/jdk/test/java/lang/invoke/modules/src/m2/q2/Type2.java @@ -0,0 +1,27 @@ +/* + * 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 q2; + +public class Type2 { + public Type2() { } +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java new file mode 100644 index 00000000000..5acf3f3bee0 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestAccessClass.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @compile TestAccessClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestAccessClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestAccessClass { + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException { + lookup().accessClass(Class1.class); + assertFalse(initializedClass1); + } + + @Test + public void returnsSameClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().accessClass(Class1.class); + assertEquals(Class1.class, aClass); + } + + @DataProvider + Object[][] illegalAccessAccess() { + return new Object[][] { + {publicLookup(), Class1.class}, + {publicLookup(), TestCls.getPrivateSIC()} + }; + } + + @Test(dataProvider = "illegalAccessAccess", expectedExceptions = {IllegalAccessException.class}) + public void illegalAccessExceptionTest(Lookup lookup, Class klass) throws IllegalAccessException, ClassNotFoundException { + lookup.accessClass(klass); + } + + @Test + public void okAccess() throws IllegalAccessException { + lookup().accessClass(TestCls.getPrivateSIC()); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestCls.java b/jdk/test/java/lang/invoke/t8150782/TestCls.java new file mode 100644 index 00000000000..1aec2657d0a --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestCls.java @@ -0,0 +1,38 @@ +/* + * 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 test.java.lang.invoke.t8150782; + +import static java.lang.invoke.MethodHandles.*; + +public class TestCls { + + public static final Lookup LOOKUP = lookup(); + + private static class PrivateSIC {} + public static Class getPrivateSIC() { return PrivateSIC.class; } + public static Lookup getLookupForPrivateSIC() { return lookup(); } + +} + diff --git a/jdk/test/java/lang/invoke/t8150782/TestFindClass.java b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java new file mode 100644 index 00000000000..b49118c2b16 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestFindClass.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @compile TestFindClass.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestFindClass + */ +package test.java.lang.invoke.t8150782; + +import java.lang.invoke.*; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +import org.testng.annotations.*; + +public class TestFindClass { + + private static final String PACKAGE_PREFIX = "test.java.lang.invoke.t8150782."; + + private static boolean initializedClass1; + + private static class Class1 { + static { + initializedClass1 = true; + } + } + + @Test + public void initializerNotRun() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertFalse(initializedClass1); + } + + @Test + public void returnsRequestedClass() throws IllegalAccessException, ClassNotFoundException { + Class aClass = lookup().findClass(PACKAGE_PREFIX + "TestFindClass$Class1"); + assertEquals(Class1.class, aClass); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void classNotFoundExceptionTest() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestFindClass$NonExistent"); + } + + @DataProvider + Object[][] illegalAccessFind() { + return new Object[][] { + {publicLookup(), PACKAGE_PREFIX + "TestFindClass$Class1"}, + {publicLookup(), PACKAGE_PREFIX + "TestCls$PrivateSIC"} + }; + } + + /** + * Assertion: @throws IllegalAccessException if the class is not accessible, using the allowed access modes. + */ + @Test(dataProvider = "illegalAccessFind", expectedExceptions = {ClassNotFoundException.class}) + public void illegalAccessExceptionTest(Lookup lookup, String className) throws IllegalAccessException, ClassNotFoundException { + lookup.findClass(className); + } + + @Test + public void okAccess() throws IllegalAccessException, ClassNotFoundException { + lookup().findClass(PACKAGE_PREFIX + "TestCls$PrivateSIC"); + } + +} diff --git a/jdk/test/java/lang/invoke/t8150782/TestLookup.java b/jdk/test/java/lang/invoke/t8150782/TestLookup.java new file mode 100644 index 00000000000..1d49959cbc9 --- /dev/null +++ b/jdk/test/java/lang/invoke/t8150782/TestLookup.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @compile TestLookup.java TestCls.java + * @run testng/othervm -ea -esa test.java.lang.invoke.t8150782.TestLookup + */ +package test.java.lang.invoke.t8150782; + +import org.testng.annotations.Test; + +import static java.lang.invoke.MethodHandles.*; + +import static org.testng.AssertJUnit.*; + +public class TestLookup { + + @Test + public void testClassLoaderChange() { + Lookup lookup = lookup(); + assertNotNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(Object.class); + assertNull(lookup2.lookupClass().getClassLoader()); + } + + @Test(expectedExceptions = {ClassNotFoundException.class}) + public void testPublicCannotLoadUserClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("test.java.lang.invoke.t8150782.TestCls"); + } + + @Test + public void testPublicCanLoadSystemClass() throws IllegalAccessException, ClassNotFoundException { + Lookup lookup = publicLookup(); + lookup.findClass("java.util.HashMap"); + } + + @Test + public void testPublicInChangesClassLoader() { + Lookup lookup = publicLookup(); + // Temporarily exclude until 8148697 is resolved, specifically: + // "publicLookup changed so that the lookup class is in an unnamed module" + //assertNull(lookup.lookupClass().getClassLoader()); + Lookup lookup2 = lookup.in(TestCls.class); + assertNotNull(lookup2.lookupClass().getClassLoader()); + } + +} diff --git a/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java b/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java index 9b026b96980..80ca1c41540 100644 --- a/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java +++ b/jdk/test/java/lang/management/CompositeData/ThreadInfoCompositeData.java @@ -39,6 +39,7 @@ import javax.management.openmbean.*; import java.lang.management.LockInfo; import java.lang.management.MonitorInfo; import java.lang.management.ThreadInfo; +import java.util.Objects; public class ThreadInfoCompositeData { private static StackTraceElement[] ste = new StackTraceElement[1]; @@ -173,6 +174,14 @@ public class ThreadInfoCompositeData { throw new RuntimeException("Class name = " + s2.getClassName() + " expected = " + s1.getClassName()); } + if (!Objects.equals(s1.getModuleName(), s2.getModuleName())) { + throw new RuntimeException("Module name = " + + s2.getModuleName() + " expected = " + s1.getModuleName()); + } + if (!Objects.equals(s1.getModuleVersion(), s2.getModuleVersion())) { + throw new RuntimeException("Module version = " + + s2.getModuleVersion() + " expected = " + s1.getModuleVersion()); + } if (!s1.getMethodName().equals(s2.getMethodName())) { throw new RuntimeException("Method name = " + s2.getMethodName() + " expected = " + s1.getMethodName()); @@ -329,6 +338,8 @@ public class ThreadInfoCompositeData { private static final String[] steItemNames = { "className", + "moduleName", + "moduleVersion", "methodName", "fileName", "lineNumber", @@ -352,6 +363,8 @@ public class ThreadInfoCompositeData { final Object[] steValue = { ste[0].getClassName(), + ste[0].getModuleName(), + ste[0].getModuleVersion(), ste[0].getMethodName(), ste[0].getFileName(), new Integer(ste[0].getLineNumber()), diff --git a/jdk/test/java/lang/management/MemoryMXBean/PendingAllGC.sh b/jdk/test/java/lang/management/MemoryMXBean/PendingAllGC.sh index 2cc76ee5158..c189894b7a5 100644 --- a/jdk/test/java/lang/management/MemoryMXBean/PendingAllGC.sh +++ b/jdk/test/java/lang/management/MemoryMXBean/PendingAllGC.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,8 @@ # @summary # @author Mandy Chung # @requires vm.gc=="null" -# @modules java.base/sun.misc +# @modules java.base/jdk.internal.misc +# java.management # @run compile Pending.java # @run shell PendingAllGC.sh # diff --git a/jdk/test/java/lang/module/AutomaticModulesTest.java b/jdk/test/java/lang/module/AutomaticModulesTest.java new file mode 100644 index 00000000000..d400ffb86cf --- /dev/null +++ b/jdk/test/java/lang/module/AutomaticModulesTest.java @@ -0,0 +1,572 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @build AutomaticModulesTest ModuleUtils + * @run testng AutomaticModulesTest + * @summary Basic tests for automatic modules + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.module.Configuration; +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.ResolvedModule; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.stream.Collectors; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class AutomaticModulesTest { + + private static final Path USER_DIR + = Paths.get(System.getProperty("user.dir")); + + + @DataProvider(name = "names") + public Object[][] createNames() { + + return new Object[][] { + + // JAR file name module-name[/version] + + { "foo.jar", "foo" }, + + { "foo-1.jar", "foo/1" }, + { "foo-1.2.jar", "foo/1.2" }, + { "foo-1.2.3.jar", "foo/1.2.3" }, + { "foo-1.2.3.4.jar", "foo/1.2.3.4" }, + + { "foo-10.jar", "foo/10" }, + { "foo-10.20.jar", "foo/10.20" }, + { "foo-10.20.30.jar", "foo/10.20.30" }, + { "foo-10.20.30.40.jar", "foo/10.20.30.40" }, + + { "foo-bar.jar", "foo.bar" }, + { "foo-bar-1.jar", "foo.bar/1" }, + { "foo-bar-1.2.jar", "foo.bar/1.2"}, + { "foo-bar-10.jar", "foo.bar/10" }, + { "foo-bar-10.20.jar", "foo.bar/10.20" }, + + { "foo-1.2-SNAPSHOT.jar", "foo/1.2-SNAPSHOT" }, + { "foo-bar-1.2-SNAPSHOT.jar", "foo.bar/1.2-SNAPSHOT" }, + + { "foo--bar-1.0.jar", "foo.bar/1.0" }, + { "-foo-bar-1.0.jar", "foo.bar/1.0" }, + { "foo-bar--1.0.jar", "foo.bar/1.0" }, + + }; + } + + /** + * Test mapping of JAR file names to module names + */ + @Test(dataProvider = "names") + public void testNames(String fn, String mid) throws IOException { + + String[] s = mid.split("/"); + String mn = s[0]; + String vs = (s.length == 2) ? s[1] : null; + + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path jf = dir.resolve(fn); + + // create empty JAR file + createJarFile(jf); + + // create a ModuleFinder to find modules in the directory + ModuleFinder finder = ModuleFinder.of(dir); + + // a module with the expected name should be found + Optional mref = finder.find(mn); + assertTrue(mref.isPresent(), mn + " not found"); + + ModuleDescriptor descriptor = mref.get().descriptor(); + assertEquals(descriptor.name(), mn); + if (vs == null) { + assertFalse(descriptor.version().isPresent()); + } else { + assertEquals(descriptor.version().get().toString(), vs); + } + + } + + + /** + * Test all packages are exported + */ + public void testExports() throws IOException { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createJarFile(dir.resolve("m1.jar"), + "p/C1.class", "p/C2.class", "q/C1.class"); + + ModuleFinder finder = ModuleFinder.of(dir); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + + ModuleDescriptor m1 = findDescriptor(cf, "m1"); + + Set exports + = m1.exports().stream().map(Exports::source).collect(Collectors.toSet()); + + assertTrue(exports.size() == 2); + assertTrue(exports.contains("p")); + assertTrue(exports.contains("q")); + assertTrue(m1.conceals().isEmpty()); + } + + + /** + * Test that a JAR file with a Main-Class attribute results + * in a module with a main class. + */ + public void testMainClass() throws IOException { + String mainClass = "p.Main"; + + Manifest man = new Manifest(); + Attributes attrs = man.getMainAttributes(); + attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0"); + attrs.put(Attributes.Name.MAIN_CLASS, mainClass); + + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createJarFile(dir.resolve("m1.jar"), man); + + ModuleFinder finder = ModuleFinder.of(dir); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + + ModuleDescriptor m1 = findDescriptor(cf, "m1"); + + assertTrue(m1.mainClass().isPresent()); + assertEquals(m1.mainClass().get(), mainClass); + } + + + /** + * Basic test of a configuration created with automatic modules. + * m1 requires m2* + * m1 requires m3* + * m2* + * m3* + */ + public void testConfiguration1() throws Exception { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .requires("m3") + .requires("java.base") + .build(); + + // m2 and m3 are automatic modules + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createJarFile(dir.resolve("m2.jar"), "p/T.class"); + createJarFile(dir.resolve("m3.jar"), "q/T.class"); + + // module finder locates m1 and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + + assertTrue(cf.modules().size() == 3); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + + ResolvedModule base = cf.findModule("java.base").get(); + assertTrue(base.configuration() == Layer.boot().configuration()); + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + + // m2 && m3 only require java.base + assertTrue(m2.reference().descriptor().requires().size() == 1); + assertTrue(m3.reference().descriptor().requires().size() == 1); + + // readability + + assertTrue(m1.reads().size() == 3); + assertTrue(m1.reads().contains(base)); + assertTrue(m1.reads().contains(m2)); + assertTrue(m1.reads().contains(m3)); + + assertTrue(m2.reads().contains(m1)); + assertTrue(m2.reads().contains(m3)); + testReadAllBootModules(cf, "m2"); // m2 reads all modules in boot layer + + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + testReadAllBootModules(cf, "m3"); // m3 reads all modules in boot layer + + } + + /** + * Basic test of a configuration created with automatic modules + * m1 requires m2 + * m2 requires m3* + * m3* + * m4* + */ + public void testInConfiguration2() throws IOException { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .requires("java.base") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m3") + .requires("java.base") + .build(); + + // m3 and m4 are automatic modules + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createJarFile(dir.resolve("m3.jar"), "p/T.class"); + createJarFile(dir.resolve("m4.jar"), "q/T.class"); + + // module finder locates m1 and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1", "m4"); + + assertTrue(cf.modules().size() == 4); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + assertTrue(cf.findModule("m4").isPresent()); + + // m3 && m4 should only require java.base + assertTrue(findDescriptor(cf, "m3").requires().size() == 1); + assertTrue(findDescriptor(cf, "m4").requires().size() == 1); + + // readability + + ResolvedModule base = cf.findModule("java.base").get(); + assertTrue(base.configuration() == Layer.boot().configuration()); + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + ResolvedModule m4 = cf.findModule("m4").get(); + + assertTrue(m1.reads().size() == 2); + assertTrue(m1.reads().contains(m2)); + assertTrue(m1.reads().contains(base)); + + assertTrue(m2.reads().size() == 3); + assertTrue(m2.reads().contains(m3)); + assertTrue(m2.reads().contains(m4)); + assertTrue(m2.reads().contains(base)); + + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + assertTrue(m3.reads().contains(m4)); + testReadAllBootModules(cf, "m3"); // m3 reads all modules in boot layer + + assertTrue(m4.reads().contains(m1)); + assertTrue(m4.reads().contains(m2)); + assertTrue(m4.reads().contains(m3)); + testReadAllBootModules(cf, "m4"); // m4 reads all modules in boot layer + + } + + + /** + * Basic test of a configuration created with automatic modules + * m1 requires m2 + * m2 requires public m3* + * m3* + * m4* + */ + public void testInConfiguration3() throws IOException { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .requires("java.base") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m3") + .requires("java.base") + .build(); + + // m3 and m4 are automatic modules + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createJarFile(dir.resolve("m3.jar"), "p/T.class"); + createJarFile(dir.resolve("m4.jar"), "q/T.class"); + + // module finder locates m1 and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor1, descriptor2), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1", "m4"); + + assertTrue(cf.modules().size() == 4); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + assertTrue(cf.findModule("m4").isPresent()); + + ResolvedModule base = cf.findModule("java.base").get(); + assertTrue(base.configuration() == Layer.boot().configuration()); + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + ResolvedModule m4 = cf.findModule("m4").get(); + + // m3 && m4 should only require java.base + assertTrue(findDescriptor(cf, "m3").requires().size() == 1); + assertTrue(findDescriptor(cf, "m4").requires().size() == 1); + + // readability + + assertTrue(m1.reads().size() == 4); + assertTrue(m1.reads().contains(m2)); + assertTrue(m1.reads().contains(m3)); + assertTrue(m1.reads().contains(m4)); + assertTrue(m1.reads().contains(base)); + + assertTrue(m2.reads().size() == 3); + assertTrue(m2.reads().contains(m3)); + assertTrue(m2.reads().contains(m4)); + assertTrue(m2.reads().contains(base)); + + assertTrue(reads(cf, "m2", "m3")); + assertTrue(reads(cf, "m2", "m4")); + assertTrue(reads(cf, "m2", "java.base")); + + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + assertTrue(m3.reads().contains(m4)); + testReadAllBootModules(cf, "m3"); // m3 reads all modules in boot layer + + assertTrue(m4.reads().contains(m1)); + assertTrue(m4.reads().contains(m2)); + assertTrue(m4.reads().contains(m3)); + testReadAllBootModules(cf, "m4"); // m4 reads all modules in boot layer + + } + + + /** + * Basic test of Layer containing automatic modules + */ + public void testInLayer() throws IOException { + ModuleDescriptor descriptor + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .requires("m3") + .build(); + + // m2 and m3 are simple JAR files + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createJarFile(dir.resolve("m2.jar"), "p/T.class"); + createJarFile(dir.resolve("m3.jar"), "q/T2.class"); + + // module finder locates m1 and the modules in the directory + ModuleFinder finder + = ModuleFinder.compose(ModuleUtils.finderOf(descriptor), + ModuleFinder.of(dir)); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolve(parent, finder, "m1"); + assertTrue(cf.modules().size() == 3); + + // each module gets its own loader + Layer layer = Layer.boot().defineModules(cf, mn -> new ClassLoader() { }); + + // an unnamed module + Module unnamed = (new ClassLoader() { }).getUnnamedModule(); + + Module m2 = layer.findModule("m2").get(); + assertTrue(m2.isNamed()); + assertTrue(m2.canRead(unnamed)); + testsReadsAll(m2, layer); + + Module m3 = layer.findModule("m3").get(); + assertTrue(m3.isNamed()); + assertTrue(m2.canRead(unnamed)); + testsReadsAll(m3, layer); + } + + + /** + * Test miscellaneous methods. + */ + public void testMisc() throws IOException { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path m1_jar = createJarFile(dir.resolve("m1.jar"), "p/T.class"); + + ModuleFinder finder = ModuleFinder.of(m1_jar); + + assertTrue(finder.find("m1").isPresent()); + ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + + // test miscellaneous methods + assertTrue(m1.isAutomatic()); + assertFalse(m1.isSynthetic()); + assertFalse(m1.osName().isPresent()); + assertFalse(m1.osArch().isPresent()); + assertFalse(m1.osVersion().isPresent()); + } + + + /** + * Invokes parent.resolveRequires to resolve the given root modules. + */ + static Configuration resolve(Configuration parent, + ModuleFinder finder, + String... roots) { + return parent.resolveRequires(finder, ModuleFinder.empty(), Set.of(roots)); + } + + /** + * Finds a module in the given configuration or its parents, returning + * the module descriptor (or null if not found) + */ + static ModuleDescriptor findDescriptor(Configuration cf, String name) { + Optional om = cf.findModule(name); + if (om.isPresent()) { + return om.get().reference().descriptor(); + } else { + return null; + } + } + + /** + * Test that a module in a configuration reads all modules in the boot + * configuration. + */ + static void testReadAllBootModules(Configuration cf, String mn) { + + Set bootModules = Layer.boot().modules().stream() + .map(Module::getName) + .collect(Collectors.toSet()); + + bootModules.forEach(other -> assertTrue(reads(cf, mn, other))); + + } + + /** + * Test that the given Module reads all module in the given Layer + * and its parent Layers. + */ + static void testsReadsAll(Module m, Layer layer) { + while (layer != Layer.empty()) { + + // check that m reads all module in the layer + layer.configuration().modules().stream() + .map(ResolvedModule::name) + .map(layer::findModule) + .map(Optional::get) + .forEach(m2 -> assertTrue(m.canRead(m2))); + + layer = layer.parent().get(); + } + } + + /** + * Returns {@code true} if the configuration contains module mn1 + * that reads module mn2. + */ + static boolean reads(Configuration cf, String mn1, String mn2) { + Optional om1 = cf.findModule(mn1); + if (!om1.isPresent()) + return false; + + return om1.get().reads().stream() + .map(ResolvedModule::name) + .anyMatch(mn2::equals); + } + + /** + * Creates a JAR file, optionally with a manifest, and with the given + * entries. The entries will be empty in the resulting JAR file. + */ + static Path createJarFile(Path file, Manifest man, String... entries) + throws IOException + { + try (OutputStream out = Files.newOutputStream(file)) { + try (JarOutputStream jos = new JarOutputStream(out)) { + + if (man != null) { + JarEntry je = new JarEntry(JarFile.MANIFEST_NAME); + jos.putNextEntry(je); + man.write(jos); + jos.closeEntry(); + } + + for (String entry : entries) { + JarEntry je = new JarEntry(entry); + jos.putNextEntry(je); + jos.closeEntry(); + } + + } + } + return file; + } + + /** + * Creates a JAR file and with the given entries. The entries will be empty + * in the resulting JAR file. + */ + static Path createJarFile(Path file, String... entries) + throws IOException + { + return createJarFile(file, null, entries); + } + +} diff --git a/jdk/test/java/lang/module/ConfigurationTest.java b/jdk/test/java/lang/module/ConfigurationTest.java new file mode 100644 index 00000000000..9e7e9d4357c --- /dev/null +++ b/jdk/test/java/lang/module/ConfigurationTest.java @@ -0,0 +1,1554 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @build ConfigurationTest ModuleUtils + * @run testng ConfigurationTest + * @summary Basic tests for java.lang.module.Configuration + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.module.ModuleFinder; +import java.lang.module.ResolutionException; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.util.Optional; +import java.util.Set; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ConfigurationTest { + + + /** + * Basic test of resolver + * m1 requires m2, m2 requires m3 + */ + public void testBasic() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m3") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 3); + + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + + assertTrue(cf.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + + // m1 reads m2 + assertTrue(m1.reads().size() == 1); + assertTrue(m1.reads().contains(m2)); + + // m2 reads m3 + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m3)); + + // m3 reads nothing + assertTrue(m3.reads().size() == 0); + + // toString + assertTrue(cf.toString().contains("m1")); + assertTrue(cf.toString().contains("m2")); + assertTrue(cf.toString().contains("m3")); + } + + + /** + * Basic test of "requires public": + * m1 requires m2, m2 requires public m3 + */ + public void testRequiresPublic1() { + // m1 requires m2, m2 requires public m3 + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m3") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 3); + + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + + assertTrue(cf.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + + // m1 reads m2 and m3 + assertTrue(m1.reads().size() == 2); + assertTrue(m1.reads().contains(m2)); + assertTrue(m1.reads().contains(m3)); + + // m2 reads m3 + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m3)); + + // m3 reads nothing + assertTrue(m3.reads().size() == 0); + } + + + /** + * Basic test of "requires public" with configurations. + * + * The test consists of three configurations: + * - Configuration cf1: m1, m2 requires public m1 + * - Configuration cf2: m3 requires m1 + */ + public void testRequiresPublic2() { + + // cf1: m1 and m2, m2 requires public m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m2"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("m2").isPresent()); + assertTrue(cf1.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + ResolvedModule m2 = cf1.findModule("m2").get(); + + assertTrue(m1.reads().size() == 0); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + + + // cf2: m3, m3 requires m2 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m1").isPresent()); // in parent + assertTrue(cf2.findModule("m2").isPresent()); // in parent + assertTrue(cf2.findModule("m3").isPresent()); + assertTrue(cf2.parent().get() == cf1); + + ResolvedModule m3 = cf2.findModule("m3").get(); + assertTrue(m3.configuration() == cf2); + assertTrue(m3.reads().size() == 2); + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + } + + + /** + * Basic test of "requires public" with configurations. + * + * The test consists of three configurations: + * - Configuration cf1: m1 + * - Configuration cf2: m2 requires public m3, m3 requires m2 + */ + public void testRequiresPublic3() { + + // cf1: m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + assertTrue(m1.reads().size() == 0); + + + // cf2: m2, m3: m2 requires public m1, m3 requires m2 + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m1") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + assertTrue(cf2.modules().size() == 2); + assertTrue(cf2.findModule("m1").isPresent()); // in parent + assertTrue(cf2.findModule("m2").isPresent()); + assertTrue(cf2.findModule("m3").isPresent()); + assertTrue(cf2.parent().get() == cf1); + + ResolvedModule m2 = cf2.findModule("m2").get(); + ResolvedModule m3 = cf2.findModule("m3").get(); + + assertTrue(m2.configuration() == cf2); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + + assertTrue(m3.configuration() == cf2); + assertTrue(m3.reads().size() == 2); + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + } + + + /** + * Basic test of "requires public" with configurations. + * + * The test consists of three configurations: + * - Configuration cf1: m1 + * - Configuration cf2: m2 requires public m1 + * - Configuraiton cf3: m3 requires m3 + */ + public void testRequiresPublic4() { + + // cf1: m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + assertTrue(m1.reads().size() == 0); + + + // cf2: m2 requires public m1 + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + + Configuration cf2 = resolveRequires(cf1, finder2, "m2"); + + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m1").isPresent()); // in parent + assertTrue(cf2.findModule("m2").isPresent()); + assertTrue(cf2.parent().get() == cf1); + + ResolvedModule m2 = cf2.findModule("m2").get(); + + assertTrue(m2.configuration() == cf2); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + + + // cf3: m3 requires m2 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); + + Configuration cf3 = resolveRequires(cf2, finder3, "m3"); + + assertTrue(cf3.modules().size() == 1); + assertTrue(cf3.findModule("m1").isPresent()); // in parent + assertTrue(cf3.findModule("m2").isPresent()); // in parent + assertTrue(cf3.findModule("m3").isPresent()); + assertTrue(cf3.parent().get() == cf2); + + ResolvedModule m3 = cf3.findModule("m3").get(); + + assertTrue(m3.configuration() == cf3); + assertTrue(m3.reads().size() == 2); + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + } + + + /** + * Basic test of "requires public" with configurations. + * + * The test consists of two configurations: + * - Configuration cf1: m1, m2 requires public m1 + * - Configuration cf2: m3 requires public m2, m4 requires m3 + */ + public void testRequiresPublic5() { + + // cf1: m1, m2 requires public m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m2"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("m2").isPresent()); + assertTrue(cf1.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + ResolvedModule m2 = cf1.findModule("m2").get(); + + assertTrue(m1.configuration() == cf1); + assertTrue(m1.reads().size() == 0); + + assertTrue(m2.configuration() == cf1); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + + + // cf2: m3 requires public m2, m4 requires m3 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires(Modifier.PUBLIC, "m2") + .build(); + + ModuleDescriptor descriptor4 + = new ModuleDescriptor.Builder("m4") + .requires("m3") + .build(); + + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4"); + + assertTrue(cf2.modules().size() == 2); + assertTrue(cf2.findModule("m1").isPresent()); // in parent + assertTrue(cf2.findModule("m2").isPresent()); // in parent + assertTrue(cf2.findModule("m3").isPresent()); + assertTrue(cf2.findModule("m4").isPresent()); + assertTrue(cf2.parent().get() == cf1); + + ResolvedModule m3 = cf2.findModule("m3").get(); + ResolvedModule m4 = cf2.findModule("m4").get(); + + assertTrue(m3.configuration() == cf2); + assertTrue(m3.reads().size() == 2); + assertTrue(m3.reads().contains(m1)); + assertTrue(m3.reads().contains(m2)); + + assertTrue(m4.configuration() == cf2); + assertTrue(m4.reads().size() == 3); + assertTrue(m4.reads().contains(m1)); + assertTrue(m4.reads().contains(m2)); + assertTrue(m4.reads().contains(m3)); + } + + + /** + * Basic test of binding services + * m1 uses p.S + * m2 provides p.S + */ + public void testServiceBinding1() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolveRequiresAndUses(finder, "m1"); + + assertTrue(cf.modules().size() == 2); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + + assertTrue(m1.configuration() == cf); + assertTrue(m1.reads().size() == 0); + + assertTrue(m2.configuration() == cf); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + } + + + /** + * Basic test of binding services + * m1 uses p.S1 + * m2 provides p.S1, m2 uses p.S2 + * m3 provides p.S2 + */ + public void testServiceBinding2() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .uses("p.S2") + .conceals("q") + .provides("p.S1", "q.Service1Impl") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m1") + .conceals("q") + .provides("p.S2", "q.Service2Impl") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + Configuration cf = resolveRequiresAndUses(finder, "m1"); + + assertTrue(cf.modules().size() == 3); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + assertTrue(cf.findModule("m3").isPresent()); + assertTrue(cf.parent().get() == Configuration.empty()); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + ResolvedModule m3 = cf.findModule("m3").get(); + + assertTrue(m1.configuration() == cf); + assertTrue(m1.reads().size() == 0); + + assertTrue(m2.configuration() == cf); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + + assertTrue(m3.configuration() == cf); + assertTrue(m3.reads().size() == 1); + assertTrue(m3.reads().contains(m1)); + } + + + /** + * Basic test of binding services with configurations. + * + * The test consists of two configurations: + * - Configuration cf1: m1 uses p.S + * - Configuration cf2: m2 provides p.S + */ + public void testServiceBindingWithConfigurations1() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + + Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots + + assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m2").isPresent()); + + ResolvedModule m1 = cf1.findModule("m1").get(); + ResolvedModule m2 = cf2.findModule("m2").get(); + + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + } + + + /** + * Basic test of binding services with configurations. + * + * The test consists of two configurations: + * - Configuration cf1: m1 uses p.S && provides p.S, + * m2 provides p.S + * - Configuration cf2: m3 provides p.S + * m4 provides p.S + */ + public void testServiceBindingWithConfigurations2() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S") + .conceals("p1") + .provides("p.S", "p1.ServiceImpl") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .conceals("p2") + .provides("p.S", "p2.ServiceImpl") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequiresAndUses(finder1, "m1"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("m2").isPresent()); + + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m1") + .conceals("p3") + .provides("p.S", "p3.ServiceImpl") + .build(); + + ModuleDescriptor descriptor4 + = new ModuleDescriptor.Builder("m4") + .requires("m1") + .conceals("p4") + .provides("p.S", "p4.ServiceImpl") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); + + Configuration cf2 = resolveRequiresAndUses(cf1, finder2); // no roots + + assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.modules().size() == 2); + assertTrue(cf2.findModule("m3").isPresent()); + assertTrue(cf2.findModule("m4").isPresent()); + + ResolvedModule m1 = cf2.findModule("m1").get(); // should find in parent + ResolvedModule m2 = cf2.findModule("m2").get(); + ResolvedModule m3 = cf2.findModule("m3").get(); + ResolvedModule m4 = cf2.findModule("m4").get(); + + assertTrue(m1.reads().size() == 0); + + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + + assertTrue(m3.reads().size() == 1); + assertTrue(m3.reads().contains(m1)); + + assertTrue(m4.reads().size() == 1); + assertTrue(m4.reads().contains(m1)); + } + + + /** + * Basic test of binding services with configurations. + * + * Configuration cf1: p@1.0 provides p.S + * Test configuration cf2: m1 uses p.S + * Test configuration cf2: m1 uses p.S, p@2.0 uses p.S + */ + public void testServiceBindingWithConfigurations3() { + + ModuleDescriptor service + = new ModuleDescriptor.Builder("s") + .exports("p") + .build(); + + ModuleDescriptor provider_v1 + = new ModuleDescriptor.Builder("p") + .version("1.0") + .requires("s") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(service, provider_v1); + + Configuration cf1 = resolveRequires(finder1, "p"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("s").isPresent()); + assertTrue(cf1.findModule("p").isPresent()); + + // p@1.0 in cf1 + ResolvedModule p = cf1.findModule("p").get(); + assertEquals(p.reference().descriptor(), provider_v1); + + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("s") + .uses("p.S") + .build(); + + ModuleDescriptor provider_v2 + = new ModuleDescriptor.Builder("p") + .version("2.0") + .requires("s") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, provider_v2); + + + // finder2 is the before ModuleFinder and so p@2.0 should be located + + Configuration cf2 = resolveRequiresAndUses(cf1, finder2, "m1"); + + assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.modules().size() == 2); + + // p should be found in cf2 + p = cf2.findModule("p").get(); + assertTrue(p.configuration() == cf2); + assertEquals(p.reference().descriptor(), provider_v2); + + + // 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.empty(), finder2, "m1"); + + assertTrue(cf2.parent().get() == cf1); + assertTrue(cf2.modules().size() == 1); + + // p should be found in cf1 + p = cf2.findModule("p").get(); + assertTrue(p.configuration() == cf1); + assertEquals(p.reference().descriptor(), provider_v1); + } + + + /** + * Basic test with two module finders. + * + * Module m2 can be found by both the before and after finders. + */ + public void testWithTwoFinders1() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .build(); + + ModuleDescriptor descriptor2_v1 + = new ModuleDescriptor.Builder("m2") + .version("1.0") + .build(); + + ModuleDescriptor descriptor2_v2 + = new ModuleDescriptor.Builder("m2") + .version("2.0") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor2_v1); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor2_v2); + + Configuration cf = resolveRequires(finder1, finder2, "m1"); + + assertTrue(cf.modules().size() == 2); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + + assertEquals(m1.reference().descriptor(), descriptor1); + assertEquals(m2.reference().descriptor(), descriptor2_v1); + } + + + /** + * Basic test with two modules finders and service binding. + * + * The before and after ModuleFinders both locate a service provider module + * named "m2" that provide implementations of the same service type. + */ + public void testWithTwoFinders2() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S") + .build(); + + ModuleDescriptor descriptor2_v1 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleDescriptor descriptor2_v2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2_v1); + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2_v2); + + Configuration cf = resolveRequiresAndUses(finder1, finder2, "m1"); + + assertTrue(cf.modules().size() == 2); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + + assertEquals(m1.reference().descriptor(), descriptor1); + assertEquals(m2.reference().descriptor(), descriptor2_v1); + } + + + /** + * Basic test for resolving a module that is located in the parent + * configuration. + */ + public void testResolvedInParent1() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder, "m1"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + + Configuration cf2 = resolveRequires(cf1, finder, "m1"); + + assertTrue(cf2.modules().size() == 1); + } + + + /** + * Basic test for resolving a module that has a dependency on a module + * in the parent configuration. + */ + public void testResolvedInParent2() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + + Configuration cf2 = resolveRequires(cf1, ModuleFinder.empty(), finder2, "m2"); + + assertTrue(cf2.modules().size() == 1); + assertTrue(cf2.findModule("m2").isPresent()); + + ResolvedModule m1 = cf2.findModule("m1").get(); // find in parent + ResolvedModule m2 = cf2.findModule("m2").get(); + + assertTrue(m1.reads().size() == 0); + assertTrue(m2.reads().size() == 1); + assertTrue(m2.reads().contains(m1)); + } + + + /** + * Basic test of using the beforeFinder to override a module in the parent + * configuration. + */ + public void testOverriding1() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder, "m1"); + assertTrue(cf1.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + + Configuration cf2 = resolveRequires(cf1, finder, "m1"); + assertTrue(cf2.modules().size() == 1); + assertTrue(cf1.findModule("m1").isPresent()); + } + + + /** + * Basic test of using the beforeFinder to override a module in the parent + * configuration but where implied readability in the picture so that the + * module in the parent is read. + * + * The test consists of two configurations: + * - Configuration cf1: m1, m2 requires public m1 + * - Configuration cf2: m1, m3 requires m2 + */ + public void testOverriding2() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m2"); + + assertTrue(cf1.modules().size() == 2); + assertTrue(cf1.findModule("m1").isPresent()); + assertTrue(cf1.findModule("m2").isPresent()); + + // cf2: m3 requires m2, m1 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m1", "m3"); + + assertTrue(cf2.parent().get() == cf1); + + assertTrue(cf2.modules().size() == 2); + assertTrue(cf2.findModule("m1").isPresent()); + assertTrue(cf2.findModule("m3").isPresent()); + + ResolvedModule m1_1 = cf1.findModule("m1").get(); + ResolvedModule m1_2 = cf2.findModule("m1").get(); + ResolvedModule m2 = cf1.findModule("m2").get(); + ResolvedModule m3 = cf2.findModule("m3").get(); + + assertTrue(m1_1.configuration() == cf1); + assertTrue(m1_2.configuration() == cf2); + assertTrue(m3.configuration() == cf2); + + + // check that m3 reads cf1/m1 and cf2/m2 + assertTrue(m3.reads().size() == 2); + assertTrue(m3.reads().contains(m1_1)); + assertTrue(m3.reads().contains(m2)); + } + + + /** + * Root module not found + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testRootNotFound() { + resolveRequires(ModuleFinder.empty(), "m1"); + } + + + /** + * Direct dependency not found + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testDirectDependencyNotFound() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1").requires("m2").build(); + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + resolveRequires(finder, "m1"); + } + + + /** + * Transitive dependency not found + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testTransitiveDependencyNotFound() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1").requires("m2").build(); + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2").requires("m3").build(); + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + resolveRequires(finder, "m1"); + } + + + /** + * Service provider dependency not found + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testServiceProviderDependencyNotFound() { + + // service provider dependency (on m3) not found + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .requires("m3") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + // should throw ResolutionException because m3 is not found + Configuration cf = resolveRequiresAndUses(finder, "m1"); + } + + + /** + * Simple cycle. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testSimpleCycle() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1").requires("m2").build(); + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2").requires("m3").build(); + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3").requires("m1").build(); + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + resolveRequires(finder, "m1"); + } + + /** + * Basic test for detecting cycles involving a service provider module + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testCycleInProvider() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .uses("p.S") + .build(); + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .requires("m3") + .conceals("q") + .provides("p.S", "q.T") + .build(); + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + // should throw ResolutionException because of the m2 <--> m3 cycle + resolveRequiresAndUses(finder, "m1"); + } + + + /** + * Test two modules exporting package p to a module that reads both. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testPackageSuppliedByTwoOthers() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .requires("m3") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .exports("p") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .exports("p", "m1") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + // m2 and m3 export package p to module m1 + resolveRequires(finder, "m1"); + } + + + /** + * Test the scenario where a module has a concealed package p and reads + * a module that exports package p. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testPackageSuppliedBySelfAndOther() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .conceals("p") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .exports("p") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + // m1 contains package p, module m2 exports package p to m1 + resolveRequires(finder, "m1"); + } + + + /** + * Test the scenario where a module has a concealed package p and reads + * a module that also has a concealed package p. + */ + public void testPackagePrivateToSelfAndOther() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .conceals("p") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .conceals("p") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 2); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + + // m1 reads m2, m2 reads nothing + ResolvedModule m1 = cf.findModule("m1").get(); + ResolvedModule m2 = cf.findModule("m2").get(); + assertTrue(m1.reads().size() == 1); + assertTrue(m1.reads().contains(m2)); + assertTrue(m2.reads().size() == 0); + } + + + /** + * Test the scenario where a module that exports a package that is also + * exported by a module that it reads in a parent layer. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testExportSamePackageAsBootLayer() { + ModuleDescriptor descriptor + = new ModuleDescriptor.Builder("m1") + .requires("java.base") + .exports("java.lang") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration bootConfiguration = Layer.boot().configuration(); + + // m1 contains package java.lang, java.base exports package java.lang to m1 + resolveRequires(bootConfiguration, finder, "m1"); + } + + + /** + * Test "uses p.S" where p is a concealed package in the same module. + */ + public void testConcealedService1() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .conceals("p") + .uses("p.S") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 1); + assertTrue(cf.findModule("m1").isPresent()); + } + + + /** + * Test "uses p.S" where p is a concealed package in a different module. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testConcealedService2() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .conceals("p") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .uses("p.S") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + // m2 does not read a module that exports p + resolveRequires(finder, "m2"); + } + + + /** + * Test "provides p.S" where p is a concealed package in the same module. + */ + public void testConcealedService3() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .conceals("p") + .conceals("q") + .provides("p.S", "q.S1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 1); + assertTrue(cf.findModule("m1").isPresent()); + } + + + /** + * Test "provides p.S" where p is a concealed package in a different module. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testConcealedService4() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .conceals("p") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .conceals("q") + .provides("p.S", "q.S1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + // m2 does not read a module that exports p + resolveRequires(finder, "m2"); + } + + + /** + * Test "uses p.S" where p is not exported to the module. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testServiceTypePackageNotExported1() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .uses("p.S") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + // m1 does not read a module that exports p + resolveRequires(finder, "m1"); + } + + + /** + * Test "provides p.S" where p is not exported to the module. + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testServiceTypePackageNotExported2() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .conceals("q") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + // m1 does not read a module that exports p + resolveRequires(finder, "m1"); + } + + + /** + * Test "provides p.S" where p is not local + */ + @Test(expectedExceptions = { ResolutionException.class }) + public void testProviderPackageNotLocal() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .exports("q") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m1") + .provides("p.S", "q.T") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + // q.T not in module m2 + resolveRequires(finder, "m2"); + } + + + /** + * Test the empty configuration. + */ + public void testEmptyConfiguration() { + Configuration cf = Configuration.empty(); + + assertFalse(cf.parent().isPresent()); + + assertTrue(cf.modules().isEmpty()); + assertFalse(cf.findModule("java.base").isPresent()); + } + + + // platform specific modules + + @DataProvider(name = "platformmatch") + public Object[][] createPlatformMatches() { + return new Object[][]{ + + { "linux-*-*", "*-*-*" }, + { "*-arm-*", "*-*-*" }, + { "*-*-2.6", "*-*-*" }, + + { "linux-arm-*", "*-*-*" }, + { "linux-*-2.6", "*-*-*" }, + { "*-arm-2.6", "*-*-*" }, + + { "linux-arm-2.6", "*-*-*" }, + + { "linux-*-*", "linux-*-*" }, + { "*-arm-*", "*-arm-*" }, + { "*-*-2.6", "*-*-2.6" }, + + { "linux-arm-*", "linux-arm-*" }, + { "linux-arm-*", "linux-*-*" }, + { "linux-*-2.6", "linux-*-2.6" }, + { "linux-*-2.6", "linux-arm-*" }, + + { "linux-arm-2.6", "linux-arm-2.6" }, + + }; + + }; + + @DataProvider(name = "platformmismatch") + public Object[][] createBad() { + return new Object[][] { + + { "linux-*-*", "solaris-*-*" }, + { "linux-x86-*", "linux-arm-*" }, + { "linux-*-2.4", "linux-x86-2.6" }, + }; + } + + /** + * Test creating a configuration containing platform specific modules. + */ + @Test(dataProvider = "platformmatch") + public void testPlatformMatch(String s1, String s2) { + + ModuleDescriptor.Builder builder + = new ModuleDescriptor.Builder("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]); + + ModuleDescriptor descriptor1 = builder.build(); + + builder = new ModuleDescriptor.Builder("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]); + + ModuleDescriptor descriptor2 = builder.build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolveRequires(finder, "m1"); + + assertTrue(cf.modules().size() == 2); + assertTrue(cf.findModule("m1").isPresent()); + assertTrue(cf.findModule("m2").isPresent()); + } + + /** + * Test attempting to create a configuration with modules for different + * platforms. + */ + @Test(dataProvider = "platformmismatch", + expectedExceptions = ResolutionException.class ) + public void testPlatformMisMatch(String s1, String s2) { + testPlatformMatch(s1, s2); + } + + + // null handling + + // finder1, finder2, roots + + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresWithNull1() { + resolveRequires((ModuleFinder)null, ModuleFinder.empty()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresWithNull2() { + resolveRequires(ModuleFinder.empty(), (ModuleFinder)null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresAndUsesWithNull1() { + resolveRequiresAndUses((ModuleFinder) null, ModuleFinder.empty()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testResolveRequiresAndUsesWithNull2() { + resolveRequiresAndUses(ModuleFinder.empty(), (ModuleFinder) null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testFindModuleWithNull() { + Configuration.empty().findModule(null); + } + + // immutable sets + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testImmutableSet1() { + Configuration cf = Layer.boot().configuration(); + ResolvedModule base = cf.findModule("java.base").get(); + cf.modules().add(base); + } + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testImmutableSet2() { + Configuration cf = Layer.boot().configuration(); + ResolvedModule base = cf.findModule("java.base").get(); + base.reads().add(base); + } + + + /** + * Invokes parent.resolveRequires(...) + */ + private Configuration resolveRequires(Configuration parent, + ModuleFinder before, + ModuleFinder after, + String... roots) { + return parent.resolveRequires(before, after, Set.of(roots)); + } + + private Configuration resolveRequires(Configuration parent, + ModuleFinder before, + String... roots) { + return resolveRequires(parent, before, ModuleFinder.empty(), roots); + } + + private Configuration resolveRequires(ModuleFinder before, + ModuleFinder after, + String... roots) { + return resolveRequires(Configuration.empty(), before, after, roots); + } + + private Configuration resolveRequires(ModuleFinder before, + String... roots) { + return resolveRequires(Configuration.empty(), before, roots); + } + + + /** + * Invokes parent.resolveRequiresAndUses(...) + */ + private Configuration resolveRequiresAndUses(Configuration parent, + ModuleFinder before, + ModuleFinder after, + String... roots) { + return parent.resolveRequiresAndUses(before, after, Set.of(roots)); + } + + private Configuration resolveRequiresAndUses(Configuration parent, + ModuleFinder before, + String... roots) { + return resolveRequiresAndUses(parent, before, ModuleFinder.empty(), roots); + } + + private Configuration resolveRequiresAndUses(ModuleFinder before, + ModuleFinder after, + String... roots) { + return resolveRequiresAndUses(Configuration.empty(), before, after, roots); + } + + private Configuration resolveRequiresAndUses(ModuleFinder before, + String... roots) { + return resolveRequiresAndUses(Configuration.empty(), before, roots); + } + + + /** + * Returns {@code true} if the configuration contains module mn1 + * that reads module mn2. + */ + static boolean reads(Configuration cf, String mn1, String mn2) { + Optional om1 = cf.findModule(mn1); + if (!om1.isPresent()) + return false; + + return om1.get().reads().stream() + .map(ResolvedModule::name) + .anyMatch(mn2::equals); + } + + +} diff --git a/jdk/test/java/lang/module/ModuleDescriptorTest.java b/jdk/test/java/lang/module/ModuleDescriptorTest.java new file mode 100644 index 00000000000..61dfc4ea315 --- /dev/null +++ b/jdk/test/java/lang/module/ModuleDescriptorTest.java @@ -0,0 +1,727 @@ +/* + * 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 + * 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 + * @run testng ModuleDescriptorTest + * @summary Basic test for java.lang.module.ModuleDescriptor and its builder + */ + +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Builder; +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Provides; +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.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ModuleDescriptorTest { + + @DataProvider(name = "invalidjavaidentifiers") + public Object[][] invalidJavaIdentifiers() { + return new Object[][]{ + + { null, null }, + { ".foo", null }, + { "foo.", null }, + { "[foo]", null }, + + }; + } + + + // requires + + private Requires requires(Set mods, String mn) { + return new Builder("m") + .requires(mods, mn) + .build() + .requires() + .iterator() + .next(); + } + + public void testRequiresWithRequires() { + Requires r1 = requires(null, "foo"); + ModuleDescriptor descriptor = new Builder("m").requires(r1).build(); + Requires r2 = descriptor.requires().iterator().next(); + assertEquals(r1, r2); + } + + public void testRequiresWithNullModifiers() { + Requires r = requires(null, "foo"); + assertEquals(r, r); + assertTrue(r.compareTo(r) == 0); + assertTrue(r.modifiers().isEmpty()); + assertEquals(r.name(), "foo"); + } + + public void testRequiresWithNoModifiers() { + Requires r = requires(EnumSet.noneOf(Requires.Modifier.class), "foo"); + assertEquals(r, r); + assertTrue(r.compareTo(r) == 0); + assertTrue(r.modifiers().isEmpty()); + assertEquals(r.name(), "foo"); + } + + public void testRequiresWithOneModifier() { + Requires r = requires(EnumSet.of(PUBLIC), "foo"); + assertEquals(r, r); + assertTrue(r.compareTo(r) == 0); + assertEquals(r.modifiers(), EnumSet.of(PUBLIC)); + assertEquals(r.name(), "foo"); + } + + public void testRequiresWithTwoModifiers() { + Requires r = requires(EnumSet.of(PUBLIC, SYNTHETIC), "foo"); + assertEquals(r, r); + assertTrue(r.compareTo(r) == 0); + assertEquals(r.modifiers(), EnumSet.of(PUBLIC, SYNTHETIC)); + assertEquals(r.name(), "foo"); + } + + public void testRequiresWithAllModifiers() { + Requires r = requires(EnumSet.allOf(Modifier.class), "foo"); + assertEquals(r, r); + assertTrue(r.compareTo(r) == 0); + assertEquals(r.modifiers(), EnumSet.allOf(Modifier.class)); + assertEquals(r.name(), "foo"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testRequiresWithDuplicatesRequires() { + Requires r = requires(null, "foo"); + new Builder("m").requires(r).requires(r); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testRequiresSelfWithRequires() { + Requires r = requires(null, "m"); + new Builder("m").requires(r); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testRequiresSelfWithNoModifier() { + new Builder("m").requires("m"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testRequiresSelfWithOneModifier() { + new Builder("m").requires(PUBLIC, "m"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testRequiresSelfWithAllModifiers() { + new Builder("m").requires(EnumSet.allOf(Modifier.class), "m"); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testRequiresWithBadModuleName(String mn, String ignore) { + requires(EnumSet.noneOf(Modifier.class), mn); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testRequiresWithNullRequires() { + new Builder("m").requires((Requires) null); + } + + public void testRequiresCompare() { + Requires r1 = requires(EnumSet.noneOf(Modifier.class), "foo"); + Requires r2 = requires(EnumSet.noneOf(Modifier.class), "bar"); + int n = "foo".compareTo("bar"); + assertTrue(r1.compareTo(r2) == n); + assertTrue(r2.compareTo(r1) == -n); + } + + public void testRequiresToString() { + Requires r = requires(EnumSet.noneOf(Modifier.class), "foo"); + assertTrue(r.toString().contains("foo")); + } + + + // exports + + private Exports exports(String pn) { + return new Builder("foo") + .exports(pn) + .build() + .exports() + .iterator() + .next(); + } + + private Exports exports(String pn, String target) { + return new Builder("foo") + .exports(pn, target) + .build() + .exports() + .iterator() + .next(); + } + + public void testExportsExports() { + Exports e1 = exports("p"); + ModuleDescriptor descriptor = new Builder("m").exports(e1).build(); + Exports e2 = descriptor.exports().iterator().next(); + assertEquals(e1, e2); + } + + public void testExportsToAll() { + Exports e = exports("p"); + assertEquals(e, e); + assertEquals(e.source(), "p"); + assertFalse(e.isQualified()); + assertTrue(e.targets().isEmpty()); + } + + public void testExportsToTarget() { + Exports e = exports("p", "bar"); + assertEquals(e, e); + assertEquals(e.source(), "p"); + assertTrue(e.isQualified()); + assertTrue(e.targets().size() == 1); + assertTrue(e.targets().contains("bar")); + } + + public void testExportsToTargets() { + Set targets = new HashSet<>(); + targets.add("bar"); + targets.add("gus"); + Exports e + = new Builder("foo") + .exports("p", targets) + .build() + .exports() + .iterator() + .next(); + assertEquals(e, e); + assertEquals(e.source(), "p"); + assertTrue(e.isQualified()); + assertTrue(e.targets().size() == 2); + assertTrue(e.targets().contains("bar")); + assertTrue(e.targets().contains("gus")); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsWithDuplicate1() { + Exports e = exports("p"); + new Builder("foo").exports(e).exports(e); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsWithDuplicate2() { + new Builder("foo").exports("p").exports("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsWithConcealedPackage() { + new Builder("foo").conceals("p").exports("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testExportsToTargetWithConcealedPackage() { + new Builder("foo").conceals("p").exports("p", "bar"); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testExportsWithEmptySet() { + new Builder("foo").exports("p", Collections.emptySet()); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testExportsWithBadName(String pn, String ignore) { + new Builder("foo").exports(pn); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testExportsWithNullExports() { + new Builder("foo").exports((Exports)null); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testExportsWithNullTarget() { + new Builder("foo").exports("p", (String) null); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testExportsWithNullTargets() { + new Builder("foo").exports("p", (Set) null); + } + + public void testExportsToString() { + String s = new Builder("foo") + .exports("p1", "bar") + .build() + .exports() + .iterator() + .next() + .toString(); + assertTrue(s.contains("p1")); + assertTrue(s.contains("bar")); + } + + + // uses + + public void testUses() { + Set uses + = new Builder("foo") + .uses("p.S") + .uses("q.S") + .build() + .uses(); + assertTrue(uses.size() == 2); + assertTrue(uses.contains("p.S")); + assertTrue(uses.contains("q.S")); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testUsesWithDuplicate() { + new Builder("foo").uses("p.S").uses("p.S"); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testUsesWithBadName(String service, String ignore) { + new Builder("foo").uses(service); + } + + + // provides + + private Provides provides(String st, String pc) { + return new Builder("foo") + .provides("p.S", pc) + .build() + .provides() + .values() + .iterator() + .next(); + } + + public void testProvidesWithProvides() { + Provides p1 = provides("p.S", "q.S1"); + ModuleDescriptor descriptor = new Builder("m").provides(p1).build(); + Provides p2 = descriptor.provides().get("p.S"); + assertEquals(p1, p2); + } + + public void testProvides() { + Set pns = new HashSet<>(); + pns.add("q.P1"); + pns.add("q.P2"); + + Map map + = new Builder("foo") + .provides("p.S", pns) + .build() + .provides(); + assertTrue(map.size() == 1); + + Provides p = map.values().iterator().next(); + assertEquals(p, p); + assertTrue(p.providers().size() == 2); + assertTrue(p.providers().contains("q.P1")); + assertTrue(p.providers().contains("q.P2")); + } + + @Test(expectedExceptions = IllegalStateException.class ) + public void testProvidesWithDuplicateProvides() { + Provides p = provides("p.S", "q.S2"); + new Builder("m").provides("p.S", "q.S1").provides(p); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithEmptySet() { + new Builder("foo").provides("p.Service", Collections.emptySet()); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithBadService(String service, String ignore) { + new Builder("foo").provides(service, "p.Provider"); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testProvidesWithBadProvider(String provider, String ignore) { + new Builder("foo").provides("p.Service", provider); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testProvidesWithNullProvides() { + new Builder("foo").provides((Provides)null); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testProvidesWithNullProviders() { + new Builder("foo").provides("p.S", (Set) null); + } + + + // conceals + + public void testConceals() { + Set conceals + = new Builder("foo").conceals("p").conceals("q").build().conceals(); + assertTrue(conceals.size() == 2); + assertTrue(conceals.contains("p")); + assertTrue(conceals.contains("q")); + } + + public void testConcealsWithEmptySet() { + Set conceals + = new Builder("foo").conceals(Collections.emptySet()).build().conceals(); + assertTrue(conceals.size() == 0); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testConcealsWithDuplicate() { + new Builder("foo").conceals("p").conceals("p"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testConcealsWithExportedPackage() { + new Builder("foo").exports("p").conceals("p"); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testConcealsWithBadName(String pn, String ignore) { + new Builder("foo").conceals(pn); + } + + + // packages + + public void testPackages() { + Set packages + = new Builder("foo").exports("p").conceals("q").build().packages(); + assertTrue(packages.size() == 2); + assertTrue(packages.contains("p")); + assertTrue(packages.contains("q")); + } + + + // name + + public void testModuleName() { + String mn = new Builder("foo").build().name(); + assertEquals(mn, "foo"); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testBadModuleName(String mn, String ignore) { + new Builder(mn); + } + + + // version + + public void testVersion1() { + Version v1 = Version.parse("1.0"); + Version v2 = new Builder("foo").version(v1).build().version().get(); + assertEquals(v1, v2); + } + + public void testVersion2() { + String vs = "1.0"; + Version v1 = new Builder("foo").version(vs).build().version().get(); + Version v2 = Version.parse(vs); + assertEquals(v1, v2); + } + + @Test(expectedExceptions = NullPointerException.class ) + public void testNullVersion1() { + new Builder("foo").version((Version)null); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testNullVersion2() { + new Builder("foo").version((String)null); + } + + @Test(expectedExceptions = IllegalArgumentException.class ) + public void testEmptyVersion() { + new Builder("foo").version(""); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testDuplicateVersion1() { + Version v = Version.parse("2.0"); + new Builder("foo").version("1.0").version(v); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testDuplicateVersion2() { + new Builder("foo").version("1.0").version("2.0"); + } + + + // toNameAndVersion + + public void testToNameAndVersion() { + ModuleDescriptor md1 = new Builder("foo").build(); + assertEquals(md1.toNameAndVersion(), "foo"); + + ModuleDescriptor md2 = new Builder("foo").version("1.0").build(); + assertEquals(md2.toNameAndVersion(), "foo@1.0"); + } + + + // isAutomatic + public void testIsAutomatic() { + ModuleDescriptor descriptor = new Builder("foo").build(); + assertFalse(descriptor.isAutomatic()); + } + + // isSynthetic + public void testIsSynthetic() { + assertFalse(Object.class.getModule().getDescriptor().isSynthetic()); + + ModuleDescriptor descriptor = new Builder("foo").build(); + assertFalse(descriptor.isSynthetic()); + } + + + // mainClass + + public void testMainClass() { + String mainClass + = new Builder("foo").mainClass("p.Main").build().mainClass().get(); + assertEquals(mainClass, "p.Main"); + } + + @Test(dataProvider = "invalidjavaidentifiers", + expectedExceptions = IllegalArgumentException.class ) + public void testMainClassWithBadName(String mainClass, String ignore) { + Builder builder = new Builder("foo"); + builder.mainClass(mainClass); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testDuplicateMainClass() { + new Builder("foo").mainClass("p.Main").mainClass("p.Main"); + } + + + // osName + + public void testOsName() { + String osName = new Builder("foo").osName("Linux").build().osName().get(); + assertEquals(osName, "Linux"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNullOsName() { + new Builder("foo").osName(null); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testEmptyOsName() { + new Builder("foo").osName(""); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testDuplicateOsName() { + new Builder("foo").osName("Linux").osName("Linux"); + } + + + // osArch + + public void testOsArch() { + String osArch = new Builder("foo").osName("arm").build().osName().get(); + assertEquals(osArch, "arm"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNullOsArch() { + new Builder("foo").osArch(null); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testEmptyOsArch() { + new Builder("foo").osArch(""); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testDuplicateOsArch() { + new Builder("foo").osArch("arm").osArch("arm"); + } + + + // osVersion + + public void testOsVersion() { + String osVersion = new Builder("foo").osName("11.2").build().osName().get(); + assertEquals(osVersion, "11.2"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNullOsVersion() { + new Builder("foo").osVersion(null); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testEmptyOsVersion() { + new Builder("foo").osVersion(""); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testDuplicateOsVersion() { + new Builder("foo").osVersion("11.2").osVersion("11.2"); + } + + + // reads + + private static InputStream EMPTY_INPUT_STREAM = new InputStream() { + @Override + public int read() { + return -1; + } + }; + + private static InputStream FAILING_INPUT_STREAM = new InputStream() { + @Override + public int read() throws IOException { + throw new IOException(); + } + }; + + public void testRead() throws Exception { + Module base = Object.class.getModule(); + + try (InputStream in = base.getResourceAsStream("module-info.class")) { + ModuleDescriptor descriptor = ModuleDescriptor.read(in); + assertTrue(in.read() == -1); // all bytes read + assertEquals(descriptor.name(), "java.base"); + } + + try (InputStream in = base.getResourceAsStream("module-info.class")) { + ByteBuffer bb = ByteBuffer.wrap(in.readAllBytes()); + ModuleDescriptor descriptor = ModuleDescriptor.read(bb); + assertFalse(bb.hasRemaining()); // no more remaining bytes + assertEquals(descriptor.name(), "java.base"); + } + } + + public void testReadsWithPackageFinder() { + // TBD: Need way to write a module-info.class without a + // ConcealedPackages attribute + } + + @Test(expectedExceptions = InvalidModuleDescriptorException.class) + public void testReadFromEmptyInputStream() throws Exception { + ModuleDescriptor.read(EMPTY_INPUT_STREAM); + } + + @Test(expectedExceptions = IOException.class) + public void testReadFromFailingInputStream() throws Exception { + ModuleDescriptor.read(FAILING_INPUT_STREAM); + } + + @Test(expectedExceptions = InvalidModuleDescriptorException.class) + public void testReadFromEmptyBuffer() { + ByteBuffer bb = ByteBuffer.allocate(0); + ModuleDescriptor.read(bb); + } + + public void testReadWithNull() throws Exception { + Module base = Object.class.getModule(); + + try { + ModuleDescriptor.read((InputStream)null); + assertTrue(false); + } catch (NullPointerException expected) { } + + + try (InputStream in = base.getResourceAsStream("module-info.class")) { + try { + ModuleDescriptor.read(in, null); + assertTrue(false); + } catch (NullPointerException expected) { } + } + + try { + ModuleDescriptor.read((ByteBuffer)null); + assertTrue(false); + } catch (NullPointerException expected) { } + + + try (InputStream in = base.getResourceAsStream("module-info.class")) { + ByteBuffer bb = ByteBuffer.wrap(in.readAllBytes()); + try { + ModuleDescriptor.read(bb, null); + assertTrue(false); + } catch (NullPointerException expected) { } + } + } + + + // equals/hashCode/compareTo/toString + + public void testEqualsAndHashCode() { + ModuleDescriptor md1 = new Builder("foo").build(); + ModuleDescriptor md2 = new Builder("foo").build(); + assertEquals(md1, md1); + assertEquals(md1.hashCode(), md2.hashCode()); + } + + public void testCompare() { + ModuleDescriptor md1 = new Builder("foo").build(); + ModuleDescriptor md2 = new Builder("bar").build(); + int n = "foo".compareTo("bar"); + assertTrue(md1.compareTo(md2) == n); + assertTrue(md2.compareTo(md1) == -n); + } + + public void testToString() { + String s = new Builder("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 new file mode 100644 index 00000000000..2306ba3a2f9 --- /dev/null +++ b/jdk/test/java/lang/module/ModuleFinderTest.java @@ -0,0 +1,568 @@ +/* + * 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. + */ + +/** + * @test + * @modules java.base/jdk.internal.module + * @build ModuleFinderTest + * @run testng ModuleFinderTest + * @summary Basic tests for java.lang.module.ModuleFinder + */ + +import java.io.OutputStream; +import java.lang.module.FindException; +import java.lang.module.InvalidModuleDescriptorException; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.stream.Collectors; + +import jdk.internal.module.ModuleInfoWriter; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ModuleFinderTest { + + private static final Path USER_DIR + = Paths.get(System.getProperty("user.dir")); + + + /** + * Test ModuleFinder.ofSystem + */ + public void testOfSystem() { + ModuleFinder finder = ModuleFinder.ofSystem(); + + assertTrue(finder.find("java.se").isPresent()); + assertTrue(finder.find("java.base").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + + Set names = finder.findAll().stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()); + assertTrue(names.contains("java.se")); + assertTrue(names.contains("java.base")); + assertFalse(names.contains("java.rhubarb")); + } + + + /** + * Test ModuleFinder.of with zero entries + */ + public void testOfZeroEntries() { + ModuleFinder finder = ModuleFinder.of(); + assertTrue(finder.findAll().isEmpty()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with one directory of modules + */ + public void testOfOneDirectory() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createExplodedModule(dir.resolve("m1"), "m1"); + createModularJar(dir.resolve("m2.jar"), "m2"); + + ModuleFinder finder = ModuleFinder.of(dir); + assertTrue(finder.findAll().size() == 2); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with two directories + */ + public void testOfTwoDirectories() throws Exception { + Path dir1 = Files.createTempDirectory(USER_DIR, "mods1"); + createExplodedModule(dir1.resolve("m1"), "m1@1.0"); + createModularJar(dir1.resolve("m2.jar"), "m2@1.0"); + + Path dir2 = Files.createTempDirectory(USER_DIR, "mods2"); + createExplodedModule(dir2.resolve("m1"), "m1@2.0"); + createModularJar(dir2.resolve("m2.jar"), "m2@2.0"); + createExplodedModule(dir2.resolve("m3"), "m3"); + createModularJar(dir2.resolve("m4.jar"), "m4"); + + ModuleFinder finder = ModuleFinder.of(dir1, dir2); + assertTrue(finder.findAll().size() == 4); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertTrue(finder.find("m3").isPresent()); + assertTrue(finder.find("m4").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + + // check that m1@1.0 (and not m1@2.0) is found + ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + assertEquals(m1.version().get().toString(), "1.0"); + + // check that m2@1.0 (and not m2@2.0) is found + ModuleDescriptor m2 = finder.find("m2").get().descriptor(); + assertEquals(m2.version().get().toString(), "1.0"); + } + + + /** + * Test ModuleFinder.of with one JAR file + */ + public void testOfOneJarFile() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1"); + + ModuleFinder finder = ModuleFinder.of(jar1); + assertTrue(finder.findAll().size() == 1); + assertTrue(finder.find("m1").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with two JAR files + */ + public void testOfTwoJarFiles() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + + Path jar1 = createModularJar(dir.resolve("m1.jar"), "m1"); + Path jar2 = createModularJar(dir.resolve("m2.jar"), "m2"); + + ModuleFinder finder = ModuleFinder.of(jar1, jar2); + assertTrue(finder.findAll().size() == 2); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with many JAR files + */ + public void testOfManyJarFiles() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + + Path jar1 = createModularJar(dir.resolve("m1@1.0.jar"), "m1@1.0"); + Path jar2 = createModularJar(dir.resolve("m2@1.0.jar"), "m2"); + Path jar3 = createModularJar(dir.resolve("m1@2.0.jar"), "m1@2.0"); // shadowed + Path jar4 = createModularJar(dir.resolve("m3@1.0.jar"), "m3"); + + ModuleFinder finder = ModuleFinder.of(jar1, jar2, jar3, jar4); + assertTrue(finder.findAll().size() == 3); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertTrue(finder.find("m3").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + + // check that m1@1.0 (and not m1@2.0) is found + ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + assertEquals(m1.version().get().toString(), "1.0"); + } + + + /** + * Test ModuleFinder.of with one exploded module. + */ + public void testOfOneExplodedModule() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1"); + + ModuleFinder finder = ModuleFinder.of(m1_dir); + assertTrue(finder.findAll().size() == 1); + assertTrue(finder.find("m1").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with two exploded modules. + */ + public void testOfTwoExplodedModules() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path m1_dir = createExplodedModule(dir.resolve("m1"), "m1"); + Path m2_dir = createExplodedModule(dir.resolve("m2"), "m2"); + + ModuleFinder finder = ModuleFinder.of(m1_dir, m2_dir); + assertTrue(finder.findAll().size() == 2); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with a mix of module directories and JAR files. + */ + public void testOfMixDirectoriesAndJars() throws Exception { + + // directory with m1@1.0 and m2@1.0 + Path dir1 = Files.createTempDirectory(USER_DIR, "mods1"); + createExplodedModule(dir1.resolve("m1"), "m1@1.0"); + createModularJar(dir1.resolve("m2.jar"), "m2@1.0"); + + // JAR files: m1@2.0, m2@2.0, m3@2.0, m4@2.0 + Path dir2 = Files.createTempDirectory(USER_DIR, "mods2"); + Path jar1 = createModularJar(dir2.resolve("m1.jar"), "m1@2.0"); + Path jar2 = createModularJar(dir2.resolve("m2.jar"), "m2@2.0"); + Path jar3 = createModularJar(dir2.resolve("m3.jar"), "m3@2.0"); + Path jar4 = createModularJar(dir2.resolve("m4.jar"), "m4@2.0"); + + // directory with m3@3.0 and m4@3.0 + Path dir3 = Files.createTempDirectory(USER_DIR, "mods3"); + createExplodedModule(dir3.resolve("m3"), "m3@3.0"); + createModularJar(dir3.resolve("m4.jar"), "m4@3.0"); + + // JAR files: m5 and m6 + Path dir4 = Files.createTempDirectory(USER_DIR, "mods4"); + Path jar5 = createModularJar(dir4.resolve("m5.jar"), "m5@4.0"); + Path jar6 = createModularJar(dir4.resolve("m6.jar"), "m6@4.0"); + + + ModuleFinder finder + = ModuleFinder.of(dir1, jar1, jar2, jar3, jar4, dir3, jar5, jar6); + assertTrue(finder.findAll().size() == 6); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertTrue(finder.find("m3").isPresent()); + assertTrue(finder.find("m4").isPresent()); + assertTrue(finder.find("m5").isPresent()); + assertTrue(finder.find("m6").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + + // m1 and m2 should be located in dir1 + ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + assertEquals(m1.version().get().toString(), "1.0"); + ModuleDescriptor m2 = finder.find("m2").get().descriptor(); + assertEquals(m2.version().get().toString(), "1.0"); + + // m3 and m4 should be located in JAR files + ModuleDescriptor m3 = finder.find("m3").get().descriptor(); + assertEquals(m3.version().get().toString(), "2.0"); + ModuleDescriptor m4 = finder.find("m4").get().descriptor(); + assertEquals(m4.version().get().toString(), "2.0"); + + // m5 and m6 should be located in JAR files + ModuleDescriptor m5 = finder.find("m5").get().descriptor(); + assertEquals(m5.version().get().toString(), "4.0"); + ModuleDescriptor m6 = finder.find("m6").get().descriptor(); + assertEquals(m6.version().get().toString(), "4.0"); + } + + + /** + * Test ModuleFinder.of with a mix of module directories and exploded + * modules. + */ + public void testOfMixDirectoriesAndExplodedModules() throws Exception { + // directory with m1@1.0 and m2@1.0 + Path dir1 = Files.createTempDirectory(USER_DIR, "mods1"); + createExplodedModule(dir1.resolve("m1"), "m1@1.0"); + createModularJar(dir1.resolve("m2.jar"), "m2@1.0"); + + // exploded modules: m1@2.0, m2@2.0, m3@2.0, m4@2.0 + Path dir2 = Files.createTempDirectory(USER_DIR, "mods2"); + Path m1_dir = createExplodedModule(dir2.resolve("m1"), "m1@2.0"); + Path m2_dir = createExplodedModule(dir2.resolve("m2"), "m2@2.0"); + Path m3_dir = createExplodedModule(dir2.resolve("m3"), "m3@2.0"); + Path m4_dir = createExplodedModule(dir2.resolve("m4"), "m4@2.0"); + + ModuleFinder finder = ModuleFinder.of(dir1, m1_dir, m2_dir, m3_dir, m4_dir); + assertTrue(finder.findAll().size() == 4); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertTrue(finder.find("m3").isPresent()); + assertTrue(finder.find("m4").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + + // m1 and m2 should be located in dir1 + ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + assertEquals(m1.version().get().toString(), "1.0"); + ModuleDescriptor m2 = finder.find("m2").get().descriptor(); + assertEquals(m2.version().get().toString(), "1.0"); + + // m3 and m4 should be located in dir2 + ModuleDescriptor m3 = finder.find("m3").get().descriptor(); + assertEquals(m3.version().get().toString(), "2.0"); + ModuleDescriptor m4 = finder.find("m4").get().descriptor(); + assertEquals(m4.version().get().toString(), "2.0"); + } + + + /** + * Test ModuleFinder.of with a path to a file that does not exist. + */ + public void testOfWithDoesNotExistEntry() throws Exception { + Path dir1 = Files.createTempDirectory(USER_DIR, "mods1"); + + Path dir2 = Files.createTempDirectory(USER_DIR, "mods2"); + createModularJar(dir2.resolve("m2.jar"), "m2@1.0"); + + Files.delete(dir1); + + ModuleFinder finder = ModuleFinder.of(dir1, dir2); + + assertTrue(finder.find("m2").isPresent()); + assertTrue(finder.findAll().size() == 1); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test ModuleFinder.of with a file path to an unrecognized file type. + */ + public void testOfWithUnrecognizedEntry() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + Path mod = Files.createTempFile(dir, "m", "mod"); + + ModuleFinder finder = ModuleFinder.of(mod); + try { + finder.find("java.rhubarb"); + assertTrue(false); + } catch (FindException e) { + // expected + } + + finder = ModuleFinder.of(mod); + try { + finder.findAll(); + assertTrue(false); + } catch (FindException e) { + // expected + } + } + + + /** + * Test ModuleFinder.of with a directory that contains two + * versions of the same module + */ + public void testOfDuplicateModulesInDirectory() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + createModularJar(dir.resolve("m1@1.0.jar"), "m1"); + createModularJar(dir.resolve("m1@2.0.jar"), "m1"); + + ModuleFinder finder = ModuleFinder.of(dir); + try { + finder.find("m1"); + assertTrue(false); + } catch (FindException expected) { } + + finder = ModuleFinder.of(dir); + try { + finder.findAll(); + assertTrue(false); + } catch (FindException expected) { } + } + + + /** + * Test ModuleFinder.of with a truncated module-info.class + */ + public void testOfWithTruncatedModuleInfo() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mods"); + + // create an empty /rhubarb/module-info.class + Path subdir = Files.createDirectory(dir.resolve("rhubarb")); + Files.createFile(subdir.resolve("module-info.class")); + + ModuleFinder finder = ModuleFinder.of(dir); + try { + finder.find("rhubarb"); + assertTrue(false); + } catch (FindException e) { + assertTrue(e.getCause() instanceof InvalidModuleDescriptorException); + } + + finder = ModuleFinder.of(dir); + try { + finder.findAll(); + assertTrue(false); + } catch (FindException e) { + assertTrue(e.getCause() instanceof InvalidModuleDescriptorException); + } + } + + + /** + * Test ModuleFinder.compose + */ + public void testCompose() throws Exception { + Path dir1 = Files.createTempDirectory(USER_DIR, "mods1"); + createExplodedModule(dir1.resolve("m1"), "m1@1.0"); + createExplodedModule(dir1.resolve("m2"), "m2@1.0"); + + Path dir2 = Files.createTempDirectory(USER_DIR, "mods2"); + createExplodedModule(dir2.resolve("m1"), "m1@2.0"); + createExplodedModule(dir2.resolve("m2"), "m2@2.0"); + createExplodedModule(dir2.resolve("m3"), "m3"); + createExplodedModule(dir2.resolve("m4"), "m4"); + + ModuleFinder finder1 = ModuleFinder.of(dir1); + ModuleFinder finder2 = ModuleFinder.of(dir2); + + ModuleFinder finder = ModuleFinder.compose(finder1, finder2); + assertTrue(finder.findAll().size() == 4); + assertTrue(finder.find("m1").isPresent()); + assertTrue(finder.find("m2").isPresent()); + assertTrue(finder.find("m3").isPresent()); + assertTrue(finder.find("m4").isPresent()); + assertFalse(finder.find("java.rhubarb").isPresent()); + + // check that m1@1.0 (and not m1@2.0) is found + ModuleDescriptor m1 = finder.find("m1").get().descriptor(); + assertEquals(m1.version().get().toString(), "1.0"); + + // check that m2@1.0 (and not m2@2.0) is found + ModuleDescriptor m2 = finder.find("m2").get().descriptor(); + assertEquals(m2.version().get().toString(), "1.0"); + } + + + /** + * Test ModuleFinder.empty + */ + public void testEmpty() { + ModuleFinder finder = ModuleFinder.empty(); + assertTrue(finder.findAll().isEmpty()); + assertFalse(finder.find("java.rhubarb").isPresent()); + } + + + /** + * Test null handling + */ + public void testNulls() { + + try { + ModuleFinder.ofSystem().find(null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + ModuleFinder.of().find(null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + ModuleFinder.empty().find(null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + ModuleFinder.of((Path[])null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + ModuleFinder.of((Path)null); + assertTrue(false); + } catch (NullPointerException expected) { } + + // compose + ModuleFinder finder = ModuleFinder.of(); + try { + ModuleFinder.compose(finder, null); + assertTrue(false); + } catch (NullPointerException expected) { } + try { + ModuleFinder.compose(null, finder); + assertTrue(false); + } catch (NullPointerException expected) { } + + } + + + /** + * Parses a string of the form {@code name[@version]} and returns a + * ModuleDescriptor with that name and version. The ModuleDescriptor + * will have a requires on java.base. + */ + static ModuleDescriptor newModuleDescriptor(String mid) { + String mn; + String vs; + int i = mid.indexOf("@"); + if (i == -1) { + mn = mid; + vs = null; + } else { + mn = mid.substring(0, i); + vs = mid.substring(i+1); + } + ModuleDescriptor.Builder builder + = new ModuleDescriptor.Builder(mn).requires("java.base"); + if (vs != null) + builder.version(vs); + return builder.build(); + } + + /** + * Creates an exploded module in the given directory and containing a + * module descriptor with the given module name/version. + */ + static Path createExplodedModule(Path dir, String mid) throws Exception { + ModuleDescriptor descriptor = newModuleDescriptor(mid); + Files.createDirectories(dir); + Path mi = dir.resolve("module-info.class"); + try (OutputStream out = Files.newOutputStream(mi)) { + ModuleInfoWriter.write(descriptor, out); + } + return dir; + } + + /** + * Creates a JAR file with the given file path and containing a module + * descriptor with the given module name/version. + */ + static Path createModularJar(Path file, String mid, String ... entries) + throws Exception + { + ModuleDescriptor descriptor = newModuleDescriptor(mid); + try (OutputStream out = Files.newOutputStream(file)) { + try (JarOutputStream jos = new JarOutputStream(out)) { + + JarEntry je = new JarEntry("module-info.class"); + jos.putNextEntry(je); + ModuleInfoWriter.write(descriptor, jos); + jos.closeEntry(); + + for (String entry : entries) { + je = new JarEntry(entry); + jos.putNextEntry(je); + jos.closeEntry(); + } + } + + } + return file; + } + +} + diff --git a/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java new file mode 100644 index 00000000000..ecaf6f45dff --- /dev/null +++ b/jdk/test/java/lang/module/ModuleReader/ModuleReaderTest.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules java.base/jdk.internal.module + * jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @build ModuleReaderTest CompilerUtils JarUtils + * @run testng ModuleReaderTest + * @summary Basic tests for java.lang.module.ModuleReader + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.net.URL; +import java.net.URLConnection; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Optional; + +import jdk.internal.module.ConfigurableModuleFinder; +import jdk.internal.module.ConfigurableModuleFinder.Phase; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ModuleReaderTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + + // the module name of the test module + private static final String TEST_MODULE = "m"; + + // 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[] RESOURCES = { + "p/Main.class" + }; + + // a resource that is not in the test module + private static final String NOT_A_RESOURCE = "NotAResource"; + + + @BeforeTest + public void compileTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + boolean compiled + = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE)); + assertTrue(compiled, "test module did not compile"); + } + + + /** + * Test exploded module + */ + public void testExplodedModule() throws Exception { + test(MODS_DIR); + } + + + /** + * Test modular JAR + */ + public void testModularJar() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mlib"); + + // jar cf mlib/${TESTMODULE}.jar -C mods . + JarUtils.createJarFile(dir.resolve("m.jar"), + MODS_DIR.resolve(TEST_MODULE)); + + test(dir); + } + + + /** + * Test JMOD + */ + public void testJMod() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mlib"); + + // jmod create --class-path mods/${TESTMODULE} mlib/${TESTMODULE}.jmod + String cp = MODS_DIR.resolve(TEST_MODULE).toString(); + String jmod = dir.resolve("m.jmod").toString(); + String[] args = { "create", "--class-path", cp, jmod }; + jdk.tools.jmod.JmodTask task = new jdk.tools.jmod.JmodTask(); + assertEquals(task.run(args), 0); + + test(dir); + } + + + /** + * The test module is found on the given module path. Open a ModuleReader + * to the test module and test the reader. + */ + void test(Path mp) throws Exception { + + ModuleFinder finder = ModuleFinder.of(mp); + if (finder instanceof ConfigurableModuleFinder) { + // need ModuleFinder to be in the phase to find JMOD files + ((ConfigurableModuleFinder)finder).configurePhase(Phase.LINK_TIME); + } + + ModuleReference mref = finder.find(TEST_MODULE).get(); + ModuleReader reader = mref.open(); + + try (reader) { + + // test each of the known resources in the module + for (String name : RESOURCES) { + byte[] expectedBytes + = Files.readAllBytes(MODS_DIR + .resolve(TEST_MODULE) + .resolve(name.replace('/', File.separatorChar))); + + testFind(reader, name, expectedBytes); + testOpen(reader, name, expectedBytes); + testRead(reader, name, expectedBytes); + } + + // test "not found" + assertFalse(reader.open(NOT_A_RESOURCE).isPresent()); + assertFalse(reader.read(NOT_A_RESOURCE).isPresent()); + + // test nulls + try { + reader.find(null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + reader.open(null); + assertTrue(false); + } catch (NullPointerException expected) { } + + try { + reader.read(null); + assertTrue(false); + } catch (NullPointerException expected) { } + + // should release(null) throw NPE? + + } + + // test closed ModuleReader + try { + reader.open(RESOURCES[0]); + assertTrue(false); + } catch (IOException expected) { } + + + try { + reader.read(RESOURCES[0]); + assertTrue(false); + } catch (IOException expected) { } + } + + /** + * Test ModuleReader#find + */ + void testFind(ModuleReader reader, String name, byte[] expectedBytes) + throws Exception + { + Optional ouri = reader.find(name); + assertTrue(ouri.isPresent()); + + URL url = ouri.get().toURL(); + if (!url.getProtocol().equalsIgnoreCase("jmod")) { + URLConnection uc = url.openConnection(); + uc.setUseCaches(false); + try (InputStream in = uc.getInputStream()) { + byte[] bytes = in.readAllBytes(); + assertTrue(Arrays.equals(bytes, expectedBytes)); + } + } + } + + /** + * Test ModuleReader#open + */ + void testOpen(ModuleReader reader, String name, byte[] expectedBytes) + throws Exception + { + Optional oin = reader.open(name); + assertTrue(oin.isPresent()); + + InputStream in = oin.get(); + try (in) { + byte[] bytes = in.readAllBytes(); + assertTrue(Arrays.equals(bytes, expectedBytes)); + } + } + + /** + * Test ModuleReader#read + */ + void testRead(ModuleReader reader, String name, byte[] expectedBytes) + throws Exception + { + Optional obb = reader.read(name); + assertTrue(obb.isPresent()); + + ByteBuffer bb = obb.get(); + try { + int rem = bb.remaining(); + assertTrue(rem == expectedBytes.length); + byte[] bytes = new byte[rem]; + bb.get(bytes); + assertTrue(Arrays.equals(bytes, expectedBytes)); + } finally { + reader.release(bb); + } + } + +} diff --git a/jdk/test/java/lang/module/ModuleReader/src/m/module-info.java b/jdk/test/java/lang/module/ModuleReader/src/m/module-info.java new file mode 100644 index 00000000000..cf46bcc808e --- /dev/null +++ b/jdk/test/java/lang/module/ModuleReader/src/m/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m { +} diff --git a/jdk/test/java/lang/module/ModuleReader/src/m/p/Main.java b/jdk/test/java/lang/module/ModuleReader/src/m/p/Main.java new file mode 100644 index 00000000000..b0be05f52ca --- /dev/null +++ b/jdk/test/java/lang/module/ModuleReader/src/m/p/Main.java @@ -0,0 +1,33 @@ +/* + * 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 p; + +/** + * Main class for dummy module. + */ + +public class Main { + public static void main(String[] args) { + } +} diff --git a/jdk/test/java/lang/module/ModuleReferenceTest.java b/jdk/test/java/lang/module/ModuleReferenceTest.java new file mode 100644 index 00000000000..25b927716b1 --- /dev/null +++ b/jdk/test/java/lang/module/ModuleReferenceTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @run testng ModuleReferenceTest + * @summary Basic tests for java.lang.module.ModuleReference + */ + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.util.function.Supplier; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ModuleReferenceTest { + + private Supplier makeSupplier() { + return () -> { throw new UnsupportedOperationException(); }; + } + + public void testBasic() throws Exception { + ModuleDescriptor descriptor + = new ModuleDescriptor.Builder("m") + .exports("p") + .exports("q") + .conceals("p.internal") + .build(); + + URI uri = URI.create("module:/m"); + + Supplier supplier = makeSupplier(); + + ModuleReference mref = new ModuleReference(descriptor, uri, supplier); + + assertTrue(mref.descriptor().equals(descriptor)); + assertTrue(mref.location().get().equals(uri)); + + // check that the supplier is called + try { + mref.open(); + assertTrue(false); + } catch (UnsupportedOperationException expected) { } + } + + + @Test(expectedExceptions = { NullPointerException.class }) + public void testNullDescriptor() throws Exception { + URI location = URI.create("module:/m"); + new ModuleReference(null, location, makeSupplier()); + } + + public void testNullLocation() { + ModuleDescriptor descriptor + = new ModuleDescriptor.Builder("m") + .exports("p") + .build(); + Supplier supplier = makeSupplier(); + ModuleReference mref = new ModuleReference(descriptor, null, supplier); + assertTrue(!mref.location().isPresent()); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testNullSupplier() throws Exception { + ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m").build(); + URI location = URI.create("module:/m"); + new ModuleReference(descriptor, location, null); + } + + + public void testEqualsAndHashCode() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .build(); + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m1") + .exports("p") + .build(); + + URI uri = URI.create("module:/m1"); + Supplier supplier = makeSupplier(); + + ModuleReference mref1 = new ModuleReference(descriptor1, uri, supplier); + ModuleReference mref2 = new ModuleReference(descriptor2, uri, supplier); + ModuleReference mref3 = new ModuleReference(descriptor1, null, supplier); + + assertTrue(mref1.equals(mref1)); + assertTrue(mref1.equals(mref1)); + assertTrue(mref2.equals(mref1)); + assertTrue(mref1.hashCode() == mref2.hashCode()); + + assertTrue(mref3.equals(mref3)); + assertFalse(mref3.equals(mref1)); + assertFalse(mref1.equals(mref3)); + } + + + public void testToString() { + ModuleDescriptor descriptor = new ModuleDescriptor.Builder("m1").build(); + URI uri = URI.create("module:/m1"); + Supplier supplier = makeSupplier(); + ModuleReference mref = new ModuleReference(descriptor, uri, supplier); + String s = mref.toString(); + assertTrue(s.contains("m1")); + assertTrue(s.contains(uri.toString())); + } + +} diff --git a/jdk/test/java/lang/module/VersionTest.java b/jdk/test/java/lang/module/VersionTest.java new file mode 100644 index 00000000000..41d45306ff4 --- /dev/null +++ b/jdk/test/java/lang/module/VersionTest.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +/** + * @test + * @run testng VersionTest + * @summary Basic tests for java.lang.module.ModuleDescriptor.Version. + */ + +import java.lang.module.ModuleDescriptor.Version; + +import org.testng.annotations.Test; +import org.testng.annotations.DataProvider; +import static org.testng.Assert.*; + +@Test +public class VersionTest { + + // valid version strings + @DataProvider(name = "validVersions") + public Object[][] validVersions() { + return new Object[][]{ + + { "1.0", null }, + { "1.0.0", null }, + { "1.0.0.0", null }, + + { "99", null }, + { "99.99", null }, + { "99.99.99", null }, + + { "1-SNAPSHOT", null }, + { "1.0-SNAPSHOT", null }, + { "1.0.0-SNAPSHOT", null }, + + { "9-ea", null }, + { "9-ea+110", null }, + { "9.3.2.1+42-8839942", null} + + }; + } + + // invalid version strings + @DataProvider(name = "invalidVersions") + public Object[][] invalidVersions() { + return new Object[][]{ + + { null, null }, + { "", null }, + { "A1", null }, // does not start with number + { "1.0-", null }, // empty branch + + }; + } + + // Test parsing valid version strings + @Test(dataProvider = "validVersions") + public void testParseValidVersions(String vs, String ignore) { + Version v = Version.parse(vs); + assertEquals(v.toString(), vs); + } + + // Test parsing an invalid version strings + @Test(dataProvider = "invalidVersions", + expectedExceptions = IllegalArgumentException.class ) + public void testParseInvalidVersions(String vs, String ignore) { + Version.parse(vs); + } + + // Test equals and hashCode + @Test(dataProvider = "validVersions") + public void testEqualsAndHashCode(String vs, String ignore) { + + Version v1 = Version.parse(vs); + Version v2 = Version.parse(vs); + assertEquals(v1, v2); + assertEquals(v2, v1); + assertEquals(v1.hashCode(), v2.hashCode()); + + Version v3 = Version.parse("1.0-rhubarb"); + assertNotEquals(v1, v3); + assertNotEquals(v2, v3); + assertNotEquals(v3, v1); + assertNotEquals(v3, v2); + + } + + // ordered version strings + @DataProvider(name = "orderedVersions") + public Object[][] orderedVersions() { + return new Object[][]{ + + { "1.0", "2.0" }, + { "1.0-SNAPSHOT", "1.0" }, + { "1.0-SNAPSHOT2", "1.0" }, + { "1.2.3-ea", "1.2.3" }, + { "1.2.3-ea+104", "1.2.3-ea+105" }, + { "1.2.3-ea+104-4084552", "1.2.3-ea+104-4084552+8849330" }, + { "1+104", "1+105" }, + { "1.0-alpha1", "1.0-alpha2" } + + }; + } + + /** + * Test compareTo with ordered versions. + */ + @Test(dataProvider = "orderedVersions") + public void testCompareOrderedVersions(String vs1, String vs2) { + + Version v1 = Version.parse(vs1); + assertTrue(v1.compareTo(v1) == 0); + + Version v2 = Version.parse(vs2); + assertTrue(v2.compareTo(v2) == 0); + + // v1 < v2 + assertTrue(v1.compareTo(v2) < 0); + assertTrue(v2.compareTo(v1) > 0); + + } + + // equal version strings + @DataProvider(name = "equalVersions") + public Object[][] equalVersions() { + return new Object[][]{ + + { "1", "1.0.0" }, + { "1.0", "1.0.0" }, + { "1.0-beta", "1.0.0-beta" }, + + }; + } + + /** + * Test compareTo with equal versions. + */ + @Test(dataProvider = "equalVersions") + public void testCompareEqualsVersions(String vs1, String vs2) { + + Version v1 = Version.parse(vs1); + assertTrue(v1.compareTo(v1) == 0); + + Version v2 = Version.parse(vs2); + assertTrue(v2.compareTo(v2) == 0); + + assertTrue(v1.compareTo(v2) == 0); + assertTrue(v2.compareTo(v1) == 0); + assertEquals(v1, v2); + assertEquals(v2, v1); + + } + +} diff --git a/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java new file mode 100644 index 00000000000..8d9196658b5 --- /dev/null +++ b/jdk/test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @build ModuleSetAccessibleTest + * @modules java.base/jdk.internal.misc + * @run testng ModuleSetAccessibleTest + * @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; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Module; + +import jdk.internal.misc.Unsafe; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ModuleSetAccessibleTest { + + /** + * Invoke a private constructor on a public class in an exported package + */ + public void testPrivateConstructorInExportedPackage() throws Exception { + Constructor ctor = Unsafe.class.getDeclaredConstructor(); + + try { + ctor.newInstance(); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + ctor.setAccessible(true); + Unsafe unsafe = (Unsafe) ctor.newInstance(); + } + + + /** + * Invoke a private method on a public class in an exported package + */ + public void testPrivateMethodInExportedPackage() throws Exception { + Method m = Unsafe.class.getDeclaredMethod("throwIllegalAccessError"); + try { + m.invoke(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + m.setAccessible(true); + try { + m.invoke(null); + assertTrue(false); + } catch (InvocationTargetException e) { + // thrown by throwIllegalAccessError + assertTrue(e.getCause() instanceof IllegalAccessError); + } + } + + + /** + * Access a private field in a public class that is an exported package + */ + public void testPrivateFieldInExportedPackage() throws Exception { + Field f = Unsafe.class.getDeclaredField("theUnsafe"); + + try { + f.get(null); + assertTrue(false); + } catch (IllegalAccessException expected) { } + + f.setAccessible(true); + 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) { } + + try { + ctor.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + ctor.setAccessible(false); // should succeed + } + + + /** + * 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) { } + + try { + f.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + f.setAccessible(false); // should succeed + } + + + /** + * Test that only public members of java.lang.reflect.Module can be make + * accessible. + */ + public void testJavaLangReflectModule() throws Exception { + + // non-public constructor + Constructor ctor + = Module.class.getDeclaredConstructor(ClassLoader.class, + ModuleDescriptor.class); + AccessibleObject[] ctors = { ctor }; + + try { + ctor.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + try { + AccessibleObject.setAccessible(ctors, true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + // should succeed + ctor.setAccessible(false); + AccessibleObject.setAccessible(ctors, false); + + + // public method + Method method = Module.class.getMethod("addReads", Module.class); + AccessibleObject[] methods = { method }; + method.setAccessible(true); + AccessibleObject.setAccessible(methods, true); + method.setAccessible(false); + AccessibleObject.setAccessible(methods, false); + + // non-public method + method = Module.class.getDeclaredMethod("implAddReadsNoSync", Module.class); + methods[0] = method; + + try { + method.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + try { + AccessibleObject.setAccessible(methods, true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + // should succeed + method.setAccessible(false); + AccessibleObject.setAccessible(methods, false); + + + // non-public field + Field field = Module.class.getDeclaredField("name"); + AccessibleObject[] fields = { field }; + + try { + field.setAccessible(true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + try { + AccessibleObject.setAccessible(fields, true); + assertTrue(false); + } catch (InaccessibleObjectException expected) { } + + // should succeed + field.setAccessible(false); + AccessibleObject.setAccessible(fields, false); + + } + + + /** + * 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 }; + + try { + ctor.setAccessible(true); + assertTrue(false); + } catch (SecurityException expected) { } + + try { + AccessibleObject.setAccessible(ctors, true); + assertTrue(false); + } catch (SecurityException expected) { } + + // should succeed + ctor.setAccessible(false); + AccessibleObject.setAccessible(ctors, false); + + } + +} diff --git a/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java new file mode 100644 index 00000000000..f54a320a3f8 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/BasicLayerTest.java @@ -0,0 +1,867 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @build BasicLayerTest ModuleUtils + * @compile layertest/Test.java + * @run testng BasicLayerTest + * @summary Basic tests for java.lang.reflect.Layer + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import static java.lang.module.ModuleFinder.empty; +import java.lang.reflect.Layer; +import java.lang.reflect.LayerInstantiationException; +import java.lang.reflect.Module; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class BasicLayerTest { + + /** + * Exercise Layer.empty() + */ + public void testEmpty() { + Layer emptyLayer = Layer.empty(); + + assertFalse(emptyLayer.parent().isPresent()); + + assertTrue(emptyLayer.configuration() == Configuration.empty()); + + assertTrue(emptyLayer.modules().isEmpty()); + + assertFalse(emptyLayer.findModule("java.base").isPresent()); + + try { + emptyLayer.findLoader("java.base"); + assertTrue(false); + } catch (IllegalArgumentException expected) { } + } + + + /** + * Exercise Layer.boot() + */ + public void testBoot() { + Layer bootLayer = Layer.boot(); + + // configuration + Configuration cf = bootLayer.configuration(); + assertTrue(cf.findModule("java.base").get() + .reference() + .descriptor() + .exports() + .stream().anyMatch(e -> (e.source().equals("java.lang") + && !e.isQualified()))); + + // modules + Set modules = bootLayer.modules(); + assertTrue(modules.contains(Object.class.getModule())); + int count = (int) modules.stream().map(Module::getName).count(); + assertEquals(count, modules.size()); // module names are unique + + // findModule + Module base = Object.class.getModule(); + assertTrue(bootLayer.findModule("java.base").get() == base); + assertTrue(base.getLayer() == bootLayer); + + // findLoader + assertTrue(bootLayer.findLoader("java.base") == null); + + // parent + assertTrue(bootLayer.parent().get() == Layer.empty()); + } + + + /** + * Exercise Layer.create, created on an empty layer + */ + public void testLayerOnEmpty() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .exports("p1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("m3") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2, descriptor3); + + Configuration cf = resolveRequires(finder, "m1"); + + // map each module to its own class loader for this test + ClassLoader loader1 = new ClassLoader() { }; + ClassLoader loader2 = new ClassLoader() { }; + ClassLoader loader3 = new ClassLoader() { }; + Map map = new HashMap<>(); + map.put("m1", loader1); + map.put("m2", loader2); + map.put("m3", loader3); + + Layer layer = Layer.empty().defineModules(cf, map::get); + + // configuration + assertTrue(layer.configuration() == cf); + assertTrue(layer.configuration().modules().size() == 3); + + // modules + Set modules = layer.modules(); + assertTrue(modules.size() == 3); + Set names = modules.stream() + .map(Module::getName) + .collect(Collectors.toSet()); + assertTrue(names.contains("m1")); + assertTrue(names.contains("m2")); + assertTrue(names.contains("m3")); + + // findModule + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + Module m3 = layer.findModule("m3").get(); + assertEquals(m1.getName(), "m1"); + assertEquals(m2.getName(), "m2"); + assertEquals(m3.getName(), "m3"); + assertTrue(m1.getDescriptor() == descriptor1); + assertTrue(m2.getDescriptor() == descriptor2); + assertTrue(m3.getDescriptor() == descriptor3); + assertTrue(m1.getLayer() == layer); + assertTrue(m2.getLayer() == layer); + assertTrue(m3.getLayer() == layer); + assertTrue(modules.contains(m1)); + assertTrue(modules.contains(m2)); + assertTrue(modules.contains(m3)); + assertFalse(layer.findModule("godot").isPresent()); + + // findLoader + assertTrue(layer.findLoader("m1") == loader1); + assertTrue(layer.findLoader("m2") == loader2); + assertTrue(layer.findLoader("m3") == loader3); + try { + ClassLoader loader = layer.findLoader("godot"); + assertTrue(false); + } catch (IllegalArgumentException ignore) { } + + // parent + assertTrue(layer.parent().get() == Layer.empty()); + } + + + /** + * Exercise Layer.create, created over the boot layer + */ + public void testLayerOnBoot() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .requires("java.base") + .exports("p1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires("java.base") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = resolveRequires(parent, finder, "m1"); + + ClassLoader loader = new ClassLoader() { }; + + Layer layer = Layer.boot().defineModules(cf, mn -> loader); + + // configuration + assertTrue(layer.configuration() == cf); + assertTrue(layer.configuration().modules().size() == 2); + + // modules + Set modules = layer.modules(); + assertTrue(modules.size() == 2); + Set names = modules.stream() + .map(Module::getName) + .collect(Collectors.toSet()); + assertTrue(names.contains("m1")); + assertTrue(names.contains("m2")); + + // findModule + Module m1 = layer.findModule("m1").get(); + Module m2 = layer.findModule("m2").get(); + assertEquals(m1.getName(), "m1"); + assertEquals(m2.getName(), "m2"); + assertTrue(m1.getDescriptor() == descriptor1); + assertTrue(m2.getDescriptor() == descriptor2); + assertTrue(m1.getLayer() == layer); + assertTrue(m2.getLayer() == layer); + assertTrue(modules.contains(m1)); + assertTrue(modules.contains(m2)); + assertTrue(layer.findModule("java.base").get() == Object.class.getModule()); + assertFalse(layer.findModule("godot").isPresent()); + + // findLoader + assertTrue(layer.findLoader("m1") == loader); + assertTrue(layer.findLoader("m2") == loader); + assertTrue(layer.findLoader("java.base") == null); + + // parent + assertTrue(layer.parent().get() == Layer.boot()); + } + + + /** + * Layer.create with a configuration of two modules that have the same + * module-private package. + */ + public void testSameConcealedPackage() { + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .conceals("p") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .conceals("p") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = resolveRequires(finder, "m1"); + assertTrue(cf.modules().size() == 2); + + // one loader per module, should be okay + Layer.empty().defineModules(cf, mn -> new ClassLoader() { }); + + // same class loader + try { + ClassLoader loader = new ClassLoader() { }; + Layer.empty().defineModules(cf, mn -> loader); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + } + + + /** + * Layer.create with a configuration with a partitioned graph. The same + * package is exported in both partitions. + */ + public void testSameExportInPartitionedGraph() { + + // m1 reads m2, m2 exports p to m1 + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("m2") + .build(); + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .exports("p", "m1") + .build(); + + // m3 reads m4, m4 exports p to m3 + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m4") + .build(); + ModuleDescriptor descriptor4 + = new ModuleDescriptor.Builder("m4") + .exports("p", "m3") + .build(); + + ModuleFinder finder + = ModuleUtils.finderOf(descriptor1, + descriptor2, + descriptor3, + descriptor4); + + Configuration cf = resolveRequires(finder, "m1", "m3"); + assertTrue(cf.modules().size() == 4); + + // one loader per module + Layer.empty().defineModules(cf, mn -> new ClassLoader() { }); + + // m1 & m2 in one loader, m3 & m4 in another loader + ClassLoader loader1 = new ClassLoader() { }; + ClassLoader loader2 = new ClassLoader() { }; + Map map = new HashMap<>(); + map.put("m1", loader1); + map.put("m2", loader1); + map.put("m3", loader2); + map.put("m3", loader2); + Layer.empty().defineModules(cf, map::get); + + // same loader + try { + ClassLoader loader = new ClassLoader() { }; + Layer.empty().defineModules(cf, mn -> loader); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + } + + + /** + * Layer.create with a configuration that contains a module that has a + * concealed package that is the same name as a non-exported package + * in a parent layer. + */ + public void testConcealSamePackageAsBootLayer() { + + // check assumption that java.base contains sun.launcher + ModuleDescriptor base = Object.class.getModule().getDescriptor(); + assertTrue(base.conceals().contains("sun.launcher")); + + ModuleDescriptor descriptor + = new ModuleDescriptor.Builder("m1") + .requires("java.base") + .conceals("sun.launcher") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m1")); + assertTrue(cf.modules().size() == 1); + + ClassLoader loader = new ClassLoader() { }; + Layer layer = Layer.boot().defineModules(cf, mn -> loader); + assertTrue(layer.modules().size() == 1); + } + + + /** + * Test layers with implied readability. + * + * The test consists of three configurations: + * - Configuration/layer1: m1, m2 requires public m1 + * - Configuration/layer2: m3 requires m1 + */ + public void testImpliedReadabilityWithLayers1() { + + // cf1: m1 and m2, m2 requires public m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m2"); + + ClassLoader cl1 = new ClassLoader() { }; + Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m3, m3 requires m2 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + ClassLoader cl2 = new ClassLoader() { }; + Layer layer2 = layer1.defineModules(cf2, mn -> cl2); + + assertTrue(layer1.parent().get() == Layer.empty()); + assertTrue(layer2.parent().get() == layer1); + + Module m1 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + Module m3 = layer2.findModule("m3").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer1); + assertTrue(m3.getLayer() == layer2); + + assertTrue(m1.getClassLoader() == cl1); + assertTrue(m2.getClassLoader() == cl1); + assertTrue(m3.getClassLoader() == cl2); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m2.canRead(m3)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + } + + + /** + * Test layers with implied readability. + * + * The test consists of three configurations: + * - Configuration/layer1: m1 + * - Configuration/layer2: m2 requires public m3, m3 requires m2 + */ + public void testImpliedReadabilityWithLayers2() { + + // cf1: m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + ClassLoader cl1 = new ClassLoader() { }; + Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m2, m3: m2 requires public m1, m3 requires m2 + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + .build(); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2, descriptor3); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3"); + + ClassLoader cl2 = new ClassLoader() { }; + Layer layer2 = layer1.defineModules(cf2, mn -> cl2); + + assertTrue(layer1.parent().get() == Layer.empty()); + assertTrue(layer2.parent().get() == layer1); + + Module m1 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + Module m3 = layer2.findModule("m3").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer2); + assertTrue(m3.getLayer() == layer2); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m2.canRead(m3)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + } + + + /** + * Test layers with implied readability. + * + * The test consists of three configurations: + * - Configuration/layer1: m1 + * - Configuration/layer2: m2 requires public m1 + * - Configuration/layer3: m3 requires m1 + */ + public void testImpliedReadabilityWithLayers3() { + + // cf1: m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1); + + Configuration cf1 = resolveRequires(finder1, "m1"); + + ClassLoader cl1 = new ClassLoader() { }; + Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m2 requires public m1 + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2); + + Configuration cf2 = resolveRequires(cf1, finder2, "m2"); + + ClassLoader cl2 = new ClassLoader() { }; + Layer layer2 = layer1.defineModules(cf2, mn -> cl2); + + + // cf3: m3 requires m2 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires("m2") + .build(); + + ModuleFinder finder3 = ModuleUtils.finderOf(descriptor3); + + Configuration cf3 = resolveRequires(cf2, finder3, "m3"); + + ClassLoader cl3 = new ClassLoader() { }; + Layer layer3 = layer2.defineModules(cf3, mn -> cl3); + + assertTrue(layer1.parent().get() == Layer.empty()); + assertTrue(layer2.parent().get() == layer1); + assertTrue(layer3.parent().get() == layer2); + + Module m1 = layer3.findModule("m1").get(); + Module m2 = layer3.findModule("m2").get(); + Module m3 = layer3.findModule("m3").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer2); + assertTrue(m3.getLayer() == layer3); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m2.canRead(m3)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + } + + + /** + * Test layers with implied readability. + * + * The test consists of two configurations: + * - Configuration/layer1: m1, m2 requires public m1 + * - Configuration/layer2: m3 requires public m2, m4 requires m3 + */ + public void testImpliedReadabilityWithLayers4() { + + // cf1: m1, m2 requires public m1 + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2") + .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m1") + .build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = resolveRequires(finder1, "m2"); + + ClassLoader cl1 = new ClassLoader() { }; + Layer layer1 = Layer.empty().defineModules(cf1, mn -> cl1); + + + // cf2: m3 requires public m2, m4 requires m3 + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3") + .requires(ModuleDescriptor.Requires.Modifier.PUBLIC, "m2") + .build(); + + ModuleDescriptor descriptor4 + = new ModuleDescriptor.Builder("m4") + .requires("m3") + .build(); + + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); + + Configuration cf2 = resolveRequires(cf1, finder2, "m3", "m4"); + + ClassLoader cl2 = new ClassLoader() { }; + Layer layer2 = layer1.defineModules(cf2, mn -> cl2); + + assertTrue(layer1.parent().get() == Layer.empty()); + assertTrue(layer2.parent().get() == layer1); + + Module m1 = layer2.findModule("m1").get(); + Module m2 = layer2.findModule("m2").get(); + Module m3 = layer2.findModule("m3").get(); + Module m4 = layer2.findModule("m4").get(); + + assertTrue(m1.getLayer() == layer1); + assertTrue(m2.getLayer() == layer1); + assertTrue(m3.getLayer() == layer2); + assertTrue(m4.getLayer() == layer2); + + assertTrue(m1.canRead(m1)); + assertFalse(m1.canRead(m2)); + assertFalse(m1.canRead(m3)); + assertFalse(m1.canRead(m4)); + + assertTrue(m2.canRead(m1)); + assertTrue(m2.canRead(m2)); + assertFalse(m1.canRead(m3)); + assertFalse(m1.canRead(m4)); + + assertTrue(m3.canRead(m1)); + assertTrue(m3.canRead(m2)); + assertTrue(m3.canRead(m3)); + assertFalse(m3.canRead(m4)); + + assertTrue(m4.canRead(m1)); + assertTrue(m4.canRead(m2)); + assertTrue(m4.canRead(m3)); + assertTrue(m4.canRead(m4)); + } + + + /** + * Attempt to use Layer.create to create a layer with a module defined to a + * class loader that already has a module of the same name defined to the + * class loader. + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testModuleAlreadyDefinedToLoader() { + + ModuleDescriptor md + = new ModuleDescriptor.Builder("m") + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(md); + + Configuration parent = Layer.boot().configuration(); + + Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m")); + + ClassLoader loader = new ClassLoader() { }; + + Layer.boot().defineModules(cf, mn -> loader); + + // should throw LayerInstantiationException as m1 already defined to loader + Layer.boot().defineModules(cf, mn -> loader); + + } + + + /** + * Attempt to use Layer.create to create a Layer with a module containing + * package {@code p} where the class loader already has a module defined + * to it containing package {@code p}. + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testPackageAlreadyInNamedModule() { + + ModuleDescriptor md1 + = new ModuleDescriptor.Builder("m1") + .conceals("p") + .requires("java.base") + .build(); + + ModuleDescriptor md2 + = new ModuleDescriptor.Builder("m2") + .conceals("p") + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(md1, md2); + + ClassLoader loader = new ClassLoader() { }; + + // define m1 containing package p to class loader + + Configuration parent = Layer.boot().configuration(); + + Configuration cf1 = parent.resolveRequires(finder, empty(), 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, empty(), Set.of("m2")); + + // should throw exception because p already in m1 + Layer layer2 = Layer.boot().defineModules(cf2, mn -> loader); + + } + + + /** + * Attempt to use Layer.create to create a Layer with a module containing + * a package in which a type is already loaded by the class loader. + */ + @Test(expectedExceptions = { LayerInstantiationException.class }) + public void testPackageAlreadyInUnnamedModule() throws Exception { + + Class c = layertest.Test.class; + assertFalse(c.getModule().isNamed()); // in unnamed module + + ModuleDescriptor md + = new ModuleDescriptor.Builder("m") + .conceals(c.getPackageName()) + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(md); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m")); + + Layer.boot().defineModules(cf, mn -> c.getClassLoader()); + } + + + /** + * Parent of configuration != configuration of parent Layer + */ + @Test(expectedExceptions = { IllegalArgumentException.class }) + public void testIncorrectParent1() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .requires("java.base") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration parent = Layer.boot().configuration(); + Configuration cf = parent.resolveRequires(finder, empty(), Set.of("m1")); + + ClassLoader loader = new ClassLoader() { }; + Layer.empty().defineModules(cf, mn -> loader); + } + + + /** + * Parent of configuration != configuration of parent Layer + */ + @Test(expectedExceptions = { IllegalArgumentException.class }) + public void testIncorrectParent2() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1") + .build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1); + + Configuration cf = resolveRequires(finder, "m1"); + + ClassLoader loader = new ClassLoader() { }; + Layer.boot().defineModules(cf, mn -> loader); + } + + + // null handling + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull1() { + ClassLoader loader = new ClassLoader() { }; + Layer.empty().defineModules(null, mn -> loader); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull2() { + ClassLoader loader = new ClassLoader() { }; + Configuration cf = resolveRequires(Layer.boot().configuration(), empty()); + Layer.boot().defineModules(cf, null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull3() { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer.empty().defineModulesWithOneLoader(null, scl); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testCreateWithNull4() { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer.empty().defineModulesWithManyLoaders(null, scl); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testFindModuleWithNull() { + Layer.boot().findModule(null); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testFindLoaderWithNull() { + Layer.boot().findLoader(null); + } + + + // immutable sets + + @Test(expectedExceptions = { UnsupportedOperationException.class }) + public void testImmutableSet() { + Module base = Object.class.getModule(); + Layer.boot().modules().add(base); + } + + + /** + * 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, empty(), Set.of(roots)); + } + + private static Configuration resolveRequires(ModuleFinder finder, + String... roots) { + return resolveRequires(Configuration.empty(), finder, roots); + } +} diff --git a/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java new file mode 100644 index 00000000000..b37813fd290 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/LayerAndLoadersTest.java @@ -0,0 +1,673 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @build LayerAndLoadersTest CompilerUtils ModuleUtils + * @run testng LayerAndLoadersTest + * @summary Tests for java.lang.reflect.Layer@createWithXXX methods + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import static java.lang.module.ModuleFinder.empty; +import java.lang.module.ModuleReference; +import java.lang.reflect.Layer; +import java.lang.reflect.LayerInstantiationException; +import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class LayerAndLoadersTest { + + 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"); + + @BeforeTest + public void setup() throws Exception { + + // javac -d mods -modulesourcepath src src/** + assertTrue(CompilerUtils.compile(SRC_DIR, MODS_DIR, + "-modulesourcepath", SRC_DIR.toString())); + } + + + /** + * Basic test of Layer.createWithOneLoader + * + * Test scenario: + * m1 requires m2 and m3 + */ + public void testWithOneLoader() throws Exception { + + Configuration cf = resolveRequires("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); + + checkLayer(layer, "m1", "m2", "m3"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2 == cl1); + assertTrue(cl3 == cl1); + + invoke(layer, "m1", "p.Main"); + + } + + + /** + * Basic test of Layer.createWithManyLoaders + * + * Test scenario: + * m1 requires m2 and m3 + */ + public void testWithManyLoaders() throws Exception { + + Configuration cf = resolveRequires("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + + checkLayer(layer, "m1", "m2", "m3"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2.getParent() == scl); + assertTrue(cl3.getParent() == scl); + assertTrue(cl2 != cl1); + assertTrue(cl3 != cl1); + assertTrue(cl3 != cl2); + + invoke(layer, "m1", "p.Main"); + + } + + + /** + * Basic test of Layer.createWithOneLoader where one of the modules + * is a service provider module. + * + * Test scenario: + * m1 requires m2 and m3 + * m1 uses S + * m4 provides S with ... + */ + public void testServicesWithOneLoader() throws Exception { + + Configuration cf = resolveRequiresAndUses("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + Layer layer = Layer.boot().defineModulesWithOneLoader(cf, scl); + + checkLayer(layer, "m1", "m2", "m3", "m4"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + ClassLoader cl4 = layer.findLoader("m4"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2 == cl1); + assertTrue(cl3 == cl1); + assertTrue(cl4 == cl1); + + Class serviceType = cl1.loadClass("p.Service"); + assertTrue(serviceType.getClassLoader() == cl1); + + Iterator iter = ServiceLoader.load(serviceType, cl1).iterator(); + Object provider = iter.next(); + assertTrue(serviceType.isInstance(provider)); + assertTrue(provider.getClass().getClassLoader() == cl1); + assertFalse(iter.hasNext()); + + } + + + /** + * Basic test of Layer.createWithManyLoaders where one of the modules + * is a service provider module. + * + * Test scenario: + * m1 requires m2 and m3 + * m1 uses S + * m4 provides S with ... + */ + public void testServicesWithManyLoaders() throws Exception { + + Configuration cf = resolveRequiresAndUses("m1"); + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + + Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + + checkLayer(layer, "m1", "m2", "m3", "m4"); + + ClassLoader cl1 = layer.findLoader("m1"); + ClassLoader cl2 = layer.findLoader("m2"); + ClassLoader cl3 = layer.findLoader("m3"); + ClassLoader cl4 = layer.findLoader("m4"); + + assertTrue(cl1.getParent() == scl); + assertTrue(cl2.getParent() == scl); + assertTrue(cl3.getParent() == scl); + assertTrue(cl4.getParent() == scl); + assertTrue(cl2 != cl1); + assertTrue(cl3 != cl1); + assertTrue(cl3 != cl2); + assertTrue(cl4 != cl1); + assertTrue(cl4 != cl2); + assertTrue(cl4 != cl3); + + Class serviceType = cl1.loadClass("p.Service"); + assertTrue(serviceType.getClassLoader() == cl1); + + // Test that the service provider can be located via any of + // the class loaders in the layer + for (Module m : layer.modules()) { + ClassLoader loader = m.getClassLoader(); + Iterator iter = ServiceLoader.load(serviceType, loader).iterator(); + Object provider = iter.next(); + assertTrue(serviceType.isInstance(provider)); + assertTrue(provider.getClass().getClassLoader() == cl4); + assertFalse(iter.hasNext()); + } + + } + + + /** + * Tests that the class loaders created by Layer.createWithXXX delegate + * to the given parent class loader. + */ + public void testDelegationToParent() throws Exception { + + Configuration cf = resolveRequires("m1"); + + ClassLoader parent = this.getClass().getClassLoader(); + String cn = this.getClass().getName(); + + // one loader + Layer layer = Layer.boot().defineModulesWithOneLoader(cf, parent); + testLoad(layer, cn); + + // one loader with boot loader as parent + layer = Layer.boot().defineModulesWithOneLoader(cf, null); + testLoadFail(layer, cn); + + // many loaders + layer = Layer.boot().defineModulesWithManyLoaders(cf, parent); + testLoad(layer, cn); + + // many loader with boot loader as parent + layer = Layer.boot().defineModulesWithManyLoaders(cf, null); + testLoadFail(layer, cn); + + } + + + /** + * Test Layer.createWithXXX when modules that have overlapping packages. + * + * Test scenario: + * m1 exports p + * m2 exports p + */ + public void testOverlappingPackages() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1").exports("p").build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2").exports("p").build(); + + ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf = Layer.boot() + .configuration() + .resolveRequires(finder, empty(), Set.of("m1", "m2")); + + // cannot define both module m1 and m2 to the same class loader + try { + Layer.boot().defineModulesWithOneLoader(cf, null); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + + // should be okay to have one module per class loader + Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, null); + checkLayer(layer, "m1", "m2"); + + } + + + /** + * Test Layer.createWithXXX with split delegation. + * + * Test scenario: + * layer1: m1 exports p, m2 exports p + * layer2: m3 reads m1, m4 reads m2 + */ + public void testSplitDelegation() { + + ModuleDescriptor descriptor1 + = new ModuleDescriptor.Builder("m1").exports("p").build(); + + ModuleDescriptor descriptor2 + = new ModuleDescriptor.Builder("m2").exports("p").build(); + + ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2); + + Configuration cf1 = Layer.boot() + .configuration() + .resolveRequires(finder1, empty(), Set.of("m1", "m2")); + + Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); + checkLayer(layer1, "m1", "m2"); + + ModuleDescriptor descriptor3 + = new ModuleDescriptor.Builder("m3").requires("m1").build(); + + ModuleDescriptor descriptor4 + = new ModuleDescriptor.Builder("m4").requires("m2").build(); + + ModuleFinder finder2 = ModuleUtils.finderOf(descriptor3, descriptor4); + + Configuration cf2 = cf1.resolveRequires(finder2, empty(), Set.of("m3", "m4")); + + // package p cannot be supplied by two class loaders + try { + layer1.defineModulesWithOneLoader(cf2, null); + assertTrue(false); + } catch (LayerInstantiationException expected) { } + + // no split delegation when modules have their own class loader + Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); + checkLayer(layer2, "m3", "m4"); + + } + + + /** + * Test Layer.createWithXXX when the modules that override same named + * modules in the parent layer. + * + * Test scenario: + * layer1: m1, m2, m3 => same loader + * layer2: m1, m2, m4 => same loader + */ + public void testOverriding1() throws Exception { + + Configuration cf1 = resolveRequires("m1"); + + Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1")); + + Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); + checkLayer(layer2, "m1", "m2", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer1.findLoader("m2"); + ClassLoader loader3 = layer1.findLoader("m3"); + + ClassLoader loader4 = layer2.findLoader("m1"); + ClassLoader loader5 = layer2.findLoader("m2"); + ClassLoader loader6 = layer2.findLoader("m3"); + + assertTrue(loader1 == loader2); + assertTrue(loader1 == loader3); + + assertTrue(loader4 == loader5); + assertTrue(loader4 == loader6); + assertTrue(loader4 != loader1); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1); + + assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); + assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader4); + assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader4); + + } + + + /** + * Test Layer.createWithXXX when the modules that override same named + * modules in the parent layer. + * + * Test scenario: + * layer1: m1, m2, m3 => loader pool + * layer2: m1, m2, m3 => loader pool + */ + public void testOverriding2() throws Exception { + + Configuration cf1 = resolveRequires("m1"); + + Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1")); + + Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); + checkLayer(layer2, "m1", "m2", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer1.findLoader("m2"); + ClassLoader loader3 = layer1.findLoader("m3"); + + ClassLoader loader4 = layer2.findLoader("m1"); + ClassLoader loader5 = layer2.findLoader("m2"); + ClassLoader loader6 = layer2.findLoader("m3"); + + assertTrue(loader4 != loader1); + assertTrue(loader5 != loader2); + assertTrue(loader6 != loader3); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3); + + // p.Main is not visible via loader2 + try { + loader2.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // w.Hello is not visible via loader2 + try { + loader2.loadClass("w.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // p.Main is not visible via loader3 + try { + loader3.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // q.Hello is not visible via loader3 + try { + loader3.loadClass("q.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + + assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); + assertTrue(loader5.loadClass("q.Hello").getClassLoader() == loader5); + assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); + + // p.Main is not visible via loader5 + try { + loader5.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // w.Hello is not visible via loader5 + try { + loader5.loadClass("w.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // p.Main is not visible via loader6 + try { + loader6.loadClass("p.Main"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + // q.Hello is not visible via loader6 + try { + loader6.loadClass("q.Hello"); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + + } + + + /** + * Test Layer.createWithXXX when the modules that override same named + * modules in the parent layer. + * + * layer1: m1, m2, m3 => same loader + * layer2: m1, m3 => same loader + */ + public void testOverriding3() throws Exception { + + Configuration cf1 = resolveRequires("m1"); + + Layer layer1 = Layer.boot().defineModulesWithOneLoader(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = finderFor("m1", "m3"); + + Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1")); + + Layer layer2 = layer1.defineModulesWithOneLoader(cf2, null); + checkLayer(layer2, "m1", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer2.findLoader("m1"); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader1); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader1); + + assertTrue(loader2.loadClass("p.Main").getClassLoader() == loader2); + assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader1); + assertTrue(loader2.loadClass("w.Hello").getClassLoader() == loader2); + + } + + + /** + * Test Layer.createWithXXX when the modules that override same named + * modules in the parent layer. + * + * layer1: m1, m2, m3 => loader pool + * layer2: m1, m3 => loader pool + */ + public void testOverriding4() throws Exception { + + Configuration cf1 = resolveRequires("m1"); + + Layer layer1 = Layer.boot().defineModulesWithManyLoaders(cf1, null); + checkLayer(layer1, "m1", "m2", "m3"); + + ModuleFinder finder = finderFor("m1", "m3"); + + Configuration cf2 = cf1.resolveRequires(finder, empty(), Set.of("m1")); + + Layer layer2 = layer1.defineModulesWithManyLoaders(cf2, null); + checkLayer(layer2, "m1", "m3"); + invoke(layer1, "m1", "p.Main"); + + ClassLoader loader1 = layer1.findLoader("m1"); + ClassLoader loader2 = layer1.findLoader("m2"); + ClassLoader loader3 = layer1.findLoader("m3"); + + ClassLoader loader4 = layer2.findLoader("m1"); + ClassLoader loader5 = layer2.findLoader("m2"); + ClassLoader loader6 = layer2.findLoader("m3"); + + assertTrue(loader4 != loader1); + assertTrue(loader5 == loader2); // m2 not overridden + assertTrue(loader6 != loader3); + + assertTrue(loader1.loadClass("p.Main").getClassLoader() == loader1); + assertTrue(loader1.loadClass("q.Hello").getClassLoader() == loader2); + assertTrue(loader1.loadClass("w.Hello").getClassLoader() == loader3); + + assertTrue(loader2.loadClass("q.Hello").getClassLoader() == loader2); + + assertTrue(loader3.loadClass("w.Hello").getClassLoader() == loader3); + + assertTrue(loader4.loadClass("p.Main").getClassLoader() == loader4); + assertTrue(loader4.loadClass("q.Hello").getClassLoader() == loader2); + assertTrue(loader4.loadClass("w.Hello").getClassLoader() == loader6); + + assertTrue(loader6.loadClass("w.Hello").getClassLoader() == loader6); + + } + + + // -- supporting methods -- + + + /** + * Resolve the given modules, by name, and returns the resulting + * Configuration. + */ + private static Configuration resolveRequires(String... roots) { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + return Layer.boot() + .configuration() + .resolveRequires(finder, empty(), Set.of(roots)); + } + + /** + * Resolve the given modules, by name, and returns the resulting + * Configuration. + */ + private static Configuration resolveRequiresAndUses(String... roots) { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + return Layer.boot() + .configuration() + .resolveRequiresAndUses(finder, empty(), Set.of(roots)); + } + + + /** + * Invokes the static void main(String[]) method on the given class + * in the given module. + */ + private static void invoke(Layer layer, String mn, String mc) throws Exception { + ClassLoader loader = layer.findLoader(mn); + Class c = loader.loadClass(mc); + Method mainMethod = c.getMethod("main", String[].class); + mainMethod.invoke(null, (Object)new String[0]); + } + + + /** + * Checks that the given layer contains exactly the expected modules + * (by name). + */ + private void checkLayer(Layer layer, String ... expected) { + Set names = layer.modules().stream() + .map(Module::getName) + .collect(Collectors.toSet()); + assertTrue(names.size() == expected.length); + for (String name : expected) { + assertTrue(names.contains(name)); + } + } + + + /** + * Test that a class can be loaded via the class loader of all modules + * in the given layer. + */ + static void testLoad(Layer layer, String cn) throws Exception { + for (Module m : layer.modules()) { + ClassLoader l = m.getClassLoader(); + l.loadClass(cn); + } + } + + + /** + * Test that a class cannot be loaded via any of the class loaders of + * the modules in the given layer. + */ + static void testLoadFail(Layer layer, String cn) throws Exception { + for (Module m : layer.modules()) { + ClassLoader l = m.getClassLoader(); + try { + l.loadClass(cn); + assertTrue(false); + } catch (ClassNotFoundException expected) { } + } + } + + + /** + * Returns a ModuleFinder that only finds the given test modules + */ + static ModuleFinder finderFor(String... names) { + + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + + Map mrefs = new HashMap<>(); + for (String name : names) { + Optional omref = finder.find(name); + assert omref.isPresent(); + mrefs.put(name, omref.get()); + } + + return new ModuleFinder() { + @Override + public Optional find(String name) { + ModuleReference mref = mrefs.get(name); + return Optional.ofNullable(mref); + } + @Override + public Set findAll() { + return mrefs.values().stream().collect(Collectors.toSet()); + } + }; + } + +} diff --git a/jdk/test/java/lang/reflect/Layer/layertest/Test.java b/jdk/test/java/lang/reflect/Layer/layertest/Test.java new file mode 100644 index 00000000000..f5c76ccbde5 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/layertest/Test.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +/** + * Supporting class for tests of java.lang.reflect.Layer. + */ + +package layertest; + +public class Test { } + diff --git a/jdk/test/java/lang/reflect/Layer/src/m1/module-info.java b/jdk/test/java/lang/reflect/Layer/src/m1/module-info.java new file mode 100644 index 00000000000..d989339e3f9 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m1/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module m1 { + requires m2; + requires m3; + exports p; + uses p.Service; +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m1/p/Main.java b/jdk/test/java/lang/reflect/Layer/src/m1/p/Main.java new file mode 100644 index 00000000000..51f94075d68 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m1/p/Main.java @@ -0,0 +1,39 @@ +/* + * 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 p; + +import java.net.URL; + +public class Main { + public static void main(String[] args) { + + URL url1 = Main.class.getResource("Main.class"); + if (url1 == null) throw new RuntimeException(); + URL url2 = Main.class.getResource("/p/Main.class"); + if (url2 == null) throw new RuntimeException(); + + q.Hello.hello(); + w.Hello.hello(); + } +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m1/p/Service.java b/jdk/test/java/lang/reflect/Layer/src/m1/p/Service.java new file mode 100644 index 00000000000..0cbc7d04132 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m1/p/Service.java @@ -0,0 +1,26 @@ +/* + * 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 p; + +public interface Service { } diff --git a/jdk/test/java/lang/reflect/Layer/src/m2/module-info.java b/jdk/test/java/lang/reflect/Layer/src/m2/module-info.java new file mode 100644 index 00000000000..3e0ed03fb59 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + exports q; +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m2/q/Hello.java b/jdk/test/java/lang/reflect/Layer/src/m2/q/Hello.java new file mode 100644 index 00000000000..50c9bf0e6d2 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m2/q/Hello.java @@ -0,0 +1,40 @@ +/* + * 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 q; + +import java.net.URL; + +public class Hello { + + public static void hello() { + + URL url1 = Hello.class.getResource("Hello.class"); + if (url1 == null) throw new RuntimeException(); + URL url2 = Hello.class.getResource("/q/Hello.class"); + if (url2 == null) throw new RuntimeException(); + + System.out.println("Hello!"); + } + +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m3/module-info.java b/jdk/test/java/lang/reflect/Layer/src/m3/module-info.java new file mode 100644 index 00000000000..292c9192173 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m3/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m3 { + // qualified export + exports w to m1; +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m3/w/Hello.java b/jdk/test/java/lang/reflect/Layer/src/m3/w/Hello.java new file mode 100644 index 00000000000..353493c22cd --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m3/w/Hello.java @@ -0,0 +1,40 @@ +/* + * 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 w; + +import java.net.URL; + +public class Hello { + + public static void hello() { + + URL url1 = Hello.class.getResource("Hello.class"); + if (url1 == null) throw new RuntimeException(); + URL url2 = Hello.class.getResource("/w/Hello.class"); + if (url2 == null) throw new RuntimeException(); + + System.out.println("Hello!"); + } + +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m4/impl/ServiceImpl.java b/jdk/test/java/lang/reflect/Layer/src/m4/impl/ServiceImpl.java new file mode 100644 index 00000000000..ae637012331 --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m4/impl/ServiceImpl.java @@ -0,0 +1,27 @@ +/* + * 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 impl; + +public class ServiceImpl implements p.Service { +} diff --git a/jdk/test/java/lang/reflect/Layer/src/m4/module-info.java b/jdk/test/java/lang/reflect/Layer/src/m4/module-info.java new file mode 100644 index 00000000000..ec106f4251c --- /dev/null +++ b/jdk/test/java/lang/reflect/Layer/src/m4/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m4 { + requires m1; + provides p.Service with impl.ServiceImpl; +} diff --git a/jdk/test/java/lang/reflect/Module/AddExportsTest.java b/jdk/test/java/lang/reflect/Module/AddExportsTest.java new file mode 100644 index 00000000000..020f38ef8f5 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/AddExportsTest.java @@ -0,0 +1,112 @@ +/* + * 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 + * @run main/othervm -XaddExports:java.desktop/sun.awt=java.base AddExportsTest + * @run main/othervm -XaddExports:java.desktop/sun.awt=ALL-UNNAMED AddExportsTest + * @summary Test Module isExported methods with exports changed by -AddExportsTest + */ + +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.Optional; + +public class AddExportsTest { + + public static void main(String[] args) { + + String addExports = System.getProperty("jdk.launcher.addexports.0"); + assertTrue(addExports != null, "Expected to be run with -XaddExports"); + + Layer bootLayer = Layer.boot(); + + Module unnamedModule = AddExportsTest.class.getModule(); + assertFalse(unnamedModule.isNamed()); + + for (String expr : addExports.split(",")) { + + String[] s = expr.split("="); + assertTrue(s.length == 2); + + // $MODULE/$PACKAGE + String[] moduleAndPackage = s[0].split("/"); + assertTrue(moduleAndPackage.length == 2); + + String mn = moduleAndPackage[0]; + String pn = moduleAndPackage[1]; + + // source module + Module source; + Optional om = bootLayer.findModule(mn); + assertTrue(om.isPresent(), mn + " not in boot layer"); + source = om.get(); + + // package should not be exported unconditionally + assertFalse(source.isExported(pn), + pn + " should not be exported unconditionally"); + + // $TARGET + String tn = s[1]; + if ("ALL-UNNAMED".equals(tn)) { + + // package is exported to all unnamed modules + assertTrue(source.isExported(pn, unnamedModule), + pn + " should be exported to all unnamed modules"); + + } else { + + om = bootLayer.findModule(tn); + assertTrue(om.isPresent()); + Module target = om.get(); + + // package should be exported to target module + assertTrue(source.isExported(pn, target), + pn + " should be exported to " + target); + + // package should not be exported to unnamed modules + assertFalse(source.isExported(pn, unnamedModule), + pn + " should not be exported to unnamed modules"); + + } + + } + } + + static void assertTrue(boolean cond) { + if (!cond) throw new RuntimeException(); + } + + static void assertTrue(boolean cond, String msg) { + if (!cond) throw new RuntimeException(msg); + } + + static void assertFalse(boolean cond) { + if (cond) throw new RuntimeException(); + } + + static void assertFalse(boolean cond, String msg) { + if (cond) throw new RuntimeException(msg); + } + +} diff --git a/jdk/test/java/lang/reflect/Module/BasicModuleTest.java b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java new file mode 100644 index 00000000000..32a945a5ce4 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/BasicModuleTest.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.module.ModuleDescriptor.Exports; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/* + * @test + * @summary Basic test of java.lang.reflect.Module + * @modules java.desktop java.xml + * @run testng BasicModuleTest + */ + +public class BasicModuleTest { + + /** + * Tests that the given module reads all modules in the boot Layer. + */ + private void testReadsAllBootModules(Module m) { + Layer bootLayer = Layer.boot(); + bootLayer.configuration() + .modules() + .stream() + .map(ResolvedModule::name) + .map(bootLayer::findModule) + .forEach(target -> assertTrue(m.canRead(target.get()))); + } + + /** + * Returns {@code true} if the array contains the given object. + */ + private boolean contains(T[] array, T obj) { + return Stream.of(array).anyMatch(obj::equals); + } + + /** + * Returns a {@code Predicate} to test if a package is exported. + */ + private Predicate doesExport(String pn) { + return e -> (e.source().equals(pn) && !e.isQualified()); + } + + + + @Test + public void testThisModule() { + Module thisModule = BasicModuleTest.class.getModule(); + Module baseModule = Object.class.getModule(); + + assertFalse(thisModule.isNamed()); + assertTrue(thisModule.getName() == null); + assertTrue(thisModule.getDescriptor() == null); + assertTrue(thisModule.getLayer() == null); + assertTrue(thisModule.toString().startsWith("unnamed module ")); + + ClassLoader thisLoader = BasicModuleTest.class.getClassLoader(); + assertTrue(thisLoader == thisModule.getClassLoader()); + assertTrue(thisLoader.getUnnamedModule() == thisModule); + + // unnamed modules read all other modules + ClassLoader cl; + cl = ClassLoader.getPlatformClassLoader(); + assertTrue(thisModule.canRead(cl.getUnnamedModule())); + cl = ClassLoader.getSystemClassLoader(); + assertTrue(thisModule.canRead(cl.getUnnamedModule())); + testReadsAllBootModules(thisModule); + + // unnamed modules export all packages + assertTrue(thisModule.isExported("")); + assertTrue(thisModule.isExported("", thisModule)); + assertTrue(thisModule.isExported("", baseModule)); + assertTrue(thisModule.isExported("p")); + assertTrue(thisModule.isExported("p", thisModule)); + assertTrue(thisModule.isExported("p", baseModule)); + + // this test is in the unnamed package + assertTrue(contains(thisModule.getPackages(), "")); + } + + + @Test + public void testUnnamedModules() { + Module thisModule = BasicModuleTest.class.getModule(); + Module baseModule = Object.class.getModule(); + + ClassLoader loader1 = ClassLoader.getSystemClassLoader(); + ClassLoader loader2 = loader1.getParent(); + + Module m1 = loader1.getUnnamedModule(); + Module m2 = loader2.getUnnamedModule(); + + assertTrue(m1 != m2); + + assertFalse(m1.isNamed()); + assertFalse(m2.isNamed()); + + assertTrue(m1.getLayer() == null); + assertTrue(m2.getLayer() == null); + + assertTrue(m1.toString().startsWith("unnamed module ")); + assertTrue(m2.toString().startsWith("unnamed module ")); + + // unnamed module reads all modules + assertTrue(m1.canRead(m2)); + assertTrue(m2.canRead(m1)); + + testReadsAllBootModules(m1); + testReadsAllBootModules(m2); + + assertTrue(m1.isExported("")); + assertTrue(m1.isExported("", thisModule)); + assertTrue(m1.isExported("", baseModule)); + assertTrue(m1.isExported("p")); + assertTrue(m1.isExported("p", thisModule)); + assertTrue(m1.isExported("p", baseModule)); + } + + + + @Test + public void testBaseModule() { + Module base = Object.class.getModule(); + Module thisModule = BasicModuleTest.class.getModule(); + + // getName + assertTrue(base.getName().equals("java.base")); + + // getDescriptor + assertTrue(base.getDescriptor().exports().stream() + .anyMatch(doesExport("java.lang"))); + + // getClassLoader + assertTrue(base.getClassLoader() == null); + + // getLayer + assertTrue(base.getLayer() == Layer.boot()); + + // toString + assertEquals(base.toString(), "module java.base"); + + // getPackages + assertTrue(contains(base.getPackages(), "java.lang")); + + // canRead + assertTrue(base.canRead(base)); + + // isExported + assertTrue(base.isExported("java.lang")); + assertTrue(base.isExported("java.lang", thisModule)); + assertFalse(base.isExported("java.wombat")); + assertFalse(base.isExported("java.wombat", thisModule)); + } + + + @Test + public void testDesktopModule() { + Module desktop = java.awt.Component.class.getModule(); + Module base = Object.class.getModule(); + Module xml = javax.xml.XMLConstants.class.getModule(); + Module thisModule = BasicModuleTest.class.getModule(); + + // name + assertTrue(desktop.getName().equals("java.desktop")); + + // descriptor + assertTrue(desktop.getDescriptor().exports().stream() + .anyMatch(doesExport("java.awt"))); + + // getClassLoader + assertTrue(desktop.getClassLoader() == null); + + // getLayer + assertTrue(desktop.getLayer() == Layer.boot()); + + // toString + assertEquals(desktop.toString(), "module java.desktop"); + + // getPackages + assertTrue(contains(desktop.getPackages(), "java.awt")); + assertTrue(contains(desktop.getPackages(), "sun.awt")); + + // canRead + assertTrue(desktop.canRead(base)); + assertTrue(desktop.canRead(xml)); + + // isExported + assertTrue(desktop.isExported("java.awt")); + assertTrue(desktop.isExported("java.awt", thisModule)); + assertFalse(desktop.isExported("java.wombat")); + assertFalse(desktop.isExported("java.wombat", thisModule)); + } + + + @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/access/AccessTest.java b/jdk/test/java/lang/reflect/Module/access/AccessTest.java new file mode 100644 index 00000000000..35e58a9d8b1 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/AccessTest.java @@ -0,0 +1,85 @@ +/* + * 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 java.compiler + * @build AccessTest CompilerUtils jdk.testlibrary.* + * @run testng AccessTest + * @summary Driver for test that checks access to public members in exported + * and non-exported packages. + */ + +@Test +public class AccessTest { + + 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("test", "target"); + + + /** + * Compiles all modules used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + for (String mn : modules) { + Path src = SRC_DIR.resolve(mn); + Path mods = MODS_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(src, mods)); + } + } + + /** + * Run the test + */ + public void runTest() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "target", + "-m", "test/test.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + +} diff --git a/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java new file mode 100644 index 00000000000..9c987c725fc --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module target { + exports p; +} diff --git a/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java b/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java new file mode 100644 index 00000000000..73bdb3405c3 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p/Exported.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package p; + +public class Exported { + + /** + * Public constructor + */ + public Exported() { } + + /** + * Public field + */ + public static Object field; + + /** + * Public method + */ + public static void run() { + } +} diff --git a/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java b/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java new file mode 100644 index 00000000000..b834364d4fd --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/p/Helper.java @@ -0,0 +1,34 @@ +/* + * 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 p; + +import java.lang.reflect.Module; + +public class Helper { + Helper() { } + + public static void exportPackage(String pn, Module who) { + Helper.class.getModule().addExports(pn, who); + } +} diff --git a/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java b/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java new file mode 100644 index 00000000000..f0dabdd1653 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/target/q/Internal.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package q; + +public class Internal { + + /** + * Public constructor + */ + public Internal() { } + + /** + * Public field + */ + public static Object field; + + /** + * Public method + */ + public static void run() { + } +} diff --git a/jdk/test/java/lang/reflect/Module/access/src/test/module-info.java b/jdk/test/java/lang/reflect/Module/access/src/test/module-info.java new file mode 100644 index 00000000000..bcdacb29e64 --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/test/module-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +module test { } diff --git a/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java new file mode 100644 index 00000000000..0ba28a775df --- /dev/null +++ b/jdk/test/java/lang/reflect/Module/access/src/test/test/Main.java @@ -0,0 +1,194 @@ +/* + * 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 test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InaccessibleObjectException; +import java.lang.reflect.Layer; +import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.util.Optional; + +/** + * Test access to public members in exported and non-exported packages. + */ + +public class Main { + + public static void main(String[] args) throws Exception { + + Module thisModule = Main.class.getModule(); + assertTrue(thisModule.isNamed()); + + Optional om = Layer.boot().findModule("target"); + assertTrue(om.isPresent()); + + Module target = om.get(); + + assertTrue(target.isExported("p")); + assertTrue(target.isExported("p", thisModule)); + + assertFalse(target.isExported("q")); + assertFalse(target.isExported("q", thisModule)); + + + // thisModule does not read the target module + + assertFalse(thisModule.canRead(target)); + + tryAccessPublicMembers("p.Exported", true); + tryAccessPublicMembers("q.Internal", false); + + + + // thisModule reads the target module + + thisModule.addReads(target); + assertTrue(thisModule.canRead(target)); + + tryAccessPublicMembers("p.Exported", true); + tryAccessPublicMembers("q.Internal", false); + + + + // change target module to export its internal package to thisModule + + targetAddExports("q", thisModule); + assertFalse(target.isExported("q")); + assertTrue(target.isExported("q", thisModule)); + + tryAccessPublicMembers("p.Exported", true); + tryAccessPublicMembers("q.Internal", true); + } + + + /** + * Attempt to access public members in a target class. + */ + static void tryAccessPublicMembers(String cn, boolean shouldSucceed) + throws Exception + { + + Class clazz = Class.forName(cn); + + Module thisModule = Main.class.getModule(); + Module targetModule = clazz.getModule(); + + // check if the target class is in an exported package + String pn = cn.substring(0, cn.lastIndexOf('.')); + boolean exported = targetModule.isExported(pn, thisModule); + assertTrue(exported == shouldSucceed); + boolean shouldFail = !shouldSucceed; + + + // Class.newInstance + + try { + clazz.newInstance(); + assertTrue(shouldSucceed); + } catch (IllegalAccessException e) { + assertTrue(shouldFail); + } + + + // Constructor.newInstance and Constructor.setAccessible + + Constructor ctor = clazz.getConstructor(); + try { + ctor.newInstance(); + assertTrue(shouldSucceed); + } catch (IllegalAccessException e) { + assertTrue(shouldFail); + } + try { + ctor.setAccessible(true); + assertTrue(shouldSucceed); + ctor.newInstance(); + } catch (InaccessibleObjectException e) { + assertTrue(shouldFail); + } + + + // Method.invoke and Method.setAccessible + + Method m = clazz.getDeclaredMethod("run"); + try { + m.invoke(null); + assertTrue(shouldSucceed); + } catch (IllegalAccessException e) { + assertTrue(shouldFail); + } + try { + m.setAccessible(true); + assertTrue(shouldSucceed); + m.invoke(null); + } catch (InaccessibleObjectException e) { + assertTrue(shouldFail); + } + + // Field.get, Field.set and Field.setAccessible + + Field f = clazz.getDeclaredField("field"); + try { + f.get(null); + assertTrue(shouldSucceed); + } catch (IllegalAccessException e) { + assertTrue(shouldFail); + } + try { + f.set(null, 100); + assertTrue(shouldSucceed); + } catch (IllegalAccessException e) { + assertTrue(shouldFail); + } + try { + f.setAccessible(true); + f.get(null); + f.set(null, 100); + assertTrue(shouldSucceed); + } catch (InaccessibleObjectException e) { + assertTrue(shouldFail); + } + + } + + /** + * Update target module to export a package to the given module. + */ + static void targetAddExports(String pn, Module who) throws Exception { + Class helper = Class.forName("p.Helper"); + Method m = helper.getMethod("exportPackage", String.class, Module.class); + m.invoke(null, pn, who); + } + + + static void assertTrue(boolean expr) { + if (!expr) throw new RuntimeException(); + } + + static void assertFalse(boolean expr) { + assertTrue(!expr); + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/Basic1.java b/jdk/test/java/lang/reflect/Proxy/Basic1.java index 41233f90974..b2440ccd9f9 100644 --- a/jdk/test/java/lang/reflect/Proxy/Basic1.java +++ b/jdk/test/java/lang/reflect/Proxy/Basic1.java @@ -108,7 +108,7 @@ public class Basic1 { * Verify that its protection domain is the bootstrap domain. */ ProtectionDomain pd = proxyClass.getProtectionDomain(); - System.err.println("+ proxy class's protextion domain: " + pd); + System.err.println("+ proxy class's protection domain: " + pd); if (!pd.implies(new AllPermission())) { throw new RuntimeException( "proxy class does not have AllPermission"); @@ -143,7 +143,7 @@ public class Basic1 { /* * Invoke a method on a proxy instance. */ - Method m = Runnable.class.getMethod("run", null); + Method m = Runnable.class.getMethod("run"); ((Runnable) proxy).run(); if (!handler.lastMethod.equals(m)) { throw new RuntimeException( diff --git a/jdk/test/java/lang/reflect/Proxy/NullClassLoader.java b/jdk/test/java/lang/reflect/Proxy/NullClassLoader.java index 861a2742dff..244af0092ad 100644 --- a/jdk/test/java/lang/reflect/Proxy/NullClassLoader.java +++ b/jdk/test/java/lang/reflect/Proxy/NullClassLoader.java @@ -42,8 +42,8 @@ public class NullClassLoader { "\nTest creating proxy class with the null class loader.\n"); try { - Class p = Proxy.getProxyClass(null, - new Class[] { Runnable.class, Observer.class }); + ClassLoader ld = null; + Class p = Proxy.getProxyClass(ld, new Class[] { Runnable.class, Observer.class }); System.err.println("proxy class: " + p); ClassLoader loader = p.getClassLoader(); diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java new file mode 100644 index 00000000000..529f294401d --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/ProxyClassAccessTest.java @@ -0,0 +1,119 @@ +/* + * 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.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.lang.reflect.Proxy; +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 ProxyClassAccessTest q.NP CompilerUtils jdk.testlibrary.* + * @run testng ProxyClassAccessTest + * @summary Driver for testing proxy class doesn't have access to + * types referenced by proxy interfaces + */ + +public class ProxyClassAccessTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String TEST_CLASSES = System.getProperty("test.classes"); + + 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", "m3", "test"); + + /** + * 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, "-modulesourcepath", SRC_DIR.toString())); + } + } + + /** + * Run the modular test + */ + @Test + public void runTest() throws Exception { + int exitValue = executeTestJava("-mp", MODS_DIR.toString(), + "-m", "test/jdk.test.ProxyClassAccess") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + /** + * Test unnamed module has no access to other proxy interface + */ + @Test + public void testNoReadAccess() throws Exception { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Layer bootLayer = Layer.boot(); + Configuration cf = bootLayer + .configuration() + .resolveRequiresAndUses(ModuleFinder.empty(), finder, modules); + ClassLoader parentLoader = this.getClass().getClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, parentLoader); + + ClassLoader loader = layer.findLoader("m1"); + Class[] interfaces = new Class[] { + Class.forName("p.one.I", false, loader), + Class.forName("q.NP", false, loader) // non-public interface in unnamed module + }; + checkIAE(loader, interfaces); + } + + private void checkIAE(ClassLoader loader, Class[] interfaces) { + try { + Proxy.getProxyClass(loader, interfaces); + throw new RuntimeException("Expected IllegalArgumentException thrown"); + } catch (IllegalArgumentException e) {} + + try { + Proxy.newProxyInstance(loader, interfaces, + (proxy, m, params) -> { throw new RuntimeException(m.toString()); }); + throw new RuntimeException("Expected IllegalArgumentException thrown"); + } catch (IllegalArgumentException e) {} + } + +} diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyForMethodHandle.java b/jdk/test/java/lang/reflect/Proxy/ProxyForMethodHandle.java new file mode 100644 index 00000000000..bbe74b66ecf --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/ProxyForMethodHandle.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandleProxies; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Module; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * @test + * @summary test MethodHandleProxies that adds qualified export of sun.invoke + * from java.base to a dynamic module + * @run testng ProxyForMethodHandle + */ +public class ProxyForMethodHandle { + /** + * MethodHandleProxies will add qualified export of sun.invoke from java.base + * to a dynamic module + */ + @Test + static void testRunnableMethodHandle() throws Exception { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodType mt = MethodType.methodType(void.class); + MethodHandle mh = lookup.findStatic(ProxyForMethodHandle.class, "runForRunnable", mt); + Runnable proxy = MethodHandleProxies.asInterfaceInstance(Runnable.class, mh); + proxy.run(); + + Class proxyClass = proxy.getClass(); + Module target = proxyClass.getModule(); + assertDynamicModule(target, proxyClass.getClassLoader(), proxyClass); + } + + static void runForRunnable() { + System.out.println("runForRunnable"); + } + + public static void assertDynamicModule(Module m, ClassLoader ld, Class proxyClass) { + if (!m.isNamed() || !m.getName().startsWith("jdk.proxy")) { + throw new RuntimeException(m.getName() + " not dynamic module"); + } + + if (ld != m.getClassLoader() || proxyClass.getClassLoader() != ld) { + throw new RuntimeException("unexpected class loader"); + } + + try { + Constructor cons = proxyClass.getConstructor(InvocationHandler.class); + cons.newInstance(handler); + throw new RuntimeException("Expected IllegalAccessException: " + proxyClass); + } catch (IllegalAccessException e) { + // expected + } catch (NoSuchMethodException|InstantiationException|InvocationTargetException e) { + throw new RuntimeException(e); + } + } + private final static InvocationHandler handler = + (proxy, m, params) -> { throw new RuntimeException(m.toString()); }; +} diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java new file mode 100644 index 00000000000..4ee43ea11c1 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/ProxyLayerTest.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Layer; +import java.lang.reflect.Proxy; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +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 ProxyTest CompilerUtils jdk.testlibrary.ProcessTools + * @run testng ProxyLayerTest + * @summary Test proxies to implement interfaces in a layer + */ + +public class ProxyLayerTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String TEST_CLASSES = System.getProperty("test.classes"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path CPATH_DIR = Paths.get(TEST_CLASSES); + + // the names of the modules in this test + private static String[] modules = new String[] {"m1", "m2", "m3"}; + + + /** + * 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, "-modulesourcepath", SRC_DIR.toString())); + } + } + + /** + * Test proxy implementing interfaces in a Layer defined in + * an unnamed module + */ + @Test + public void testProxyInUnnamed() throws Exception { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Layer bootLayer = Layer.boot(); + Configuration cf = bootLayer + .configuration() + .resolveRequiresAndUses(ModuleFinder.empty(), finder, Arrays.asList(modules)); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + + ClassLoader loader = layer.findLoader("m1"); + + assertTrue(layer.findModule("m1").isPresent()); + assertTrue(layer.findModule("m2").isPresent()); + assertTrue(layer.findModule("m3").isPresent()); + + Class[] interfaces = new Class[] { + Class.forName("p.one.I", false, loader), + Class.forName("p.two.A", false, loader), + Class.forName("p.three.P", false, loader), + }; + Object o = Proxy.newProxyInstance(loader, interfaces, handler); + + Class proxyClass = o.getClass(); + Package pkg = proxyClass.getPackage(); + assertFalse(proxyClass.getModule().isNamed()); + assertFalse(pkg.isSealed()); + assertEquals(proxyClass.getModule().getLayer(), null); + } + + /** + * Test proxy implementing interfaces in a Layer and defined in a + * dynamic module + */ + @Test + public void testProxyInDynamicModule() throws Exception { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Layer bootLayer = Layer.boot(); + Configuration cf = bootLayer + .configuration() + .resolveRequiresAndUses(ModuleFinder.empty(), finder, Arrays.asList(modules)); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + + ClassLoader loader = layer.findLoader("m1"); + + assertTrue(layer.findModule("m1").isPresent()); + assertTrue(layer.findModule("m2").isPresent()); + assertTrue(layer.findModule("m3").isPresent()); + + Class[] interfaces = new Class[] { + Class.forName("p.one.internal.J", false, loader), + }; + Object o = Proxy.newProxyInstance(loader, interfaces, handler); + Class proxyClass = o.getClass(); + Package pkg = proxyClass.getPackage(); + assertTrue(proxyClass.getModule().isNamed()); + assertTrue(pkg.isSealed()); + assertEquals(proxyClass.getModule().getLayer(), null); + } + + /** + * Test proxy implementing interfaces that the target module has no access + */ + @Test + public void testNoReadAccess() throws Exception { + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Layer bootLayer = Layer.boot(); + Configuration cf = bootLayer + .configuration() + .resolveRequiresAndUses(ModuleFinder.empty(), finder, Arrays.asList(modules)); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + + ClassLoader loader = layer.findLoader("m1"); + + assertTrue(layer.findModule("m1").isPresent()); + assertTrue(layer.findModule("m2").isPresent()); + assertTrue(layer.findModule("m3").isPresent()); + + Class[] interfaces = new Class[] { + Class.forName("p.one.I", false, loader), + Class.forName("p.two.B", false, loader) // non-public interface but exported package + }; + checkIAE(loader, interfaces); + } + + private void checkIAE(ClassLoader loader, Class[] interfaces) { + try { + Proxy.getProxyClass(loader, interfaces); + throw new RuntimeException("Expected IllegalArgumentException thrown"); + } catch (IllegalArgumentException e) {} + + try { + Proxy.newProxyInstance(loader, interfaces, handler); + throw new RuntimeException("Expected IllegalArgumentException thrown"); + } catch (IllegalArgumentException e) {} + } + + private final static InvocationHandler handler = + (proxy, m, params) -> { throw new RuntimeException(m.toString()); }; + +} diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyModuleMapping.java b/jdk/test/java/lang/reflect/Proxy/ProxyModuleMapping.java new file mode 100644 index 00000000000..db3af7d5e6f --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/ProxyModuleMapping.java @@ -0,0 +1,105 @@ +/* + * 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. + */ + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Module; +import java.lang.reflect.Proxy; + +/* + * @test + * @summary Basic test of proxy module mapping and the access to Proxy class + * @modules java.base/sun.invoke + */ + +public class ProxyModuleMapping { + public static void main(String... args) throws Exception { + ClassLoader ld = ProxyModuleMapping.class.getClassLoader(); + Module unnamed = ld.getUnnamedModule(); + new ProxyModuleMapping(unnamed, Runnable.class).test(); + + // unnamed module gets access to sun.invoke package (e.g. via -XaddExports) + new ProxyModuleMapping(sun.invoke.WrapperInstance.class).test(); + + Class modulePrivateIntf = Class.forName("sun.net.ProgressListener"); + new ProxyModuleMapping(modulePrivateIntf).test(); + } + + final Module target; + final ClassLoader loader; + final Class[] interfaces; + ProxyModuleMapping(Module m, Class... interfaces) { + this.target = m; + this.loader = m.getClassLoader(); + this.interfaces = interfaces; + } + + ProxyModuleMapping(Class... interfaces) { + this.target = null; // expected to be dynamic module + this.loader = interfaces[0].getClassLoader(); // same class loader + this.interfaces = interfaces; + } + + void test() throws Exception { + verifyProxyClass(); + verifyNewProxyInstance(); + } + + void verifyProxyClass() throws Exception { + Class c = Proxy.getProxyClass(loader, interfaces); + Module m = c.getModule(); + if (target != null && m != target) { + throw new RuntimeException(c.getModule() + " not expected: " + target); + } + // expect dynamic module + if (target == null && (!m.isNamed() || !m.getName().startsWith("jdk.proxy"))) { + throw new RuntimeException("Unexpected:" + m); + } + + Module module = c.getModule(); + try { + Constructor cons = c.getConstructor(InvocationHandler.class); + cons.newInstance(ih); + if (module.isNamed()) { + throw new RuntimeException("expected IAE not thrown"); + } + } catch (IllegalAccessException e) { + if (!module.isNamed()) { + throw e; + } + } + } + + void verifyNewProxyInstance() throws Exception { + Object o = Proxy.newProxyInstance(loader, interfaces, ih); + Module m = o.getClass().getModule(); + if (target != null && m != target) { + throw new RuntimeException(m + " not expected: " + target); + } + if (target == null && (!m.isNamed() || !m.getName().startsWith("jdk.proxy"))) { + throw new RuntimeException(m + " not expected: dynamic module"); + } + } + private final static InvocationHandler ih = + (proxy, m, params) -> { System.out.println(m); return null; }; +} diff --git a/jdk/test/java/lang/reflect/Proxy/ProxyTest.java b/jdk/test/java/lang/reflect/Proxy/ProxyTest.java new file mode 100644 index 00000000000..80c8b76ae9a --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/ProxyTest.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +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 ProxyTest q.U CompilerUtils jdk.testlibrary.* + * @run testng ProxyTest + * @summary Driver for testing proxies accessing interfaces in named modules + */ + +public class ProxyTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String TEST_CLASSES = System.getProperty("test.classes"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path CPATH_DIR = Paths.get(TEST_CLASSES); + + // the names of the modules in this test + private static List modules = Arrays.asList("test", "m1", "m2", "m3"); + + + /** + * 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, "-modulesourcepath", SRC_DIR.toString())); + } + } + + /** + * Run the modular test + */ + @Test + public void runTest() throws Exception { + int exitValue = executeTestJava("-cp", CPATH_DIR.toString(), + "-mp", MODS_DIR.toString(), + "-m", "test/jdk.test.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/q/NP.java b/jdk/test/java/lang/reflect/Proxy/q/NP.java new file mode 100644 index 00000000000..da41a5dd72a --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/q/NP.java @@ -0,0 +1,27 @@ +/* + * 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 q; + +interface NP { +} diff --git a/jdk/test/java/lang/reflect/Proxy/q/U.java b/jdk/test/java/lang/reflect/Proxy/q/U.java new file mode 100644 index 00000000000..c217cbed587 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/q/U.java @@ -0,0 +1,27 @@ +/* + * 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 q; + +public interface U { +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m1/module-info.java b/jdk/test/java/lang/reflect/Proxy/src/m1/module-info.java new file mode 100644 index 00000000000..dd84f096764 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m1/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m1 { + exports p.one; + exports p.one.internal to test; +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m1/p/one/I.java b/jdk/test/java/lang/reflect/Proxy/src/m1/p/one/I.java new file mode 100644 index 00000000000..09e68870f0a --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m1/p/one/I.java @@ -0,0 +1,28 @@ +/* + * 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 p.one; + +public interface I { + void run(); +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m1/p/one/internal/J.java b/jdk/test/java/lang/reflect/Proxy/src/m1/p/one/internal/J.java new file mode 100644 index 00000000000..f6bd6a07ea3 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m1/p/one/internal/J.java @@ -0,0 +1,27 @@ +/* + * 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 p.one.internal; + +public interface J { +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m2/module-info.java b/jdk/test/java/lang/reflect/Proxy/src/m2/module-info.java new file mode 100644 index 00000000000..e7541d68bd3 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m2/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m2 { + exports p.two; + exports p.two.internal to test; +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/A.java b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/A.java new file mode 100644 index 00000000000..b54f0d80365 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/A.java @@ -0,0 +1,27 @@ +/* + * 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 p.two; + +public interface A { +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/B.java b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/B.java new file mode 100644 index 00000000000..7ba14544707 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/B.java @@ -0,0 +1,27 @@ +/* + * 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 p.two; + +interface B { +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/Bar.java b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/Bar.java new file mode 100644 index 00000000000..fedade0cf77 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/Bar.java @@ -0,0 +1,34 @@ +/* + * 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 p.two; + +public class Bar { + public Bar() { + } + + @Override + public String toString() { + return this.getClass().getName(); + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/internal/C.java b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/internal/C.java new file mode 100644 index 00000000000..f403f5a99d5 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m2/p/two/internal/C.java @@ -0,0 +1,27 @@ +/* + * 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 p.two.internal; + +public interface C { +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java new file mode 100644 index 00000000000..cf4da7cc254 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m3/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m3 { + requires public m2; + exports p.three; +} diff --git a/langtools/test/tools/jdeps/VerboseFormat/use/unsafe/UseUnsafeClass.java b/jdk/test/java/lang/reflect/Proxy/src/m3/p/three/P.java similarity index 89% rename from langtools/test/tools/jdeps/VerboseFormat/use/unsafe/UseUnsafeClass.java rename to jdk/test/java/lang/reflect/Proxy/src/m3/p/three/P.java index 2d8dc577e03..3be0bd85aba 100644 --- a/langtools/test/tools/jdeps/VerboseFormat/use/unsafe/UseUnsafeClass.java +++ b/jdk/test/java/lang/reflect/Proxy/src/m3/p/three/P.java @@ -21,11 +21,12 @@ * questions. */ -package use.unsafe; +package p.three; -import sun.misc.Unsafe; +import p.two.Bar; -public class UseUnsafeClass { - static Unsafe unsafe = Unsafe.getUnsafe(); +public interface P { + public Bar bar(); + public Bar[][][] barArrays(); } diff --git a/jdk/test/java/lang/reflect/Proxy/src/m3/p/three/internal/Q.java b/jdk/test/java/lang/reflect/Proxy/src/m3/p/three/internal/Q.java new file mode 100644 index 00000000000..7fe9fd09bb1 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/m3/p/three/internal/Q.java @@ -0,0 +1,27 @@ +/* + * 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 p.three.internal; + +public interface Q { +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..188e3d9e084 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/Main.java @@ -0,0 +1,163 @@ +/* + * 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 jdk.test; + +import java.net.URL; +import java.net.URLClassLoader; +import java.lang.reflect.Module; +import static jdk.test.ProxyTest.*; + +public class Main { + public static void main(String... args) { + ProxyTest ptest = new jdk.test.ProxyTest(); + for (Data d : proxiesForExportedTypes()) { + ptest.test(d); + } + + for (Data d : proxiesForPackagePrivateTypes()) { + ptest.test(d); + } + + for (Data d : proxiesForModulePrivateTypes()) { + ptest.test(d); + } + + for (Data d : proxiesWithAddReads()) { + ptest.test(d); + } + + for (Data d : proxiesWithAddExports()) { + ptest.test(d); + } + } + + private final static Module m1 = p.one.I.class.getModule(); + private final static Module m2 = p.two.A.class.getModule(); + private final static Module m3 = p.three.P.class.getModule(); + private final static Module test = Main.class.getModule(); + private final static Class unnamedModuleClass = classForName("q.U"); + private final static Class m3InternalType = classForName("p.three.internal.Q"); + + /* + * Test cases for proxy class to implement exported proxy interfaces + * will result in the unnamed module. + * + * The proxy class is accessible to unnamed module. + */ + static Data[] proxiesForExportedTypes() { + ClassLoader ld = Main.class.getClassLoader(); + Module unnamed = ld.getUnnamedModule(); + ClassLoader ld2 = new URLClassLoader(new URL[0], ld); + Module unnamed2 = ld2.getUnnamedModule(); + + return new Data[] { + new Data(unnamed, ld, Runnable.class), + new Data(unnamed, ld, p.one.I.class), + new Data(unnamed, ld, p.one.I.class, p.two.A.class), + new Data(unnamed, ld, p.one.I.class, unnamedModuleClass), + new Data(unnamed2, ld2, Runnable.class), + new Data(unnamed2, ld2, p.one.I.class), + new Data(unnamed2, ld2, p.one.I.class, p.two.A.class), + new Data(unnamed2, ld2, p.one.I.class, unnamedModuleClass), + new Data(unnamed, m1.getClassLoader(), p.one.I.class), + new Data(unnamed, m2.getClassLoader(), p.two.A.class), + new Data(unnamed, m3.getClassLoader(), p.three.P.class), + }; + } + + /* + * Test cases for proxy class to implement package-private proxy interface + * will result in same runtime package and same module as the proxy interface + * + * The proxy class is accessible to classes in the same runtime package + */ + static Data[] proxiesForPackagePrivateTypes() { + Class bClass = classForName("p.two.B"); // package-private type + + return new Data[] { + new Data(m2, m2.getClassLoader(), p.two.A.class, bClass), + new Data(m2, m2.getClassLoader(), p.two.A.class, bClass, p.two.internal.C.class) + }; + } + + /* + * Test cases for proxy class to implement one or more module-private types. + * + * This will result in a dynamic module which can read the modules of the interfaces + * and their dependences and also qualified exports to the module-private packages. + * The proxy class is not accessible to any module. + */ + static Data[] proxiesForModulePrivateTypes() { + ClassLoader ld = Main.class.getClassLoader(); + ClassLoader customLoader = new URLClassLoader(new URL[0], ld); + return new Data[] { + // different loaders + new Data(m1.getClassLoader(), p.one.internal.J.class), + new Data(customLoader, p.one.internal.J.class), + new Data(m2.getClassLoader(), p.two.internal.C.class, Runnable.class), + // interfaces from m2 only + new Data(m2.getClassLoader(), p.two.internal.C.class, p.two.A.class), + // p.two.A is accessible to m3 + new Data(m3.getClassLoader(), m3InternalType, p.two.A.class), + new Data(customLoader, unnamedModuleClass, jdk.test.internal.R.class, p.one.I.class), + // two module-private types in two different modules + new Data(m3.getClassLoader(), p.two.internal.C.class, m3InternalType), + new Data(m3.getClassLoader(), p.three.P.class, m3InternalType, jdk.test.internal.R.class), + }; + } + + /* + * Test cases for proxy class to implement accessible proxy interfaces + * after addReads. That does not change the target module. + */ + static Data[] proxiesWithAddReads() { + Module unnamed = test.getClassLoader().getUnnamedModule(); + test.addReads(unnamed); + return new Data[] { + new Data(test.getClassLoader(), + unnamedModuleClass, p.one.I.class, + jdk.test.internal.R.class), // module-private interface in test + }; + } + + /* + * Test cases for proxy class to implement accessible proxy interfaces + * after addExports. That does not change the target module. + */ + static Data[] proxiesWithAddExports() { + return new Data[] { + new Data(test.getClassLoader(), + p.one.internal.J.class, + p.two.internal.C.class), // module-private interfaces in m2 and m3 + }; + } + + static Class classForName(String cn) { + try { + return Class.forName(cn); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/NP.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/NP.java new file mode 100644 index 00000000000..6ddf7adf1bc --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/NP.java @@ -0,0 +1,31 @@ +/* + * 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 jdk.test; + +/* + * Non-public interface + */ +interface NP { + void test(); +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyClassAccess.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyClassAccess.java new file mode 100644 index 00000000000..1593aa96e78 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyClassAccess.java @@ -0,0 +1,109 @@ +/* + * 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 jdk.test; + +import jdk.test.internal.*; +import jdk.test.internal.foo.*; +import p.two.Bar; +import p.three.P; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Test proxy class to have access to types referenced in the public methods. + */ +public class ProxyClassAccess { + public static void main(String... args) throws Exception { + testImplClass(); + testProxyClass1(); + testProxyClass2(); + testNonPublicProxy(); + } + + /* + * Invoke methods from implementation class + */ + static void testImplClass() { + R impl = new RImpl(); + impl.foo(); + Bar[][] bars = new Bar[0][0]; + impl.setBarArray(bars); + try { + impl.throwException(); + throw new RuntimeException("FooException not thrown"); + } catch (FooException e) { } + } + + /* + * Invoke methods via proxy + */ + static void testProxyClass1() { + R proxy = (R) Proxy.newProxyInstance(R.class.getClassLoader(), + new Class[] { R.class }, handler); + proxy.foo(); + Bar[][] bars = new Bar[0][0]; + proxy.setBarArray(bars); + } + + /* + * Invoke methods via proxy defined with a custom class loader + */ + static void testProxyClass2() { + URLClassLoader loader = new URLClassLoader(new URL[0]); + P proxy = (P) Proxy.newProxyInstance(loader, + new Class[] { R.class, P.class }, handler); + proxy.bar(); + proxy.barArrays(); + } + + static void testNonPublicProxy() { + NP proxy = (NP) Proxy.newProxyInstance(NP.class.getClassLoader(), + new Class[]{NP.class}, handler); + proxy.test(); + + try { + URLClassLoader loader = new URLClassLoader(new URL[0]); + proxy = (NP) Proxy.newProxyInstance(loader, + new Class[]{NP.class}, handler); + throw new RuntimeException("IllegalArgumentException not thrown"); + } catch (IllegalArgumentException e) { + } + } + + static InvocationHandler handler = new InvocationHandler() { + final R impl = new RImpl(); + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getDeclaringClass() == R.class) { + return method.invoke(impl, args); + } else { + return null; + } + } + }; +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java new file mode 100644 index 00000000000..bbe260bf159 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/ProxyTest.java @@ -0,0 +1,115 @@ +/* + * 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 jdk.test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Module; +import java.lang.reflect.Proxy; +import java.util.Arrays; + +public class ProxyTest { + public static class Data { + private static int count = 0; + final int testcase; + final ClassLoader loader; + final Module module; + final Class[] interfaces; + // Expected the proxy class in the specified module + public Data(Module m, ClassLoader loader, Class... interfaces) { + this.module = m; + this.loader = loader; + this.interfaces = interfaces; + this.testcase = ++count; + } + // Expected the proxy class in a dynamic module + public Data(ClassLoader loader, Class... interfaces) { + this(null, loader, interfaces); + } + + @Override + public String toString() { + String expected = module != null + ? (module.isNamed() ? module.getName() : "unnamed") + : "dynamic"; + return String.format("%2d: Expected: %s %s loader: %s", testcase, expected, + Arrays.toString(interfaces), loader); + } + } + + public void test(Data d) { + System.out.println(d); + + if (d.module != null) { + testProxyClass(d.module, d.loader, d.interfaces); + } else { + testDynamicModule(d); + } + } + + private void testDynamicModule(Data d) { + Class proxyClass = Proxy.getProxyClass(d.loader, d.interfaces); + assertDynamicModule(proxyClass.getModule(), d.loader, proxyClass); + + Object proxy = Proxy.newProxyInstance(d.loader, d.interfaces, handler); + assertDynamicModule(proxy.getClass().getModule(), d.loader, proxy.getClass()); + } + + private static void testProxyClass(Module module, ClassLoader ld, Class... interfaces) { + Class proxyClass = Proxy.getProxyClass(ld, interfaces); + assertEquals(proxyClass.getModule(), module); + + Object proxy = Proxy.newProxyInstance(ld, interfaces, handler); + assertEquals(proxy.getClass().getModule(), module); + } + + public static void assertDynamicModule(Module m, ClassLoader ld, Class proxyClass) { + if (!m.isNamed() || !m.getName().startsWith("jdk.proxy")) { + throw new RuntimeException(m.getName() + " not dynamic module"); + } + + if (ld != m.getClassLoader() || proxyClass.getClassLoader() != ld) { + throw new RuntimeException("unexpected class loader"); + } + + try { + Constructor cons = proxyClass.getConstructor(InvocationHandler.class); + cons.newInstance(handler); + throw new RuntimeException("Expected IllegalAccessException: " + proxyClass); + } catch (IllegalAccessException e) { + // expected + } catch (NoSuchMethodException|InstantiationException|InvocationTargetException e) { + throw new RuntimeException(e); + } + } + + public static void assertEquals(Object o1, Object o2) { + if (o1 != o2) { + throw new RuntimeException(o1 + " != " + o2); + } + } + private final static InvocationHandler handler = + (proxy, m, params) -> { throw new RuntimeException(m.toString()); }; +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/R.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/R.java new file mode 100644 index 00000000000..40f4219b151 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/R.java @@ -0,0 +1,34 @@ +/* + * 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 jdk.test.internal; + +import jdk.test.internal.foo.*; +import p.two.Bar; + +public interface R { + public Foo foo(); + public void throwException() throws FooException; + + public void setBarArray(Bar[][] array); +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/RImpl.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/RImpl.java new file mode 100644 index 00000000000..0770c09f293 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/RImpl.java @@ -0,0 +1,38 @@ +/* + * 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 jdk.test.internal; + +import jdk.test.internal.foo.*; +import p.two.Bar; + +public class RImpl implements R { + public Foo foo() { + return new Foo(); + } + public void throwException() throws FooException { + throw new FooException(); + } + public void setBarArray(Bar[][] array) { + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/Foo.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/Foo.java new file mode 100644 index 00000000000..1773ba814a0 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/Foo.java @@ -0,0 +1,31 @@ +/* + * 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 jdk.test.internal.foo; + +public class Foo { + @Override + public String toString() { + return this.getClass().getName(); + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/FooException.java b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/FooException.java new file mode 100644 index 00000000000..3270476f9e6 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/jdk/test/internal/foo/FooException.java @@ -0,0 +1,29 @@ +/* + * 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 jdk.test.internal.foo; + +public class FooException extends RuntimeException { + public FooException() { + } +} diff --git a/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java new file mode 100644 index 00000000000..75c2d33dfd6 --- /dev/null +++ b/jdk/test/java/lang/reflect/Proxy/src/test/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module test { + requires m1; + requires m3; // requires public m2 + + exports jdk.test; +} diff --git a/jdk/test/java/net/Authenticator/B4933582.sh b/jdk/test/java/net/Authenticator/B4933582.sh index c696f411f37..728de44a0c9 100644 --- a/jdk/test/java/net/Authenticator/B4933582.sh +++ b/jdk/test/java/net/Authenticator/B4933582.sh @@ -43,8 +43,12 @@ case "$OS" in exit 1; ;; esac -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ + +EXTRAOPTS="-XaddExports:java.base/sun.net.www=ALL-UNNAMED,java.base/sun.net.www.protocol.http=ALL-UNNAMED" +export EXTRAOPTS + +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \ -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest" ${TESTSRC}${FS}B4933582.java rm -f cache.ser auth.save -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 first +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath "${TESTSRC}${FS}..${FS}..${FS}..${FS}sun${FS}net${FS}www${FS}httptest${PS}." B4933582 second diff --git a/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java b/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java index df4d9b0b5e7..fe6874ba130 100644 --- a/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java +++ b/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/ADatagramSocket.java @@ -25,8 +25,8 @@ * @bug 4132931 * @summary DatagramSocket should use a factory for its impl * - * @build ADatagramSocket - * @run shell ADatagramSocket.sh + * @compile/module=java.base java/net/MyDatagramSocketImplFactory.java + * @run main ADatagramSocket */ import java.io.*; import java.net.*; diff --git a/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java/net/MyDatagramSocketImplFactory.java b/jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java.base/java/net/MyDatagramSocketImplFactory.java similarity index 100% rename from jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java/net/MyDatagramSocketImplFactory.java rename to jdk/test/java/net/DatagramSocket/SetDatagramSocketImplFactory/java.base/java/net/MyDatagramSocketImplFactory.java diff --git a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java index 6659cd861d2..7d8646d5361 100644 --- a/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java +++ b/jdk/test/java/net/NetworkInterface/NetworkInterfaceStreamTest.java @@ -24,8 +24,8 @@ /* @test * @bug 8081678 8131155 * @summary Tests for stream returning methods - * @library ../../util/stream/bootlib/java.base - * @build java.util.stream.OpTestCase + * @library ../../util/stream/bootlib + * @build java.base/java.util.stream.OpTestCase * @run testng/othervm NetworkInterfaceStreamTest * @run testng/othervm -Djava.net.preferIPv4Stack=true NetworkInterfaceStreamTest * @key intermittent diff --git a/jdk/test/java/net/URI/URItoURLTest.java b/jdk/test/java/net/URI/URItoURLTest.java index 05fadebf8f9..0b97f24fc7e 100644 --- a/jdk/test/java/net/URI/URItoURLTest.java +++ b/jdk/test/java/net/URI/URItoURLTest.java @@ -38,9 +38,7 @@ public class URItoURLTest { public static void main(String args[]) throws Exception { - URItoURLTest testClass = new URItoURLTest(); - URL classUrl = testClass.getClass(). - getResource("/java/lang/Object.class"); + URL classUrl = new URL("jrt:/java.base/java/lang/Object.class"); String[] uris = { "mailto:xyz@abc.de", diff --git a/jdk/test/java/net/URLPermission/nstest/lookup.sh b/jdk/test/java/net/URLPermission/nstest/lookup.sh index eefd73cae12..ac00c50ec00 100644 --- a/jdk/test/java/net/URLPermission/nstest/lookup.sh +++ b/jdk/test/java/net/URLPermission/nstest/lookup.sh @@ -24,6 +24,7 @@ # @test # @library /lib/testlibrary +# @modules java.base/sun.net.spi.nameservice # @build jdk.testlibrary.* # @compile -XDignore.symbol.file=true SimpleNameService.java # LookupTest.java SimpleNameServiceDescriptor.java @@ -57,6 +58,7 @@ grant { POLICY ${TESTJAVA}/bin/java ${TESTVMOPTS} \ + -XaddExports:java.base/sun.net.spi.nameservice=ALL-UNNAMED \ -Djava.security.policy=file:./policy \ -Dsun.net.spi.nameservice.provider.1=simple,sun \ -cp ${TESTCLASSPATH}${PS}${TESTSRC} LookupTest -runtest ${port} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg1/Class2Pkg1.java b/jdk/test/java/net/httpclient/whitebox/Driver.java similarity index 86% rename from langtools/test/com/sun/javadoc/testProfiles/pkg1/Class2Pkg1.java rename to jdk/test/java/net/httpclient/whitebox/Driver.java index 33ecb01e45e..fbbdb05dbed 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg1/Class2Pkg1.java +++ b/jdk/test/java/net/httpclient/whitebox/Driver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,8 @@ * questions. */ -package pkg1; - -/** - * A test class. - * - * @author Bhavesh Patel +/* + * @test + * @bug 8151299 + * @run testng java.httpclient/java.net.http.SelectorTest */ -public class Class2Pkg1 { -} diff --git a/jdk/test/java/net/httpclient/whitebox/TEST.properties b/jdk/test/java/net/httpclient/whitebox/TEST.properties deleted file mode 100644 index 1d784754199..00000000000 --- a/jdk/test/java/net/httpclient/whitebox/TEST.properties +++ /dev/null @@ -1,3 +0,0 @@ -TestNG.dirs = . - -bootclasspath.dirs = /java/net/httpclient diff --git a/jdk/test/java/net/httpclient/whitebox/java/net/http/SelectorTest.java b/jdk/test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java similarity index 98% rename from jdk/test/java/net/httpclient/whitebox/java/net/http/SelectorTest.java rename to jdk/test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java index 74ef4ff2991..001e7a4c8eb 100644 --- a/jdk/test/java/net/httpclient/whitebox/java/net/http/SelectorTest.java +++ b/jdk/test/java/net/httpclient/whitebox/java.httpclient/java/net/http/SelectorTest.java @@ -21,11 +21,6 @@ * questions. */ -/** - * @test - * @bug 8151299 - * @summary Http client SelectorManager overwriting read and write events - */ package java.net.http; import java.net.*; diff --git a/jdk/test/java/nio/Buffer/LimitDirectMemory.sh b/jdk/test/java/nio/Buffer/LimitDirectMemory.sh index f2e7a93b878..372dc0532db 100644 --- a/jdk/test/java/nio/Buffer/LimitDirectMemory.sh +++ b/jdk/test/java/nio/Buffer/LimitDirectMemory.sh @@ -27,8 +27,8 @@ # @bug 4627316 6743526 # @summary Test option to limit direct memory allocation # +# @requires (os.arch == "x86_64") | (os.arch == "amd64") | (os.arch == "sparcv9") # @build LimitDirectMemory -# @ignore JDK-8129343 # @run shell LimitDirectMemory.sh TMP1=tmp_$$ diff --git a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java index 4172efe0daf..d897fa0ea55 100644 --- a/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java +++ b/jdk/test/java/nio/channels/AsyncCloseAndInterrupt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* @test * @bug 4460583 4470470 4840199 6419424 6710579 6596323 6824135 6395224 7142919 + * 8151582 * @run main/othervm AsyncCloseAndInterrupt * @summary Comprehensive test of asynchronous closing and interruption * @author Mark Reinhold @@ -89,7 +90,7 @@ public class AsyncCloseAndInterrupt { private static void initRefuser() throws IOException { refuser = ServerSocketChannel.open(); - refuser.socket().bind(wildcardAddress); + refuser.bind(wildcardAddress, 1); // use minimum backlog } // Dead pipe source and sink @@ -349,7 +350,7 @@ public class AsyncCloseAndInterrupt { static final Op CONNECT = new Op("connect") { void setup() { - waitPump("connect wait for pumping refuser ..."); + waitPump("connect waiting for pumping refuser ..."); } void doIO(InterruptibleChannel ich) throws IOException { SocketChannel sc = (SocketChannel)ich; @@ -361,7 +362,7 @@ public class AsyncCloseAndInterrupt { static final Op FINISH_CONNECT = new Op("finishConnect") { void setup() { - waitPump("finishConnect wait for pumping refuser ..."); + waitPump("finishConnect waiting for pumping refuser ..."); } void doIO(InterruptibleChannel ich) throws IOException { SocketChannel sc = (SocketChannel)ich; @@ -498,12 +499,11 @@ public class AsyncCloseAndInterrupt { private static volatile boolean pumpReady = false; private static void waitPump(String msg){ - pumpReady = false; log.println(msg); - while (!pumpReady){ sleep(200); } + log.println(msg + " done"); } // Create a pump thread dedicated to saturate refuser's connection backlog @@ -520,28 +520,34 @@ public class AsyncCloseAndInterrupt { // Saturate the refuser's connection backlog so that further connection // attempts will be blocked + pumpReady = false; while (!pumpDone) { SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); boolean connected = sc.connect(refuser.socket().getLocalSocketAddress()); // Assume that the connection backlog is saturated if a - // client cannot connect to the refuser within 50 miliseconds + // client cannot connect to the refuser within 50 milliseconds long start = System.currentTimeMillis(); - while (!connected && (System.currentTimeMillis() - start < 50)) { + while (!pumpReady && !connected + && (System.currentTimeMillis() - start < 50)) { connected = sc.finishConnect(); } if (connected) { // Retain so that finalizer doesn't close refuserClients.add(sc); - pumpReady = false; } else { sc.close(); pumpReady = true; } } + for (SocketChannel sc : refuserClients) { + sc.close(); + } + refuser.close(); + log.println("Stop pumping refuser ..."); return refuserClients.size(); } @@ -565,8 +571,6 @@ public class AsyncCloseAndInterrupt { sleep(50); } while (!t.ready); - sleep(100); - switch (test) { case TEST_INTR: diff --git a/jdk/test/java/nio/channels/Selector/ChangingInterests.java b/jdk/test/java/nio/channels/Selector/ChangingInterests.java index c3e1dbd0964..bd8ab27a1b5 100644 --- a/jdk/test/java/nio/channels/Selector/ChangingInterests.java +++ b/jdk/test/java/nio/channels/Selector/ChangingInterests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,6 +23,7 @@ /* @test * @bug 7200742 + * @key intermittent * @summary Test that Selector doesn't spin when changing interest ops */ diff --git a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh index 8c6355073d6..371b62fa5f7 100644 --- a/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh +++ b/jdk/test/java/nio/channels/spi/SelectorProvider/inheritedChannel/run_tests.sh @@ -109,7 +109,8 @@ failures=0 go() { echo '' - sh -xc "$JAVA ${TESTVMOPTS} $DFLAG $1 $2 $3 $4 $5 $6 $7 $8" 2>&1 + sh -xc "$JAVA ${TESTVMOPTS} -XaddExports:java.base/sun.nio.ch=ALL-UNNAMED $DFLAG \ + $1 $2 $3 $4 $5 $6 $7 $8" 2>&1 if [ $? != 0 ]; then failures=`expr $failures + 1`; fi } diff --git a/jdk/test/java/nio/file/Files/StreamLinesTest.java b/jdk/test/java/nio/file/Files/StreamLinesTest.java index 4f45026004d..aa4c9ba3220 100644 --- a/jdk/test/java/nio/file/Files/StreamLinesTest.java +++ b/jdk/test/java/nio/file/Files/StreamLinesTest.java @@ -23,8 +23,8 @@ /* @test * @bug 8072773 - * @library /lib/testlibrary/ ../../../util/stream/bootlib/java.base - * @build java.util.stream.OpTestCase + * @library /lib/testlibrary/ ../../../util/stream/bootlib + * @build java.base/java.util.stream.OpTestCase * @build jdk.testlibrary.RandomFactory * @run testng/othervm StreamLinesTest * @summary Tests streams returned from Files.lines, primarily focused on diff --git a/jdk/test/java/nio/file/spi/SetDefaultProvider.java b/jdk/test/java/nio/file/spi/SetDefaultProvider.java index bcb0ae24b1b..10629f89b1d 100644 --- a/jdk/test/java/nio/file/spi/SetDefaultProvider.java +++ b/jdk/test/java/nio/file/spi/SetDefaultProvider.java @@ -25,7 +25,6 @@ * @bug 4313887 7006126 * @summary Unit test for java.nio.file.spi.FileSystemProvider * @build TestProvider SetDefaultProvider - * @ignore JDK-8129343 * @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider SetDefaultProvider */ diff --git a/jdk/test/java/nio/file/spi/TestProvider.java b/jdk/test/java/nio/file/spi/TestProvider.java index b2744f4c0e5..f0538e5067b 100644 --- a/jdk/test/java/nio/file/spi/TestProvider.java +++ b/jdk/test/java/nio/file/spi/TestProvider.java @@ -21,20 +21,34 @@ * questions. */ -import java.nio.file.spi.FileSystemProvider; +import java.io.File; import java.nio.file.*; -import java.nio.file.attribute.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.FileAttributeView; +import java.nio.file.attribute.UserPrincipalLookupService; +import java.nio.file.spi.FileSystemProvider; import java.nio.channels.SeekableByteChannel; import java.net.URI; -import java.util.*; import java.io.IOException; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; public class TestProvider extends FileSystemProvider { - private final FileSystem theFileSystem; + private final FileSystemProvider defaultProvider; + private final TestFileSystem theFileSystem; public TestProvider(FileSystemProvider defaultProvider) { - theFileSystem = new TestFileSystem(this); + this.defaultProvider = defaultProvider; + FileSystem fs = defaultProvider.getFileSystem(URI.create("file:/")); + this.theFileSystem = new TestFileSystem(fs, this); + } + + FileSystemProvider defaultProvider() { + return defaultProvider; } @Override @@ -43,8 +57,8 @@ public class TestProvider extends FileSystemProvider { } @Override - public FileSystem newFileSystem(URI uri, Map env) { - throw new RuntimeException("not implemented"); + public FileSystem newFileSystem(URI uri, Map env) throws IOException { + return defaultProvider.newFileSystem(uri, env); } @Override @@ -54,7 +68,8 @@ public class TestProvider extends FileSystemProvider { @Override public Path getPath(URI uri) { - throw new RuntimeException("not implemented"); + Path path = defaultProvider.getPath(uri); + return theFileSystem.wrap(path); } @Override @@ -62,7 +77,7 @@ public class TestProvider extends FileSystemProvider { LinkOption... options) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override @@ -70,7 +85,8 @@ public class TestProvider extends FileSystemProvider { LinkOption... options) throws IOException { - throw new RuntimeException("not implemented"); + Path delegate = theFileSystem.unwrap(file); + return defaultProvider.readAttributes(delegate, attributes, options); } @Override @@ -79,7 +95,8 @@ public class TestProvider extends FileSystemProvider { LinkOption... options) throws IOException { - throw new RuntimeException("not implemented"); + Path delegate = theFileSystem.unwrap(file); + return defaultProvider.readAttributes(delegate, type, options); } @Override @@ -87,45 +104,46 @@ public class TestProvider extends FileSystemProvider { Class type, LinkOption... options) { - throw new RuntimeException("not implemented"); + Path delegate = theFileSystem.unwrap(file); + return defaultProvider.getFileAttributeView(delegate, type, options); } - @Override public void delete(Path file) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override public void createLink(Path link, Path existing) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override public Path readSymbolicLink(Path link) throws IOException { - throw new RuntimeException("not implemented"); + Path delegate = theFileSystem.unwrap(link); + Path target = defaultProvider.readSymbolicLink(delegate); + return theFileSystem.wrap(target); } - @Override public void copy(Path source, Path target, CopyOption... options) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override public void move(Path source, Path target, CopyOption... options) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override @@ -140,7 +158,7 @@ public class TestProvider extends FileSystemProvider { public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override @@ -149,13 +167,18 @@ public class TestProvider extends FileSystemProvider { FileAttribute... attrs) throws IOException { + if (options.contains(StandardOpenOption.READ) && options.size() == 1) { + Path delegate = theFileSystem.unwrap(file); + options = Collections.singleton(StandardOpenOption.READ); + return defaultProvider.newByteChannel(delegate, options, attrs); + } + throw new RuntimeException("not implemented"); } - @Override public boolean isHidden(Path file) throws IOException { - throw new RuntimeException("not implemented"); + throw new ReadOnlyFileSystemException(); } @Override @@ -176,12 +199,26 @@ public class TestProvider extends FileSystemProvider { } static class TestFileSystem extends FileSystem { + private final FileSystem delegate; private final TestProvider provider; - TestFileSystem(TestProvider provider) { + TestFileSystem(FileSystem delegate, TestProvider provider) { + this.delegate = delegate; this.provider = provider; } + Path wrap(Path path) { + return (path != null) ? new TestPath(this, path) : null; + } + + Path unwrap(Path wrapper) { + if (wrapper == null) + throw new NullPointerException(); + if (!(wrapper instanceof TestPath)) + throw new ProviderMismatchException(); + return ((TestPath)wrapper).unwrap(); + } + @Override public FileSystemProvider provider() { return provider; @@ -194,17 +231,17 @@ public class TestProvider extends FileSystemProvider { @Override public boolean isOpen() { - throw new RuntimeException("not implemented"); + return true; } @Override public boolean isReadOnly() { - throw new RuntimeException("not implemented"); + return true; } @Override public String getSeparator() { - throw new RuntimeException("not implemented"); + return delegate.getSeparator(); } @Override @@ -219,27 +256,209 @@ public class TestProvider extends FileSystemProvider { @Override public Set supportedFileAttributeViews() { - throw new RuntimeException("not implemented"); + return delegate.supportedFileAttributeViews(); } @Override public Path getPath(String first, String... more) { - throw new RuntimeException("not implemented"); + Path path = delegate.getPath(first, more); + return wrap(path); } @Override public PathMatcher getPathMatcher(String syntaxAndPattern) { - throw new RuntimeException("not implemented"); + return delegate.getPathMatcher(syntaxAndPattern); } @Override public UserPrincipalLookupService getUserPrincipalLookupService() { - throw new RuntimeException("not implemented"); + return delegate.getUserPrincipalLookupService(); } @Override public WatchService newWatchService() throws IOException { - throw new RuntimeException("not implemented"); + throw new UnsupportedOperationException(); + } + } + + static class TestPath implements Path { + private final TestFileSystem fs; + private final Path delegate; + + TestPath(TestFileSystem fs, Path delegate) { + this.fs = fs; + this.delegate = delegate; + } + + Path unwrap() { + return delegate; + } + + @Override + public FileSystem getFileSystem() { + return fs; + } + + @Override + public boolean isAbsolute() { + return delegate.isAbsolute(); + } + + @Override + public Path getRoot() { + return fs.wrap(delegate.getRoot()); + } + + @Override + public Path getParent() { + return fs.wrap(delegate.getParent()); + } + + @Override + public int getNameCount() { + return delegate.getNameCount(); + } + + @Override + public Path getFileName() { + return fs.wrap(delegate.getFileName()); + } + + @Override + public Path getName(int index) { + return fs.wrap(delegate.getName(index)); + } + + @Override + public Path subpath(int beginIndex, int endIndex) { + return fs.wrap(delegate.subpath(beginIndex, endIndex)); + } + + @Override + public boolean startsWith(Path other) { + return delegate.startsWith(fs.unwrap(other)); + } + + @Override + public boolean startsWith(String other) { + return delegate.startsWith(other); + } + + @Override + public boolean endsWith(Path other) { + return delegate.endsWith(fs.unwrap(other)); + } + + @Override + public boolean endsWith(String other) { + return delegate.endsWith(other); + } + + @Override + public Path normalize() { + return fs.wrap(delegate.normalize()); + } + + @Override + public Path resolve(Path other) { + return fs.wrap(delegate.resolve(fs.unwrap(other))); + } + + @Override + public Path resolve(String other) { + return fs.wrap(delegate.resolve(other)); + } + + @Override + public Path resolveSibling(Path other) { + return fs.wrap(delegate.resolveSibling(fs.unwrap(other))); + } + + @Override + public Path resolveSibling(String other) { + return fs.wrap(delegate.resolveSibling(other)); + } + + @Override + public Path relativize(Path other) { + return fs.wrap(delegate.relativize(fs.unwrap(other))); + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof TestPath)) + return false; + return delegate.equals(fs.unwrap((TestPath) other)); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public URI toUri() { + String ssp = delegate.toUri().getSchemeSpecificPart(); + return URI.create(fs.provider().getScheme() + ":" + ssp); + } + + @Override + public Path toAbsolutePath() { + return fs.wrap(delegate.toAbsolutePath()); + } + + @Override + public Path toRealPath(LinkOption... options) throws IOException { + return fs.wrap(delegate.toRealPath(options)); + } + + @Override + public File toFile() { + return delegate.toFile(); + } + + @Override + public Iterator iterator() { + final Iterator itr = delegate.iterator(); + return new Iterator() { + @Override + public boolean hasNext() { + return itr.hasNext(); + } + @Override + public Path next() { + return fs.wrap(itr.next()); + } + @Override + public void remove() { + itr.remove(); + } + }; + } + + @Override + public int compareTo(Path other) { + return delegate.compareTo(fs.unwrap(other)); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) + { + throw new UnsupportedOperationException(); + } + + @Override + public WatchKey register(WatchService watcher, + WatchEvent.Kind... events) + { + throw new UnsupportedOperationException(); } } } diff --git a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh index 3b6143f2616..70e9c2b221b 100644 --- a/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh +++ b/jdk/test/java/rmi/activation/Activatable/extLoadedImpl/ext.sh @@ -51,5 +51,6 @@ rm classes/ExtLoadedImpl.class classes/ExtLoadedImpl_Stub.class classes/CheckLoa mkdir -p ext $COMPILEJAVA/bin/jar ${TESTTOOLVMOPTS} cf ext/ext.jar -C $TESTCLASSES ExtLoadedImpl.class -C $TESTCLASSES ExtLoadedImpl_Stub.class -C $TESTCLASSES CheckLoader.class +TESTVMOPTS="${TESTVMOPTS} -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" $TESTJAVA/bin/java ${TESTVMOPTS} -cp classes -Dtest.src=$TESTSRC -Dtest.classes=$TESTCLASSES -Djava.security.policy=$TESTSRC/security.policy -Djava.ext.dirs=ext ExtLoadedImplTest diff --git a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java index 2752d729344..1b2288c7786 100644 --- a/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java +++ b/jdk/test/java/rmi/activation/ActivationGroup/downloadActivationGroup/DownloadActivationGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -41,13 +41,19 @@ * @run main/othervm/policy=security.policy/timeout=240 DownloadActivationGroup */ -import java.io.*; -import java.rmi.*; -import java.net.*; -import java.rmi.activation.*; -import java.rmi.server.*; -import java.rmi.registry.*; -import java.util.Vector; +import java.net.URL; +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.activation.Activatable; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroup; +import java.rmi.activation.ActivationGroupDesc; +import java.rmi.activation.ActivationGroupDesc.CommandEnvironment; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.server.UnicastRemoteObject; import java.util.Properties; public class DownloadActivationGroup @@ -130,11 +136,16 @@ public class DownloadActivationGroup Properties p = new Properties(); p.put("java.security.policy", TestParams.defaultGroupPolicy); + CommandEnvironment cmd = new ActivationGroupDesc.CommandEnvironment( + null, + new String[] { "-XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED," + + "java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED," + + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" }); ActivationGroupDesc groupDesc = new ActivationGroupDesc("MyActivationGroupImpl", groupURL.toExternalForm(), - null, p, null); + null, p, cmd); ActivationGroupID groupID = ActivationGroup.getSystem().registerGroup(groupDesc); diff --git a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java index 9de4500c542..2ee592f7591 100644 --- a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java +++ b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/StubClassesPermitted.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,14 +37,20 @@ * @run main/othervm/java.security.policy=security.policy/secure=java.lang.SecurityManager/timeout=240 StubClassesPermitted */ -import java.io.*; -import java.rmi.*; -import java.rmi.server.*; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.rmi.MarshalledObject; +import java.rmi.RemoteException; +import java.rmi.activation.Activatable; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationGroup; +import java.rmi.activation.ActivationGroupDesc; +import java.rmi.activation.ActivationGroupDesc.CommandEnvironment; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.ActivationSystem; import java.rmi.registry.Registry; -import java.rmi.activation.*; -import java.security.CodeSource; import java.util.Properties; -import java.util.StringTokenizer; /** * The RMI activation system needs to explicitly allow itself to @@ -113,8 +119,13 @@ public class StubClassesPermitted // sun.rmi.server.Activation$ActivationMonitorImpl_Stub // System.err.println("Create activation group, in a new VM"); + CommandEnvironment cmd = new ActivationGroupDesc.CommandEnvironment(null, + new String[] { "-XaddExports:java.base/sun.security.provider=ALL-UNNAMED," + + "java.rmi/sun.rmi.registry=ALL-UNNAMED,java.rmi/sun.rmi.server=ALL-UNNAMED," + + "java.rmi/sun.rmi.transport=ALL-UNNAMED,java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" }); + ActivationGroupDesc groupDesc = - new ActivationGroupDesc(p, null); + new ActivationGroupDesc(p, cmd); ActivationSystem system = ActivationGroup.getSystem(); ActivationGroupID groupID = system.registerGroup(groupDesc); diff --git a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy index 27379746e6e..0c1df59fe99 100644 --- a/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy +++ b/jdk/test/java/rmi/activation/ActivationSystem/stubClassesPermitted/rmid.security.policy @@ -1,4 +1,7 @@ grant { permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.manager=java.lang.SecurityManager"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=*"; + + // test needs to export a set of internal APIs to access them from unamed module + permission com.sun.rmi.rmid.ExecOptionPermission "*"; }; diff --git a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java index 37f9508c531..72911b95b67 100644 --- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java +++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/InheritedChannelNotServerSocket.java @@ -105,9 +105,9 @@ public class InheritedChannelNotServerSocket { RMID.removeLog(); rmid = RMID.createRMID(System.out, System.err, true, true, TestLibrary.INHERITEDCHANNELNOTSERVERSOCKET_ACTIVATION_PORT); - rmid.addOptions(new String[]{ - "-Djava.nio.channels.spi.SelectorProvider=" + - "InheritedChannelNotServerSocket$SP"}); + rmid.addOptions( + "-XaddExports:java.base/sun.nio.ch=ALL-UNNAMED", + "-Djava.nio.channels.spi.SelectorProvider=InheritedChannelNotServerSocket$SP"); rmid.start(); /* diff --git a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java index e34af8c88cc..25018495faa 100644 --- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java +++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java @@ -92,8 +92,9 @@ public class RmidViaInheritedChannel implements Callback { RMID.removeLog(); rmid = RMID.createRMID(System.out, System.err, true, false, TestLibrary.RMIDVIAINHERITEDCHANNEL_ACTIVATION_PORT); - rmid.addOptions(new String[]{ - "-Djava.nio.channels.spi.SelectorProvider=RmidViaInheritedChannel$RmidSelectorProvider"}); + rmid.addOptions( + "-XaddExports:java.base/sun.nio.ch=ALL-UNNAMED", + "-Djava.nio.channels.spi.SelectorProvider=RmidViaInheritedChannel$RmidSelectorProvider"); if (System.getProperty("os.name").startsWith("Windows") && System.getProperty("os.version").startsWith("5.")) { diff --git a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java index bc1c2dc50ba..f30be86df4d 100644 --- a/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java +++ b/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java @@ -30,6 +30,7 @@ * rather than pinning it indefinitely. * @author Peter Jones * + * @modules java.rmi/sun.rmi.transport * @build DGCAckFailure DGCAckFailure_Stub * @run main/othervm DGCAckFailure */ diff --git a/jdk/test/java/rmi/registry/readTest/readTest.sh b/jdk/test/java/rmi/registry/readTest/readTest.sh index f397b44ef79..5c5490eceb4 100644 --- a/jdk/test/java/rmi/registry/readTest/readTest.sh +++ b/jdk/test/java/rmi/registry/readTest/readTest.sh @@ -23,6 +23,10 @@ # @test # @bug 7102369 7094468 7100592 +# @modules java.rmi/sun.rmi.registry +# java.rmi/sun.rmi.server +# java.rmi/sun.rmi.transport +# java.rmi/sun.rmi.transport.tcp # @library ../../testlibrary # @build TestLibrary # @summary remove java.rmi.server.codebase property parsing from registyimpl @@ -94,6 +98,7 @@ case "$OS" in ;; esac # trailing / after code base is important for rmi codebase property. +TESTVMOPTS="${TESTVMOPTS} -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED,java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED,java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp $TEST_CLASSPATH ${ARGS} -Djava.rmi.server.codebase=${FILEURL}$CODEBASE/ readTest > OUT.TXT 2>&1 & TEST_PID=$! #bulk of testcase - let it run for a while diff --git a/jdk/test/java/rmi/reliability/benchmark/bench/HtmlReporter.java b/jdk/test/java/rmi/reliability/benchmark/bench/HtmlReporter.java index d3059329da3..d0d302e257d 100644 --- a/jdk/test/java/rmi/reliability/benchmark/bench/HtmlReporter.java +++ b/jdk/test/java/rmi/reliability/benchmark/bench/HtmlReporter.java @@ -41,7 +41,7 @@ public class HtmlReporter implements Reporter { static final int PRECISION = 3; static final String[] PROPNAMES = { "os.name", "os.arch", "os.version", "java.home", "java.vm.version", "java.vm.vendor", "java.vm.name", - "java.compiler", "java.class.path", "sun.boot.class.path" }; + "java.compiler", "java.class.path" }; OutputStream out; String title; diff --git a/jdk/test/java/rmi/reliability/benchmark/bench/TextReporter.java b/jdk/test/java/rmi/reliability/benchmark/bench/TextReporter.java index 89d35a602a8..5ce3af75ffe 100644 --- a/jdk/test/java/rmi/reliability/benchmark/bench/TextReporter.java +++ b/jdk/test/java/rmi/reliability/benchmark/bench/TextReporter.java @@ -47,7 +47,7 @@ public class TextReporter implements Reporter { static final int PROPNAME_WIDTH = 25; static final String[] PROPNAMES = { "os.name", "os.arch", "os.version", "java.home", "java.vm.version", "java.vm.vendor", "java.vm.name", - "java.compiler", "java.class.path", "sun.boot.class.path" }; + "java.compiler", "java.class.path" }; OutputStream out; String title; diff --git a/jdk/test/java/rmi/testlibrary/JavaVM.java b/jdk/test/java/rmi/testlibrary/JavaVM.java index b0c4afd1113..37faa1e6fb7 100644 --- a/jdk/test/java/rmi/testlibrary/JavaVM.java +++ b/jdk/test/java/rmi/testlibrary/JavaVM.java @@ -78,7 +78,7 @@ public class JavaVM { } // Prepends passed opts array to current options - public void addOptions(String[] opts) { + public void addOptions(String... opts) { String newOpts = ""; for (int i = 0 ; i < opts.length ; i ++) { newOpts += " " + opts[i]; @@ -88,7 +88,7 @@ public class JavaVM { } // Prepends passed arguments array to current args - public void addArguments(String[] arguments) { + public void addArguments(String... arguments) { String newArgs = ""; for (int i = 0 ; i < arguments.length ; i ++) { newArgs += " " + arguments[i]; diff --git a/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java b/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java index b9c8f9861d1..1dc6d1fbc07 100644 --- a/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java +++ b/jdk/test/java/rmi/transport/checkFQDN/CheckFQDN.java @@ -123,6 +123,9 @@ public class CheckFQDN extends UnicastRemoteObject propOption + property + equal + propertyValue + extraProp + + " -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED," + + "java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED," + + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" + " -Drmi.registry.port=" + REGISTRY_PORT, ""); diff --git a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java index 7cddcd7d436..a02e6a39273 100644 --- a/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java +++ b/jdk/test/java/rmi/transport/dgcDeadLock/DGCDeadLock.java @@ -74,6 +74,10 @@ public class DGCDeadLock implements Runnable { try { String options = " -Djava.security.policy=" + TestParams.defaultPolicy + + " -XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED," + + "java.rmi/sun.rmi.server=ALL-UNNAMED," + + "java.rmi/sun.rmi.transport=ALL-UNNAMED," + + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" + " -Djava.rmi.dgc.leaseValue=500000" + " -Dsun.rmi.dgc.checkInterval=" + (HOLD_TARGET_TIME - 5000) + diff --git a/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java b/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java index e472ee36397..63d962e93b7 100644 --- a/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java +++ b/jdk/test/java/security/PermissionCollection/PermissionCollectionStreamTest.java @@ -24,8 +24,8 @@ /* @test * @bug 8081678 * @summary Tests for stream returning methods - * @library ../../util/stream/bootlib/java.base - * @build java.util.stream.OpTestCase + * @library ../../util/stream/bootlib + * @build java.base/java.util.stream.OpTestCase * @run testng/othervm PermissionCollectionStreamTest */ diff --git a/jdk/test/java/security/Provider/DefaultProviderList.java b/jdk/test/java/security/Provider/DefaultProviderList.java new file mode 100644 index 00000000000..c2836642f42 --- /dev/null +++ b/jdk/test/java/security/Provider/DefaultProviderList.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 7191662 + * @summary Ensure non-java.base providers can be found by ServiceLoader + * @author Valerie Peng + */ + +import java.util.*; +import java.security.*; + +public class DefaultProviderList { + + public static void main(String[] args) throws Exception { + Provider[] defaultProvs = Security.getProviders(); + System.out.println("Providers: " + Arrays.asList(defaultProvs)); + System.out.println(); + + ServiceLoader sl = ServiceLoader.load(Provider.class); + boolean failed = false; + for (Provider p : defaultProvs) { + String pName = p.getName(); + // only providers outside java.base are loaded by ServiceLoader + if (pName.equals("SUN") || pName.equals("SunRsaSign") || + pName.equals("SunJCE") || pName.equals("SunJSSE")) { + System.out.println("Skip test for provider " + pName); + continue; + } + String pClassName = p.getClass().getName(); + // Should be able to find each one through ServiceLoader + Iterator provIter = sl.iterator(); + boolean found = false; + while (provIter.hasNext()) { + Provider pFromSL = provIter.next(); + if (pFromSL.getClass().getName().equals(pClassName)) { + found = true; + break; + } + } + System.out.println("Found " + p.getName() + " = " + found); + if (!found) { + failed = true; + System.out.println("Error: no provider class " + pClassName + + " found"); + } + } + if (!failed) { + System.out.println("Test Passed"); + } else { + throw new Exception("One or more provider not loaded by SL"); + } + } +} diff --git a/jdk/test/java/security/Provider/SecurityProviderModularTest.java b/jdk/test/java/security/Provider/SecurityProviderModularTest.java new file mode 100644 index 00000000000..bdde99ffaa7 --- /dev/null +++ b/jdk/test/java/security/Provider/SecurityProviderModularTest.java @@ -0,0 +1,337 @@ +/* + * 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. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Arrays; +import java.io.IOException; +import java.lang.module.ModuleDescriptor; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.OutputAnalyzer; +import org.testng.annotations.BeforeTest; + +/** + * @test + * @bug 8130360 + * @library /lib/testlibrary + * @library /java/security/modules + * @modules java.base/jdk.internal.module + * @build CompilerUtils JarUtils + * @summary Test custom security provider module with all possible modular + * condition. The test includes different combination of security + * client/provider modules interaction with or without service + * description. + * @run testng SecurityProviderModularTest + */ +public class SecurityProviderModularTest extends ModularTest { + + private static final Path S_SRC = SRC.resolve("TestSecurityProvider.java"); + private static final String S_PKG = "provider"; + private static final String S_JAR_NAME = S_PKG + JAR_EXTN; + private static final String S_WITH_DESCR_JAR_NAME = S_PKG + DESCRIPTOR + + JAR_EXTN; + private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN; + private static final String MS_WITH_DESCR_JAR_NAME = MODULAR + S_PKG + + DESCRIPTOR + JAR_EXTN; + + private static final Path C_SRC = SRC.resolve( + "TestSecurityProviderClient.java"); + private static final String C_PKG = "client"; + private static final String C_JAR_NAME = C_PKG + JAR_EXTN; + private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR + + C_PKG + AUTO + JAR_EXTN; + private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN; + + private static final Path BUILD_DIR = Paths.get(".").resolve("build"); + private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin"); + private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG); + private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve( + S_PKG + DESCRIPTOR); + private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG); + private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase"); + private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts"); + + private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG); + private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME); + private static final Path S_WITH_DESCRIPTOR_JAR = S_ARTIFACTS_DIR.resolve( + S_WITH_DESCR_JAR_NAME); + private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve( + MS_JAR_NAME); + private static final Path MS_WITH_DESCR_JAR = S_ARTIFACTS_DIR.resolve( + MS_WITH_DESCR_JAR_NAME); + + private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG); + private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME); + private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME); + private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR + .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME); + + private static final String MAIN = C_PKG + ".TestSecurityProviderClient"; + private static final String S_INTERFACE = "java.security.Provider"; + private static final String S_IMPL = S_PKG + ".TestSecurityProvider"; + private static final List M_REQUIRED = Arrays.asList("java.base"); + private static final Path META_DESCR_PATH = Paths.get("META-INF") + .resolve("services").resolve(S_INTERFACE); + private static final Path S_META_DESCR_FPATH = S_WITH_META_DESCR_BUILD_DIR + .resolve(META_DESCR_PATH); + + private static final boolean WITH_S_DESCR = true; + private static final boolean WITHOUT_S_DESCR = false; + private static final String CLASS_NOT_FOUND_MSG = "NoClassDefFoundError:" + + " provider/TestSecurityProvider"; + private static final String PROVIDER_NOT_FOUND_MSG = "Unable to find Test" + + " Security Provider"; + private static final String CAN_NOT_ACCESS_MSG = "cannot access class"; + private static final String NO_FAILURE = null; + private static final String SERVICE_LOADER = "SERVICE_LOADER"; + private static final String CLASS_LOADER = "CLASS_LOADER"; + private static final String SECURITY_PROP = "SECURITY_PROP"; + private static final List MECHANISMS = Arrays.asList(SERVICE_LOADER, + CLASS_LOADER, SECURITY_PROP); + private static final Path SECURE_PROP_EXTN = Paths.get("./java.secure.ext"); + + /** + * Generates Test specific input parameters. + */ + @Override + public Object[][] getTestInput() { + + List> params = new ArrayList<>(); + MECHANISMS.stream().forEach((mechanism) -> { + boolean useCLoader = CLASS_LOADER.equals(mechanism); + boolean useSLoader = SERVICE_LOADER.equals(mechanism); + String[] args = new String[]{mechanism}; + //PARAMETER ORDERS - + //client Module Type, Service Module Type, + //Service META Descriptor Required, + //Expected Failure message, mech used to find the provider + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT, + WITHOUT_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO, + WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG + : NO_FAILURE), args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO, + WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED, + WITH_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG + : NO_FAILURE), args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED, + WITHOUT_S_DESCR, ((useCLoader) ? CAN_NOT_ACCESS_MSG + : ((useSLoader) ? PROVIDER_NOT_FOUND_MSG + : NO_FAILURE)), args)); + + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO, + WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED, + WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG + : NO_FAILURE), args)); + + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT, + WITHOUT_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO, + WITHOUT_S_DESCR, CLASS_NOT_FOUND_MSG, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED, + WITHOUT_S_DESCR, ((useSLoader) ? PROVIDER_NOT_FOUND_MSG + : NO_FAILURE), args)); + }); + return params.stream().map(p -> p.toArray()).toArray(Object[][]::new); + } + + /** + * Pre-compile and generate the artifacts required to run this test before + * running each test cases. + */ + @BeforeTest + public void buildArtifacts() { + + boolean done = true; + try { + + done &= CompilerUtils.compile(S_SRC, S_BUILD_DIR); + done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR); + done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL); + //Generate regular/modular jars with(out) META-INF + //Service descriptor + generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false); + generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR, + S_WITH_META_DESCR_BUILD_DIR, false); + generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false); + generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR, + S_WITH_META_DESCR_BUILD_DIR, false); + //Generate regular/modular(depends on explicit/auto Service) + //jars for client + done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR, "-cp", + S_JAR.toFile().getCanonicalPath()); + generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true); + generateJar(false, MODULE_TYPE.EXPLICIT, + MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false); + generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false); + System.out.format("%nArtifacts generated successfully? %s", done); + if (!done) { + throw new RuntimeException("Artifacts generation failed"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Generate modular/regular jar based on module type for this test. + */ + private void generateJar(boolean isService, MODULE_TYPE moduleType, + Path jar, Path compilePath, boolean depends) throws IOException { + + ModuleDescriptor mDescriptor = null; + if (isService) { + mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG, + S_PKG, S_INTERFACE, S_IMPL, null, M_REQUIRED, depends); + } else { + mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG, + C_PKG, S_INTERFACE, null, S_PKG, M_REQUIRED, depends); + } + generateJar(mDescriptor, jar, compilePath); + } + + /** + * Holds Logic for the test. This method will get called with each test + * parameter. + */ + @Override + public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType, + Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath, + String... args) throws Exception { + + OutputAnalyzer output = null; + try { + + //For automated/explicit module type copy the corresponding + //jars to module base folder, which will be considered as + //module base path during execution. + if (!(cModuleType == MODULE_TYPE.UNNAMED + && sModuletype == MODULE_TYPE.UNNAMED)) { + copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH); + copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH); + } + + System.out.format("%nExecuting java client with required" + + " custom security provider in class/module path."); + String mName = getModuleName(cModuleType, cJarPath, C_PKG); + Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED + || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null; + String cPath = buildClassPath(cModuleType, cJarPath, sModuletype, + sJarPath); + + Map VM_ARGS = getVMArgs(sModuletype, args); + output = ProcessTools.executeTestJava( + getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS, + args)).outputTo(System.out).errorTo(System.out); + } finally { + //clean module path so that the modulepath can hold only + //the required jars for next run. + cleanModuleBasePath(M_BASE_PATH); + System.out.println("--------------------------------------------"); + } + return output; + } + + /** + * Decide the pre-generated client/service jar path for each test case + * based on client/service module type. + */ + @Override + public Path findJarPath(boolean isService, MODULE_TYPE moduleType, + boolean addMetaDesc, boolean dependsOnServiceModule) { + if (isService) { + if (moduleType == MODULE_TYPE.EXPLICIT) { + if (addMetaDesc) { + return MS_WITH_DESCR_JAR; + } else { + return MS_JAR; + } + } else { + if (addMetaDesc) { + return S_WITH_DESCRIPTOR_JAR; + } else { + return S_JAR; + } + } + } else { + if (moduleType == MODULE_TYPE.EXPLICIT) { + if (dependsOnServiceModule) { + return MC_JAR; + } else { + return MC_DEPENDS_ON_AUTO_SERVICE_JAR; + } + } else { + return C_JAR; + } + } + } + + /** + * VM argument required for the test. + */ + private Map getVMArgs(MODULE_TYPE sModuletype, + String... args) throws IOException { + final Map VM_ARGS = new LinkedHashMap<>(); + VM_ARGS.put("-Duser.language=", "en"); + VM_ARGS.put("-Duser.region=", "US"); + //If mechanism selected to find the provider through + //Security.getProvider() then use providerName/ProviderClassName based + //on modular/regular provider jar in security configuration file. + if (args != null && args.length > 0 && SECURITY_PROP.equals(args[0])) { + if (sModuletype == MODULE_TYPE.UNNAMED) { + Files.write(SECURE_PROP_EXTN, ("security.provider.10=" + S_IMPL) + .getBytes()); + } else { + Files.write(SECURE_PROP_EXTN, "security.provider.10=TEST" + .getBytes()); + } + VM_ARGS.put("-Djava.security.properties=", SECURE_PROP_EXTN.toFile() + .getCanonicalPath()); + } + return VM_ARGS; + } + +} diff --git a/jdk/test/java/security/Provider/TestSecurityProvider.java b/jdk/test/java/security/Provider/TestSecurityProvider.java new file mode 100644 index 00000000000..df6b82b7562 --- /dev/null +++ b/jdk/test/java/security/Provider/TestSecurityProvider.java @@ -0,0 +1,45 @@ +/* + * 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 provider; + +import java.security.Provider; + +/** + * Custom Security provider for modular test. + */ +public final class TestSecurityProvider extends Provider { + + public TestSecurityProvider() { + super("TEST", 1.0d, "Test Security provider"); + System.out.println(String.format("TEST Security provider loaded" + + " successfully : %s", this.toString())); + } + + @Override + public String toString() { + return "TestSecurityProvider [getName()=" + getName() + + ", getVersion()=" + getVersion() + ", getInfo()=" + + getInfo() + ", toString()=" + super.toString() + "]"; + } + +} diff --git a/jdk/test/java/security/Provider/TestSecurityProviderClient.java b/jdk/test/java/security/Provider/TestSecurityProviderClient.java new file mode 100644 index 00000000000..a4f7b41e7aa --- /dev/null +++ b/jdk/test/java/security/Provider/TestSecurityProviderClient.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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 client; + +import java.security.Provider; +import java.security.Security; +import java.util.Iterator; +import java.util.ServiceLoader; + +/** + * Modular test for client using different mechanism to find the custom security + * provider. It uses ServiceLoader and ClassLoader to find the TEST provider + * available in classPath/modulePath. It also tries to find, if the provider is + * configured through "java.security" file. + */ +public class TestSecurityProviderClient { + + private static final String CUSTOM_PROVIDER_NAME = "TEST"; + private static final String EXCEPTION_MESSAGE + = "Unable to find Test Security Provider"; + private static final String SERVICE_LOADER = "SERVICE_LOADER"; + private static final String CLASS_LOADER = "CLASS_LOADER"; + + public static void main(String[] args) { + Provider provider = null; + //Try to find the TEST provider loaded by ServiceLoader. + if (args != null && args.length > 0 + && SERVICE_LOADER.equals(args[0])) { + System.out.println( + "Using service loader to find Security provider."); + ServiceLoader services + = ServiceLoader.load(java.security.Provider.class); + Iterator iterator = services.iterator(); + while (iterator.hasNext()) { + Provider p = iterator.next(); + if (p.getName().equals(CUSTOM_PROVIDER_NAME)) { + provider = p; + break; + } + } + } else if (args != null && args.length > 0 + && CLASS_LOADER.equals(args[0])) { + System.out.println("Using class loader to find Security provider."); + //Find the TEST provider loaded by ClassLoader. + provider = new provider.TestSecurityProvider(); + } else { + //Find the TEST provider configured through Security.getProvider(). + System.out.println("Finding Security provider through" + + " Security.getProvider()."); + provider = Security.getProvider(CUSTOM_PROVIDER_NAME); + } + + if (provider != null) { + System.out.format("%nTest Security provider named '%s' loaded " + + "successfully", CUSTOM_PROVIDER_NAME); + } else { + throw new RuntimeException(EXCEPTION_MESSAGE); + } + } +} diff --git a/jdk/test/java/security/cert/X509Certificate/EmptySubject.java b/jdk/test/java/security/cert/X509Certificate/EmptySubject.java index 5a15110d766..6436405301f 100644 --- a/jdk/test/java/security/cert/X509Certificate/EmptySubject.java +++ b/jdk/test/java/security/cert/X509Certificate/EmptySubject.java @@ -33,8 +33,6 @@ import java.security.Principal; import java.security.cert.*; import javax.security.auth.x500.X500Principal; -import sun.security.x509.*; - public class EmptySubject { public static void main(String[] args) throws Exception { diff --git a/jdk/test/java/security/modules/ModularTest.java b/jdk/test/java/security/modules/ModularTest.java new file mode 100644 index 00000000000..4a1ffbc5b9c --- /dev/null +++ b/jdk/test/java/security/modules/ModularTest.java @@ -0,0 +1,277 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.lang.module.ModuleDescriptor; +import jdk.testlibrary.OutputAnalyzer; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import jdk.internal.module.ModuleInfoWriter; +import static java.lang.module.ModuleDescriptor.Builder; + +/** + * Base class need to be extended by modular test for security. + */ +public abstract class ModularTest { + + /** + * Enum represents all supported module types supported in JDK9. i.e. + * EXPLICIT - Modules have module descriptor(module-info.java) + * defining the module. + * AUTO - Are regular jar files but provided in MODULE_PATH instead + * of CLASS_PATH. + * UNNAMED - Are regular jar but provided through CLASS_PATH. + */ + public enum MODULE_TYPE { + + EXPLICIT, AUTO, UNNAMED; + } + + public static final String SPACE = " "; + public static final Path SRC = Paths.get(System.getProperty("test.src")); + public static final String DESCRIPTOR = "MetaService"; + public static final String MODULAR = "Modular"; + public static final String AUTO = "AutoServiceType"; + public static final String JAR_EXTN = ".jar"; + + /** + * Setup test data for the test. + */ + @DataProvider(name = "TestParams") + public Object[][] setUpTestData() { + return getTestInput(); + } + + /** + * Test method for TestNG. + */ + @Test(dataProvider = "TestParams") + public void runTest(MODULE_TYPE cModuleType, MODULE_TYPE sModuletype, + boolean addMetaDesc, String failureMsgExpected, String[] args) + throws Exception { + + String testName = new StringJoiner("_").add(cModuleType.toString()) + .add(sModuletype.toString()).add( + (addMetaDesc) ? "DESCRIPTOR" : "NO_DESCRIPTOR") + .toString(); + + System.out.format("%nStarting Test case: '%s'", testName); + Path cJarPath = findJarPath(false, cModuleType, false, + (sModuletype == MODULE_TYPE.EXPLICIT)); + Path sJarPath = findJarPath(true, sModuletype, addMetaDesc, false); + System.out.format("%nClient jar path : %s ", cJarPath); + System.out.format("%nService jar path : %s ", sJarPath); + OutputAnalyzer output = executeTestClient(cModuleType, cJarPath, + sModuletype, sJarPath, args); + + if (output.getExitValue() != 0) { + if (failureMsgExpected != null + && output.getOutput().contains(failureMsgExpected)) { + System.out.println("PASS: Test is expected to fail here."); + } else { + System.out.format("%nUnexpected failure occured with exit code" + + " '%s'.", output.getExitValue()); + throw new RuntimeException("Unexpected failure occured."); + } + } + } + + /** + * Abstract method need to be implemented by each Test type to provide + * test parameters. + */ + public abstract Object[][] getTestInput(); + + /** + * Execute the test client to access required service. + */ + public abstract OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType, + Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath, + String... args) throws Exception; + + /** + * Find the Jar for service/client based on module type and if service + * descriptor required. + */ + public abstract Path findJarPath(boolean service, MODULE_TYPE moduleType, + boolean addMetaDesc, boolean dependsOnServiceModule); + + /** + * Constructs a Java Command line string based on modular structure followed + * by modular client and service. + */ + public String[] getJavaCommand(Path modulePath, String classPath, + String clientModuleName, String mainClass, + Map vmArgs, String... options) throws IOException { + + final StringJoiner command = new StringJoiner(SPACE, SPACE, SPACE); + vmArgs.forEach((key, value) -> command.add(key + value)); + if (modulePath != null) { + command.add("-mp").add(modulePath.toFile().getCanonicalPath()); + } + if (classPath != null && classPath.length() > 0) { + command.add("-cp").add(classPath); + } + if (clientModuleName != null && clientModuleName.length() > 0) { + command.add("-m").add(clientModuleName + "/" + mainClass); + } else { + command.add(mainClass); + } + command.add(Arrays.stream(options).collect(Collectors.joining(SPACE))); + return command.toString().trim().split("[\\s]+"); + } + + /** + * Generate ModuleDescriptor object for explicit/auto based client/Service + * modules type. + */ + public ModuleDescriptor generateModuleDescriptor(boolean isService, + MODULE_TYPE moduleType, String moduleName, String pkg, + String serviceInterface, String serviceImpl, + String serviceModuleName, List requiredModules, + boolean depends) { + + final Builder builder; + if (moduleType == MODULE_TYPE.EXPLICIT) { + System.out.format(" %nGenerating ModuleDescriptor object"); + builder = new Builder(moduleName).exports(pkg); + if (isService) { + builder.provides(serviceInterface, serviceImpl); + } else { + builder.uses(serviceInterface); + if (depends) { + builder.requires(serviceModuleName); + } + } + } else { + System.out.format(" %nModuleDescriptor object not required."); + return null; + } + requiredModules.stream().forEach(reqMod -> builder.requires(reqMod)); + return builder.build(); + } + + /** + * Generates service descriptor inside META-INF folder. + */ + public boolean createMetaInfServiceDescriptor( + Path serviceDescriptorFile, String serviceImpl) { + boolean created = true; + System.out.format("%nCreating META-INF service descriptor for '%s' " + + "at path '%s'", serviceImpl, serviceDescriptorFile); + try { + Path parent = serviceDescriptorFile.getParent(); + if (parent != null) { + Files.createDirectories(parent); + } + Files.write(serviceDescriptorFile, serviceImpl.getBytes("UTF-8")); + System.out.println( + "META-INF service descriptor generated successfully"); + } catch (IOException e) { + e.printStackTrace(System.out); + created = false; + } + return created; + } + + /** + * Generate modular/regular jar file. + */ + public void generateJar(ModuleDescriptor mDescriptor, Path jar, + Path compilePath) throws IOException { + System.out.format("%nCreating jar file '%s'", jar); + JarUtils.createJarFile(jar, compilePath); + if (mDescriptor != null) { + Path dir = Files.createTempDirectory("tmp"); + Path mi = dir.resolve("module-info.class"); + try (OutputStream out = Files.newOutputStream(mi)) { + ModuleInfoWriter.write(mDescriptor, out); + } + System.out.format("%nAdding 'module-info.class' to jar '%s'", jar); + JarUtils.updateJarFile(jar, dir); + } + } + + /** + * Copy pre-generated jar files to the module base path. + */ + public void copyJarsToModuleBase(MODULE_TYPE moduleType, Path jar, + Path mBasePath) throws IOException { + if (mBasePath != null) { + Files.createDirectories(mBasePath); + } + if (moduleType != MODULE_TYPE.UNNAMED) { + Path artifactName = mBasePath.resolve(jar.getFileName()); + System.out.format("%nCopy jar path: '%s' to module base path: %s", + jar, artifactName); + Files.copy(jar, artifactName); + } + } + + /** + * Construct class path string. + */ + public String buildClassPath(MODULE_TYPE cModuleType, + Path cJarPath, MODULE_TYPE sModuletype, + Path sJarPath) throws IOException { + StringJoiner classPath = new StringJoiner(File.pathSeparator); + classPath.add((cModuleType == MODULE_TYPE.UNNAMED) + ? cJarPath.toFile().getCanonicalPath() : ""); + classPath.add((sModuletype == MODULE_TYPE.UNNAMED) + ? sJarPath.toFile().getCanonicalPath() : ""); + return classPath.toString(); + } + + /** + * Construct executable module name for java. It is fixed for explicit + * module type while it is same as jar file name for automated module type. + */ + public String getModuleName(MODULE_TYPE moduleType, + Path jarPath, String mName) { + String jarName = jarPath.toFile().getName(); + return (moduleType == MODULE_TYPE.EXPLICIT) ? mName + : ((moduleType == MODULE_TYPE.AUTO) ? jarName.substring(0, + jarName.indexOf(JAR_EXTN)) : ""); + } + + /** + * Delete all the files inside the base module path. + */ + public void cleanModuleBasePath(Path mBasePath) { + Arrays.asList(mBasePath.toFile().listFiles()).forEach(f -> { + System.out.println("delete: " + f); + f.delete(); + }); + } + +} diff --git a/jdk/test/java/security/testlibrary/Proc.java b/jdk/test/java/security/testlibrary/Proc.java index 1ab58bf5212..6f9fa5d6b2d 100644 --- a/jdk/test/java/security/testlibrary/Proc.java +++ b/jdk/test/java/security/testlibrary/Proc.java @@ -33,6 +33,7 @@ import java.nio.file.Paths; import java.security.Permission; import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -182,15 +183,21 @@ public class Proc { cmd.add(new File(new File(System.getProperty("java.home"), "bin"), "java").getPath()); } - cmd.add("-cp"); - StringBuilder cp = new StringBuilder(); - for (URL url: ((URLClassLoader)Proc.class.getClassLoader()).getURLs()) { - if (cp.length() != 0) { - cp.append(File.pathSeparatorChar); - } - cp.append(url.getFile()); + + int n = 0; + String addexports; + while ((addexports = System.getProperty("jdk.launcher.addexports." + n)) != null) { + prop("jdk.launcher.addexports." + n, addexports); + n++; } - cmd.add(cp.toString()); + + Collections.addAll(cmd, splitProperty("test.vm.opts")); + Collections.addAll(cmd, splitProperty("test.java.opts")); + + cmd.add("-cp"); + cmd.add(System.getProperty("test.class.path") + File.pathSeparator + + System.getProperty("test.src.path")); + for (Entry e: prop.entrySet()) { cmd.add("-D" + e.getKey() + "=" + e.getValue()); } @@ -322,4 +329,12 @@ public class Proc { public static void d(Throwable e) throws IOException { e.printStackTrace(); } + + private static String[] splitProperty(String prop) { + String s = System.getProperty(prop); + if (s == null || s.trim().isEmpty()) { + return new String[] {}; + } + return s.trim().split("\\s+"); + } } diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java index ad87637605b..db21759b3dd 100644 --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -761,6 +761,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { {"2012-06-30T12:30:40-01:00[UT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "UT-01:00"}, {"2012-06-30T12:30:40-01:00[UTC-01:00]", 2012, 6, 30, 12, 30, 40, 0, "UTC-01:00"}, {"2012-06-30T12:30:40+01:00[Europe/London]", 2012, 6, 30, 12, 30, 40, 0, "Europe/London"}, + {"2012-06-30T12:30:40+01", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, }; } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java index c5a017c911e..696ba8109cc 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java @@ -59,11 +59,13 @@ */ package tck.java.time.format; +import static java.time.format.DateTimeFormatter.BASIC_ISO_DATE; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.HOUR_OF_DAY; import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.NANO_OF_SECOND; +import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; @@ -73,6 +75,7 @@ import java.time.YearMonth; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; import java.time.format.SignStyle; import java.time.format.TextStyle; import java.time.temporal.Temporal; @@ -339,6 +342,18 @@ public class TCKDateTimeFormatterBuilder { {"+HH", 2, 0, 45, "+02"}, {"+HH", 2, 30, 45, "+02"}, + {"+HHmm", 2, 0, 0, "+02"}, + {"+HHmm", -2, 0, 0, "-02"}, + {"+HHmm", 2, 30, 0, "+0230"}, + {"+HHmm", 2, 0, 45, "+02"}, + {"+HHmm", 2, 30, 45, "+0230"}, + + {"+HH:mm", 2, 0, 0, "+02"}, + {"+HH:mm", -2, 0, 0, "-02"}, + {"+HH:mm", 2, 30, 0, "+02:30"}, + {"+HH:mm", 2, 0, 45, "+02"}, + {"+HH:mm", 2, 30, 45, "+02:30"}, + {"+HHMM", 2, 0, 0, "+0200"}, {"+HHMM", -2, 0, 0, "-0200"}, {"+HHMM", 2, 30, 0, "+0230"}, @@ -374,6 +389,20 @@ public class TCKDateTimeFormatterBuilder { {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, + + {"+HHmmss", 2, 0, 0, "+02"}, + {"+HHmmss", -2, 0, 0, "-02"}, + {"+HHmmss", 2, 30, 0, "+0230"}, + {"+HHmmss", 2, 0, 45, "+020045"}, + {"+HHmmss", 2, 30, 45, "+023045"}, + + {"+HH:mm:ss", 2, 0, 0, "+02"}, + {"+HH:mm:ss", -2, 0, 0, "-02"}, + {"+HH:mm:ss", 2, 30, 0, "+02:30"}, + {"+HH:mm:ss", 2, 0, 45, "+02:00:45"}, + {"+HH:mm:ss", 2, 30, 45, "+02:30:45"}, + + }; } @@ -878,4 +907,82 @@ public class TCKDateTimeFormatterBuilder { assertEquals(parsed.getLong(MINUTE_OF_HOUR), 30L); } + @DataProvider(name="lenientOffsetParseData") + Object[][] data_lenient_offset_parse() { + return new Object[][] { + {"+HH", "+01", 3600}, + {"+HH", "+0101", 3660}, + {"+HH", "+010101", 3661}, + {"+HH", "+01", 3600}, + {"+HH", "+01:01", 3660}, + {"+HH", "+01:01:01", 3661}, + {"+HHmm", "+01", 3600}, + {"+HHmm", "+0101", 3660}, + {"+HHmm", "+010101", 3661}, + {"+HH:mm", "+01", 3600}, + {"+HH:mm", "+01:01", 3660}, + {"+HH:mm", "+01:01:01", 3661}, + {"+HHMM", "+01", 3600}, + {"+HHMM", "+0101", 3660}, + {"+HHMM", "+010101", 3661}, + {"+HH:MM", "+01", 3600}, + {"+HH:MM", "+01:01", 3660}, + {"+HH:MM", "+01:01:01", 3661}, + {"+HHMMss", "+01", 3600}, + {"+HHMMss", "+0101", 3660}, + {"+HHMMss", "+010101", 3661}, + {"+HH:MM:ss", "+01", 3600}, + {"+HH:MM:ss", "+01:01", 3660}, + {"+HH:MM:ss", "+01:01:01", 3661}, + {"+HHMMSS", "+01", 3600}, + {"+HHMMSS", "+0101", 3660}, + {"+HHMMSS", "+010101", 3661}, + {"+HH:MM:SS", "+01", 3600}, + {"+HH:MM:SS", "+01:01", 3660}, + {"+HH:MM:SS", "+01:01:01", 3661}, + {"+HHmmss", "+01", 3600}, + {"+HHmmss", "+0101", 3660}, + {"+HHmmss", "+010101", 3661}, + {"+HH:mm:ss", "+01", 3600}, + {"+HH:mm:ss", "+01:01", 3660}, + {"+HH:mm:ss", "+01:01:01", 3661}, + }; + } + + @Test(dataProvider="lenientOffsetParseData") + public void test_lenient_offset_parse_1(String pattern, String offset, int offsetSeconds) { + assertEquals(new DateTimeFormatterBuilder().parseLenient().appendOffset(pattern, "Z").toFormatter().parse(offset).get(OFFSET_SECONDS), + offsetSeconds); + } + + @Test + public void test_lenient_offset_parse_2() { + assertEquals(new DateTimeFormatterBuilder().parseLenient().appendOffsetId().toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_strict_appendOffsetId() { + assertEquals(new DateTimeFormatterBuilder().appendOffsetId().toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_strict_appendOffset_1() { + assertEquals(new DateTimeFormatterBuilder().appendOffset("+HH:MM:ss", "Z").toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_strict_appendOffset_2() { + assertEquals(new DateTimeFormatterBuilder().appendOffset("+HHMMss", "Z").toFormatter().parse("+01").get(OFFSET_SECONDS), + 3600); + } + + @Test + public void test_basic_iso_date() { + assertEquals(BASIC_ISO_DATE.parse("20021231+01").get(OFFSET_SECONDS), 3600); + assertEquals(BASIC_ISO_DATE.parse("20021231+0101").get(OFFSET_SECONDS), 3660); + } + } diff --git a/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java index 76cfa56f88d..d841172ce90 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java +++ b/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java @@ -199,6 +199,30 @@ public class TCKOffsetPrinterParser { {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23:00"}, {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"}, {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23:45"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"}, + {"+HH:mm:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+012345"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "+000045"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-012345"}, + {"+HHmmss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"}, }; } diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java index 1bfa4799320..c9c513fa542 100644 --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatter.java @@ -79,19 +79,24 @@ import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.Chronology; import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DecimalStyle; import java.time.format.SignStyle; +import java.time.format.TextStyle; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.util.Locale; import java.util.function.Function; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** * Test DateTimeFormatter. + * @bug 8085887 */ @Test public class TestDateTimeFormatter { @@ -196,4 +201,75 @@ public class TestDateTimeFormatter { assertTrue(msg.contains("11:30:56"), msg); } + @DataProvider(name="nozone_exception_cases") + Object[][] exceptionCases() { + return new Object[][] { + {LocalDateTime.of(2000, 1, 1, 1, 1), "z", "ZoneId"}, + {OffsetDateTime.of(2000, 1, 1, 3, 3, 3, 0, ZoneOffset.ofTotalSeconds(60)), "z", "ZoneId"}, + }; + } + + // Test cases that should throw an exception with a cogent message + // containing the Type being queried and the Temporal being queried. + @Test(dataProvider="nozone_exception_cases") + public void test_throws_message(Temporal temporal, String pattern, String queryName) { + DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pattern); + try { + fmt.format(temporal); + fail("Format using \"" + pattern + "\" with " + + temporal + " should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains(queryName), + String.format("\"%s\" missing from %s", queryName, msg)); + String s = temporal.toString(); + assertTrue(msg.contains(s), + String.format("\"%s\" missing from %s", s, msg)); + } + + } + + // Test cases that should throw an exception with a cogent message when missing the Chronology + @Test + public void test_throws_message_chrono() { + Chronology chrono = ThaiBuddhistChronology.INSTANCE; + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneId().toFormatter() + .withChronology(chrono); + LocalTime now = LocalTime.now(); + try { + fmt.format(now); + fail("Format using appendZoneId() should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains("ZoneId"), + String.format("\"%s\" missing from %s", "ZoneId", msg)); + assertTrue(msg.contains(chrono.toString()), + String.format("\"%s\" missing from %s", chrono.toString(), msg)); + } + + } + + // Test cases that should throw an exception with a cogent message when missing the ZoneId + @Test + public void test_throws_message_zone() { + ZoneId zone = ZoneId.of("Pacific/Honolulu"); + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendChronologyId().toFormatter() + .withZone(zone); + LocalTime now = LocalTime.now(); + try { + fmt.format(now); + fail("Format using appendChronologyId() should have failed"); + } catch (DateTimeException dte) { + String msg = dte.getMessage(); + // Verify message contains the type that is missing and the temporal value + assertTrue(msg.contains("Chronology"), + String.format("\"%s\" missing from %s", "Chronology", msg)); + assertTrue(msg.contains(zone.toString()), + String.format("\"%s\" missing from %s", zone.toString(), msg)); + } + + } + } diff --git a/jdk/test/java/util/Calendar/GenericTimeZoneNamesTest.sh b/jdk/test/java/util/Calendar/GenericTimeZoneNamesTest.sh index bc80b3f4767..5d722c3dd55 100644 --- a/jdk/test/java/util/Calendar/GenericTimeZoneNamesTest.sh +++ b/jdk/test/java/util/Calendar/GenericTimeZoneNamesTest.sh @@ -24,20 +24,22 @@ # @test # @bug 8003267 # @summary Unit test for generic time zone names support -# @compile -XDignore.symbol.file GenericTimeZoneNamesTest.java +# @modules java.base/sun.util.locale.provider +# @compile GenericTimeZoneNamesTest.java # @run shell GenericTimeZoneNamesTest.sh # This test is locale data-dependent and assumes that both JRE and CLDR # have the same geneic time zone names in English. +EXTRAOPTS="-XaddExports:java.base/sun.util.locale.provider=ALL-UNNAMED" STATUS=0 echo "Locale providers: default" -if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} -cp "${TESTCLASSES}" GenericTimeZoneNamesTest en-US; then +if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} ${EXTRAOPTS} -cp "${TESTCLASSES}" GenericTimeZoneNamesTest en-US; then STATUS=1 fi echo "Locale providers: CLDR" -if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} -cp "${TESTCLASSES}" -Djava.locale.providers=CLDR GenericTimeZoneNamesTest en-US; then +if ! ${TESTJAVA}/bin/java -esa ${TESTVMOPTS} ${EXTRAOPTS} -cp "${TESTCLASSES}" -Djava.locale.providers=CLDR GenericTimeZoneNamesTest en-US; then STATUS=1 fi exit ${STATUS} diff --git a/jdk/test/java/util/Currency/CheckDataVersion.java b/jdk/test/java/util/Currency/CheckDataVersion.java index 70320cbb330..204a80a8557 100644 --- a/jdk/test/java/util/Currency/CheckDataVersion.java +++ b/jdk/test/java/util/Currency/CheckDataVersion.java @@ -29,6 +29,7 @@ import java.io.*; import java.lang.reflect.*; import java.security.*; +import java.util.Currency; class CheckDataVersion { static final String datafile = "tablea1.txt"; @@ -63,9 +64,9 @@ class CheckDataVersion { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { + InputStream in = Currency.class.getModule().getResourceAsStream("java/util/currency.data"); String sep = File.separator; - DataInputStream dis = new DataInputStream( - new BufferedInputStream(getClass().getResourceAsStream("/java/util/currency.data"))); + DataInputStream dis = new DataInputStream(in); int magic = dis.readInt(); if (magic != 0x43757244) { throw new RuntimeException("The magic number in the JRE's currency data is incorrect. Expected: 0x43757244, Got: 0x"+magic); diff --git a/jdk/test/java/util/Currency/CurrencyTest.java b/jdk/test/java/util/Currency/CurrencyTest.java index fc164593670..05d3cbf7265 100644 --- a/jdk/test/java/util/Currency/CurrencyTest.java +++ b/jdk/test/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ * @bug 4290801 4692419 4693631 5101540 5104960 6296410 6336600 6371531 * 6488442 7036905 8008577 8039317 8074350 8074351 * @summary Basic tests for Currency class. + * @modules jdk.localedata */ import java.io.ByteArrayInputStream; diff --git a/jdk/test/java/util/Formatter/Basic.sh b/jdk/test/java/util/Formatter/Basic.sh index 25bd5bac1cb..0bf4162f17b 100644 --- a/jdk/test/java/util/Formatter/Basic.sh +++ b/jdk/test/java/util/Formatter/Basic.sh @@ -23,7 +23,8 @@ # -${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -cp ${TESTSRC} -d . \ +EXTRAOPTS="-XaddExports:java.base/jdk.internal.math=ALL-UNNAMED" +${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -cp ${TESTSRC} -d . \ ${TESTSRC}/Basic.java expectPass() { @@ -39,7 +40,7 @@ runTest() { echo "Testing:" ${1} TZ="${1}"; export TZ echo " " $TZ - ${TESTJAVA}/bin/java ${TESTVMOPTS} Basic + ${TESTJAVA}/bin/java ${TESTVMOPTS} ${EXTRAOPTS} Basic expectPass $? } diff --git a/jdk/test/java/util/Locale/LocaleProviders.sh b/jdk/test/java/util/Locale/LocaleProviders.sh index 798fce5ce6d..f90a66fd1e9 100644 --- a/jdk/test/java/util/Locale/LocaleProviders.sh +++ b/jdk/test/java/util/Locale/LocaleProviders.sh @@ -26,7 +26,9 @@ # @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577 # 8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006 # @summary tests for "java.locale.providers" system property -# @compile -XDignore.symbol.file LocaleProviders.java +# @modules java.base/sun.util.locale +# java.base/sun.util.locale.provider +# @compile LocaleProviders.java # @run shell/timeout=600 LocaleProviders.sh if [ "${TESTSRC}" = "" ] @@ -118,18 +120,21 @@ mk ${SPIDIR}${FS}dest${FS}META-INF${FS}services${FS}java.util.spi.TimeZoneNamePr tznp tznp8013086 EOF + +EXTRAOPTS="-XaddExports:java.base/sun.util.locale=ALL-UNNAMED,java.base/sun.util.locale.provider=ALL-UNNAMED" + ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d ${SPIDIR}${FS}dest \ ${SPIDIR}${FS}src${FS}tznp.java \ ${SPIDIR}${FS}src${FS}tznp8013086.java ${COMPILEJAVA}${FS}bin${FS}jar ${TESTTOOLVMOPTS} cvf ${SPIDIR}${FS}tznp.jar -C ${SPIDIR}${FS}dest . # get the platform default locales -PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale display` +PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale display` DEFLANG=`echo ${PLATDEF} | sed -e "s/,.*//"` DEFCTRY=`echo ${PLATDEF} | sed -e "s/.*,//"` echo "DEFLANG=${DEFLANG}" echo "DEFCTRY=${DEFCTRY}" -PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale format` +PLATDEF=`${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath ${TESTCLASSES} LocaleProviders getPlatformLocale format` DEFFMTLANG=`echo ${PLATDEF} | sed -e "s/,.*//"` DEFFMTCTRY=`echo ${PLATDEF} | sed -e "s/.*,//"` echo "DEFFMTLANG=${DEFFMTLANG}" @@ -137,7 +142,7 @@ echo "DEFFMTCTRY=${DEFFMTCTRY}" runTest() { - RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -classpath ${TESTCLASSES}${PS}${SPICLASSES} -Djava.locale.providers=$PREFLIST LocaleProviders $METHODNAME $PARAM1 $PARAM2 $PARAM3" + RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -classpath ${TESTCLASSES}${PS}${SPICLASSES} -Djava.locale.providers=$PREFLIST LocaleProviders $METHODNAME $PARAM1 $PARAM2 $PARAM3" echo ${RUNCMD} ${RUNCMD} result=$? diff --git a/jdk/test/java/util/PluggableLocale/ExecTest.sh b/jdk/test/java/util/PluggableLocale/ExecTest.sh index bb8977317ff..190d5abb7fd 100644 --- a/jdk/test/java/util/PluggableLocale/ExecTest.sh +++ b/jdk/test/java/util/PluggableLocale/ExecTest.sh @@ -92,10 +92,13 @@ case "$1" in ;; esac + +EXTRA_OPTS="-XaddExports:java.base/sun.util.locale.provider=ALL-UNNAMED,java.base/sun.util.resources=ALL-UNNAMED" + # compile cp ${TESTSRC}${FS}ProviderTest.java . cp ${TESTSRC}${FS}$2.java . -COMPILE="${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ +COMPILE="${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRA_OPTS} \ -XDignore.symbol.file -d . -classpath ${CLASSPATHARG} $2.java" echo ${COMPILE} ${COMPILE} @@ -120,7 +123,7 @@ then fi # run -RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${SECURITYOPTS} -classpath ${CLASSPATHARG} -Djava.locale.providers=JRE,SPI $2 " +RUNCMD="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRA_OPTS} ${SECURITYOPTS} -classpath ${CLASSPATHARG} -Djava.locale.providers=JRE,SPI $2 " echo ${RUNCMD} ${RUNCMD} diff --git a/jdk/test/java/util/PluggableLocale/ProviderTest.java b/jdk/test/java/util/PluggableLocale/ProviderTest.java index 32b5b639954..30cc49fc7e3 100644 --- a/jdk/test/java/util/PluggableLocale/ProviderTest.java +++ b/jdk/test/java/util/PluggableLocale/ProviderTest.java @@ -26,7 +26,6 @@ import java.text.*; import java.util.*; -import sun.text.resources.*; import sun.util.locale.provider.*; public class ProviderTest { diff --git a/jdk/test/java/util/ResourceBundle/Bug4168625Test.java b/jdk/test/java/util/ResourceBundle/Bug4168625Test.java index 09568a24b9b..e6dca7828d0 100644 --- a/jdk/test/java/util/ResourceBundle/Bug4168625Test.java +++ b/jdk/test/java/util/ResourceBundle/Bug4168625Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -425,26 +425,36 @@ public class Bug4168625Test extends RBTestFmwk { throws ClassNotFoundException { Class result; synchronized (this) { - logln(">>"+threadName()+">load "+className); - loadedClasses.addElement(className); + try { + logln(">>"+threadName()+">load "+className); + loadedClasses.addElement(className); - result = findLoadedClass(className); - if (result == null) { - final byte[] classData = getClassData(className); - if (classData == null) { - //we don't have a local copy of this one - logln("Loading system class: "+className); - result = loadFromSystem(className); - } else { - result = defineClass(classData, 0, classData.length); - if (result == null) { - //there was an error defining the class + result = findLoadedClass(className); + if (result == null) { + final byte[] classData = getClassData(className); + if (classData == null) { + //we don't have a local copy of this one + logln("Loading system class: "+className); result = loadFromSystem(className); + } else { + result = defineClass(classData, 0, classData.length); + if (result == null) { + //there was an error defining the class + result = loadFromSystem(className); + } + } + if ((result != null) && resolveIt) { + resolveClass(result); } } - if ((result != null) && resolveIt) { - resolveClass(result); + } catch (ClassNotFoundException e) { + // Ignore loading of Bug4168625ResourceProvider + if (className.equals("Bug4168625ResourceProvider")) { + logln("Ignoring " + className); + loadedClasses.remove(className); + return null; } + throw e; } } for (int i = classesToWaitFor.length-1; i >= 0; --i) { diff --git a/jdk/test/java/util/ResourceBundle/Bug6299235Test.java b/jdk/test/java/util/ResourceBundle/Bug6299235Test.java index 9d44671ecd4..ed42ee3a7e7 100644 --- a/jdk/test/java/util/ResourceBundle/Bug6299235Test.java +++ b/jdk/test/java/util/ResourceBundle/Bug6299235Test.java @@ -20,13 +20,9 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -/* - * - */ -import java.io.File; + +import java.awt.Toolkit; import java.util.Locale; -import java.util.ResourceBundle; -import sun.util.CoreResourceBundleControl; /* * After introducing CoreResourceBundleControl for Awt/Swing resources @@ -39,24 +35,26 @@ import sun.util.CoreResourceBundleControl; */ public class Bug6299235Test { + static final Locale ru_RU = new Locale("ru", "RU"); - public static void main(String args[]) throws Exception { - /* Try to load "sun.awt.resources.awt_ru_RU.properties which - * is in awtres.jar. - */ - ResourceBundle russionAwtRes = ResourceBundle.getBundle("sun.awt.resources.awt", - new Locale("ru", "RU"), - CoreResourceBundleControl.getRBControlInstance()); - - /* If this call throws MissingResourceException, the test fails. */ - if (russionAwtRes != null) { - String result = russionAwtRes.getString("foo"); - if (result.equals("bar")) { - System.out.println("Bug6299235Test passed"); - } else { - System.err.println("Bug6299235Test failed"); - throw new Exception("Resource found, but value of key foo is not correct\n"); + public static void main(String args[]) { + Locale locale = Locale.getDefault(); + try { + Locale.setDefault(ru_RU); + // Get the value for the test key "foo" + String value = Toolkit.getProperty("foo", "undefined"); + if (!value.equals("bar")) { + throw new RuntimeException("key = foo, value = " + value); } + // Get the value for a valid key "AWT.enter" + value = Toolkit.getProperty("AWT.enter", "DO NOT ENTER"); + if (value.equals("DO NOT ENTER")) { + throw new RuntimeException("AWT.enter undefined."); + } + } finally { + // Restore the default Locale + Locale.setDefault(locale); } + System.out.println("Bug6299235Test passed"); } } diff --git a/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh b/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh index a29c7444ecb..35725bc0e71 100644 --- a/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh +++ b/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh @@ -58,11 +58,17 @@ fi echo "TESTJAVA=${TESTJAVA}" echo "TESTSRC=${TESTSRC}" echo "TESTCLASSES=${TESTCLASSES}" -echo "NEW_EXT_DIR=${NEW_EXT_DIR}" -cd ${TESTSRC} +PATCHDIR=${TESTCLASSES}/patches +rm -rf $PATCHDIR +mkdir -p $PATCHDIR/java.desktop + +cd ${PATCHDIR}/java.desktop +${TESTJAVA}/bin/jar xf ${TESTSRC}/awtres.jar + echo -${TESTJAVA}/bin/java ${TESTVMOPTS} -cp ${TESTCLASSES}${PATHSEP}${TESTSRC}${FILESEP}awtres.jar Bug6299235Test +${TESTJAVA}/bin/java ${TESTVMOPTS} -Xpatch:${PATCHDIR} \ + -cp ${TESTCLASSES} Bug6299235Test if [ $? -ne 0 ] then diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java new file mode 100644 index 00000000000..059e109d74e --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java @@ -0,0 +1,46 @@ +/* + * 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 jdk.test.resources.asia; + +import java.io.IOException; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.ResourceBundle.Control; +import jdk.test.resources.MyControl; +import jdk.test.resources.MyResourcesProvider; + +public class MyResourcesAsia extends MyControl implements MyResourcesProvider { + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + if (isAsiaLocale(locale)) { + try { + ClassLoader loader = MyResourcesAsia.class.getClassLoader(); + return newBundle(baseName, locale, "java.properties", loader, false); + } catch (IllegalAccessException | InstantiationException | IOException e) { + System.out.println(e); + } + } + return null; + } +} diff --git a/jdk/src/jdk.management/share/classes/META-INF/services/sun.management.spi.PlatformMBeanProvider b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties similarity index 79% rename from jdk/src/jdk.management/share/classes/META-INF/services/sun.management.spi.PlatformMBeanProvider rename to jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties index a5611e80f23..e64ab3d8ec9 100644 --- a/jdk/src/jdk.management/share/classes/META-INF/services/sun.management.spi.PlatformMBeanProvider +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties @@ -4,9 +4,7 @@ # # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. +# published by the Free Software Foundation. # # This code is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -22,4 +20,5 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -com.sun.management.internal.PlatformMBeanProviderImpl + +key=ja: message diff --git a/jdk/src/java.desktop/share/classes/META-INF/services/java.net.ContentHandlerFactory b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties similarity index 78% rename from jdk/src/java.desktop/share/classes/META-INF/services/java.net.ContentHandlerFactory rename to jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties index 85fce1ef49b..515e71c5323 100644 --- a/jdk/src/java.desktop/share/classes/META-INF/services/java.net.ContentHandlerFactory +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties @@ -4,9 +4,7 @@ # # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. +# published by the Free Software Foundation. # # This code is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -23,5 +21,4 @@ # questions. # -# Provider for content handlers -sun.awt.www.content.MultimediaContentHandlers +key=zh: message diff --git a/jdk/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties similarity index 74% rename from jdk/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider rename to jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties index 7ab9b79274a..699d7068037 100644 --- a/jdk/src/jdk.attach/share/classes/META-INF/services/com.sun.tools.attach.spi.AttachProvider +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties @@ -1,12 +1,10 @@ # -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. +# 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 @@ -22,4 +20,5 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -sun.tools.attach.AttachProviderImpl + +key=zh-TW: message diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/module-info.java new file mode 100644 index 00000000000..0b821d5c042 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/asiabundles/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module asiabundles { + requires test; + + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.asia.MyResourcesAsia; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java new file mode 100644 index 00000000000..29d36410e6b --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java @@ -0,0 +1,46 @@ +/* + * 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 jdk.test.resources.eu; + +import java.io.IOException; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.ResourceBundle.Control; +import jdk.test.resources.MyControl; +import jdk.test.resources.MyResourcesProvider; + +public class MyResourcesEU extends MyControl implements MyResourcesProvider { + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + if (isEULocale(locale)) { + try { + ClassLoader loader = MyResourcesEU.class.getClassLoader(); + return newBundle(baseName, locale, "java.class", loader, false); + } catch (IllegalAccessException | InstantiationException | IOException e) { + System.out.println(e); + } + } + return null; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_de.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_de.java new file mode 100644 index 00000000000..e57e3877225 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_de.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java new file mode 100644 index 00000000000..4420853acd6 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/module-info.java new file mode 100644 index 00000000000..67a55c88cfa --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/eubundles/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module eubundles { + requires test; + + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.eu.MyResourcesEU; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..6866cf14330 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/Main.java @@ -0,0 +1,53 @@ +/* + * 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 jdk.test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Set; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println("locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + errors++; + } + } + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyControl.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyControl.java new file mode 100644 index 00000000000..0cf7f9b3f29 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyControl.java @@ -0,0 +1,59 @@ +/* + * 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 jdk.test.resources; + +import java.util.*; + +public class MyControl extends ResourceBundle.Control { + private static final Set euLocales, asiaLocales; + + static { + euLocales = new HashSet<>(Arrays.asList(Locale.GERMAN, Locale.FRENCH)); + asiaLocales = new HashSet<>(Arrays.asList(Locale.JAPANESE, Locale.CHINESE, Locale.TAIWAN)); + } + + @Override + public String toBundleName(String baseName, Locale locale) { + String bundleName = baseName; + if (euLocales.contains(locale)) { + bundleName = addRegion(baseName, "eu"); + } else if (asiaLocales.contains(locale)) { + bundleName = addRegion(baseName, "asia"); + } + return super.toBundleName(bundleName, locale); + } + + private String addRegion(String baseName, String region) { + int index = baseName.lastIndexOf('.'); + return baseName.substring(0, index + 1) + region + baseName.substring(index); + } + + protected static boolean isEULocale(Locale locale) { + return euLocales.contains(locale); + } + + protected static boolean isAsiaLocale(Locale locale) { + return asiaLocales.contains(locale); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources.java new file mode 100644 index 00000000000..235e80d1f71 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProvider.java new file mode 100644 index 00000000000..eacdd25ee73 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProvider.java @@ -0,0 +1,29 @@ +/* + * 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 jdk.test.resources; + +import java.util.spi.ResourceBundleProvider; + +public interface MyResourcesProvider extends ResourceBundleProvider { +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProviderImpl.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProviderImpl.java new file mode 100644 index 00000000000..91dec1fabf4 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResourcesProviderImpl.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.resources; + +import java.io.IOException; +import java.util.Locale; +import java.util.ResourceBundle; + +public class MyResourcesProviderImpl extends MyControl implements MyResourcesProvider { + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + if (locale.equals(Locale.ENGLISH) || locale.equals(Locale.ROOT)) { + try { + ClassLoader loader = MyResourcesProviderImpl.class.getClassLoader(); + return newBundle(baseName, locale, "java.class", loader, false); + } catch (IllegalAccessException | InstantiationException | IOException e) { + } + } + return null; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources_en.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources_en.java new file mode 100644 index 00000000000..65f2a64881a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/jdk/test/resources/MyResources_en.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/module-info.java new file mode 100644 index 00000000000..3ca685b7fd5 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic/src/test/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module test { + exports jdk.test.resources to eubundles, asiabundles; + uses jdk.test.resources.MyResourcesProvider; + provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProviderImpl; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/appbasic2.sh b/jdk/test/java/util/ResourceBundle/modules/appbasic2/appbasic2.sh new file mode 100644 index 00000000000..51c0f4a15d2 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/appbasic2.sh @@ -0,0 +1,68 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8044767 +# @summary Basic test for ResourceBundle with modules; named module "test" +# contains resource bundles for root and en, and separate named modules +# "eubundles" and "asiabundles" contain other resource bundles. + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java" + + +for I in eu asia +do + B=${I}bundles + mkdir -p mods/$B + CLASSES="`find $TESTSRC/src/$B -name '*.java'`" + if [ "x$CLASSES" != x ]; then + $JAVAC -g -d mods -modulesourcepath $TESTSRC/src -cp mods/test $CLASSES + fi + PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`" + if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$B/$D + cp $TESTSRC/src/$B/$P mods/$B/$D/ + done + fi +done + +mkdir -p mods/test +$JAVAC -g -d mods -modulesourcepath $TESTSRC/src `find $TESTSRC/src/test -name "*.java"` + +$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de + +exit $? diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java new file mode 100644 index 00000000000..72d1010156b --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java @@ -0,0 +1,59 @@ +/* + * 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 jdk.test.resources.asia; + +import java.util.Locale; +import jdk.test.resources.MyResourcesProvider; + +public class MyResourcesAsia extends MyResourcesProvider { + public MyResourcesAsia() { + super("java.properties"); + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + // Convert baseName to its properties resource name for the given locale + // e.g., jdk.test.resources.MyResources -> jdk/test/resources/asia/MyResources_zh_TW + StringBuilder sb = new StringBuilder(); + int index = baseName.lastIndexOf('.'); + sb.append(baseName.substring(0, index)) + .append(".asia") + .append(baseName.substring(index)); + String lang = locale.getLanguage(); + if (!lang.isEmpty()) { + sb.append('_').append(lang); + String country = locale.getCountry(); + if (!country.isEmpty()) { + sb.append('_').append(country); + } + } + return sb.toString(); + } + + @Override + protected boolean isSupportedInModule(Locale locale) { + return locale.equals(Locale.JAPANESE) + || locale.equals(Locale.CHINESE) || locale.equals(Locale.TAIWAN); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties new file mode 100644 index 00000000000..e64ab3d8ec9 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=ja: message diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties new file mode 100644 index 00000000000..515e71c5323 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh: message diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties new file mode 100644 index 00000000000..699d7068037 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh-TW: message diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/module-info.java new file mode 100644 index 00000000000..0b821d5c042 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/asiabundles/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module asiabundles { + requires test; + + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.asia.MyResourcesAsia; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java new file mode 100644 index 00000000000..f95a44f9a36 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java @@ -0,0 +1,46 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.Locale; +import jdk.test.resources.MyResourcesProvider; + +public class MyResourcesEU extends MyResourcesProvider { + public MyResourcesEU() { + super("java.class"); + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + int index = baseName.lastIndexOf('.'); + String bundleName = baseName.substring(0, index) + ".eu" + baseName.substring(index) + + '_' + locale.getLanguage(); + return bundleName; + } + + @Override + protected boolean isSupportedInModule(Locale locale) { + return locale.equals(Locale.GERMAN) || locale.equals(Locale.FRENCH); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_de.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_de.java new file mode 100644 index 00000000000..e57e3877225 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_de.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_fr.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_fr.java new file mode 100644 index 00000000000..4420853acd6 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/jdk/test/resources/eu/MyResources_fr.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/module-info.java new file mode 100644 index 00000000000..67a55c88cfa --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/eubundles/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module eubundles { + requires test; + + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.eu.MyResourcesEU; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..6866cf14330 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/Main.java @@ -0,0 +1,53 @@ +/* + * 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 jdk.test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Set; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println("locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + errors++; + } + } + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources.java new file mode 100644 index 00000000000..235e80d1f71 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProvider.java new file mode 100644 index 00000000000..2ff0ceb18d7 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProvider.java @@ -0,0 +1,45 @@ +/* + * 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 jdk.test.resources; + + +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.spi.AbstractResourceBundleProvider; + +public abstract class MyResourcesProvider extends AbstractResourceBundleProvider { + protected MyResourcesProvider(String... formats) { + super(formats); + } + + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + if (isSupportedInModule(locale)) { + return super.getBundle(baseName, locale); + } + return null; + } + + protected abstract boolean isSupportedInModule(Locale locale); +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProviderImpl.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProviderImpl.java new file mode 100644 index 00000000000..ef9c683397f --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResourcesProviderImpl.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.resources; + +import java.util.Locale; + +public class MyResourcesProviderImpl extends MyResourcesProvider { + public MyResourcesProviderImpl() { + super("java.class"); + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + return locale.equals(Locale.ROOT) ? baseName : baseName + '_' + locale.getLanguage(); + } + + @Override + protected boolean isSupportedInModule(Locale locale) { + return locale.equals(Locale.ENGLISH) || locale.equals(Locale.ROOT); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources_en.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources_en.java new file mode 100644 index 00000000000..65f2a64881a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/jdk/test/resources/MyResources_en.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/module-info.java new file mode 100644 index 00000000000..3ca685b7fd5 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/appbasic2/src/test/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module test { + exports jdk.test.resources to eubundles, asiabundles; + uses jdk.test.resources.MyResourcesProvider; + provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProviderImpl; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/basic.sh b/jdk/test/java/util/ResourceBundle/modules/basic/basic.sh new file mode 100644 index 00000000000..86fd0fde0cc --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/basic.sh @@ -0,0 +1,89 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8044767 8139067 +# @summary Basic test case for ResourceBundle with modules; +# ResourceBundle.getBundle caller is in module named "test", +# resource bundles are grouped in main (module "mainbundles"), +# EU (module "eubundles"), and Asia (module "asiabundles"). +# Also adds a jar file containing resource bundles to the class path. + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAR="$COMPILEJAVA/bin/jar" +JAVA="$TESTJAVA/bin/java" + +rm -rf mods + +CP= +for I in main eu asia +do + B=${I}bundles + mkdir -p mods/$B + CLASSES="`find $TESTSRC/src/$B -name '*.java'`" + if [ "x$CLASSES" != x ]; then + $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CP $CLASSES + fi + PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`" + if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$B/$D + cp $TESTSRC/src/$B/$P mods/$B/$D/ + done + fi + CP="-cp mods/mainbundles" +done + +mkdir -p mods/test +$JAVAC -g -cp mods/mainbundles -d mods -modulesourcepath $TESTSRC/src \ + `find $TESTSRC/src/test -name "*.java"` + +# Create a jar to be added to the class path. Expected only properties files are +# picked up from the class path. +rm -f extra.jar +mkdir -p classes +$JAVAC -d classes $TESTSRC/src/extra/jdk/test/resources/eu/*.java +$JAR -cf extra.jar -C classes jdk/test/resources/eu \ + -C $TESTSRC/src/extra jdk/test/resources/asia + +STATUS=0 + +echo "jdk.test.Main should load bundles using ResourceBundleProviders." +$JAVA -mp mods -m test/jdk.test.Main de fr ja ja-jp zh-tw en de ja-jp || STATUS=1 + +echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path." +$JAVA -cp extra.jar -mp mods -m test/jdk.test.Main es vi && STATUS=1 + +exit $STATUS diff --git a/jdk/src/jdk.accessibility/windows/classes/META-INF/services/javax.accessibility.AccessibilityProvider b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties similarity index 78% rename from jdk/src/jdk.accessibility/windows/classes/META-INF/services/javax.accessibility.AccessibilityProvider rename to jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties index 0c0e2acb434..c4b198eb8a7 100644 --- a/jdk/src/jdk.accessibility/windows/classes/META-INF/services/javax.accessibility.AccessibilityProvider +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/MyResources_ja_JP.properties @@ -1,26 +1,27 @@ -# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. Oracle designates this -# particular file as subject to the "Classpath" exception as provided -# by Oracle in the LICENSE file that accompanied this code. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. - - -com.sun.java.accessibility.internal.ProviderImpl - +# +# 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. +# + +# This resource bundle is located at jdk/test/resources to demonstrate +# the unique package requirement is not applicable to .properties bundles. + +key=ja-JP: message diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java new file mode 100644 index 00000000000..a62c8beb4ae --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResourcesAsia.java @@ -0,0 +1,38 @@ +/* + * 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 jdk.test.resources.asia; + +import java.util.Locale; +import jdk.test.resources.MyResourcesProvider; + +/** + * + */ +public class MyResourcesAsia extends MyResourcesProvider { + public MyResourcesAsia() { + super("java.properties", "asia", + Locale.JAPANESE, Locale.JAPAN, Locale.CHINESE, Locale.TAIWAN, + new Locale("vi")); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties new file mode 100644 index 00000000000..e64ab3d8ec9 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_ja.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=ja: message diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties new file mode 100644 index 00000000000..515e71c5323 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh: message diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties new file mode 100644 index 00000000000..699d7068037 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/jdk/test/resources/asia/MyResources_zh_TW.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh-TW: message diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/module-info.java new file mode 100644 index 00000000000..9c51bcca58d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/asiabundles/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module asiabundles { + requires mainbundles; + + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.asia.MyResourcesAsia; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java new file mode 100644 index 00000000000..689512002e0 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResourcesEU.java @@ -0,0 +1,37 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.Locale; +import jdk.test.resources.MyResourcesProvider; + +/** + * + */ +public class MyResourcesEU extends MyResourcesProvider { + public MyResourcesEU() { + super("java.class", "eu", + Locale.GERMAN, Locale.FRENCH, new Locale("es")); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_de.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_de.java new file mode 100644 index 00000000000..e57e3877225 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_de.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java new file mode 100644 index 00000000000..4420853acd6 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/jdk/test/resources/eu/MyResources_fr.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/module-info.java new file mode 100644 index 00000000000..4a003a57fc9 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/eubundles/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module eubundles { + requires mainbundles; + + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.eu.MyResourcesEU; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/asia/MyResources_vi.properties b/jdk/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/asia/MyResources_vi.properties new file mode 100644 index 00000000000..4662419a4a1 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/asia/MyResources_vi.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=vi: message diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/eu/MyResources_es.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/eu/MyResources_es.java new file mode 100644 index 00000000000..764bc49aa0d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/extra/jdk/test/resources/eu/MyResources_es.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.eu; + +import java.util.ListResourceBundle; + +public class MyResources_es extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "es: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources.java new file mode 100644 index 00000000000..235e80d1f71 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesMain.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesMain.java new file mode 100644 index 00000000000..ccb353cfe19 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesMain.java @@ -0,0 +1,32 @@ +/* + * 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 jdk.test.resources; + +import java.util.Locale; + +public class MyResourcesMain extends MyResourcesProvider { + public MyResourcesMain() { + super("java.class", "", Locale.ROOT, Locale.ENGLISH); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java new file mode 100644 index 00000000000..c9ebc4b837d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResourcesProvider.java @@ -0,0 +1,82 @@ +/* + * 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 jdk.test.resources; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.ResourceBundle.Control; +import java.util.Set; +import java.util.spi.AbstractResourceBundleProvider; + + +public class MyResourcesProvider extends AbstractResourceBundleProvider { + private final String region; + private final Set supportedLocales; + private final List formats; + + protected MyResourcesProvider() { + region = ""; + supportedLocales = null; + formats = Collections.emptyList(); + } + + protected MyResourcesProvider(String format, String region, Locale... locales) { + super(format); + this.region = region; + this.supportedLocales = new HashSet<>(Arrays.asList(locales)); + this.formats = Collections.singletonList(format); + } + + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + if (isSupportedInModule(locale)) { + return super.getBundle(baseName, locale); + } + return null; + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + // The resource bundle for Locale.JAPAN is loccated at jdk.test.resources + // in module "asiabundles". + String name = locale.equals(Locale.JAPAN) ? baseName : addRegion(baseName); + return Control.getControl(Control.FORMAT_DEFAULT).toBundleName(name, locale); + } + + private String addRegion(String baseName) { + if (region.isEmpty()) { + return baseName; + } + int index = baseName.lastIndexOf('.'); + return baseName.substring(0, index + 1) + region + baseName.substring(index); + } + + protected boolean isSupportedInModule(Locale locale) { + return supportedLocales.contains(locale); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources_en.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources_en.java new file mode 100644 index 00000000000..65f2a64881a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/jdk/test/resources/MyResources_en.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/module-info.java new file mode 100644 index 00000000000..64769aff1e7 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/mainbundles/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module mainbundles { + exports jdk.test.resources to test, eubundles, asiabundles; + provides jdk.test.resources.MyResourcesProvider + with jdk.test.resources.MyResourcesMain; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..65388e7066f --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/test/jdk/test/Main.java @@ -0,0 +1,51 @@ +/* + * 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 jdk.test; + +import java.util.Locale; +import java.util.ResourceBundle; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", + locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println("locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + errors++; + } + } + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/basic/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/basic/src/test/module-info.java new file mode 100644 index 00000000000..2d9e6e2990c --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/basic/src/test/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module test { + requires mainbundles; + uses jdk.test.resources.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh new file mode 100644 index 00000000000..e87e05c4f5a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/modlocal.sh @@ -0,0 +1,77 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8044767 8139067 +# @summary Test case for having resource bundles in a local named module +# with no ResourceBundleProviders. + + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAR="$COMPILEJAVA/bin/jar" +JAVA="$TESTJAVA/bin/java" + +rm -rf mods +mkdir -p mods/test + +# +# Copy .properties files +# +PROPS="`(cd $TESTSRC/src; find . -name '*.properties')`" +if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$D + cp $TESTSRC/src/$P mods/$D/ + done +fi + +$JAVAC -g -d mods -modulesourcepath $TESTSRC/src \ + -cp mods/bundles `find $TESTSRC/src/test -name "*.java"` + +# Create a jar to be added to the class path. Expected properties files are +# picked up from the class path. +rm -f extra.jar +mkdir -p classes +$JAR -cf extra.jar -C $TESTSRC/src/extra jdk/test/resources + +STATUS=0 + +echo 'jdk.test.Main should load bundles local to named module "test".' +$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de || STATUS=1 + +echo "jdk.test.Main should NOT load bundles from the jar file specified by the class-path." +$JAVA -cp extra.jar -mp mods -m test/jdk.test.Main vi && STATUS=1 + +exit $STATUS diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/extra/jdk/test/resources/MyResources_vi.properties b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/extra/jdk/test/resources/MyResources_vi.properties new file mode 100644 index 00000000000..4662419a4a1 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/extra/jdk/test/resources/MyResources_vi.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=vi: message diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..65a70cb82c7 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/Main.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * 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.test; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.ResourceBundle.Control; +import java.util.MissingResourceException; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", + locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println("locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + System.out.println("ERROR: " + value + " expected: " + tag); + errors++; + } + } + + // Make sure ResourceBundle.getBundle throws an UnsupportedOperationException with + // a ResourceBundle.Control. + try { + ResourceBundle rb; + rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", + Locale.ENGLISH, + Control.getControl(Control.FORMAT_DEFAULT)); + System.out.println("ERROR: no UnsupportedOperationException thrown with a ResourceBundle.Control"); + errors++; + } catch (UnsupportedOperationException e) { + // OK + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources.java new file mode 100644 index 00000000000..235e80d1f71 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_de.java b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_de.java new file mode 100644 index 00000000000..93bd11efb85 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_de.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_en.java b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_en.java new file mode 100644 index 00000000000..65f2a64881a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_en.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_fr.java b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_fr.java new file mode 100644 index 00000000000..5d851542be3 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_fr.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_ja.properties b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_ja.properties new file mode 100644 index 00000000000..e64ab3d8ec9 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_ja.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=ja: message diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh.properties b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh.properties new file mode 100644 index 00000000000..515e71c5323 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh: message diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh_TW.properties b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh_TW.properties new file mode 100644 index 00000000000..699d7068037 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/jdk/test/resources/MyResources_zh_TW.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh-TW: message diff --git a/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/module-info.java new file mode 100644 index 00000000000..6d6b0a17f46 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/modlocal/src/test/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module test { +} diff --git a/jdk/test/java/util/ResourceBundle/modules/security/TestPermission.java b/jdk/test/java/util/ResourceBundle/modules/security/TestPermission.java new file mode 100644 index 00000000000..68eb09ec928 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/security/TestPermission.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.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 TestPermission CompilerUtils jdk.testlibrary.* + * @run testng TestPermission + * @summary Driver for testing ResourceBundle::getBundle(String, Module) + */ + +public class TestPermission { + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String TEST_CLASSES = System.getProperty("test.classes"); + + 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("test", "m1"); + + /** + * 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, "-modulesourcepath", SRC_DIR.toString())); + } + } + + /** + * Run the modular test + */ + @Test + public void runTest() throws Exception { + int exitValue = executeTestJava("-mp", MODS_DIR.toString(), + "-m", "test/jdk.test.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/security/src/m1/module-info.java b/jdk/test/java/util/ResourceBundle/modules/security/src/m1/module-info.java new file mode 100644 index 00000000000..44b2d01cb41 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/security/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m1 { + exports p1; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/security/src/m1/p1/Bundle.java b/jdk/test/java/util/ResourceBundle/modules/security/src/m1/p1/Bundle.java new file mode 100644 index 00000000000..ea71d8c674e --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/security/src/m1/p1/Bundle.java @@ -0,0 +1,32 @@ +/* + * 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 p1; + +import java.util.ResourceBundle; + +public class Bundle { + public static ResourceBundle getBundle(String basename) { + return ResourceBundle.getBundle(basename); + } +} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg4/Anno1Pkg4.java b/jdk/test/java/util/ResourceBundle/modules/security/src/m1/p1/resources/MyResources.java similarity index 76% rename from langtools/test/com/sun/javadoc/testProfiles/pkg4/Anno1Pkg4.java rename to jdk/test/java/util/ResourceBundle/modules/security/src/m1/p1/resources/MyResources.java index 933269039e3..6766c77c4c7 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg4/Anno1Pkg4.java +++ b/jdk/test/java/util/ResourceBundle/modules/security/src/m1/p1/resources/MyResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,18 +21,15 @@ * questions. */ -package pkg4; +package p1.resources; -import java.lang.annotation.*; +import java.util.ListResourceBundle; -/** - * Test Annotation class. - * - * @author Bhavesh Patel - */ -public @interface Anno1Pkg4 { - /** - * Comment. - */ - String[] value(); +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "msg", "m1" } + }; + } } diff --git a/jdk/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..512ee4a2d91 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/Main.java @@ -0,0 +1,63 @@ +/* + * 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.test; + +import p1.Bundle; +import java.lang.reflect.Module; +import java.util.ResourceBundle; + +public class Main { + private static final String TEST_RESOURCE_BUNDLE_NAME + = "jdk.test.resources.TestResources"; + private static final String M1_RESOURCE_BUNDLE_NAME + = "p1.resources.MyResources"; + + public static void main(String[] args) { + // local resource + ResourceBundle.getBundle(TEST_RESOURCE_BUNDLE_NAME, Main.class.getModule()); + + // resource in another module + Module m1 = p1.Bundle.class.getModule(); + ResourceBundle rb1 = Bundle.getBundle(M1_RESOURCE_BUNDLE_NAME); + ResourceBundle rb2 = ResourceBundle.getBundle(M1_RESOURCE_BUNDLE_NAME, m1); + if (rb1 != rb2) { + throw new RuntimeException("unexpected resource bundle"); + } + + System.setSecurityManager(new SecurityManager()); + + // no permission needed for local resource + ResourceBundle.getBundle(TEST_RESOURCE_BUNDLE_NAME, Main.class.getModule()); + + // resource bundle through m1's exported API + Bundle.getBundle(M1_RESOURCE_BUNDLE_NAME); + + try { + // fail to get resource bundle in another module + ResourceBundle.getBundle(M1_RESOURCE_BUNDLE_NAME, m1); + throw new RuntimeException("should deny access"); + } catch (SecurityException e) {} + } + +} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg5/Interface1Pkg5.java b/jdk/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/resources/TestResources.java similarity index 75% rename from langtools/test/com/sun/javadoc/testProfiles/pkg5/Interface1Pkg5.java rename to jdk/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/resources/TestResources.java index 4660a302416..a32e3491127 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg5/Interface1Pkg5.java +++ b/jdk/test/java/util/ResourceBundle/modules/security/src/test/jdk/test/resources/TestResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,20 +21,15 @@ * questions. */ -package pkg5; +package jdk.test.resources; -/** - * A sample interface. - * - * @author Bhavesh Patel - */ -public interface Interface1Pkg5 { +import java.util.ListResourceBundle; - /** - * A test method. - * - * @param a blah. - * @param b blah. - */ - void method1(int a, int b); +public class TestResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "msg", "test" } + }; + } } diff --git a/jdk/test/java/util/ResourceBundle/modules/security/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/security/src/test/module-info.java new file mode 100644 index 00000000000..fec5381628a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/security/src/test/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module test { + requires m1; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/simple.sh b/jdk/test/java/util/ResourceBundle/modules/simple/simple.sh new file mode 100644 index 00000000000..9975d1caf5c --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/simple.sh @@ -0,0 +1,70 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8044767 +# @summary Simple test case for ResourceBundle with named modules; +# ResourceBundle.getBundle caller is in named module "test" and +# all resource bundles are in single named module "bundles" with +# service providers. + + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java" + +rm -rf mods + +mkdir -p mods/test + +B=bundles +mkdir -p mods/$B +CLASSES="`find $TESTSRC/src/$B -name '*.java'`" +if [ "x$CLASSES" != x ]; then + $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CLASSES +fi +PROPS="`(cd $TESTSRC/src/$B; find . -name '*.properties')`" +if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$B/$D + cp $TESTSRC/src/$B/$P mods/$B/$D/ + done +fi + +$JAVAC -g -d mods -modulesourcepath $TESTSRC/src \ + -cp mods/bundles `find $TESTSRC/src/test -name "*.java"` + +$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de + +exit $? diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources.java new file mode 100644 index 00000000000..235e80d1f71 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResourcesProvider.java similarity index 57% rename from hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp rename to jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResourcesProvider.java index 6481aaddca2..29fc236fa85 100644 --- a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.cpp +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResourcesProvider.java @@ -19,33 +19,30 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ -#include "precompiled.hpp" -#include "jvmci/commandLineFlagConstraintsJVMCI.hpp" -#include "runtime/arguments.hpp" -#include "runtime/globals.hpp" -#include "utilities/defaultStream.hpp" +package jdk.test.resources; -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose) { - if (!EnableJVMCI) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); - } - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; - } -} +import java.util.Locale; +import java.util.spi.AbstractResourceBundleProvider; -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose) { - if (!EnableJVMCI) { - if (verbose == true) { - jio_fprintf(defaultStream::error_stream(), "EnableJVMCI must be enabled\n"); +public class MyResourcesProvider extends AbstractResourceBundleProvider { + public MyResourcesProvider() { + super("java.class", "java.properties"); + System.err.println("MyResourcesProvider called " + this); + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + StringBuilder sb = new StringBuilder(baseName); + String lang = locale.getLanguage(); + if (!lang.isEmpty()) { + sb.append('_').append(lang); + String country = locale.getCountry(); + if (!country.isEmpty()) { + sb.append('_').append(country); + } + } + return sb.toString(); } - return Flag::VIOLATES_CONSTRAINT; - } else { - return Flag::SUCCESS; - } } diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_de.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_de.java new file mode 100644 index 00000000000..93bd11efb85 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_de.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_de extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "de: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_en.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_en.java new file mode 100644 index 00000000000..65f2a64881a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_en.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_en extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "en: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_fr.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_fr.java new file mode 100644 index 00000000000..5d851542be3 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_fr.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources; + +import java.util.ListResourceBundle; + +public class MyResources_fr extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "fr: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_ja.properties b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_ja.properties new file mode 100644 index 00000000000..e64ab3d8ec9 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_ja.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=ja: message diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh.properties b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh.properties new file mode 100644 index 00000000000..515e71c5323 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh: message diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh_TW.properties b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh_TW.properties new file mode 100644 index 00000000000..699d7068037 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/jdk/test/resources/MyResources_zh_TW.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=zh-TW: message diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/module-info.java new file mode 100644 index 00000000000..7725c44188d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/bundles/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module bundles { + exports jdk.test.resources to test; + provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..d93cb627be0 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/test/jdk/test/Main.java @@ -0,0 +1,51 @@ +/* + * 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 jdk.test; + +import java.util.Locale; +import java.util.ResourceBundle; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", + locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println("locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + System.out.println("ERROR: " + value + " expected: " + tag); + errors++; + } + } + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/simple/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/simple/src/test/module-info.java new file mode 100644 index 00000000000..c5ac262f6df --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/simple/src/test/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module test { + requires bundles; + + uses jdk.test.resources.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java new file mode 100644 index 00000000000..5e100abc89b --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithNoModuleArg.java @@ -0,0 +1,71 @@ +/* + * 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 jdk.embargo; + +import java.lang.reflect.Module; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class TestWithNoModuleArg { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.out.println("Usage: java ... basename should-be-loaded-flag"); + System.out.println(" ex. java ... jdk.test.resources.classes.MyResources false"); + return; + } + + String basename = args[0]; + boolean shouldBeLoaded = "true".equals(args[1]); + + int errors = 0; + try { + // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback + Locale.setDefault(Locale.ROOT); + ResourceBundle rb = ResourceBundle.getBundle(basename); + if (shouldBeLoaded) { + System.out.println("Passed: got resource bundle:"); + } else { + System.out.println("Failed: no MissingResourceException thrown"); + errors++; + } + System.out.println(" bundle = " + rb); + } catch (MissingResourceException e) { + if (!shouldBeLoaded) { + System.out.println("Passed: got expected " + e); + } else { + System.out.println("Failed: got unexpected " + e); + errors++; + } + System.out.println(" cause = " + e.getCause()); + } catch (Throwable t) { + System.out.println("Failed: unexpected throwable: " + t); + errors++; + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java new file mode 100644 index 00000000000..8f2ca8e1206 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/jdk/embargo/TestWithUnnamedModuleArg.java @@ -0,0 +1,78 @@ +/* + * 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 jdk.embargo; + +import java.lang.reflect.Module; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class TestWithUnnamedModuleArg { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.out.println("Usage: java ... basename should-be-loaded-flag"); + System.out.println(" ex. java ... jdk.test.resources.classes.MyResources false"); + return; + } + + String basename = args[0]; + boolean shouldBeLoaded = "true".equals(args[1]); + + int errors = 0; + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + + try { + // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback + Locale.setDefault(Locale.ROOT); + ResourceBundle rb = ResourceBundle.getBundle(basename, + cl.getUnnamedModule()); + if (shouldBeLoaded) { + System.out.println("Passed: got resource bundle:"); + } else { + System.out.println("Failed: no MissingResourceException thrown"); + errors++; + } + System.out.println(" bundle = " + rb); + } catch (MissingResourceException e) { + if (!shouldBeLoaded) { + System.out.println("Passed: got expected " + e); + } else { + System.out.println("Failed: got unexpected " + e); + errors++; + } + System.out.println(" cause = " + e.getCause()); + } catch (Throwable t) { + System.out.println("Failed: unexpected throwable: " + t); + errors++; + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/module-info.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/module-info.java new file mode 100644 index 00000000000..3455a3b8381 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/embargo/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module embargo { +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResources.java new file mode 100644 index 00000000000..8de8bea5fa2 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.exported.classes; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResourcesProvider.java similarity index 57% rename from hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java rename to jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResourcesProvider.java index c4c36d3c49d..86d9daf2089 100644 --- a/hotspot/test/compiler/jsr292/NonInlinedCall/NonInlinedReinvoker.java +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/classes/MyResourcesProvider.java @@ -20,29 +20,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package java.lang.invoke; -class NonInlinedReinvoker extends DelegatingMethodHandle { - private final MethodHandle target; +package jdk.test.resources.exported.classes; - private NonInlinedReinvoker(MethodHandle target, LambdaForm lf) { - super(target.type(), lf); - this.target = target; - } - @Override - protected MethodHandle getTarget() { - return target; +import java.util.Locale; +import java.util.spi.AbstractResourceBundleProvider; + +public class MyResourcesProvider extends AbstractResourceBundleProvider { + public MyResourcesProvider() { + super("java.class", "java.properties"); + System.err.println("MyResourcesProvider called " + this); } @Override - MethodHandle asTypeUncached(MethodType newType) { - return asTypeCache = target.asType(newType); - } - - static MethodHandle make(MethodHandle target) { - LambdaForm lform = DelegatingMethodHandle.makeReinvokerForm( - target, -1, DelegatingMethodHandle.class, "reinvoker.dontInline", - /*forceInline=*/false, DelegatingMethodHandle.NF_getTarget, null); - return new NonInlinedReinvoker(target, lform); + protected String toBundleName(String baseName, Locale locale) { + StringBuilder sb = new StringBuilder(baseName); + String lang = locale.getLanguage(); + if (!lang.isEmpty()) { + sb.append('_').append(lang); + String country = locale.getCountry(); + if (!country.isEmpty()) { + sb.append('_').append(country); + } + } + return sb.toString(); } } diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/props/MyResources.properties b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/props/MyResources.properties new file mode 100644 index 00000000000..a9885289e22 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/jdk/test/resources/exported/props/MyResources.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=root: message diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/module-info.java new file mode 100644 index 00000000000..a110e88d28d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/exported.named.bundles/module-info.java @@ -0,0 +1,30 @@ +/* + * 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. + */ + +module exported.named.bundles { + // unqualified exports to verify that resource bundles are not picked + // up by other named modules + exports jdk.test.resources.exported.classes; + provides jdk.test.resources.exported.classes.MyResourcesProvider + with jdk.test.resources.exported.classes.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResources.java new file mode 100644 index 00000000000..08cc009a12d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.test.resources.classes; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResourcesProvider.java new file mode 100644 index 00000000000..70c391c0956 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/classes/MyResourcesProvider.java @@ -0,0 +1,60 @@ +/* + * 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 jdk.test.resources.classes; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.spi.AbstractResourceBundleProvider; + +public class MyResourcesProvider extends AbstractResourceBundleProvider { + public MyResourcesProvider() { + super("java.class"); + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + StringBuilder sb = new StringBuilder(baseName); + String lang = locale.getLanguage(); + if (!lang.isEmpty()) { + sb.append('_').append(lang); + String country = locale.getCountry(); + if (!country.isEmpty()) { + sb.append('_').append(country); + } + } + return sb.toString(); + } + + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + ResourceBundle rb = super.getBundle(baseName, locale); + String tag = locale.toLanguageTag(); + if (tag.equals("und")) { + tag = "ROOT"; // to a human friendly name + } + System.out.printf(" MyResourcesProvider.getBundle(%s, %s)%n -> %s%n", + baseName, tag, rb); + return rb; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResources.properties b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResources.properties new file mode 100644 index 00000000000..a9885289e22 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResources.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=root: message diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResourcesProvider.java new file mode 100644 index 00000000000..73b92fbde35 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/jdk/test/resources/props/MyResourcesProvider.java @@ -0,0 +1,60 @@ +/* + * 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 jdk.test.resources.props; + +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.spi.AbstractResourceBundleProvider; + +public class MyResourcesProvider extends AbstractResourceBundleProvider { + public MyResourcesProvider() { + super("java.properties"); + } + + @Override + protected String toBundleName(String baseName, Locale locale) { + StringBuilder sb = new StringBuilder(baseName); + String lang = locale.getLanguage(); + if (!lang.isEmpty()) { + sb.append('_').append(lang); + String country = locale.getCountry(); + if (!country.isEmpty()) { + sb.append('_').append(country); + } + } + return sb.toString(); + } + + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + ResourceBundle rb = super.getBundle(baseName, locale); + String tag = locale.toLanguageTag(); + if (tag.equals("und")) { + tag = "ROOT"; // to a human friendly name + } + System.out.printf(" MyResourcesProvider.getBundle(%s, %s)%n -> %s%n", + baseName, tag, rb); + return rb; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/module-info.java new file mode 100644 index 00000000000..a9fd37f1ed0 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/named.bundles/module-info.java @@ -0,0 +1,31 @@ +/* + * 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. + */ + +module named.bundles { + exports jdk.test.resources.classes to test; // exports only to test + exports jdk.test.resources.props to test; // exports only to test + provides jdk.test.resources.classes.MyResourcesProvider + with jdk.test.resources.classes.MyResourcesProvider; + provides jdk.test.resources.props.MyResourcesProvider + with jdk.test.resources.props.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/classes/MyResources.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/classes/MyResources.java new file mode 100644 index 00000000000..0c8c3f73c31 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/classes/MyResources.java @@ -0,0 +1,35 @@ +/* + * 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 jdk.pkg.resources.classes; + +import java.util.ListResourceBundle; + +public class MyResources extends ListResourceBundle { + @Override + public Object[][] getContents() { + return new Object[][] { + { "key", "root: message" } + }; + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/props/MyResources.properties b/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/props/MyResources.properties new file mode 100644 index 00000000000..a9885289e22 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/resources/props/MyResources.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +key=root: message diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java new file mode 100644 index 00000000000..54ac2e7d686 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/pkg/jdk/pkg/test/Main.java @@ -0,0 +1,78 @@ +/* + * 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 jdk.pkg.test; + +import java.lang.reflect.Module; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class Main { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.out.println("Usage: java ... basename should-be-loaded-flag"); + System.out.println(" ex. java ... jdk.test.resources.classes.MyResources false"); + return; + } + + String basename = args[0]; + boolean shouldBeLoaded = "true".equals(args[1]); + + int errors = 0; + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + + try { + // Use the default Locale to avoid confusion related to fallback + Locale.setDefault(Locale.ENGLISH); + ResourceBundle rb = ResourceBundle.getBundle(basename, + cl.getUnnamedModule()); + if (shouldBeLoaded) { + System.out.println("Passed: got resource bundle:"); + } else { + System.out.println("Failed: no MissingResourceException thrown"); + errors++; + } + System.out.println(" bundle = " + rb); + } catch (MissingResourceException e) { + if (!shouldBeLoaded) { + System.out.println("Passed: got expected " + e); + } else { + System.out.println("Failed: got unexpected " + e); + errors++; + } + System.out.println(" cause = " + e.getCause()); + } catch (Throwable t) { + System.out.println("Failed: unexpected throwable: " + t); + errors++; + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java new file mode 100644 index 00000000000..19de28a8be1 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithNoModuleArg.java @@ -0,0 +1,71 @@ +/* + * 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 jdk.test; + +import java.lang.reflect.Module; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class TestWithNoModuleArg { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.out.println("Usage: java ... basename should-be-loaded-flag"); + System.out.println(" ex. java ... jdk.test.resources.classes.MyResources false"); + return; + } + + String basename = args[0]; + boolean shouldBeLoaded = "true".equals(args[1]); + + int errors = 0; + try { + // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback + Locale.setDefault(Locale.ROOT); + ResourceBundle rb = ResourceBundle.getBundle(basename); + if (shouldBeLoaded) { + System.out.println("Passed: got resource bundle:"); + } else { + System.out.println("Failed: no MissingResourceException thrown"); + errors++; + } + System.out.println(" bundle = " + rb); + } catch (MissingResourceException e) { + if (!shouldBeLoaded) { + System.out.println("Passed: got expected " + e); + } else { + System.out.println("Failed: got unexpected " + e); + errors++; + } + System.out.println(" cause = " + e.getCause()); + } catch (Throwable t) { + System.out.println("Failed: unexpected throwable: " + t); + errors++; + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java new file mode 100644 index 00000000000..d36b53f864a --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/jdk/test/TestWithUnnamedModuleArg.java @@ -0,0 +1,78 @@ +/* + * 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 jdk.test; + +import java.lang.reflect.Module; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class TestWithUnnamedModuleArg { + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.out.println("Usage: java ... basename should-be-loaded-flag"); + System.out.println(" ex. java ... jdk.test.resources.classes.MyResources false"); + return; + } + + String basename = args[0]; + boolean shouldBeLoaded = "true".equals(args[1]); + + int errors = 0; + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + if (cl == null) { + cl = ClassLoader.getSystemClassLoader(); + } + + try { + // Set the default Locale to Locale.ROOT to avoid any confusions related to fallback + Locale.setDefault(Locale.ROOT); + ResourceBundle rb = ResourceBundle.getBundle(basename, + cl.getUnnamedModule()); + if (shouldBeLoaded) { + System.out.println("Passed: got resource bundle:"); + } else { + System.out.println("Failed: no MissingResourceException thrown"); + errors++; + } + System.out.println(" bundle = " + rb); + } catch (MissingResourceException e) { + if (!shouldBeLoaded) { + System.out.println("Passed: got expected " + e); + } else { + System.out.println("Failed: got unexpected " + e); + errors++; + } + System.out.println(" cause = " + e.getCause()); + } catch (Throwable t) { + System.out.println("Failed: unexpected throwable: " + t); + errors++; + } + + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/module-info.java new file mode 100644 index 00000000000..00954c88c86 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/src/test/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module test { + // jdk.test.resources.classes.MyResourcesProvider is in named.bundles. + requires named.bundles; + uses jdk.test.resources.classes.MyResourcesProvider; + uses jdk.test.resources.props.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh new file mode 100644 index 00000000000..02ca3c43793 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/visibility/visibility.sh @@ -0,0 +1,233 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8137317 8139238 +# @summary Visibility tests for ResourceBundle.getBundle with and without +# an unnamed module argument. + + +set -e +STATUS=0 + +runJava() +{ + echo "Executing java $@" + $JAVA $@ || STATUS=1 + echo +} + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java" + +rm -rf mods classes + +MODS=`cd $TESTSRC/src; find . -name module-info.java -exec dirname {} \; | sed 's:\./::'` + +for M in $MODS +do + mkdir -p mods/$M + CLASSES="`find $TESTSRC/src/$M -name '*.java'`" + if [ "x$CLASSES" != x ]; then + $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CLASSES + fi + PROPS="`(cd $TESTSRC/src/$M; find . -name '*.properties')`" + if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$M/$D + cp $TESTSRC/src/$M/$P mods/$M/$D/ + done + fi +done + +# Package jdk.test is in named module "test". +# Package jdk.embargo is in named module "embargo". + +# jdk.{test,embargo}.TestWithUnnamedModuleArg call: +# ResourceBundle.getBundle(basename, classloader.getUnnamedModule()) +# where classloader is the TCCL or system class loader. +# jdk.{test,embargo}.TestWithNoModuleArg call: +# ResourceBundle.getBundle(basename) + +# jdk.test.resources[.exported].classes.* are class-based resource bundles. +# jdk.test.resources[.exported].props.* are properties file-based resource bundles. + +# Packages jdk.test.resources.{classes,props} in named module "named.bundles" +# are exported only to named module "test". +# Packages jdk.test.resources.exported.{classes,props} in named module +# "exported.named.bundle" are exported to unnamed modules. + +######################################## +# Test cases with jdk.test.resources.* # +######################################## + +# Tests using jdk.test.TestWithNoModuleArg and jdk.embargo.TestWithNoModuleArg +# neither of which specifies an unnamed module with ResourceBundle.getBundle(). + +# jdk.test.resources.{classes,props}.* are available only to named module "test" +# by ResourceBundleProvider. +runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.classes.MyResources true +runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.props.MyResources true +runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.classes.MyResources false +runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.props.MyResources false + +# Add mods/named.bundles to the class path. +runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.classes.MyResources true +runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.props.MyResources true +runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.classes.MyResources false +runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.props.MyResources false + +# Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg +# both of which specify an unnamed module with ResourceBundle.getBundle. + +# jdk.test.resources.classes is exported to named module "test". +# IllegalAccessException is thrown in ResourceBundle.Control.newBundle(). +runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.classes.MyResources false + +# jdk.test.resources.props is exported to named module "test". +# loader.getResource() doesn't find jdk.test.resources.props.MyResources. +runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.props.MyResources false + +# IllegalAccessException is thrown in ResourceBundle.Control.newBundle(). +runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.classes.MyResources false +# jdk.test.resources.props is exported to named module "test". +# loader.getResource() doesn't find jdk.test.resources.props.MyResources. +runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.props.MyResources false + +# Add mods/named.bundles to the class path + +# IllegalAccessException is thrown in ResourceBundle.Control.newBundle(). +runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.classes.MyResources false +# loader.getResource() finds jdk.test.resources.exported.props.MyResources. +runJava -cp mods/named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.props.MyResources true + +# jdk.test.resources.exported.classes.MyResources is treated +# as if the class is in an unnamed module. +runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.classes.MyResources true +# loader.getResource() finds jdk.test.resources.exported.props.MyResources. +runJava -cp mods/named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.props.MyResources true + +################################################# +# Test cases with jdk.test.resources.exported.* # +################################################# +# Tests using jdk.test.TestWithNoModuleArg and jdk.embargo.TestWithNoModuleArg +# neither of which specifies an unnamed module with ResourceBundle.getBundle. + +# None of jdk.test.resources.exported.** is available to the named modules. +runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.exported.classes.MyResources false +runJava -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.exported.props.MyResources false +runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.exported.classes.MyResources false +runJava -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.exported.props.MyResources false + +# Add mods/exported.named.bundles to the class path. +runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.exported.classes.MyResources false +runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithNoModuleArg \ + jdk.test.resources.exported.props.MyResources false +runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.exported.classes.MyResources false +runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithNoModuleArg \ + jdk.test.resources.exported.props.MyResources false + +# Tests using jdk.test.TestWithUnnamedModuleArg and jdk.embargo.TestWithUnnamedModuleArg +# which specify an unnamed module with ResourceBundle.getBundle. + +# loader.loadClass() doesn't find jdk.test.resources.exported.classes.MyResources +# and throws a ClassNotFoundException. +runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.classes.MyResources false +# The properties files in jdk.test.resources.exported.props are not found with loader.getResource(). +runJava -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.props.MyResources false + + +# loader.loadClass() doesn't find jdk.test.resources.exported.classes.MyResources +# and throws a ClassNotFoundException. +runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.classes.MyResources false +# The properties files in jdk.test.resources.exported.props are not found +# with loader.getResource(). +runJava -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.props.MyResources false + +# Add mods/exported.named.bundles to the class path. + +# jdk.test.resources.exported.classes.MyResources.getModule().isNamed() returns false. +runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.classes.MyResources true +# loader.getResource() finds jdk.test.resources.exported.props.MyResources. +runJava -cp mods/exported.named.bundles -mp mods -m test/jdk.test.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.props.MyResources true + +# jdk.test.resources.exported.classes.MyResources.getModule().isNamed() returns false. +runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.classes.MyResources true +# loader.getResource() finds jdk.test.resources.exported.props.MyResources. +runJava -cp mods/exported.named.bundles -mp mods -m embargo/jdk.embargo.TestWithUnnamedModuleArg \ + jdk.test.resources.exported.props.MyResources true + +####################################### +# Test cases with jdk.pkg.resources.* # +####################################### +# Prepare resource bundles in an unnamed module +PKG=$TESTSRC/src/pkg +mkdir -p classes/jdk/pkg/resources/props +$JAVAC -g -d classes $PKG/jdk/pkg/test/Main.java $PKG/jdk/pkg/resources/classes/MyResources.java +cp $PKG/jdk/pkg/resources/props/MyResources.properties classes/jdk/pkg/resources/props + +# jdk.pkg.resources.* are in an unnamed module. +# jdk.pkg.test.Main calls ResourceBundle.getBundle with an unnamed module. +runJava -cp classes jdk.pkg.test.Main jdk.pkg.resources.classes.MyResources true +runJava -cp classes jdk.pkg.test.Main jdk.pkg.resources.props.MyResources true + +exit $STATUS diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources.xml new file mode 100644 index 00000000000..dc4be6b78c3 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle + root: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResourcesProvider.java b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResourcesProvider.java new file mode 100644 index 00000000000..ca4cec531e8 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResourcesProvider.java @@ -0,0 +1,81 @@ +/* + * 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 jdk.test.resources; + +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.spi.ResourceBundleProvider; + +public class MyResourcesProvider implements ResourceBundleProvider { + @Override + public ResourceBundle getBundle(String baseName, Locale locale) { + String xmlName = toXMLName(baseName, locale); + try (InputStream is = this.getClass().getModule().getResourceAsStream(xmlName)) { + return new XMLResourceBundle(new BufferedInputStream(is)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private String toXMLName(String baseName, Locale locale) { + StringBuilder sb = new StringBuilder(baseName.replace('.', '/')); + String lang = locale.getLanguage(); + if (!lang.isEmpty()) { + sb.append('_').append(lang); + String country = locale.getCountry(); + if (!country.isEmpty()) { + sb.append('_').append(country); + } + } + return sb.append(".xml").toString(); + } + + private static class XMLResourceBundle extends ResourceBundle { + private Properties props; + + XMLResourceBundle(InputStream stream) throws IOException { + props = new Properties(); + props.loadFromXML(stream); + } + + @Override + protected Object handleGetObject(String key) { + if (key == null) { + throw new NullPointerException(); + } + return props.get(key); + } + + @Override + public Enumeration getKeys() { + // Not implemented + return null; + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_de.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_de.xml new file mode 100644 index 00000000000..cfaa5dda5a1 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_de.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle + de: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_en.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_en.xml new file mode 100644 index 00000000000..0213a2126ba --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_en.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle + en: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_fr.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_fr.xml new file mode 100644 index 00000000000..d6b57efc7cf --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_fr.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle + fr: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_ja.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_ja.xml new file mode 100644 index 00000000000..6d82961e83d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_ja.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle in named modules. + ja: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh.xml new file mode 100644 index 00000000000..df1a2b727d6 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle in named modules. + zh: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh_TW.xml b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh_TW.xml new file mode 100644 index 00000000000..5ce424a187c --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/jdk/test/resources/MyResources_zh_TW.xml @@ -0,0 +1,17 @@ + + + + + + + + + + +]> + + + Test data for ResourceBundle in named modules. + zh-TW: message + diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/module-info.java b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/module-info.java new file mode 100644 index 00000000000..7725c44188d --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/bundles/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module bundles { + exports jdk.test.resources to test; + provides jdk.test.resources.MyResourcesProvider with jdk.test.resources.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/test/jdk/test/Main.java b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..d93cb627be0 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/test/jdk/test/Main.java @@ -0,0 +1,51 @@ +/* + * 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 jdk.test; + +import java.util.Locale; +import java.util.ResourceBundle; + +public class Main { + public static void main(String[] args) throws Exception { + int errors = 0; + for (String loctag : args) { + Locale locale = Locale.forLanguageTag(loctag); + if (locale.equals(Locale.ROOT)) { + continue; + } + ResourceBundle rb = ResourceBundle.getBundle("jdk.test.resources.MyResources", + locale); + String tag = locale.toLanguageTag(); // normalized + String value = rb.getString("key"); + System.out.println("locale = " + tag + ", value = " + value); + if (!value.startsWith(tag + ':')) { + System.out.println("ERROR: " + value + " expected: " + tag); + errors++; + } + } + if (errors > 0) { + throw new RuntimeException(errors + " errors"); + } + } +} diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/test/module-info.java b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/test/module-info.java new file mode 100644 index 00000000000..c5ac262f6df --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/src/test/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module test { + requires bundles; + + uses jdk.test.resources.MyResourcesProvider; +} diff --git a/jdk/test/java/util/ResourceBundle/modules/xmlformat/xmlformat.sh b/jdk/test/java/util/ResourceBundle/modules/xmlformat/xmlformat.sh new file mode 100644 index 00000000000..849523229a5 --- /dev/null +++ b/jdk/test/java/util/ResourceBundle/modules/xmlformat/xmlformat.sh @@ -0,0 +1,68 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @summary Simple test case for ResourceBundle with modules; +# ResourceBundle.getBundle caller is in module named "test" and +# all resource bundles are in single module named "bundles". + + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java" + +rm -rf mods + +mkdir -p mods/test + +B=bundles +mkdir -p mods/$B +CLASSES="`find $TESTSRC/src/$B -name '*.java'`" +if [ "x$CLASSES" != x ]; then + $JAVAC -g -d mods -modulesourcepath $TESTSRC/src $CLASSES +fi +PROPS="`(cd $TESTSRC/src/$B; find . -name '*.xml')`" +if [ "x$PROPS" != x ]; then + for P in $PROPS + do + D=`dirname $P` + mkdir -p mods/$B/$D + cp $TESTSRC/src/$B/$P mods/$B/$D/ + done +fi + +$JAVAC -g -d mods -modulesourcepath $TESTSRC/src \ + -cp mods/bundles `find $TESTSRC/src/test -name "*.java"` + +$JAVA -mp mods -m test/jdk.test.Main de fr ja zh-tw en de + +exit $? diff --git a/jdk/test/java/util/Scanner/ScannerStreamTest.java b/jdk/test/java/util/Scanner/ScannerStreamTest.java index 0f555c50139..98d28a71a5a 100644 --- a/jdk/test/java/util/Scanner/ScannerStreamTest.java +++ b/jdk/test/java/util/Scanner/ScannerStreamTest.java @@ -46,8 +46,8 @@ import static org.testng.Assert.*; * @test * @bug 8072722 * @summary Tests of stream support in java.util.Scanner - * @library ../stream/bootlib/java.base - * @build java.util.stream.OpTestCase + * @library ../stream/bootlib + * @build java.base/java.util.stream.OpTestCase * @run testng/othervm ScannerStreamTest */ diff --git a/jdk/test/java/util/ServiceLoader/TwoIterators.java b/jdk/test/java/util/ServiceLoader/TwoIterators.java new file mode 100644 index 00000000000..ddb9cc09508 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/TwoIterators.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Test ServiceLoader with two iterators, interleaving their use + * to test that they don't interfere with each other + * @run testng TwoIterators + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Iterator; +import java.util.ServiceLoader; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +public class TwoIterators { + + // service type + public static interface S { } + + // service provider implementations + public static class S1 implements S { } + public static class S2 implements S { } + + private ClassLoader testClassLoader; + + // creates the services configuration file and sets the ClassLoader + @BeforeClass + void setup() throws Exception { + String classes = System.getProperty("test.classes"); + Path dir = Paths.get(classes, "META-INF", "services"); + Files.createDirectories(dir); + Path config = dir.resolve(S.class.getName()); + Files.write(config, Arrays.asList(S1.class.getName(), S2.class.getName())); + + this.testClassLoader = TwoIterators.class.getClassLoader(); + } + + @Test + public void testSequentialUse1() { + ServiceLoader sl = ServiceLoader.load(S.class, testClassLoader); + + Iterator iterator1 = sl.iterator(); + iterator1.next(); + iterator1.next(); + assertFalse(iterator1.hasNext()); + + Iterator iterator2 = sl.iterator(); + iterator2.next(); + iterator2.next(); + assertFalse(iterator2.hasNext()); + } + + @Test + public void testSequentialUse2() { + ServiceLoader sl = ServiceLoader.load(S.class, testClassLoader); + + Iterator iterator1 = sl.iterator(); + Iterator iterator2 = sl.iterator(); + + iterator1.next(); + iterator1.next(); + assertFalse(iterator1.hasNext()); + + iterator2.next(); + iterator2.next(); + assertFalse(iterator2.hasNext()); + } + + @Test + public void testInterleaved1() { + ServiceLoader sl = ServiceLoader.load(S.class, testClassLoader); + + Iterator iterator1 = sl.iterator(); + Iterator iterator2 = sl.iterator(); + + iterator1.next(); + iterator2.next(); + iterator1.next(); + iterator2.next(); + assertFalse(iterator1.hasNext()); + assertFalse(iterator2.hasNext()); + } + + @Test + public void testInterleaved2() { + ServiceLoader sl = ServiceLoader.load(S.class, testClassLoader); + + Iterator iterator1 = sl.iterator(); + iterator1.next(); + + Iterator iterator2 = sl.iterator(); + + assertTrue(iterator1.hasNext()); + assertTrue(iterator2.hasNext()); + + iterator1.next(); + iterator2.next(); + iterator2.next(); + + assertFalse(iterator1.hasNext()); + assertFalse(iterator2.hasNext()); + } + + @Test + public void testInterleaved3() { + ServiceLoader sl = ServiceLoader.load(S.class, testClassLoader); + + Iterator iterator1 = sl.iterator(); + iterator1.next(); + + Iterator iterator2 = sl.iterator(); + + assertTrue(iterator2.hasNext()); + assertTrue(iterator1.hasNext()); + + iterator2.next(); + iterator2.next(); + iterator1.next(); + + assertFalse(iterator1.hasNext()); + assertFalse(iterator2.hasNext()); + } +} + diff --git a/jdk/test/java/util/ServiceLoader/modules/BasicTest.java b/jdk/test/java/util/ServiceLoader/modules/BasicTest.java new file mode 100644 index 00000000000..3b64a1d7d9a --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/BasicTest.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +import java.lang.reflect.Layer; +import java.security.Provider; +import java.util.ServiceLoader; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/* + * @test + * @run testng BasicTest + * @summary Basic test of ServiceLoader with modules + */ + +public class BasicTest { + + @Test + public void testEmptyLayer() { + ServiceLoader sl + = ServiceLoader.load(Layer.empty(), Provider.class); + assertFalse(sl.iterator().hasNext()); + } + + @Test + public void testBootLayer() { + ServiceLoader sl + = ServiceLoader.load(Layer.boot(), Provider.class); + boolean found = false; + for (Provider provider : sl) { + if (provider.getName().equals("SunJCE")) + found = true; + } + assertTrue(found); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testNullLayer() { + ServiceLoader.load(null, Provider.class); + } + + @Test(expectedExceptions = { NullPointerException.class }) + public void testNullService() { + ServiceLoader.load(Layer.empty(), null); + } + +} diff --git a/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java b/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java new file mode 100644 index 00000000000..abb90c0b695 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/ServicesTest.java @@ -0,0 +1,190 @@ +/* + * 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.io.File; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.reflect.Layer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ServiceLoader; +import java.util.Set; +import javax.script.ScriptEngineFactory; + +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 java.scripting + jdk.compiler + * @build ServicesTest CompilerUtils jdk.testlibrary.* + * @run testng ServicesTest + * @summary Tests ServiceLoader to locate service providers on the module path + * and class path. Also tests ServiceLoader with a custom Layer. + */ + +@Test +public class ServicesTest { + + 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 CLASSES_DIR = Paths.get("classes"); + private static final Path MODS_DIR = Paths.get("mods"); + + // modules to compile to the module path + private static final String MODULES[] = { "test", "bananascript" }; + + // directories of classes to compile to the class path + private static final String CLASSES[] = { "pearscript" }; + + // resources to copy to the class path + private static final String RESOURCES[] = { + "pearscript/META-INF/services/javax.script.ScriptEngineFactory" + }; + + + /** + * Compiles all modules and classes used by the test + */ + @BeforeTest + public void setup() throws Exception { + + // modules + for (String mn : MODULES ) { + Path src = SRC_DIR.resolve(mn); + Path mods = MODS_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(src, mods)); + } + + // classes + for (String dir : CLASSES) { + Path src = SRC_DIR.resolve(dir); + assertTrue(CompilerUtils.compile(src, CLASSES_DIR)); + } + + // copy resources + for (String rn : RESOURCES) { + Path file = Paths.get(rn.replace('/', File.separatorChar)); + Path source = SRC_DIR.resolve(file); + + // drop directory to get a target of classes/META-INF/... + Path target = CLASSES_DIR.resolve(file.subpath(1, file.getNameCount())); + + Files.createDirectories(target.getParent()); + Files.copy(source, target); + } + + } + + + /** + * Run test with -modulepath. + * + * BananaScriptEngine should be found. + */ + public void runWithModulePath() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-m", "test/test.Main", + "BananaScriptEngine") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Run test with -modulepath and -classpath. + * + * Both BananaScriptEngine and PearScriptEngine should be found + */ + public void runWithModulePathAndClassPath() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-cp", CLASSES_DIR.toString(), + "-m", "test/test.Main", + "BananaScriptEngine", "PearScriptEngine") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Exercise ServiceLoader.load(Layer, Class). + */ + public void testWithCustomLayer() throws Exception { + + ServiceLoader sl; + + // BananaScriptEngine should not be in the boot Layer + sl = ServiceLoader.load(Layer.boot(), ScriptEngineFactory.class); + assertTrue(find("BananaScriptEngine", sl) == null); + + // create a custom Layer + ModuleFinder finder = ModuleFinder.of(MODS_DIR); + Layer bootLayer = Layer.boot(); + Configuration parent = bootLayer.configuration(); + Configuration cf + = parent.resolveRequiresAndUses(finder, ModuleFinder.empty(), Set.of()); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = bootLayer.defineModulesWithOneLoader(cf, scl); + + assertTrue(layer.findModule("bananascript").isPresent()); + ClassLoader loader = layer.findLoader("bananascript"); + + sl = ServiceLoader.load(layer, ScriptEngineFactory.class); + ScriptEngineFactory factory = find("BananaScriptEngine", sl); + assertTrue(factory != null); + assertEquals(factory.getClass().getModule().getName(), "bananascript"); + assertTrue(factory.getClass().getClassLoader() == loader); + + } + + /** + * Find the given scripting engine (by name) via the ScriptEngineFactory + * that ServiceLoader has found. + */ + static ScriptEngineFactory find(String name, + ServiceLoader sl) { + for (ScriptEngineFactory factory : sl) { + if (factory.getEngineName().equals(name)) + return factory; + } + return null; + } + + +} + diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg2/Anno2Pkg2.java b/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java similarity index 82% rename from langtools/test/com/sun/javadoc/testProfiles/pkg2/Anno2Pkg2.java rename to jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java index 87e657d5692..d599d4421a8 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg2/Anno2Pkg2.java +++ b/jdk/test/java/util/ServiceLoader/modules/src/bananascript/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,13 +21,10 @@ * questions. */ -package pkg2; +module bananascript { + requires java.scripting; -import java.lang.annotation.*; - -/* - * A sample interface. - */ -public @interface Anno2Pkg2 { - boolean value() default true; + provides javax.script.ScriptEngineFactory + with org.banana.BananaScriptEngineFactory; } + diff --git a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java b/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java new file mode 100644 index 00000000000..ddaf1e1043e --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScript.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.banana; + +import java.io.Reader; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class BananaScript implements ScriptEngine { + + @Override + public Object eval(String script, ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script, Bindings n) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , Bindings n) { + throw new RuntimeException(); + } + @Override + public void put(String key, Object value) { + throw new RuntimeException(); + } + + @Override + public Object get(String key) { + throw new RuntimeException(); + } + + @Override + public Bindings getBindings(int scope) { + throw new RuntimeException(); + } + + @Override + public void setBindings(Bindings bindings, int scope) { + throw new RuntimeException(); + } + + @Override + public Bindings createBindings() { + throw new RuntimeException(); + } + + @Override + public ScriptContext getContext() { + throw new RuntimeException(); + } + + @Override + public void setContext(ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public ScriptEngineFactory getFactory() { + throw new RuntimeException(); + } +} + diff --git a/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java b/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java new file mode 100644 index 00000000000..443415c1706 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/bananascript/org/banana/BananaScriptEngineFactory.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.banana; + +import java.util.Arrays; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class BananaScriptEngineFactory implements ScriptEngineFactory { + + @Override + public String getEngineName() { + return "BananaScriptEngine"; + } + + @Override + public String getEngineVersion() { + return "1.0"; + } + + @Override + public List getExtensions() { + return Arrays.asList("banana"); + } + + @Override + public List getMimeTypes() { + return Arrays.asList("application/x-bananascript"); + } + + @Override + public List getNames() { + return Arrays.asList("BananaScript"); + } + + @Override + public String getLanguageName() { + return "BananaScript"; + } + + @Override + public String getLanguageVersion() { + return "1.0"; + } + + @Override + public Object getParameter(String key) { + return null; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + throw new RuntimeException(); + } + + @Override + public String getOutputStatement(String toDisplay) { + throw new RuntimeException(); + } + + @Override + public String getProgram(String... statements) { + throw new RuntimeException(); + } + + @Override + public ScriptEngine getScriptEngine() { + return new BananaScript(); + } +} diff --git a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/META-INF/services/javax.script.ScriptEngineFactory b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 00000000000..c0d757e3108 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1 @@ +org.pear.PearScriptEngineFactory diff --git a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScript.java b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScript.java new file mode 100644 index 00000000000..b8400c0c9b1 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScript.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.pear; + +import java.io.Reader; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class PearScript implements ScriptEngine { + + @Override + public Object eval(String script, ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script, Bindings n) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , Bindings n) { + throw new RuntimeException(); + } + @Override + public void put(String key, Object value) { + throw new RuntimeException(); + } + + @Override + public Object get(String key) { + throw new RuntimeException(); + } + + @Override + public Bindings getBindings(int scope) { + throw new RuntimeException(); + } + + @Override + public void setBindings(Bindings bindings, int scope) { + throw new RuntimeException(); + } + + @Override + public Bindings createBindings() { + throw new RuntimeException(); + } + + @Override + public ScriptContext getContext() { + throw new RuntimeException(); + } + + @Override + public void setContext(ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public ScriptEngineFactory getFactory() { + throw new RuntimeException(); + } +} diff --git a/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java new file mode 100644 index 00000000000..c00c4b16d04 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/pearscript/org/pear/PearScriptEngineFactory.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.pear; + +import java.util.Arrays; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class PearScriptEngineFactory implements ScriptEngineFactory { + + @Override + public String getEngineName() { + return "PearScriptEngine"; + } + + @Override + public String getEngineVersion() { + return "1.0"; + } + + @Override + public List getExtensions() { + return Arrays.asList("pear"); + } + + @Override + public List getMimeTypes() { + return Arrays.asList("application/x-pearscript"); + } + + @Override + public List getNames() { + return Arrays.asList("PearScript"); + } + + @Override + public String getLanguageName() { + return "PearScript"; + } + + @Override + public String getLanguageVersion() { + return "1.0"; + } + + @Override + public Object getParameter(String key) { + return null; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + throw new RuntimeException(); + } + + @Override + public String getOutputStatement(String toDisplay) { + throw new RuntimeException(); + } + + @Override + public String getProgram(String... statements) { + throw new RuntimeException(); + } + + @Override + public ScriptEngine getScriptEngine() { + return new PearScript(); + } +} diff --git a/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java b/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java new file mode 100644 index 00000000000..a43887ccd04 --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/test/module-info.java @@ -0,0 +1,29 @@ +/* + * 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. + */ + +module test { + requires java.scripting; + + uses javax.script.ScriptEngineFactory; +} + diff --git a/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java b/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java new file mode 100644 index 00000000000..a03d8eb2c7e --- /dev/null +++ b/jdk/test/java/util/ServiceLoader/modules/src/test/test/Main.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package test; + +import java.util.HashSet; +import java.util.ServiceLoader; +import java.util.Set; +import javax.script.ScriptEngineFactory; + +public class Main { + public static void main(String[] args) { + Set engines = new HashSet<>(); + for (ScriptEngineFactory factory: ServiceLoader.load(ScriptEngineFactory.class)) { + System.out.format("loaded: %s%n" , factory.getEngineName()); + engines.add(factory.getEngineName()); + } + + for (String engine: args) { + if (!engines.contains(engine)) + throw new RuntimeException(engine + " not found"); + } + } +} diff --git a/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java b/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java index e6180e34b61..dc961b15e5a 100644 --- a/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java +++ b/jdk/test/java/util/Spliterator/SpliteratorLateBindingFailFastTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 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 @@ -52,6 +52,7 @@ import static org.testng.Assert.*; /** * @test + * @bug 8148748 * @summary Spliterator last-binding and fail-fast tests * @run testng SpliteratorLateBindingFailFastTest */ @@ -120,8 +121,8 @@ public class SpliteratorLateBindingFailFastTest { } void addList(Function, ? extends List> l) { - // @@@ If collection is instance of List then add sub-list tests addCollection(l); + addCollection(l.andThen(list -> list.subList(0, list.size()))); } void addMap(Function, ? extends Map> mapConstructor) { diff --git a/jdk/test/java/util/TimeZone/Bug6772689.java b/jdk/test/java/util/TimeZone/Bug6772689.java index f730567013d..a1ce49682b4 100644 --- a/jdk/test/java/util/TimeZone/Bug6772689.java +++ b/jdk/test/java/util/TimeZone/Bug6772689.java @@ -24,6 +24,7 @@ /* * @test * @bug 6772689 + * @key intermittent * @summary Test for standard-to-daylight transitions at midnight: * date stays on the given day. */ diff --git a/jdk/test/java/util/logging/LocalizedLevelName.java b/jdk/test/java/util/logging/LocalizedLevelName.java index cdb425a294f..561e2d17b75 100644 --- a/jdk/test/java/util/logging/LocalizedLevelName.java +++ b/jdk/test/java/util/logging/LocalizedLevelName.java @@ -21,6 +21,7 @@ * questions. */ +import java.lang.reflect.Module; import java.util.*; import java.util.logging.*; @@ -97,7 +98,10 @@ public class LocalizedLevelName { private static final String RBNAME = "sun.util.logging.resources.logging"; private static String getLocalizedMessage(Locale locale, String key) { - ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale); + // this test verifies if the logging.properties in the java.logging module + // is localized. + Module module = java.util.logging.Level.class.getModule(); + ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale, module); return rb.getString(key); } } diff --git a/jdk/test/java/util/logging/modules/GetResourceBundleTest.java b/jdk/test/java/util/logging/modules/GetResourceBundleTest.java new file mode 100644 index 00000000000..c049613e552 --- /dev/null +++ b/jdk/test/java/util/logging/modules/GetResourceBundleTest.java @@ -0,0 +1,109 @@ +/* + * 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.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import static jdk.testlibrary.ProcessTools.*; +import static org.testng.Assert.*; + +/** + * @test + * @bug 8129126 8136802 8137316 8137317 8136804 8139350 + * @library /lib/testlibrary + * @modules jdk.compiler + * @build GetResourceBundleTest CompilerUtils jdk.testlibrary.ProcessTools + * @run testng GetResourceBundleTest + * @summary Tests Logger.getLogger + logger.getResourceBundle in an named/unnamed module, + * resources are in named and unnamed modules respectively. + * Positive tests to ensure that a Logger can retrieve ResourceBundle in its current module. + * Negative tests to ensure that a Logger cannot retrieve ResourceBundle in another module. + * This test also verifies 8136802 8137316 8137317 8136804 8139350. + */ + +public class GetResourceBundleTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path MOD_SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MOD_DEST_DIR = Paths.get("mods"); + private static final Path PKG_SRC_DIR = Paths.get(TEST_SRC, "pkgs"); + private static final Path PKG_DEST_DIR = Paths.get("pkgs"); + + private static final String[] modules = new String[] {"m1", "m2"}; + + /** + * Compiles all modules used by the test, copy resource files. + */ + @BeforeClass + public void setup() throws Exception { + // compile all modules + for (String mn : modules) { + Path msrc = MOD_SRC_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(msrc, MOD_DEST_DIR, + "-modulesourcepath", MOD_SRC_DIR.toString())); + } + assertTrue(CompilerUtils.compile(PKG_SRC_DIR, PKG_DEST_DIR, + "-modulepath", MOD_DEST_DIR.toString(), "-addmods", String.join(",", modules))); + + // copy resource files + String[] files = { "m1/p1/resource/p.properties", "m2/p2/resource/p.properties" }; + for(String f : files) { + Files.copy(MOD_SRC_DIR.resolve(f), MOD_DEST_DIR.resolve(f), REPLACE_EXISTING); + } + String p3 = "p3/resource/p.properties"; + Files.copy(PKG_SRC_DIR.resolve(p3), PKG_DEST_DIR.resolve(p3), REPLACE_EXISTING); + } + + @Test + public void runWithoutSecurityManager() throws Exception { + int exitValue = executeTestJava( + "-cp", PKG_DEST_DIR.toString(), + "-mp", MOD_DEST_DIR.toString(), + "-addmods", String.join(",", modules), + "p3.test.ResourceBundleTest") + .outputTo(System.out) + .errorTo(System.err) + .getExitValue(); + assertTrue(exitValue == 0); + } + + @Test + public void runWithSecurityManager() throws Exception { + int exitValue = executeTestJava( + "-Djava.security.manager", + "-cp", PKG_DEST_DIR.toString(), + "-mp", MOD_DEST_DIR.toString(), + "-addmods", String.join(",", modules), + "p3.test.ResourceBundleTest") + .outputTo(System.out) + .errorTo(System.err) + .getExitValue(); + assertTrue(exitValue == 0); + } +} diff --git a/jdk/test/java/util/logging/modules/pkgs/p3/resource/ClassResource.java b/jdk/test/java/util/logging/modules/pkgs/p3/resource/ClassResource.java new file mode 100644 index 00000000000..2cdb7271b1a --- /dev/null +++ b/jdk/test/java/util/logging/modules/pkgs/p3/resource/ClassResource.java @@ -0,0 +1,35 @@ +/* + * 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 p3.resource; + +import java.util.ListResourceBundle; + +public class ClassResource extends ListResourceBundle { + + protected Object[][] getContents() { + return new Object[][] { + { "OkKey", "OK" }, + { "CancelKey", "Cancel" }, }; + } +} diff --git a/jdk/test/java/util/logging/modules/pkgs/p3/resource/p.properties b/jdk/test/java/util/logging/modules/pkgs/p3/resource/p.properties new file mode 100644 index 00000000000..f1861bc9aad --- /dev/null +++ b/jdk/test/java/util/logging/modules/pkgs/p3/resource/p.properties @@ -0,0 +1 @@ +OkKey=OK diff --git a/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java new file mode 100644 index 00000000000..2989a785505 --- /dev/null +++ b/jdk/test/java/util/logging/modules/pkgs/p3/test/ResourceBundleTest.java @@ -0,0 +1,186 @@ +/* + * 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 p3.test; + +import java.lang.reflect.Module; +import java.util.logging.Logger; +import java.util.MissingResourceException; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +import p2.test.ModuleLoggerAccess; + +/* + * Test Logger.getLogger + logger.getResourceBundle in unnamed/named module, + * resources are in named and unnamed modules respectively. + */ +public class ResourceBundleTest { + private static final String RESOURCE_KEY = "OkKey"; + private static final String RESOURCE_VALUE = "OK"; + + private static final String HELP_MSG = + "Test that a class in a %s module %s obtain a logger " + + "which uses a resource bundle %s bundled in " + + "%s module. ( The package in which the resource is " + + "contained is not exported by the module )"; + private static final String NAMED_POSITIVE_CLASSBUNDLE_MSG = + String.format(HELP_MSG, "named", "can", "class", "the same"); + private static final String UNNAMED_POSITIVE_CLASSBUNDLE_MSG = + String.format(HELP_MSG, "unnamed", "can", "class", "the same"); + private static final String NAMED_POSITIVE_PROPERTYBUNDLE_MSG = + String.format(HELP_MSG, "named", "can", "property", "the same"); + private static final String UNNAMED_POSITIVE_PROPERTYBUNDLE_MSG = + String.format(HELP_MSG, "unnamed", "can", "property", "the same"); + private static final String NAMED_NEGATIVE_CLASSBUNDLE_MSG = + String.format(HELP_MSG, "named", "cannot", "class", "another"); + private static final String UNNAMED_NEGATIVE_CLASSBUNDLE_MSG = + String.format(HELP_MSG, "unnamed", "cannot", "class", "another"); + private static final String NAMED_NEGATIVE_PROPERTYBUNDLE_MSG = + String.format(HELP_MSG, "named", "cannot", "property", "another"); + private static final String UNNAMED_NEGATIVE_PROPERTYBUNDLE_MSG = + String.format(HELP_MSG, "unnamed", "cannot", "property", "another"); + + public static void main(String[] args) { + verifySetup(); + testLoggerRBs(); + failToLoadRBs(); + } + + static void verifySetup() { + Module m = ResourceBundleTest.class.getModule(); + System.out.println("Module Name for ResourceBundleTest : " + m.getName()); + assertTrue(!m.isNamed()); + m = ModuleLoggerAccess.class.getModule(); + System.out.println("Module Name for ModuleLoggerAccess : " + m.getName()); + assertTrue(m.isNamed()); + } + + /* + * Positive tests : + * Should be able to access class/property resource bundle in current module, + * no matter named or unnamed module. + */ + static void testLoggerRBs() { + testLoggerClassRBs(); + testLoggerPropertyRBs(); + } + + static void testLoggerClassRBs() { + testLoggerResoureBundle( + Logger.getLogger("mylogger.a", "p3.resource.ClassResource"), + p3.resource.ClassResource.class, + UNNAMED_POSITIVE_CLASSBUNDLE_MSG); + testLoggerResoureBundle( + ModuleLoggerAccess.getLogger("mylogger.b", "p2.resource.ClassResource"), + ModuleLoggerAccess.getResourceClass(), + NAMED_POSITIVE_CLASSBUNDLE_MSG); + } + + static void testLoggerPropertyRBs() { + testLoggerResoureBundle( + Logger.getLogger("mylogger.c", "p3.resource.p"), + PropertyResourceBundle.class, + UNNAMED_POSITIVE_PROPERTYBUNDLE_MSG); + testLoggerResoureBundle( + ModuleLoggerAccess.getLogger("mylogger.d", "p2.resource.p"), + PropertyResourceBundle.class, + NAMED_POSITIVE_PROPERTYBUNDLE_MSG); + } + + static void testLoggerResoureBundle(Logger logger, Class rbType, String helpMsg) { + System.out.println(helpMsg); + ResourceBundle rb = logger.getResourceBundle(); + assertTrue(rbType.isInstance(rb)); + assertTrue(RESOURCE_VALUE.equals(rb.getString(RESOURCE_KEY))); + } + + /* + * Negative tests : + * MissingResourceException should be thrown when access class/property resource bundle + * from another module, no matter named or unnamed module. + */ + static void failToLoadRBs() { + failToLoadClassRBs(); + failToLoadPropertyRBs(); + } + + static void failToLoadClassRBs() { + // in an unnamed module, try to create a logger with + // class resource bundle in named module m1 or m2. + failToLoadResourceBundle("mylogger.e", "p1.resource.ClassResource", + false, UNNAMED_NEGATIVE_CLASSBUNDLE_MSG); + failToLoadResourceBundle("mylogger.f", "p2.resource.ClassResource", + false, UNNAMED_NEGATIVE_CLASSBUNDLE_MSG); + // in named module m2, try to create a logger with + // class resource bundle in another named module m1. + failToLoadResourceBundle("mylogger.g", "p1.resource.ClassResource", + true, NAMED_NEGATIVE_CLASSBUNDLE_MSG); + // in named module m2, try to create a logger with + // class resource bundle in an unnamed module. + failToLoadResourceBundle("mylogger.h", "p3.resource.ClassResource", + true, NAMED_NEGATIVE_CLASSBUNDLE_MSG); + } + + static void failToLoadPropertyRBs() { + // in an unnamed module, try to create a logger with + // property resource bundle in named module m1 or m2. + failToLoadResourceBundle("mylogger.i", "p1.resource.p", + false, UNNAMED_NEGATIVE_PROPERTYBUNDLE_MSG); + failToLoadResourceBundle("mylogger.j", "p2.resource.p", + false, UNNAMED_NEGATIVE_PROPERTYBUNDLE_MSG); + // in named module m2, try to create a logger with + // property resource bundle in another named module m1. + failToLoadResourceBundle("mylogger.k", "p1.resource.p", + true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG); + // in named module m2, try to create a logger with + // property resource bundle in an unnamed module. + failToLoadResourceBundle("mylogger.l", "p3.resource.p", + true, NAMED_NEGATIVE_PROPERTYBUNDLE_MSG); + } + + static void failToLoadResourceBundle(String loggerName, String rbName, + boolean getLoggerInNamedModule, String helpMsg) { + String msg = String.format( + "Logger : %s. Expected exception is not thrown for ResourceBundle : %s.", + loggerName, rbName); + System.out.println(helpMsg); + try { + if(getLoggerInNamedModule) { + ModuleLoggerAccess.getLogger(loggerName, rbName); + } else { + Logger.getLogger(loggerName, rbName); + } + throw new RuntimeException(msg); + } catch (MissingResourceException expected) { + System.out.println("Get expected exception : " + expected); + return; + } + } + + public static void assertTrue(boolean b) { + if (!b) { + throw new RuntimeException("Expect true, get false!"); + } + } +} diff --git a/jdk/test/java/util/logging/modules/src/m1/module-info.java b/jdk/test/java/util/logging/modules/src/m1/module-info.java new file mode 100644 index 00000000000..a6e576f7b76 --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m1 { + requires java.logging; +} diff --git a/jdk/test/java/util/logging/modules/src/m1/p1/resource/ClassResource.java b/jdk/test/java/util/logging/modules/src/m1/p1/resource/ClassResource.java new file mode 100644 index 00000000000..227ff3d7efb --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m1/p1/resource/ClassResource.java @@ -0,0 +1,35 @@ +/* + * 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.resource; + +import java.util.ListResourceBundle; + +public class ClassResource extends ListResourceBundle { + + protected Object[][] getContents() { + return new Object[][] { + { "OkKey", "OK" }, + { "CancelKey", "Cancel" }, }; + } +} diff --git a/jdk/test/java/util/logging/modules/src/m1/p1/resource/p.properties b/jdk/test/java/util/logging/modules/src/m1/p1/resource/p.properties new file mode 100644 index 00000000000..f1861bc9aad --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m1/p1/resource/p.properties @@ -0,0 +1 @@ +OkKey=OK diff --git a/jdk/test/java/util/logging/modules/src/m2/module-info.java b/jdk/test/java/util/logging/modules/src/m2/module-info.java new file mode 100644 index 00000000000..a2f3c669bef --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m2/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module m2 { + requires m1; + requires java.logging; + exports p2.test; +} diff --git a/jdk/test/java/util/logging/modules/src/m2/p2/resource/ClassResource.java b/jdk/test/java/util/logging/modules/src/m2/p2/resource/ClassResource.java new file mode 100644 index 00000000000..09bd51641d1 --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m2/p2/resource/ClassResource.java @@ -0,0 +1,34 @@ +/* + * 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 p2.resource; + +import java.util.ListResourceBundle; + +public class ClassResource extends ListResourceBundle { + protected Object[][] getContents() { + return new Object[][] { + { "OkKey", "OK" }, + { "CancelKey", "Cancel" }, }; + } +} diff --git a/jdk/test/java/util/logging/modules/src/m2/p2/resource/p.properties b/jdk/test/java/util/logging/modules/src/m2/p2/resource/p.properties new file mode 100644 index 00000000000..f1861bc9aad --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m2/p2/resource/p.properties @@ -0,0 +1 @@ +OkKey=OK diff --git a/jdk/test/java/util/logging/modules/src/m2/p2/test/ModuleLoggerAccess.java b/jdk/test/java/util/logging/modules/src/m2/p2/test/ModuleLoggerAccess.java new file mode 100644 index 00000000000..4d322e0ea5f --- /dev/null +++ b/jdk/test/java/util/logging/modules/src/m2/p2/test/ModuleLoggerAccess.java @@ -0,0 +1,41 @@ +/* + * 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 p2.test; + +import java.util.logging.Logger; + +/* + * Logger in this named module m2 loading a resource bundle + * in m2, m1 or unnamed module. + */ +public class ModuleLoggerAccess { + + public static Logger getLogger(String loggerName, String rbName) { + return Logger.getLogger(loggerName, rbName); + } + + public static Class getResourceClass() { + return p2.resource.ClassResource.class; + } +} diff --git a/jdk/test/java/util/regex/PatternStreamTest.java b/jdk/test/java/util/regex/PatternStreamTest.java index 1ac3bfd23e8..1f02e410321 100644 --- a/jdk/test/java/util/regex/PatternStreamTest.java +++ b/jdk/test/java/util/regex/PatternStreamTest.java @@ -25,8 +25,8 @@ * @test * @bug 8016846 8024341 8071479 8145006 * @summary Unit tests stream and lambda-based methods on Pattern and Matcher - * @library ../stream/bootlib/java.base - * @build java.util.stream.OpTestCase + * @library ../stream/bootlib + * @build java.base/java.util.stream.OpTestCase * @run testng/othervm PatternStreamTest */ diff --git a/jdk/test/java/util/stream/bootlib/TEST.properties b/jdk/test/java/util/stream/bootlib/TEST.properties deleted file mode 100644 index 317080b0b37..00000000000 --- a/jdk/test/java/util/stream/bootlib/TEST.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file identifies root(s) of the test-ng hierarchy. - -bootclasspath.dirs = java.base diff --git a/jdk/test/java/util/stream/boottest/TEST.properties b/jdk/test/java/util/stream/boottest/TEST.properties index 980a89fecc8..3c930e3afa3 100644 --- a/jdk/test/java/util/stream/boottest/TEST.properties +++ b/jdk/test/java/util/stream/boottest/TEST.properties @@ -1,5 +1,4 @@ # This file identifies root(s) of the test-ng hierarchy. -TestNG.dirs = java.base -bootclasspath.dirs = java.base -lib.dirs = /java/util/stream/bootlib/java.base +TestNG.dirs = . +lib.dirs = /java/util/stream/bootlib diff --git a/jdk/test/java/util/stream/test/TEST.properties b/jdk/test/java/util/stream/test/TEST.properties index 706ed7c570e..4128f6afd75 100644 --- a/jdk/test/java/util/stream/test/TEST.properties +++ b/jdk/test/java/util/stream/test/TEST.properties @@ -2,7 +2,7 @@ TestNG.dirs = . -lib.dirs = /java/util/stream/bootlib/java.base +lib.dirs = /java/util/stream/bootlib # Tests that must run in othervm mode othervm.dirs= /java/util/stream diff --git a/jdk/test/javax/crypto/NullCipher/TestWithoutInit.java b/jdk/test/javax/crypto/NullCipher/TestWithoutInit.java index 6039d09ac44..a3fbf7707cd 100644 --- a/jdk/test/javax/crypto/NullCipher/TestWithoutInit.java +++ b/jdk/test/javax/crypto/NullCipher/TestWithoutInit.java @@ -34,7 +34,6 @@ import java.security.spec.*; import javax.crypto.*; import javax.crypto.spec.*; -import com.sun.crypto.provider.*; public class TestWithoutInit { diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh b/jdk/test/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh new file mode 100644 index 00000000000..196189a0c42 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/TestClassPathPlugin.sh @@ -0,0 +1,107 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @bug 8081729 +# @summary Test external plugin as classpath jar and as a modular jar. +# Test both cases with and without a security manager. + +set -e + +exception=0 + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then echo "No Java path specified. Exiting."; fi + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAR="$COMPILEJAVA/bin/jar" +JAVA="$TESTJAVA/bin/java ${TESTVMOPTS}" + +TESTDIR="$TESTCLASSES/classes" +PLUGINDIR="$TESTCLASSES/classes" +mkdir -p $TESTDIR +$JAVAC -d $TESTDIR `find $TESTSRC/src/simptest -name "*.java"` + +# compile the plugin java sources and services file into a temp location. + +mkdir -p $TESTCLASSES/tmpdir/simp +cp -r $TESTSRC/src/simp/META-INF $TESTCLASSES/tmpdir +$JAVAC -d $TESTCLASSES/tmpdir `find $TESTSRC/src/simp -name "*.java"` + +# create modular jar file (inc. module-info.java) from the class files. +mkdir -p $PLUGINDIR +$JAR cf $PLUGINDIR/simp.jar -C $TESTCLASSES/tmpdir META-INF/services \ + -C $TESTCLASSES/tmpdir module-info.class -C $TESTCLASSES/tmpdir simp + +OS=`uname -s` +case "$OS" in + Windows_* | CYGWIN* ) +CPSEP=";" + ;; + * ) +CPSEP=":" + ;; +esac + +# expect to find SimpReader via jar on classpath. +# Will be treated as a regular jar. +echo "Test classpath jar .. " +$JAVA -cp ${TESTDIR}${CPSEP}${PLUGINDIR}/simp.jar simptest.TestSIMPPlugin +if [ $? -ne 0 ]; then + exception=1 + echo "Classpath test failed: exception thrown!" +fi +echo "Test classpath jar with security manager .." +$JAVA -Djava.security.manager -cp .${CPSEP}${TESTDIR}${CPSEP}${PLUGINDIR}/simp.jar simptest.TestSIMPPlugin +if [ $? -ne 0 ]; then + exception=1 + echo "Classpath + SecurityManager test failed: exception thrown!" +fi + +# expect to find SimpReader on module path +echo "Test modular jar .. " +$JAVA -mp $PLUGINDIR -cp $TESTDIR simptest.TestSIMPPlugin + +if [ $? -ne 0 ]; then + exception=1 + echo "modular jar test failed: exception thrown!" +fi + +echo "Test modular jar with security manager .." +$JAVA -Djava.security.manager -mp $PLUGINDIR -cp $TESTDIR simptest.TestSIMPPlugin +if [ $? -ne 0 ]; then + exception=1 + echo "modular jar with security manager test failed: exception thrown!" +fi + +if [ $exception -ne 0 ]; then + echo "TEST FAILED" + exit 1 +fi +exit 0 diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/META-INF/services/javax.imageio.spi.ImageReaderSpi b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/META-INF/services/javax.imageio.spi.ImageReaderSpi new file mode 100644 index 00000000000..c0a0b0f8992 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/META-INF/services/javax.imageio.spi.ImageReaderSpi @@ -0,0 +1 @@ +simp.SIMPImageReaderSpi diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReader.java b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReader.java new file mode 100644 index 00000000000..8118272aa78 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPImageReader.java @@ -0,0 +1,145 @@ +/** + * 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 simp; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import javax.imageio.IIOException; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; + +/** + * A simple image format which has no compression and is a + * header with bytes 'SIMP', two signed bytes for width and height, + * and then unpadded 3 byte per pixel data representing RGB assumed + * to be in sRGB. The signed byte implies a maximum size of 127x127 pixels. + * Trailing data is ignored but there must be at least + * 3*width*height bytes of data following the simple 6 byte header. + */ +public class SIMPImageReader extends ImageReader { + + private ImageInputStream stream = null; + private byte width = -1, height = -1; + SIMPMetadata metadata = null; + byte[] imageData = null; + + public SIMPImageReader(ImageReaderSpi originatingProvider) { + super(originatingProvider); + } + + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) { + super.setInput(input, seekForwardOnly, ignoreMetadata); + stream = (ImageInputStream) input; + } + + private void checkState(int imageIndex) throws IOException { + if (stream == null) { + throw new IllegalStateException("input not set."); + } + if (imageIndex != 0) { + throw new IndexOutOfBoundsException("index != 0"); + } + if (width==-1) { + byte[] sig = new byte[4]; + stream.reset(); + stream.read(sig); + boolean ok = sig[0]=='S' && sig[1]=='I' && + sig[2]=='M' && sig[3]=='P'; + if (!ok) { + throw new IIOException("Not a SIMP image"); + } + width = stream.readByte(); + height = stream.readByte(); + } + if (width <= 0 || height <= 0) { + throw new IOException("bad image size"); + } + metadata = new SIMPMetadata(width, height); + } + + public int getWidth(int imageIndex) throws IOException { + checkState(imageIndex); + return width; + } + + public int getHeight(int imageIndex) throws IOException { + checkState(imageIndex); + return height; + } + + public int getNumImages(boolean allowSearch) throws IOException { + checkState(0); + return 1; + } + + public IIOMetadata getStreamMetadata() throws IOException { + return null; + } + + public IIOMetadata getImageMetadata(int imageIndex) throws IOException { + checkState(imageIndex); + return metadata; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException { + + checkState(imageIndex); + BufferedImage bi = + new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + ArrayList list = new ArrayList<>(1); + list.add(new ImageTypeSpecifier(bi)); + return list.iterator(); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException { + checkState(imageIndex); + int len = 3*width*height; + byte[] imageData = new byte[len]; + // The following is not efficient and is skipping all the + // progress updates, and ignoring the ImageReadParam, which + // it should not, but it is all we need for this test. + stream.readFully(imageData, 0, len); + BufferedImage bi = + new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + int off = 0; + for (int h=0;h[] { ImageInputStream.class }, // input types + null, // writer class names. TBD. + true, // supports native metadata, + null, // [no] native stream metadata format + null, // [no] native stream metadata class + null, // [no] native extra stream metadata format + null, // [no] native extra stream metadata class + true, // supports standard metadata, + "simp_metadata_1.0", // metadata format name, + "simp.SIMPMetadataFormat", // metadata format class name + null, // [no] extra image metadata format + null // [no] extra image metadata format class + ); + System.out.println("INIT SIMPImageReaderSpi"); + } + + public String getDescription(Locale locale) { + return "SIMPle Image Format Reader"; + } + + public boolean canDecodeInput(Object source) throws IOException { + if (!(source instanceof ImageInputStream)) { + return false; + } + ImageInputStream stream = (ImageInputStream)source; + + stream.mark(); + try { + byte[] sig = new byte[4]; + stream.read(sig); + return sig[0]=='S' && sig[1]=='I' && sig[2]=='M' && sig[3]=='P'; + } finally { + stream.reset(); + } + } + + public ImageReader createReaderInstance(Object extension) + throws IIOException { + return new SIMPImageReader(this); + } +} diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadata.java b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadata.java new file mode 100644 index 00000000000..a69f944e8bf --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadata.java @@ -0,0 +1,94 @@ +/** + * 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 simp; + +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataNode; +import javax.imageio.metadata.IIOMetadataFormatImpl; +import org.w3c.dom.Node; + +public class SIMPMetadata extends IIOMetadata { + + static final String nativeMetadataFormatName = "simp_metadata_1.0"; + + private int width, height; + + public SIMPMetadata() { + super(true, + nativeMetadataFormatName, "simp.SIMPMetadataFormat", null, null); + } + + public SIMPMetadata(int width, int height) { + this(); + this.width = width; + this.height = height; + } + + public boolean isReadOnly() { + return true; + } + + public void setFromTree(String formatName, Node root) { + } + + public void mergeTree(String formatName, Node root) { + throw new IllegalStateException("read only metadata"); + } + + public void reset() { + throw new IllegalStateException("read only metadata"); + } + + private IIOMetadataNode addChildNode(IIOMetadataNode root, + String name, + Object object) { + IIOMetadataNode child = new IIOMetadataNode(name); + if (object != null) { + child.setUserObject(object); + child.setNodeValue(object.toString()); + } + root.appendChild(child); + return child; + } + + private Node getNativeTree() { + IIOMetadataNode root = + new IIOMetadataNode(nativeMetadataFormatName); + addChildNode(root, "width", width); + addChildNode(root, "weight", height); + return root; + } + + public Node getAsTree(String formatName) { + if (formatName.equals(nativeMetadataFormatName)) { + return getNativeTree(); + } else if (formatName.equals + (IIOMetadataFormatImpl.standardMetadataFormatName)) { + return getStandardTree(); + } else { + throw new IllegalArgumentException("unsupported format"); + } + } +} + diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadataFormat.java b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadataFormat.java new file mode 100644 index 00000000000..56e7e8b516b --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/SIMPMetadataFormat.java @@ -0,0 +1,62 @@ +/** + * 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 simp; + +import java.util.Arrays; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.metadata.IIOMetadataFormat; +import javax.imageio.metadata.IIOMetadataFormatImpl; + +public class SIMPMetadataFormat extends IIOMetadataFormatImpl { + + private static IIOMetadataFormat instance = null; + + public static synchronized IIOMetadataFormat getInstance() { + if (instance == null) { + instance = new SIMPMetadataFormat(); + } + return instance; + } + + public boolean canNodeAppear(String elementName, + ImageTypeSpecifier imageType) { + return true; + } + + private SIMPMetadataFormat() { + super(SIMPMetadata.nativeMetadataFormatName, + CHILD_POLICY_SOME); + + addElement("ImageDescriptor", + SIMPMetadata.nativeMetadataFormatName, + CHILD_POLICY_EMPTY); + + addAttribute("ImageDescriptor", "width", + DATATYPE_INTEGER, true, null, + "1", "127", true, true); + addAttribute("ImageDescriptor", "height", + DATATYPE_INTEGER, true, null, + "1", "127", true, true); + } +} diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/module-info.java b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/module-info.java new file mode 100644 index 00000000000..aac3c899610 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simp/module-info.java @@ -0,0 +1,28 @@ +/** + * 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. + */ + +module simp { + requires java.desktop; + exports simp to java.desktop; + provides javax.imageio.spi.ImageReaderSpi with simp.SIMPImageReaderSpi; +} diff --git a/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simptest/TestSIMPPlugin.java b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simptest/TestSIMPPlugin.java new file mode 100644 index 00000000000..a572bbbca63 --- /dev/null +++ b/jdk/test/javax/imageio/plugins/external_plugin_tests/src/simptest/TestSIMPPlugin.java @@ -0,0 +1,73 @@ +/** + * 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 simptest; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Iterator; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.metadata.IIOMetadataFormat; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; + +public class TestSIMPPlugin { + + static byte[] simpData = { (byte)'S', (byte)'I', (byte)'M', (byte)'P', + 1, 1, 0, 0, 0}; + + public static void main(String args[]) throws Exception { + Iterator readers = ImageIO.getImageReadersBySuffix("simp"); + ImageReader simpReader = null; + if (readers.hasNext()) { + simpReader = readers.next(); + System.out.println("reader="+simpReader); + } + if (simpReader == null) { + throw new RuntimeException("Reader not found."); + } + + ImageReaderSpi spi = simpReader.getOriginatingProvider(); + IIOMetadataFormat spiFmt = + spi.getImageMetadataFormat("simp_metadata_1.0"); + System.out.println("fmt from SPI=" + spiFmt); + + ByteArrayInputStream bais = new ByteArrayInputStream(simpData); + ImageInputStream iis = new MemoryCacheImageInputStream(bais); + simpReader.setInput(iis); + BufferedImage bi = simpReader.read(0); + System.out.println(bi); + IIOMetadata metadata = simpReader.getImageMetadata(0); + System.out.println("Image metadata="+metadata); + IIOMetadataFormat format = + metadata.getMetadataFormat("simp_metadata_1.0"); + System.out.println("Image metadata format="+format); + if (format == null) { + throw new RuntimeException("MetadataFormat not found."); + } + } +} diff --git a/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh index f725cd74932..071550eed45 100644 --- a/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh +++ b/jdk/test/javax/imageio/stream/StreamCloserLeak/run_test.sh @@ -198,15 +198,15 @@ if [ $? -ne 0 ] ; then fail "Unable to create temp directory." fi -# Verify that all classoladers are destroyed -${TESTJAVA}/bin/java ${TESTVMOPTS} -cp Test.jar test.Main +# Verify that all classloaders are destroyed +${TESTJAVA}/bin/java -XaddExports:java.desktop/sun.awt=ALL-UNNAMED ${TESTVMOPTS} -cp Test.jar test.Main if [ $? -ne 0 ] ; then fail "Test FAILED: some classloaders weren't destroyed." fi # Verify that ImageIO shutdown hook works correcly -${TESTJAVA}/bin/java ${TESTVMOPTS} \ +${TESTJAVA}/bin/java -XaddExports:java.desktop/sun.awt=ALL-UNNAMED ${TESTVMOPTS} \ -cp Test.jar -DforgetSomeStreams=true test.Main if [ $? -ne 0 ] ; then fail "Test FAILED: some classloaders weren't destroyed of shutdown hook failed." diff --git a/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java b/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java index efcef234290..0e375aea52a 100644 --- a/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java +++ b/jdk/test/javax/management/MBeanInfo/NotificationInfoTest.java @@ -37,8 +37,13 @@ import java.io.*; import java.lang.management.*; import java.lang.reflect.*; import java.net.*; +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.*; -import java.util.jar.*; +import java.util.stream.Collectors; import javax.management.*; import javax.management.relation.*; import javax.management.remote.*; @@ -83,9 +88,13 @@ public class NotificationInfoTest { System.out.println("Checking platform MBeans..."); checkPlatformMBeans(); - URL codeBase = ClassLoader.getSystemResource("javax/management/MBeanServer.class"); - if (codeBase == null) { - throw new Exception("Could not determine codeBase for " + MBeanServer.class); + URL codeBase; + String home = System.getProperty("java.home"); + Path classFile = Paths.get(home, "modules", "java.management"); + if (Files.isDirectory(classFile)) { + codeBase = classFile.toUri().toURL(); + } else { + codeBase = URI.create("jrt:/java.management").toURL(); } System.out.println(); @@ -214,14 +223,13 @@ public class NotificationInfoTest { System.out.println(); } - private static String[] findStandardMBeans(URL codeBase) - throws Exception { + private static String[] findStandardMBeans(URL codeBase) throws Exception { Set names; - if (codeBase.getProtocol().equalsIgnoreCase("file") - && codeBase.toString().endsWith("/")) + if (codeBase.getProtocol().equalsIgnoreCase("jrt")) { + names = findStandardMBeansFromRuntime(); + } else { names = findStandardMBeansFromDir(codeBase); - else - names = findStandardMBeansFromJar(codeBase); + } Set standardMBeanNames = new TreeSet(); for (String name : names) { @@ -234,21 +242,17 @@ public class NotificationInfoTest { return standardMBeanNames.toArray(new String[0]); } - private static Set findStandardMBeansFromJar(URL codeBase) - throws Exception { - InputStream is = codeBase.openStream(); - JarInputStream jis = new JarInputStream(is); - Set names = new TreeSet(); - JarEntry entry; - while ((entry = jis.getNextJarEntry()) != null) { - String name = entry.getName(); - if (!name.endsWith(".class")) - continue; - name = name.substring(0, name.length() - 6); - name = name.replace('/', '.'); - names.add(name); - } - return names; + private static Set findStandardMBeansFromRuntime() throws Exception { + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path modules = fs.getPath("/modules"); + return Files.walk(modules) + .filter(path -> path.toString().endsWith(".class")) + .map(path -> path.subpath(2, path.getNameCount())) + .map(Path::toString) + .map(s -> s.substring(0, s.length() - 6)) // drop .class + .filter(s -> !s.equals("module-info")) + .map(s -> s.replace('/', '.')) + .collect(Collectors.toSet()); } private static Set findStandardMBeansFromDir(URL codeBase) diff --git a/jdk/test/javax/naming/module/basic.sh b/jdk/test/javax/naming/module/basic.sh new file mode 100644 index 00000000000..b48fefb4daa --- /dev/null +++ b/jdk/test/javax/naming/module/basic.sh @@ -0,0 +1,104 @@ +# +# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# @test +# @summary Test of JNDI factories using classes exported by third-party modules. + +# Demonstrates Java object storage/retrieval, LDAP control and URL context +# usage using an LDAP directory. The objects and their associated object +# factories, state factories, control factories and URL context factories +# are exported from third-party modules. +# +# Seven types of object are used: +# - an AWT object (Serializable) from the 'java.desktop' JDK module +# - a Person object (DirContext) from the 'person' third-party module +# - a Fruit object (Referenceable) from the 'fruit' third-party module +# - an RMI object (Remote) from the 'hello' third-party module +# - an LDAP request control (Control) from the 'foo' third-party module +# - an LDAP response control (Control) from the 'authz' third-party module +# - an ldapv4 URL (DirContext) from the 'ldapv4' third-party module +# + +set -e + +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift + COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" +fi + +JAVAC="$COMPILEJAVA/bin/javac" +JAVA="$TESTJAVA/bin/java" + +echo "\nPreparing the 'person' module..." +mkdir -p mods/person +$JAVAC -d mods/person `find $TESTSRC/src/person -name "*.java"` + +echo "\nPreparing the 'fruit' module..." +mkdir -p mods/fruit +$JAVAC -d mods/fruit `find $TESTSRC/src/fruit -name "*.java"` + +echo "\nPreparing the 'hello' module..." +mkdir -p mods/hello +$JAVAC -d mods/hello `find $TESTSRC/src/hello -name "*.java"` + +echo "\nPreparing the 'foo' module..." +mkdir -p mods/foo +$JAVAC -d mods/foo `find $TESTSRC/src/foo -name "*.java"` + +echo "\nPreparing the 'authz' module..." +mkdir -p mods/authz +$JAVAC -d mods/authz `find $TESTSRC/src/authz -name "*.java"` + +echo "\nPreparing the 'ldapv4' module..." +mkdir -p mods/ldapv4 +$JAVAC -d mods/ldapv4 `find $TESTSRC/src/ldapv4 -name "*.java"` + +echo "\nPreparing the 'test' module..." +mkdir -p mods/test +$JAVAC -d mods -modulesourcepath $TESTSRC/src `find $TESTSRC/src/test -name "*.java"` + + +echo "\nRunning with the 'java.desktop' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StoreObject ldap://localhost/dc=ie,dc=oracle,dc=com + +echo "\nRunning with the 'person' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StorePerson ldap://localhost/dc=ie,dc=oracle,dc=com + +echo "\nRunning with the 'fruit' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StoreFruit ldap://localhost/dc=ie,dc=oracle,dc=com + +echo "\nRunning with the 'hello' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.StoreRemote ldap://localhost/dc=ie,dc=oracle,dc=com + +echo "\nRunning with the 'foo' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.ConnectWithFoo ldap://localhost/dc=ie,dc=oracle,dc=com + +echo "\nRunning with the 'authz' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.ConnectWithAuthzId ldap://localhost/dc=ie,dc=oracle,dc=com + +echo "\nRunning with the 'ldapv4' module..." +$JAVA -Dtest.src=${TESTSRC} -mp mods -m test/test.ReadByUrl ldap://localhost/dc=ie,dc=oracle,dc=com + diff --git a/jdk/test/javax/naming/module/src/authz/module-info.java b/jdk/test/javax/naming/module/src/authz/module-info.java new file mode 100644 index 00000000000..982c5a94091 --- /dev/null +++ b/jdk/test/javax/naming/module/src/authz/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module authz { + requires java.naming; + exports org.example.authz; +} + diff --git a/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdRequestControl.java b/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdRequestControl.java new file mode 100644 index 00000000000..cd0c518d36b --- /dev/null +++ b/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdRequestControl.java @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/** + * This class implements the LDAPv3 Authorization Identity request control + * as defined in + * RFC 3829. + */ + +package org.example.authz; + +import javax.naming.ldap.*; + +public class AuthzIdRequestControl extends BasicControl { + + public static final String OID = "2.16.840.1.113730.3.4.16"; + + public AuthzIdRequestControl() { + super(OID, true, null); + } + + public AuthzIdRequestControl(boolean criticality) { + super(OID, criticality, null); + } +} diff --git a/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControl.java b/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControl.java new file mode 100644 index 00000000000..f38f916d3fe --- /dev/null +++ b/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControl.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/** + * This class implements the LDAPv3 Authorization Identity response control + * as defined in + * RFC 3829. + */ + +package org.example.authz; + +import java.io.*; +import javax.naming.ldap.*; + +public class AuthzIdResponseControl extends BasicControl { + + public static final String OID = "2.16.840.1.113730.3.4.15"; + + private String identity = null; + + public AuthzIdResponseControl(String id, boolean criticality, byte[] value) + throws IOException { + + super(id, criticality, value); + + // decode value + if (value != null && value.length > 0) { + identity = new String(value, "UTF8"); + } + } + + public String getIdentity() { + return identity; + } +} diff --git a/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControlFactory.java b/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControlFactory.java new file mode 100644 index 00000000000..865355a91e8 --- /dev/null +++ b/jdk/test/javax/naming/module/src/authz/org/example/authz/AuthzIdResponseControlFactory.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +/** + * This class constructs LDAPv3 Authorization Identity response controls. + */ + +package org.example.authz; + +import java.io.*; +import javax.naming.*; +import javax.naming.ldap.*; + +public class AuthzIdResponseControlFactory extends ControlFactory { + + public AuthzIdResponseControlFactory() { + } + + public Control getControlInstance(Control control) throws NamingException { + String id = control.getID(); + + try { + if (id.equals(AuthzIdResponseControl.OID)) { + return new AuthzIdResponseControl(id, control.isCritical(), + control.getEncodedValue()); + } + } catch (IOException e) { + NamingException ne = new NamingException(); + ne.setRootCause(e); + throw ne; + } + + return null; + } +} diff --git a/jdk/test/javax/naming/module/src/foo/module-info.java b/jdk/test/javax/naming/module/src/foo/module-info.java new file mode 100644 index 00000000000..c83ae51b3f9 --- /dev/null +++ b/jdk/test/javax/naming/module/src/foo/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module foo { + requires java.naming; + exports org.example.foo; +} + diff --git a/jdk/test/javax/naming/module/src/foo/org/example/foo/FooControl.java b/jdk/test/javax/naming/module/src/foo/org/example/foo/FooControl.java new file mode 100644 index 00000000000..ca59b7c628a --- /dev/null +++ b/jdk/test/javax/naming/module/src/foo/org/example/foo/FooControl.java @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * This is a dummy LDAP control. + */ + +package org.example.foo; + +import javax.naming.ldap.*; + +public class FooControl extends BasicControl { + + public FooControl() { + super("1.2.3.4.5.6.7.8.9", true, null); + } + + public FooControl(boolean criticality) { + super("1.2.3.4.5.6.7.8.9", criticality, null); + } +} diff --git a/jdk/test/javax/naming/module/src/fruit/module-info.java b/jdk/test/javax/naming/module/src/fruit/module-info.java new file mode 100644 index 00000000000..27af7513040 --- /dev/null +++ b/jdk/test/javax/naming/module/src/fruit/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module fruit { + requires java.naming; + exports org.example.fruit; +} + diff --git a/jdk/test/javax/naming/module/src/fruit/org/example/fruit/Fruit.java b/jdk/test/javax/naming/module/src/fruit/org/example/fruit/Fruit.java new file mode 100644 index 00000000000..2e443d9eeb1 --- /dev/null +++ b/jdk/test/javax/naming/module/src/fruit/org/example/fruit/Fruit.java @@ -0,0 +1,57 @@ +/* + * 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 org.example.fruit; + +import javax.naming.*; + +/** + * This class is used by the StoreFruit test. + * It is a referenceable class that can be stored by service + * providers like the LDAP and file system providers. + */ +public class Fruit implements Referenceable { + static String location = null; + String fruit; + + public Fruit(String f) { + fruit = f; + } + + public Reference getReference() throws NamingException { + return new Reference( + Fruit.class.getName(), + new StringRefAddr("fruit", fruit), + FruitFactory.class.getName(), + location); // factory location + } + + public String toString() { + return fruit; + } + + public static void setLocation(String loc) { + location = loc; +System.out.println("setting location to : " + location); + } +} diff --git a/jdk/test/javax/naming/module/src/fruit/org/example/fruit/FruitFactory.java b/jdk/test/javax/naming/module/src/fruit/org/example/fruit/FruitFactory.java new file mode 100644 index 00000000000..aa81b1e00f6 --- /dev/null +++ b/jdk/test/javax/naming/module/src/fruit/org/example/fruit/FruitFactory.java @@ -0,0 +1,51 @@ +/* + * 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 org.example.fruit; + +import java.util.Hashtable; +import javax.naming.*; +import javax.naming.spi.ObjectFactory; + +/** + * This is an object factory that when given a reference for a Fruit + * object, will create an instance of the corresponding Fruit. + */ +public class FruitFactory implements ObjectFactory { + public FruitFactory() { + } + + public Object getObjectInstance(Object obj, Name name, Context ctx, + Hashtable env) throws Exception { + if (obj instanceof Reference) { + Reference ref = (Reference)obj; + if (ref.getClassName().equals(Fruit.class.getName())) { + RefAddr addr = ref.get("fruit"); + if (addr != null) { + return new Fruit((String)addr.getContent()); + } + } + } + return null; + } +} diff --git a/jdk/test/javax/naming/module/src/hello/module-info.java b/jdk/test/javax/naming/module/src/hello/module-info.java new file mode 100644 index 00000000000..a26ea5a9ed9 --- /dev/null +++ b/jdk/test/javax/naming/module/src/hello/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module hello { + requires java.rmi; + exports org.example.hello; +} + diff --git a/jdk/test/javax/naming/module/src/hello/org/example/hello/Hello.java b/jdk/test/javax/naming/module/src/hello/org/example/hello/Hello.java new file mode 100644 index 00000000000..c357d64ef05 --- /dev/null +++ b/jdk/test/javax/naming/module/src/hello/org/example/hello/Hello.java @@ -0,0 +1,36 @@ +/* + * 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 org.example.hello; + +import java.rmi.Remote; +import java.rmi.RemoteException; + +/** + * This interface is used by the StoreRemote test. + * It is a Remote interface. See HelloImpl.java for an implementation. + */ + +public interface Hello extends Remote { + public String sayHello() throws RemoteException; +} diff --git a/jdk/test/javax/naming/module/src/hello/org/example/hello/HelloImpl.java b/jdk/test/javax/naming/module/src/hello/org/example/hello/HelloImpl.java new file mode 100644 index 00000000000..91307942788 --- /dev/null +++ b/jdk/test/javax/naming/module/src/hello/org/example/hello/HelloImpl.java @@ -0,0 +1,41 @@ +/* + * 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 org.example.hello; + +import java.rmi.*; +import java.rmi.server.UnicastRemoteObject; + +/** + * This class is used by the StoreRemote test. + * It is an implementation of the Hello interface. + */ + +public class HelloImpl extends UnicastRemoteObject implements Hello { + public HelloImpl() throws RemoteException { + } + + public String sayHello() throws RemoteException { + return ("Hello, the time is " + new java.util.Date()); + } +} diff --git a/jdk/test/javax/naming/module/src/ldapv4/module-info.java b/jdk/test/javax/naming/module/src/ldapv4/module-info.java new file mode 100644 index 00000000000..65cf6a2dff4 --- /dev/null +++ b/jdk/test/javax/naming/module/src/ldapv4/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module ldapv4 { + requires java.naming; + exports org.example.ldapv4; +} + diff --git a/jdk/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContext.java b/jdk/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContext.java new file mode 100644 index 00000000000..b6e5b7102fe --- /dev/null +++ b/jdk/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContext.java @@ -0,0 +1,322 @@ +/* + * 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. + */ + +/** + * This is a dummy URL context for 'ldapv4://'. + */ + +package org.example.ldapv4; + +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; +import javax.naming.spi.*; + +public class ldapv4URLContext implements DirContext { + + private DirContext ctx; + + public ldapv4URLContext(Hashtable env) throws NamingException { + ctx = new InitialDirContext(env); + } + + public Object lookup(String name) throws NamingException { + try { + return ctx.lookup(""); + } catch (Exception e) { + NamingException ne = new NamingException(); + ne.setRootCause(e); + throw ne; + } finally { + ctx.close(); + } + } + + public Object lookup(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void bind(String name, Object obj) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void bind(Name name, Object obj) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void rebind(String name, Object obj) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void rebind(Name name, Object obj) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void unbind(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void unbind(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void rename(String oldName, String newName) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void rename(Name name, Name newName) throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration list(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration list(Name name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration listBindings(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration listBindings(Name name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void destroySubcontext(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public void destroySubcontext(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public Context createSubcontext(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public Context createSubcontext(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public Object lookupLink(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public Object lookupLink(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public NameParser getNameParser(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public NameParser getNameParser(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public String composeName(String name, String prefix) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public Name composeName(Name name, Name prefix) throws NamingException { + throw new OperationNotSupportedException(); + } + + public String getNameInNamespace() throws NamingException { + throw new OperationNotSupportedException(); + } + + public Object removeFromEnvironment(String propName) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public Object addToEnvironment(String propName, Object propVal) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public Hashtable getEnvironment() throws NamingException { + throw new OperationNotSupportedException(); + } + + public void close() throws NamingException { + throw new OperationNotSupportedException(); + } + + public Attributes getAttributes(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public Attributes getAttributes(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public Attributes getAttributes(Name name, String[] attrIds) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public Attributes getAttributes(String name, String[] attrIds) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void modifyAttributes(Name name, int mod_op, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void modifyAttributes(String name, int mod_op, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void modifyAttributes(Name name, ModificationItem[] mods) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void modifyAttributes(String name, ModificationItem[] mods) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void bind(Name name, Object obj, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void bind(String name, Object obj, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void rebind(Name name, Object obj, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public void rebind(String name, Object obj, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public DirContext createSubcontext(Name name, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public DirContext createSubcontext(String name, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public DirContext getSchema(Name name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public DirContext getSchema(String name) throws NamingException { + throw new OperationNotSupportedException(); + } + + public DirContext getSchemaClassDefinition(Name name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public DirContext getSchemaClassDefinition(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(Name name, + Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(String name, + Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(Name name, Attributes matchingAttributes) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(String name, Attributes matchingAttributes) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(Name name, + String filter, + SearchControls cons) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(String name, + String filter, + SearchControls cons) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(Name name, + String filterExpr, + Object[] filterArgs, + SearchControls cons) + throws NamingException { + throw new OperationNotSupportedException(); + } + + public NamingEnumeration + search(String name, + String filterExpr, + Object[] filterArgs, + SearchControls cons) + throws NamingException { + throw new OperationNotSupportedException(); + } +} diff --git a/jdk/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContextFactory.java b/jdk/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContextFactory.java new file mode 100644 index 00000000000..e731b77c9ea --- /dev/null +++ b/jdk/test/javax/naming/module/src/ldapv4/org/example/ldapv4/ldapv4URLContextFactory.java @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/** + * This is a dumy URL context factory for 'ldapv4://'. + */ + +package org.example.ldapv4; + +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; +import javax.naming.spi.*; + +public class ldapv4URLContextFactory implements ObjectFactory { + + public ldapv4URLContextFactory() { + } + + public Object getObjectInstance(Object urlInfo, Name name, Context nameCtx, + Hashtable env) throws Exception { + + Hashtable env2 = new Hashtable<>(); + env2.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + String ldapUrl = (String)env.get(Context.PROVIDER_URL); + env2.put(Context.PROVIDER_URL, ldapUrl.replaceFirst("ldapv4", "ldap")); + //env2.put("com.sun.jndi.ldap.trace.ber", System.out); + return new ldapv4URLContext(env2); + } +} diff --git a/jdk/test/javax/naming/module/src/person/module-info.java b/jdk/test/javax/naming/module/src/person/module-info.java new file mode 100644 index 00000000000..f7881b11999 --- /dev/null +++ b/jdk/test/javax/naming/module/src/person/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module person { + requires java.naming; + exports org.example.person; +} + diff --git a/jdk/test/javax/naming/module/src/person/org/example/person/Person.java b/jdk/test/javax/naming/module/src/person/org/example/person/Person.java new file mode 100644 index 00000000000..1d2427cb053 --- /dev/null +++ b/jdk/test/javax/naming/module/src/person/org/example/person/Person.java @@ -0,0 +1,245 @@ +/* + * 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. + */ + +/** + * This class has DirContext attributes and is used by the StorePerson test. + * Implementation of the inetOrgPerson LDAP object class as defined in + * draft-smith-ldap-inetorgperson-03.txt. + */ + +package org.example.person; + +import javax.naming.*; +import javax.naming.directory.*; + +public class Person { + + private BasicAttributes attrs; + + public Person(String commonName, String surname) { + + attrs = new BasicAttributes(true); + Attribute objectClass = new BasicAttribute("objectClass"); + objectClass.add("top"); + objectClass.add("person"); + objectClass.add("inetOrgPerson"); + + attrs.put(objectClass); + attrs.put(new BasicAttribute("cn", commonName)); + attrs.put(new BasicAttribute("sn", surname)); + } + + public Attributes getAttributes() { + return attrs; + } + + public void setAudio(byte[] value) { + attrs.put(new BasicAttribute("audio", value)); + } + + public void setBusinessCategory(String value) { + attrs.put(new BasicAttribute("businessCategory", value)); + } + + public void setCarLicense(String value) { + attrs.put(new BasicAttribute("carLicense", value)); + } + + public void setDepartmentNumber(String value) { + attrs.put(new BasicAttribute("departmentNumber", value)); + } + + public void setDisplayName(String value) { + attrs.put(new BasicAttribute("displayName", value)); + } + + public void setEmployeeNumber(String value) { + attrs.put(new BasicAttribute("employeeNumber", value)); + } + + public void setEmployeeType(String value) { + attrs.put(new BasicAttribute("employeeType", value)); + } + + public void setGivenName(String value) { + attrs.put(new BasicAttribute("givenName", value)); + } + + public void setHomePhoneNumber(String value) { + attrs.put(new BasicAttribute("homePhone", value)); + } + + public void setHomePostalAddress(String value) { + attrs.put(new BasicAttribute("homePostalAddress", value)); + } + + public void setInitials(String value) { + attrs.put(new BasicAttribute("initials", value)); + } + + public void setJPEGPhoto(String value) { + attrs.put(new BasicAttribute("jpegPhoto", value)); + } + + public void setMailAddress(String value) { + attrs.put(new BasicAttribute("mail", value)); + } + + public void setManagerName(String value) { + attrs.put(new BasicAttribute("manager", value)); + } + + public void setMobileNumber(String value) { + attrs.put(new BasicAttribute("mobile", value)); + } + + public void setOrganizationName(String value) { + attrs.put(new BasicAttribute("o", value)); + } + + public void setPagerNumber(String value) { + attrs.put(new BasicAttribute("pager", value)); + } + + public void setPhoto(String value) { + attrs.put(new BasicAttribute("photo", value)); + } + + public void setRoomNumber(String value) { + attrs.put(new BasicAttribute("roomNumber", value)); + } + + public void setSecretaryName(String value) { + attrs.put(new BasicAttribute("secretary", value)); + } + + public void setUserID(String value) { + attrs.put(new BasicAttribute("uid", value)); + } + + public void setUserCertificate(String value) { + attrs.put(new BasicAttribute("userCertificate", value)); + } + + public void setX500UniqueID(String value) { + attrs.put(new BasicAttribute("x500UniqueIdentifier", value)); + } + + public void setPreferredLanguage(String value) { + attrs.put(new BasicAttribute("preferredLanguage", value)); + } + + public void setUserSMIMECertificate(String value) { + attrs.put(new BasicAttribute("userSMIMECertificate", value)); + } + + public void setUserPKCS12(String value) { + attrs.put(new BasicAttribute("userPKCS12", value)); + } + + /* ----- Attributes inherited from the Person LDAP object class ----- */ + + public void setDescription(String value) { + attrs.put(new BasicAttribute("description", value)); + } + + public void setDestinationIndicator(String value) { + attrs.put(new BasicAttribute("destinationIndicator", value)); + } + + public void setFaxNumber(String value) { + attrs.put(new BasicAttribute("facsimileTelephoneNumber", value)); + } + + public void setISDNNumber(String value) { + attrs.put(new BasicAttribute("internationalISDNNumber", value)); + } + + public void setLocalityName(String value) { + attrs.put(new BasicAttribute("localityName", value)); + } + + public void setOrganizationalUnitName(String value) { + attrs.put(new BasicAttribute("ou", value)); + } + + public void setPhysicalDeliveryOfficeName(String value) { + attrs.put(new BasicAttribute("physicalDeliveryOfficeName", value)); + } + + public void setPostalAddress(String value) { + attrs.put(new BasicAttribute("postalAddress", value)); + } + + public void setPostalCode(String value) { + attrs.put(new BasicAttribute("postalCode", value)); + } + + public void setPostOfficeBox(String value) { + attrs.put(new BasicAttribute("postOfficeBox", value)); + } + + public void setPreferredDeliveryMethod(String value) { + attrs.put(new BasicAttribute("preferredDeliveryMethod", value)); + } + + public void setRegisteredAddress(String value) { + attrs.put(new BasicAttribute("registeredAddress", value)); + } + + public void setSeeAlso(String value) { + attrs.put(new BasicAttribute("seeAlso", value)); + } + + public void setStateOrProvinceName(String value) { + attrs.put(new BasicAttribute("st", value)); + } + + public void setStreetAddress(String value) { + attrs.put(new BasicAttribute("street", value)); + } + + public void setTelephoneNumber(String value) { + attrs.put(new BasicAttribute("telephoneNumber", value)); + } + + public void setTeletexTerminalID(String value) { + attrs.put(new BasicAttribute("teletexTerminalIdentifier", value)); + } + + public void setTelexNumber(String value) { + attrs.put(new BasicAttribute("telexNumber", value)); + } + + public void setTitle(String value) { + attrs.put(new BasicAttribute("title", value)); + } + + public void setUserPassword(String value) { + attrs.put(new BasicAttribute("userPassword", value)); + } + + public void setX121Address(String value) { + attrs.put(new BasicAttribute("x121Address", value)); + } +} diff --git a/jdk/test/javax/naming/module/src/person/org/example/person/PersonFactory.java b/jdk/test/javax/naming/module/src/person/org/example/person/PersonFactory.java new file mode 100644 index 00000000000..5b1cf07dfae --- /dev/null +++ b/jdk/test/javax/naming/module/src/person/org/example/person/PersonFactory.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * State factory and object factory for the Person class. + */ + +package org.example.person; + +import java.util.Hashtable; +import javax.naming.*; +import javax.naming.directory.*; +import javax.naming.spi.*; + +public class PersonFactory implements DirStateFactory, DirObjectFactory { + + public PersonFactory() { + } + + @Override + public Object getStateToBind(Object obj, Name name, + Context nameCtx, Hashtable environment) throws NamingException { + + return null; + } + + @Override + public DirStateFactory.Result getStateToBind(Object obj, Name name, + Context nameCtx, Hashtable environment, Attributes inAttrs) + throws NamingException { + + if (obj instanceof Person) { + return new DirStateFactory.Result(null, + personToAttributes((Person)obj)); + } else { + return null; + } + } + + @Override + public Object getObjectInstance(Object obj, Name name, Context ctx, + Hashtable environment) throws Exception { + + return null; + } + + @Override + public Object getObjectInstance(Object obj, Name name, Context ctx, + Hashtable environment, Attributes attributes) throws Exception { + + if (obj instanceof DirContext) { + ((DirContext)obj).close(); // cleanup + return attributesToPerson(attributes); + + } else { + return null; + } + } + + private Attributes personToAttributes(Person person) { + + // TBD: build attrs using methods in Person class instead of calling ... + + return person.getAttributes(); + } + + private Person attributesToPerson(Attributes attrset) + throws NamingException { + + Attributes attrs = (Attributes)attrset; + Person person = new Person((String)attrs.get("cn").get(), + (String)attrs.get("sn").get()); + + person.setMailAddress((String)attrs.get("mail").get()); + + // TBD: extract any other attributes + + return person; + } +} diff --git a/jdk/test/javax/naming/module/src/test/module-info.java b/jdk/test/javax/naming/module/src/test/module-info.java new file mode 100644 index 00000000000..c541a6aba74 --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/module-info.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +module test { + requires java.naming; + requires java.desktop; + requires java.xml.bind; // for javax.xml.bind.DatatypeConverter + requires java.rmi; // for java.rmi.server.UnicastRemoteObject + requires person; + requires fruit; + requires hello; + requires foo; + requires authz; + requires ldapv4; +} + diff --git a/jdk/test/javax/naming/module/src/test/test/ConnectWithAuthzId.java b/jdk/test/javax/naming/module/src/test/test/ConnectWithAuthzId.java new file mode 100644 index 00000000000..27e8e49b43d --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/ConnectWithAuthzId.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +/** + * Demonstrate JNDI using an LDAP request/response control. + * The Authorization Identity controls and their associated control factory + * is supplied by a third-party module. + */ + +package test; + +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; +import javax.naming.ldap.*; + +import org.example.authz.AuthzIdRequestControl; +import org.example.authz.AuthzIdResponseControl; + +public class ConnectWithAuthzId { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + + "/src/test/test/ConnectWithAuthzId.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: ConnectWithAuthzId \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java ConnectWithAuthzId ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the ConnectWithAuthzId.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Connect to the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=ie,dc=oracle,dc=com"); + env.put(Context.SECURITY_CREDENTIALS, "changeit"); + env.put(LdapContext.CONTROL_FACTORIES, + "org.example.authz.AuthzIdResponseControlFactory"); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + System.out.println("ConnectWithAuthzId: connecting to " + ldapUri); + LdapContext ctx = null; + Control[] connectionControls = { new AuthzIdRequestControl(false) }; + + try { + ctx = new InitialLdapContext(env, connectionControls); + System.out.println("ConnectWithAuthzId: connected"); + // Retrieve the response controls + Control[] responseControls = ctx.getResponseControls(); + if (responseControls != null) { + for (Control responseControl : responseControls) { + System.out.println("ConnectWithAuthzId: received response" + + " control: " + responseControl.getID()); + if (responseControl instanceof AuthzIdResponseControl) { + AuthzIdResponseControl authzId = + (AuthzIdResponseControl)responseControl; + System.out.println("ConnectWithAuthzId: identity is " + + authzId.getIdentity()); + } + } + } + } catch (NamingException e) { + System.err.println("ConnectWithAuthzId: error connecting " + e); + } finally { + if (ctx != null) { + ctx.close(); + } + } + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/ConnectWithAuthzId.ldap b/jdk/test/javax/naming/module/src/test/test/ConnectWithAuthzId.ldap new file mode 100644 index 00000000000..5e98ad6394c --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/ConnectWithAuthzId.ldap @@ -0,0 +1,96 @@ +# +# 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. +# + +################################################################################ +# Capture file for ConnectWithAuthzId.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the ConnectWithAuthzId application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# (Some manual BER encoding was needed to simulate the response control.) +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 81: SEQUENCE { +# 2 1: INTEGER 1 +# 5 46: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 31: OCTET STRING 'cn=admin,dc=ie,dc=oracle,dc=com' +# 43 8: [0] 'changeit' +# : } +# 53 28: [0] { +# 55 26: SEQUENCE { +# 57 24: OCTET STRING '2.16.840.1.113730.3.4.16' +# : } +# : } +# : } +0000: 30 51 02 01 01 60 2E 02 01 03 04 1F 63 6E 3D 61 0Q...`......cn=a +0010: 64 6D 69 6E 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 dmin,dc=ie,dc=or +0020: 61 63 6C 65 2C 64 63 3D 63 6F 6D 80 08 63 68 61 acle,dc=com..cha +0030: 6E 67 65 69 74 A0 1C 30 1A 04 18 32 2E 31 36 2E ngeit..0...2.16. +0040: 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 2E 34 840.1.113730.3.4 +0050: 2E 31 36 .16 + +# LDAP BindResponse: +# +# 0 51: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# 14 37: [0] { +# 16 35: SEQUENCE { +# 18 24: OCTET STRING '2.16.840.1.113730.3.4.15' +# 44 7: OCTET STRING 'u:admin' +# : } +# : } +# : } +# +0000: 30 33 02 01 01 61 07 0A 01 00 04 00 04 00 A0 25 0....a.......... +0010: 30 23 04 18 32 2E 31 36 2E 38 34 30 2E 31 2E 31 0...2.16.840.1.1 +0020: 31 33 37 33 30 2E 33 2E 34 2E 31 35 04 07 75 3A 13730.3.4.15..u: +0030: 61 64 6D 69 6E admin + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 2 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 02 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 diff --git a/jdk/test/javax/naming/module/src/test/test/ConnectWithFoo.java b/jdk/test/javax/naming/module/src/test/test/ConnectWithFoo.java new file mode 100644 index 00000000000..c14e4f4f31c --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/ConnectWithFoo.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * Demonstrate JNDI using an LDAP connection control supplied by a third-party + * module. + */ + +package test; + +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; +import javax.naming.ldap.*; + +import org.example.foo.FooControl; + +public class ConnectWithFoo { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + "/src/test/test/ConnectWithFoo.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: ConnectWithFoo \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java ConnectWithFoo ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the ConnectWithFoo.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Connect to the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + System.out.println("ConnectWithFoo: connecting to " + ldapUri); + LdapContext ctx = null; + Control[] connectionControls = { new FooControl(false) }; + + try { + ctx = new InitialLdapContext(env, connectionControls); + System.out.println("ConnectWithFoo: connected"); + } catch (NamingException e) { + System.err.println("ConnectWithFoo: error connecting " + e); + } finally { + if (ctx != null) { + ctx.close(); + } + } + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/ConnectWithFoo.ldap b/jdk/test/javax/naming/module/src/test/test/ConnectWithFoo.ldap new file mode 100644 index 00000000000..c73020b1e5f --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/ConnectWithFoo.ldap @@ -0,0 +1,84 @@ +# +# 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. +# + +################################################################################ +# Capture file for ConnectWithFoo.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the ConnectWithFoo application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 35: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 0: OCTET STRING +# 12 0: [0] +# : } +# 14 21: [0] { +# 16 19: SEQUENCE { +# 18 17: OCTET STRING '1.2.3.4.5.6.7.8.9' +# : } +# : } +# : } +# +0000: 30 23 02 01 01 60 07 02 01 03 04 00 80 00 A0 15 0#...`.......... +0010: 30 13 04 11 31 2E 32 2E 33 2E 34 2E 35 2E 36 2E 0...1.2.3.4.5.6. +0020: 37 2E 38 2E 39 7.8.9 + +# LDAP BindResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........ + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 2 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 02 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 diff --git a/jdk/test/javax/naming/module/src/test/test/LDAPServer.java b/jdk/test/javax/naming/module/src/test/test/LDAPServer.java new file mode 100644 index 00000000000..01a31f038ef --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/LDAPServer.java @@ -0,0 +1,250 @@ +/* + * 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 test; + +import java.io.*; +import java.nio.file.*; +import java.math.BigInteger; +import java.net.*; +import java.util.*; +import java.util.regex.*; +import javax.xml.bind.DatatypeConverter; + +/* + * A dummy LDAP server. + * + * Loads a sequence of LDAP messages from a capture file into its cache. + * It listens for LDAP requests, finds a match in its cache and sends the + * corresponding LDAP responses. + * + * The capture file contains an LDAP protocol exchange in the hexadecimal + * dump format emitted by sun.misc.HexDumpEncoder: + * + * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................ + * + * Typically, LDAP protocol exchange is generated by running the LDAP client + * application program against a real LDAP server and setting the JNDI/LDAP + * environment property: com.sun.jndi.ldap.trace.ber to activate LDAP message + * tracing. + */ +public class LDAPServer { + + /* + * A cache of LDAP requests and responses. + * Messages with the same ID are stored in a list. + * The first element in the list is the LDAP request, + * the remaining elements are the LDAP responses. + */ + private final Map> cache = new HashMap<>(); + + public LDAPServer(ServerSocket serverSocket, String filename) + throws Exception { + + System.out.println("LDAPServer: Loading LDAP cache from: " + filename); + loadCaptureFile(filename); + + System.out.println("LDAPServer: listening on port " + + serverSocket.getLocalPort()); + + try (Socket clientSocket = serverSocket.accept(); + OutputStream out = clientSocket.getOutputStream(); + InputStream in = clientSocket.getInputStream();) { + + byte[] inBuffer = new byte[8192]; + int count; + + while ((count = in.read(inBuffer)) > 0) { + byte[] request = Arrays.copyOf(inBuffer, count); + int[] ids = getIDs(request); + int messageID = ids[0]; + String operation = getOperation(ids[1]); + System.out.println("\nLDAPServer: received LDAP " + operation + + " [message ID " + messageID + "]"); + + List encodings = cache.get(messageID); + if (encodings == null || + (!Arrays.equals(request, encodings.get(0)))) { + throw new Exception( + "LDAPServer: ERROR: received an LDAP " + operation + + " (ID=" + messageID + ") not present in cache"); + } + + for (int i = 1; i < encodings.size(); i++) { + // skip the request (at index 0) + byte[] response = encodings.get(i); + out.write(response, 0, response.length); + ids = getIDs(response); + System.out.println("\nLDAPServer: Sent LDAP " + + getOperation(ids[1]) + " [message ID " + ids[0] + "]"); + } + } + } catch (IOException e) { + System.out.println("LDAPServer: ERROR: " + e); + throw e; + } + + System.out.println("\n[LDAP server exited normally]"); + } + + /* + * Load a capture file containing an LDAP protocol exchange in the + * hexadecimal dump format emitted by sun.misc.HexDumpEncoder: + * + * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................ + */ + private void loadCaptureFile(String filename) throws IOException { + StringBuilder hexString = new StringBuilder(); + String pattern = "(....): (..) (..) (..) (..) (..) (..) (..) (..) (..) (..) (..) (..) (..) (..) (..) (..).*"; + + try (Scanner fileScanner = new Scanner(Paths.get(filename))) { + while (fileScanner.hasNextLine()){ + + try (Scanner lineScanner = + new Scanner(fileScanner.nextLine())) { + if (lineScanner.findInLine(pattern) == null) { + continue; + } + MatchResult result = lineScanner.match(); + for (int i = 1; i <= result.groupCount(); i++) { + String digits = result.group(i); + if (digits.length() == 4) { + if (digits.equals("0000")) { // start-of-message + if (hexString.length() > 0) { + addToCache(hexString.toString()); + hexString = new StringBuilder(); + } + } + continue; + } else if (digits.equals(" ")) { // short message + continue; + } + hexString.append(digits); + } + } + } + } + addToCache(hexString.toString()); + } + + /* + * Add an LDAP encoding to the cache (by messageID key). + */ + private void addToCache(String hexString) throws IOException { + byte[] encoding = DatatypeConverter.parseHexBinary(hexString); + int[] ids = getIDs(encoding); + int messageID = ids[0]; + List encodings = cache.get(messageID); + if (encodings == null) { + encodings = new ArrayList<>(); + } + System.out.println(" adding LDAP " + getOperation(ids[1]) + + " with message ID " + messageID + " to the cache"); + encodings.add(encoding); + cache.put(messageID, encodings); + } + + /* + * Extracts the message ID and operation ID from an LDAP protocol encoding + * and returns them in a 2-element array of integers. + */ + private static int[] getIDs(byte[] encoding) throws IOException { + if (encoding[0] != 0x30) { + throw new IOException("Error: bad LDAP encoding in capture file: " + + "expected ASN.1 SEQUENCE tag (0x30), encountered " + + encoding[0]); + } + + int index = 2; + if ((encoding[1] & 0x80) == 0x80) { + index += (encoding[1] & 0x0F); + } + + if (encoding[index] != 0x02) { + throw new IOException("Error: bad LDAP encoding in capture file: " + + "expected ASN.1 INTEGER tag (0x02), encountered " + + encoding[index]); + } + int length = encoding[index + 1]; + index += 2; + int messageID = + new BigInteger(1, + Arrays.copyOfRange(encoding, index, index + length)).intValue(); + index += length; + int operationID = encoding[index]; + + return new int[]{messageID, operationID}; + } + + /* + * Maps an LDAP operation ID to a string description + */ + private static String getOperation(int operationID) { + switch (operationID) { + case 0x60: + return "BindRequest"; // [APPLICATION 0] + case 0x61: + return "BindResponse"; // [APPLICATION 1] + case 0x42: + return "UnbindRequest"; // [APPLICATION 2] + case 0x63: + return "SearchRequest"; // [APPLICATION 3] + case 0x64: + return "SearchResultEntry"; // [APPLICATION 4] + case 0x65: + return "SearchResultDone"; // [APPLICATION 5] + case 0x66: + return "ModifyRequest"; // [APPLICATION 6] + case 0x67: + return "ModifyResponse"; // [APPLICATION 7] + case 0x68: + return "AddRequest"; // [APPLICATION 8] + case 0x69: + return "AddResponse"; // [APPLICATION 9] + case 0x4A: + return "DeleteRequest"; // [APPLICATION 10] + case 0x6B: + return "DeleteResponse"; // [APPLICATION 11] + case 0x6C: + return "ModifyDNRequest"; // [APPLICATION 12] + case 0x6D: + return "ModifyDNResponse"; // [APPLICATION 13] + case 0x6E: + return "CompareRequest"; // [APPLICATION 14] + case 0x6F: + return "CompareResponse"; // [APPLICATION 15] + case 0x50: + return "AbandonRequest"; // [APPLICATION 16] + case 0x73: + return "SearchResultReference"; // [APPLICATION 19] + case 0x77: + return "ExtendedRequest"; // [APPLICATION 23] + case 0x78: + return "ExtendedResponse"; // [APPLICATION 24] + case 0x79: + return "IntermediateResponse"; // [APPLICATION 25] + default: + return "Unknown"; + } + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/ReadByUrl.java b/jdk/test/javax/naming/module/src/test/test/ReadByUrl.java new file mode 100644 index 00000000000..4b68da455a3 --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/ReadByUrl.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * Demonstrate JNDI using the 'ldapv4' URL scheme supplied by a third-party + * module. + */ + +package test; + +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; +import javax.naming.ldap.*; + +public class ReadByUrl { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + "/src/test/test/ReadByUrl.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: ReadByUrl \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java ReadByUrl ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the ReadByUrl.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Connect to the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI("ldapv4", null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + // URL context factory location for 'ldapv4://' + env.put(Context.URL_PKG_PREFIXES, "org.example"); + + System.out.println("ReadByUrl: connecting to " + ldapUri); + DirContext ctx = null; + + try { + ctx = new InitialDirContext(env); + System.out.println("ReadByUrl: connected"); + DirContext entry = (DirContext) ctx.lookup(ldapUri.toString()); + entry.close(); + } catch (NamingException e) { + System.err.println("ReadByUrl: error connecting " + e); + } finally { + if (ctx != null) { + ctx.close(); + } + } + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/ReadByUrl.ldap b/jdk/test/javax/naming/module/src/test/test/ReadByUrl.ldap new file mode 100644 index 00000000000..ec9f090ddd1 --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/ReadByUrl.ldap @@ -0,0 +1,158 @@ +# +# 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. +# + +################################################################################ +# Capture file for ReadByUrl.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the ReadByUrl application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 0: OCTET STRING +# 12 0: [0] +# : } +# : } +# +0000: 30 0C 02 01 01 60 07 02 01 03 04 00 80 00 0....`........ + +# LDAP BindResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........ + +# LDAP SearchRequest: +# +# 0 88: SEQUENCE { +# 2 1: INTEGER 2 +# 5 54: [APPLICATION 3] { +# 7 22: OCTET STRING 'dc=ie,dc=oracle,dc=com' +# 31 1: ENUMERATED 0 +# 34 1: ENUMERATED 3 +# 37 1: INTEGER 0 +# 40 1: INTEGER 0 +# 43 1: BOOLEAN FALSE +# 46 11: [7] 'objectClass' +# 59 0: SEQUENCE {} +# : } +# 61 27: [0] { +# 63 25: SEQUENCE { +# 65 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +0000: 30 58 02 01 02 63 36 04 16 64 63 3D 69 65 2C 64 0X...c6..dc=ie,d +0010: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 0A c=oracle,dc=com. +0020: 01 00 0A 01 03 02 01 00 02 01 00 01 01 00 87 0B ................ +0030: 6F 62 6A 65 63 74 43 6C 61 73 73 30 00 A0 1B 30 objectClass0...0 +0040: 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 ...2.16.840.1.11 +0050: 33 37 33 30 2E 33 2E 34 2E 32 3730.3.4.2 + +# LDAP SearchResultEntry: +# +# 0 111: SEQUENCE { +# 2 1: INTEGER 2 +# 5 106: [APPLICATION 4] { +# 7 22: OCTET STRING 'dc=ie,dc=oracle,dc=com' +# 31 80: SEQUENCE { +# 33 44: SEQUENCE { +# 35 11: OCTET STRING 'objectClass' +# 48 29: SET { +# 50 3: OCTET STRING 'top' +# 55 8: OCTET STRING 'dcObject' +# 65 12: OCTET STRING 'organization' +# : } +# : } +# 79 20: SEQUENCE { +# 81 1: OCTET STRING 6F +# 84 15: SET { +# 86 13: OCTET STRING 'ie.oracle.com' +# : } +# : } +# 101 10: SEQUENCE { +# 103 2: OCTET STRING 64 63 +# 107 4: SET { +# 109 2: OCTET STRING 69 65 +# : } +# : } +# : } +# : } +# : } +# +0000: 30 6F 02 01 02 64 6A 04 16 64 63 3D 69 65 2C 64 0o...dj..dc=ie,d +0010: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0020: 50 30 2C 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 P0,..objectClass +0030: 31 1D 04 03 74 6F 70 04 08 64 63 4F 62 6A 65 63 1...top..dcObjec +0040: 74 04 0C 6F 72 67 61 6E 69 7A 61 74 69 6F 6E 30 t..organization0 +0050: 14 04 01 6F 31 0F 04 0D 69 65 2E 6F 72 61 63 6C ...o1...ie.oracl +0060: 65 2E 63 6F 6D 30 0A 04 02 64 63 31 04 04 02 69 e.com0...dc1...i +0070: 65 e + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 2 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 02 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 3 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 03 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 + diff --git a/jdk/test/javax/naming/module/src/test/test/StoreFruit.java b/jdk/test/javax/naming/module/src/test/test/StoreFruit.java new file mode 100644 index 00000000000..278102cdcdf --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StoreFruit.java @@ -0,0 +1,171 @@ +/* + * 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. + */ + +/** + * Demonstrate Java object storage and retrieval using an LDAP directory. + * The Fruit object and its associated object factory is supplied by a + * third-party module. The Fruit object implements javax.naming.Referenceable. + */ + +package test; + +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; + +import org.example.fruit.Fruit; + +public class StoreFruit { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + "/src/test/test/StoreFruit.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: StoreFruit \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java StoreFruit ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the StoreFruit.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Store fruit objects in the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + System.out.println("StoreFruit: connecting to " + ldapUri); + DirContext ctx = new InitialDirContext(env); + Fruit fruit = null; + String dn = "cn=myfruit"; + String dn2 = "cn=myapple"; + + try { + fruit = new Fruit("orange"); + ctx.bind(dn, fruit); + System.out.println("StoreFruit: created entry '" + dn + "'"); + } catch (NameAlreadyBoundException e) { + System.err.println("StoreFruit: entry '" + dn + + "' already exists"); + cleanup(ctx, (String)null); + return; + } + + try { + ctx.bind(dn2, new Fruit("apple")); + System.out.println("StoreFruit: created entry '" + dn2 + "'"); + } catch (NameAlreadyBoundException e) { + System.err.println("StoreFruit: entry '" + dn2 + + "' already exists"); + cleanup(ctx, dn); + return; + } + + /* + * Retrieve fruit objects from the LDAP directory + */ + + try { + Fruit fruit2 = (Fruit) ctx.lookup(dn); + System.out.println("StoreFruit: retrieved object: " + fruit2); + } catch (NamingException e) { + System.err.println("StoreFruit: error retrieving entry '" + + dn + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn, dn2); + return; + } + + try { + Fruit fruit3 = (Fruit) ctx.lookup(dn2); + System.out.println("StoreFruit: retrieved object: " + fruit3); + } catch (NamingException e) { + System.err.println("StoreFruit: error retrieving entry '" + + dn2 + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn, dn2); + return; + } + + cleanup(ctx, dn, dn2); + } + + /* + * Remove objects from the LDAP directory + */ + private static void cleanup(DirContext ctx, String... dns) + throws NamingException { + + for (String dn : dns) { + try { + ctx.destroySubcontext(dn); + System.out.println("StoreFruit: removed entry '" + dn + "'"); + } catch (NamingException e) { + System.err.println("StoreFruit: error removing entry '" + dn + + "' " + e); + } + } + ctx.close(); + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/StoreFruit.ldap b/jdk/test/javax/naming/module/src/test/test/StoreFruit.ldap new file mode 100644 index 00000000000..4ab630619ab --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StoreFruit.ldap @@ -0,0 +1,512 @@ +# +# 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. +# + +################################################################################ +# Capture file for StoreFruit.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the StoreFruit application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 0: OCTET STRING +# 12 0: [0] +# : } +# : } +# +0000: 30 0C 02 01 01 60 07 02 01 03 04 00 80 00 0....`........ + +# LDAP BindResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........ + +# LDAP AddRequest: +# +# 0 297: SEQUENCE { +# 4 1: INTEGER 2 +# 7 261: [APPLICATION 8] { +# 11 33: OCTET STRING 'cn=myfruit,dc=ie,dc=oracle,dc=com' +# 46 223: SEQUENCE { +# 49 68: SEQUENCE { +# 51 11: OCTET STRING 'objectClass' +# 64 53: SET { +# 66 3: OCTET STRING 'top' +# 71 13: OCTET STRING 'javaContainer' +# 86 10: OCTET STRING 'javaObject' +# 98 19: OCTET STRING 'javaNamingReference' +# : } +# : } +# 119 41: SEQUENCE { +# 121 20: OCTET STRING 'javaReferenceAddress' +# 143 17: SET { +# 145 15: OCTET STRING '#0#fruit#orange' +# : } +# : } +# 162 47: SEQUENCE { +# 164 11: OCTET STRING 'javaFactory' +# 177 32: SET { +# 179 30: OCTET STRING 'org.example.fruit.FruitFactory' +# : } +# : } +# 211 42: SEQUENCE { +# 213 13: OCTET STRING 'javaClassName' +# 228 25: SET { +# 230 23: OCTET STRING 'org.example.fruit.Fruit' +# : } +# : } +# 255 15: SEQUENCE { +# 257 2: OCTET STRING 63 6E +# 261 9: SET { +# 263 7: OCTET STRING 'myfruit' +# : } +# : } +# : } +# : } +# 272 27: [0] { +# 274 25: SEQUENCE { +# 276 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 82 01 29 02 01 02 68 82 01 05 04 21 63 6E 3D 0..)...h....!cn= +0010: 6D 79 66 72 75 69 74 2C 64 63 3D 69 65 2C 64 63 myfruit,dc=ie,dc +0020: 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 81 =oracle,dc=com0. +0030: DF 30 44 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 .0D..objectClass +0040: 31 35 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F 6E 15..top..javaCon +0050: 74 61 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A 65 tainer..javaObje +0060: 63 74 04 13 6A 61 76 61 4E 61 6D 69 6E 67 52 65 ct..javaNamingRe +0070: 66 65 72 65 6E 63 65 30 29 04 14 6A 61 76 61 52 ference0)..javaR +0080: 65 66 65 72 65 6E 63 65 41 64 64 72 65 73 73 31 eferenceAddress1 +0090: 11 04 0F 23 30 23 66 72 75 69 74 23 6F 72 61 6E ...#0#fruit#oran +00A0: 67 65 30 2F 04 0B 6A 61 76 61 46 61 63 74 6F 72 ge0/..javaFactor +00B0: 79 31 20 04 1E 6F 72 67 2E 65 78 61 6D 70 6C 65 y1 ..org.example +00C0: 2E 66 72 75 69 74 2E 46 72 75 69 74 46 61 63 74 .fruit.FruitFact +00D0: 6F 72 79 30 2A 04 0D 6A 61 76 61 43 6C 61 73 73 ory0*..javaClass +00E0: 4E 61 6D 65 31 19 04 17 6F 72 67 2E 65 78 61 6D Name1...org.exam +00F0: 70 6C 65 2E 66 72 75 69 74 2E 46 72 75 69 74 30 ple.fruit.Fruit0 +0100: 0F 04 02 63 6E 31 09 04 07 6D 79 66 72 75 69 74 ...cn1...myfruit +0110: A0 1B 30 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 ..0...2.16.840.1 +0120: 2E 31 31 33 37 33 30 2E 33 2E 34 2E 32 .113730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 2 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 02 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP AddRequest: +# +# 0 296: SEQUENCE { +# 4 1: INTEGER 3 +# 7 260: [APPLICATION 8] { +# 11 33: OCTET STRING 'cn=myapple,dc=ie,dc=oracle,dc=com' +# 46 222: SEQUENCE { +# 49 68: SEQUENCE { +# 51 11: OCTET STRING 'objectClass' +# 64 53: SET { +# 66 3: OCTET STRING 'top' +# 71 13: OCTET STRING 'javaContainer' +# 86 10: OCTET STRING 'javaObject' +# 98 19: OCTET STRING 'javaNamingReference' +# : } +# : } +# 119 40: SEQUENCE { +# 121 20: OCTET STRING 'javaReferenceAddress' +# 143 16: SET { +# 145 14: OCTET STRING '#0#fruit#apple' +# : } +# : } +# 161 47: SEQUENCE { +# 163 11: OCTET STRING 'javaFactory' +# 176 32: SET { +# 178 30: OCTET STRING 'org.example.fruit.FruitFactory' +# : } +# : } +# 210 42: SEQUENCE { +# 212 13: OCTET STRING 'javaClassName' +# 227 25: SET { +# 229 23: OCTET STRING 'org.example.fruit.Fruit' +# : } +# : } +# 254 15: SEQUENCE { +# 256 2: OCTET STRING 63 6E +# 260 9: SET { +# 262 7: OCTET STRING 'myapple' +# : } +# : } +# : } +# : } +# 271 27: [0] { +# 273 25: SEQUENCE { +# 275 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 82 01 28 02 01 03 68 82 01 04 04 21 63 6E 3D 0..(...h....!cn= +0010: 6D 79 61 70 70 6C 65 2C 64 63 3D 69 65 2C 64 63 myapple,dc=ie,dc +0020: 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 81 =oracle,dc=com0. +0030: DE 30 44 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 .0D..objectClass +0040: 31 35 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F 6E 15..top..javaCon +0050: 74 61 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A 65 tainer..javaObje +0060: 63 74 04 13 6A 61 76 61 4E 61 6D 69 6E 67 52 65 ct..javaNamingRe +0070: 66 65 72 65 6E 63 65 30 28 04 14 6A 61 76 61 52 ference0(..javaR +0080: 65 66 65 72 65 6E 63 65 41 64 64 72 65 73 73 31 eferenceAddress1 +0090: 10 04 0E 23 30 23 66 72 75 69 74 23 61 70 70 6C ...#0#fruit#appl +00A0: 65 30 2F 04 0B 6A 61 76 61 46 61 63 74 6F 72 79 e0/..javaFactory +00B0: 31 20 04 1E 6F 72 67 2E 65 78 61 6D 70 6C 65 2E 1 ..org.example. +00C0: 66 72 75 69 74 2E 46 72 75 69 74 46 61 63 74 6F fruit.FruitFacto +00D0: 72 79 30 2A 04 0D 6A 61 76 61 43 6C 61 73 73 4E ry0*..javaClassN +00E0: 61 6D 65 31 19 04 17 6F 72 67 2E 65 78 61 6D 70 ame1...org.examp +00F0: 6C 65 2E 66 72 75 69 74 2E 46 72 75 69 74 30 0F le.fruit.Fruit0. +0100: 04 02 63 6E 31 09 04 07 6D 79 61 70 70 6C 65 A0 ..cn1...myapple. +0110: 1B 30 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E .0...2.16.840.1. +0120: 31 31 33 37 33 30 2E 33 2E 34 2E 32 113730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 3 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 03 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP SearchRequest: +# +# 0 99: SEQUENCE { +# 2 1: INTEGER 4 +# 5 65: [APPLICATION 3] { +# 7 33: OCTET STRING 'cn=myfruit,dc=ie,dc=oracle,dc=com' +# 42 1: ENUMERATED 0 +# 45 1: ENUMERATED 3 +# 48 1: INTEGER 0 +# 51 1: INTEGER 0 +# 54 1: BOOLEAN FALSE +# 57 11: [7] 'objectClass' +# 70 0: SEQUENCE {} +# : } +# 72 27: [0] { +# 74 25: SEQUENCE { +# 76 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 63 02 01 04 63 41 04 21 63 6E 3D 6D 79 66 72 0c...cA.!cn=myfr +0010: 75 69 74 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 uit,dc=ie,dc=ora +0020: 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 0A 01 03 cle,dc=com...... +0030: 02 01 00 02 01 00 01 01 00 87 0B 6F 62 6A 65 63 ...........objec +0040: 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 17 32 2E tClass0...0...2. +0050: 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 16.840.1.113730. +0060: 33 2E 34 2E 32 3.4.2 + +# LDAP SearchResultEntry: +# +# 0 268: SEQUENCE { +# 4 1: INTEGER 4 +# 7 261: [APPLICATION 4] { +# 11 33: OCTET STRING 'cn=myfruit,dc=ie,dc=oracle,dc=com' +# 46 223: SEQUENCE { +# 49 68: SEQUENCE { +# 51 11: OCTET STRING 'objectClass' +# 64 53: SET { +# 66 3: OCTET STRING 'top' +# 71 13: OCTET STRING 'javaContainer' +# 86 10: OCTET STRING 'javaObject' +# 98 19: OCTET STRING 'javaNamingReference' +# : } +# : } +# 119 41: SEQUENCE { +# 121 20: OCTET STRING 'javaReferenceAddress' +# 143 17: SET { +# 145 15: OCTET STRING '#0#fruit#orange' +# : } +# : } +# 162 47: SEQUENCE { +# 164 11: OCTET STRING 'javaFactory' +# 177 32: SET { +# 179 30: OCTET STRING 'org.example.fruit.FruitFactory' +# : } +# : } +# 211 42: SEQUENCE { +# 213 13: OCTET STRING 'javaClassName' +# 228 25: SET { +# 230 23: OCTET STRING 'org.example.fruit.Fruit' +# : } +# : } +# 255 15: SEQUENCE { +# 257 2: OCTET STRING 63 6E +# 261 9: SET { +# 263 7: OCTET STRING 'myfruit' +# : } +# : } +# : } +# : } +# : } +# +0000: 30 82 01 0C 02 01 04 64 82 01 05 04 21 63 6E 3D 0......d....!cn= +0010: 6D 79 66 72 75 69 74 2C 64 63 3D 69 65 2C 64 63 myfruit,dc=ie,dc +0020: 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 81 =oracle,dc=com0. +0030: DF 30 44 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 .0D..objectClass +0040: 31 35 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F 6E 15..top..javaCon +0050: 74 61 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A 65 tainer..javaObje +0060: 63 74 04 13 6A 61 76 61 4E 61 6D 69 6E 67 52 65 ct..javaNamingRe +0070: 66 65 72 65 6E 63 65 30 29 04 14 6A 61 76 61 52 ference0)..javaR +0080: 65 66 65 72 65 6E 63 65 41 64 64 72 65 73 73 31 eferenceAddress1 +0090: 11 04 0F 23 30 23 66 72 75 69 74 23 6F 72 61 6E ...#0#fruit#oran +00A0: 67 65 30 2F 04 0B 6A 61 76 61 46 61 63 74 6F 72 ge0/..javaFactor +00B0: 79 31 20 04 1E 6F 72 67 2E 65 78 61 6D 70 6C 65 y1 ..org.example +00C0: 2E 66 72 75 69 74 2E 46 72 75 69 74 46 61 63 74 .fruit.FruitFact +00D0: 6F 72 79 30 2A 04 0D 6A 61 76 61 43 6C 61 73 73 ory0*..javaClass +00E0: 4E 61 6D 65 31 19 04 17 6F 72 67 2E 65 78 61 6D Name1...org.exam +00F0: 70 6C 65 2E 66 72 75 69 74 2E 46 72 75 69 74 30 ple.fruit.Fruit0 +0100: 0F 04 02 63 6E 31 09 04 07 6D 79 66 72 75 69 74 ...cn1...myfruit + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 4 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 04 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP SearchRequest: +# +# 0 99: SEQUENCE { +# 2 1: INTEGER 5 +# 5 65: [APPLICATION 3] { +# 7 33: OCTET STRING 'cn=myapple,dc=ie,dc=oracle,dc=com' +# 42 1: ENUMERATED 0 +# 45 1: ENUMERATED 3 +# 48 1: INTEGER 0 +# 51 1: INTEGER 0 +# 54 1: BOOLEAN FALSE +# 57 11: [7] 'objectClass' +# 70 0: SEQUENCE {} +# : } +# 72 27: [0] { +# 74 25: SEQUENCE { +# 76 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 63 02 01 05 63 41 04 21 63 6E 3D 6D 79 61 70 0c...cA.!cn=myap +0010: 70 6C 65 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 ple,dc=ie,dc=ora +0020: 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 0A 01 03 cle,dc=com...... +0030: 02 01 00 02 01 00 01 01 00 87 0B 6F 62 6A 65 63 ...........objec +0040: 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 17 32 2E tClass0...0...2. +0050: 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 16.840.1.113730. +0060: 33 2E 34 2E 32 3.4.2 + +# LDAP SearchResultEntry: +# +# 0 267: SEQUENCE { +# 4 1: INTEGER 5 +# 7 260: [APPLICATION 4] { +# 11 33: OCTET STRING 'cn=myapple,dc=ie,dc=oracle,dc=com' +# 46 222: SEQUENCE { +# 49 68: SEQUENCE { +# 51 11: OCTET STRING 'objectClass' +# 64 53: SET { +# 66 3: OCTET STRING 'top' +# 71 13: OCTET STRING 'javaContainer' +# 86 10: OCTET STRING 'javaObject' +# 98 19: OCTET STRING 'javaNamingReference' +# : } +# : } +# 119 40: SEQUENCE { +# 121 20: OCTET STRING 'javaReferenceAddress' +# 143 16: SET { +# 145 14: OCTET STRING '#0#fruit#apple' +# : } +# : } +# 161 47: SEQUENCE { +# 163 11: OCTET STRING 'javaFactory' +# 176 32: SET { +# 178 30: OCTET STRING 'org.example.fruit.FruitFactory' +# : } +# : } +# 210 42: SEQUENCE { +# 212 13: OCTET STRING 'javaClassName' +# 227 25: SET { +# 229 23: OCTET STRING 'org.example.fruit.Fruit' +# : } +# : } +# 254 15: SEQUENCE { +# 256 2: OCTET STRING 63 6E +# 260 9: SET { +# 262 7: OCTET STRING 'myapple' +# : } +# : } +# : } +# : } +# : } +# +0000: 30 82 01 0B 02 01 05 64 82 01 04 04 21 63 6E 3D 0......d....!cn= +0010: 6D 79 61 70 70 6C 65 2C 64 63 3D 69 65 2C 64 63 myapple,dc=ie,dc +0020: 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 81 =oracle,dc=com0. +0030: DE 30 44 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 .0D..objectClass +0040: 31 35 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F 6E 15..top..javaCon +0050: 74 61 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A 65 tainer..javaObje +0060: 63 74 04 13 6A 61 76 61 4E 61 6D 69 6E 67 52 65 ct..javaNamingRe +0070: 66 65 72 65 6E 63 65 30 28 04 14 6A 61 76 61 52 ference0(..javaR +0080: 65 66 65 72 65 6E 63 65 41 64 64 72 65 73 73 31 eferenceAddress1 +0090: 10 04 0E 23 30 23 66 72 75 69 74 23 61 70 70 6C ...#0#fruit#appl +00A0: 65 30 2F 04 0B 6A 61 76 61 46 61 63 74 6F 72 79 e0/..javaFactory +00B0: 31 20 04 1E 6F 72 67 2E 65 78 61 6D 70 6C 65 2E 1 ..org.example. +00C0: 66 72 75 69 74 2E 46 72 75 69 74 46 61 63 74 6F fruit.FruitFacto +00D0: 72 79 30 2A 04 0D 6A 61 76 61 43 6C 61 73 73 4E ry0*..javaClassN +00E0: 61 6D 65 31 19 04 17 6F 72 67 2E 65 78 61 6D 70 ame1...org.examp +00F0: 6C 65 2E 66 72 75 69 74 2E 46 72 75 69 74 30 0F le.fruit.Fruit0. +0100: 04 02 63 6E 31 09 04 07 6D 79 61 70 70 6C 65 ..cn1...myapple + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 5 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 05 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP DeleteRequest: +# +# 0 67: SEQUENCE { +# 2 1: INTEGER 6 +# 5 33: [APPLICATION 10] 'cn=myfruit,dc=ie,dc=oracle,dc=com' +# 40 27: [0] { +# 42 25: SEQUENCE { +# 44 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 43 02 01 06 4A 21 63 6E 3D 6D 79 66 72 75 69 0C...J!cn=myfrui +0010: 74 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 63 6C t,dc=ie,dc=oracl +0020: 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 17 32 2E e,dc=com..0...2. +0030: 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 16.840.1.113730. +0040: 33 2E 34 2E 32 3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 6 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 06 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP DeleteRequest: +# +# 0 67: SEQUENCE { +# 2 1: INTEGER 7 +# 5 33: [APPLICATION 10] 'cn=myapple,dc=ie,dc=oracle,dc=com' +# 40 27: [0] { +# 42 25: SEQUENCE { +# 44 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 43 02 01 07 4A 21 63 6E 3D 6D 79 61 70 70 6C 0C...J!cn=myappl +0010: 65 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 63 6C e,dc=ie,dc=oracl +0020: 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 17 32 2E e,dc=com..0...2. +0030: 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 16.840.1.113730. +0040: 33 2E 34 2E 32 3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 7 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 07 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 8 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 08 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 + diff --git a/jdk/test/javax/naming/module/src/test/test/StoreObject.java b/jdk/test/javax/naming/module/src/test/test/StoreObject.java new file mode 100644 index 00000000000..2834321962f --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StoreObject.java @@ -0,0 +1,169 @@ +/* + * 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. + */ + +/** + * Demonstrate Java object storage and retrieval using an LDAP directory. + * The ActionEvent object is serializable and is supplied by the java.desktop + * module. + */ + +package test; + +import java.awt.event.ActionEvent; +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; + +public class StoreObject { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + "/src/test/test/StoreObject.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: StoreObject \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java StoreObject ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the StoreObject.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Store objects in the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + System.out.println("StoreObject: connecting to " + ldapUri); + DirContext ctx = new InitialDirContext(env); + String dn = "cn=myevent"; + String dn2 = "cn=myevent2"; + + try { + ctx.bind(dn, new ActionEvent("", 1, "Hello1")); + System.out.println("StoreObject: created entry '" + dn + "'"); + } catch (NameAlreadyBoundException e) { + System.err.println("StoreObject: entry '" + dn + + "' already exists"); + cleanup(ctx, (String)null); + return; + } + + try { + ctx.bind(dn2, new ActionEvent("", 2, "Hello2")); + System.out.println("StoreObject: created entry '" + dn2 + "'"); + } catch (NameAlreadyBoundException e) { + System.err.println("StoreObject: entry '" + dn2 + + "' already exists"); + cleanup(ctx, dn); + return; + } + + /* + * Retrieve objects from the LDAP directory + */ + + try { + ActionEvent b = (ActionEvent) ctx.lookup(dn); + System.out.println("StoreObject: retrieved object: " + b); + } catch (NamingException e) { + System.err.println("StoreObject: error retrieving entry '" + + dn + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn, dn2); + return; + } + + try { + ActionEvent t = (ActionEvent) ctx.lookup(dn2); + System.out.println("StoreObject: retrieved object: " + t); + } catch (NamingException e) { + System.err.println("StoreObject: error retrieving entry '" + + dn2 + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn, dn2); + return; + } + + cleanup(ctx, dn, dn2); + ctx.close(); + } + + /* + * Remove objects from the LDAP directory + */ + private static void cleanup(DirContext ctx, String... dns) + throws NamingException { + + for (String dn : dns) { + try { + ctx.destroySubcontext(dn); + System.out.println("StoreObject: removed entry '" + dn + "'"); + } catch (NamingException e) { + System.err.println("StoreObject: error removing entry '" + dn + + "' " + e); + } + } + ctx.close(); + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/StoreObject.ldap b/jdk/test/javax/naming/module/src/test/test/StoreObject.ldap new file mode 100644 index 00000000000..af1a5d52f0a --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StoreObject.ldap @@ -0,0 +1,664 @@ +# +# 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. +# + +################################################################################ +# Capture file for StoreObject.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the StoreObject application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 0: OCTET STRING +# 12 0: [0] +# : } +# : } +# +0000: 30 0C 02 01 01 60 07 02 01 03 04 00 80 00 0....`........ + +# LDAP BindResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........ + +# LDAP AddRequest: +# +# 0 597: SEQUENCE { +# 4 1: INTEGER 2 +# 7 561: [APPLICATION 8] { +# 11 33: OCTET STRING 'cn=myevent,dc=ie,dc=oracle,dc=com' +# 46 522: SEQUENCE { +# 50 253: SEQUENCE { +# 53 18: OCTET STRING 'javaSerializedData' +# 73 230: SET { +# 76 227: OCTET STRING +# : AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74 +# : 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65 +# : 6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09 +# : 6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E +# : 4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64 +# : 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 +# : 72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77 +# : 74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF +# : 8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64 +# : 49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02 +# : 5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E +# : 45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18 +# : 6D 7D A8 02 00 00 78 70 00 00 00 00 01 70 00 00 +# : 00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C +# : 6C 6F 31 +# : } +# : } +# 306 69: SEQUENCE { +# 308 11: OCTET STRING 'objectClass' +# 321 54: SET { +# 323 3: OCTET STRING 'top' +# 328 13: OCTET STRING 'javaContainer' +# 343 10: OCTET STRING 'javaObject' +# 355 20: OCTET STRING 'javaSerializedObject' +# : } +# : } +# 377 128: SEQUENCE { +# 380 14: OCTET STRING 'javaClassNames' +# 396 110: SET { +# 398 26: OCTET STRING 'java.awt.event.ActionEvent' +# 426 17: OCTET STRING 'java.awt.AWTEvent' +# 445 21: OCTET STRING 'java.util.EventObject' +# 468 16: OCTET STRING 'java.lang.Object' +# 486 20: OCTET STRING 'java.io.Serializable' +# : } +# : } +# 508 45: SEQUENCE { +# 510 13: OCTET STRING 'javaClassName' +# 525 28: SET { +# 527 26: OCTET STRING 'java.awt.event.ActionEvent' +# : } +# : } +# 555 15: SEQUENCE { +# 557 2: OCTET STRING 'cn' +# 561 9: SET { +# 563 7: OCTET STRING 'myevent' +# : } +# : } +# : } +# : } +# 572 27: [0] { +# 574 25: SEQUENCE { +# 576 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 82 02 55 02 01 02 68 82 02 31 04 21 63 6E 3D 0..U...h..1.!cn= +0010: 6D 79 65 76 65 6E 74 2C 64 63 3D 69 65 2C 64 63 myevent,dc=ie,dc +0020: 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 82 =oracle,dc=com0. +0030: 02 0A 30 81 FD 04 12 6A 61 76 61 53 65 72 69 61 ..0....javaSeria +0040: 6C 69 7A 65 64 44 61 74 61 31 81 E6 04 81 E3 AC lizedData1...... +0050: ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74 2E ...sr..java.awt. +0060: 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65 6E event.ActionEven +0070: 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09 6D t...zX./+...I..m +0080: 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E 4C odifiersJ..whenL +0090: 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64 74 ..actionCommandt +00A0: 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 ..Ljava/lang/Str +00B0: 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77 74 ing;xr..java.awt +00C0: 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF 8A .AWTEvent..-.... +00D0: C3 02 00 03 5A 00 08 63 6F 6E 73 75 6D 65 64 49 ....Z..consumedI +00E0: 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02 5B ..id[..bdatat..[ +00F0: 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E 45 Bxr..java.util.E +0100: 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18 6D ventObjectL..N.m +0110: 7D A8 02 00 00 78 70 00 00 00 00 01 70 00 00 00 .....xp.....p... +0120: 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C 6C .........t..Hell +0130: 6F 31 30 45 04 0B 6F 62 6A 65 63 74 43 6C 61 73 o10E..objectClas +0140: 73 31 36 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F s16..top..javaCo +0150: 6E 74 61 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A ntainer..javaObj +0160: 65 63 74 04 14 6A 61 76 61 53 65 72 69 61 6C 69 ect..javaSeriali +0170: 7A 65 64 4F 62 6A 65 63 74 30 81 80 04 0E 6A 61 zedObject0....ja +0180: 76 61 43 6C 61 73 73 4E 61 6D 65 73 31 6E 04 1A vaClassNames1n.. +0190: 6A 61 76 61 2E 61 77 74 2E 65 76 65 6E 74 2E 41 java.awt.event.A +01A0: 63 74 69 6F 6E 45 76 65 6E 74 04 11 6A 61 76 61 ctionEvent..java +01B0: 2E 61 77 74 2E 41 57 54 45 76 65 6E 74 04 15 6A .awt.AWTEvent..j +01C0: 61 76 61 2E 75 74 69 6C 2E 45 76 65 6E 74 4F 62 ava.util.EventOb +01D0: 6A 65 63 74 04 10 6A 61 76 61 2E 6C 61 6E 67 2E ject..java.lang. +01E0: 4F 62 6A 65 63 74 04 14 6A 61 76 61 2E 69 6F 2E Object..java.io. +01F0: 53 65 72 69 61 6C 69 7A 61 62 6C 65 30 2D 04 0D Serializable0-.. +0200: 6A 61 76 61 43 6C 61 73 73 4E 61 6D 65 31 1C 04 javaClassName1.. +0210: 1A 6A 61 76 61 2E 61 77 74 2E 65 76 65 6E 74 2E .java.awt.event. +0220: 41 63 74 69 6F 6E 45 76 65 6E 74 30 0F 04 02 63 ActionEvent0...c +0230: 6E 31 09 04 07 6D 79 65 76 65 6E 74 A0 1B 30 19 n1...myevent..0. +0240: 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 ..2.16.840.1.113 +0250: 37 33 30 2E 33 2E 34 2E 32 730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 2 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 02 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP AddRequest: +# +# 0 599: SEQUENCE { +# 4 1: INTEGER 3 +# 7 563: [APPLICATION 8] { +# 11 34: OCTET STRING 'cn=myevent2,dc=ie,dc=oracle,dc=com' +# 47 523: SEQUENCE { +# 51 253: SEQUENCE { +# 54 18: OCTET STRING 'javaSerializedData' +# 74 230: SET { +# 77 227: OCTET STRING +# : AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74 +# : 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65 +# : 6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09 +# : 6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E +# : 4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64 +# : 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 +# : 72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77 +# : 74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF +# : 8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64 +# : 49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02 +# : 5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E +# : 45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18 +# : 6D 7D A8 02 00 00 78 70 00 00 00 00 02 70 00 00 +# : 00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C +# : 6C 6F 32 +# : } +# : } +# 307 69: SEQUENCE { +# 309 11: OCTET STRING 'objectClass' +# 322 54: SET { +# 324 3: OCTET STRING 'top' +# 325 13: OCTET STRING 'javaContainer' +# 344 10: OCTET STRING 'javaObject' +# 356 20: OCTET STRING 'javaSerializedObject' +# : } +# : } +# 378 128: SEQUENCE { +# 381 14: OCTET STRING 'javaClassNames' +# 397 110: SET { +# 399 26: OCTET STRING 'java.awt.event.ActionEvent' +# 427 17: OCTET STRING 'java.awt.AWTEvent' +# 446 21: OCTET STRING 'java.util.EventObject' +# 469 16: OCTET STRING 'java.lang.Object' +# 487 20: OCTET STRING 'java.io.Serializable' +# : } +# : } +# 509 45: SEQUENCE { +# 511 13: OCTET STRING 'javaClassName' +# 526 28: SET { +# 528 26: OCTET STRING 'java.awt.event.ActionEvent' +# : } +# : } +# 556 15: SEQUENCE { +# 558 2: OCTET STRING 'cn' +# 562 10: SET { +# 564 8: OCTET STRING 'myevent2' +# : } +# : } +# : } +# : } +# 574 27: [0] { +# 576 25: SEQUENCE { +# 578 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 82 02 57 02 01 03 68 82 02 33 04 22 63 6E 3D 0..W...h..3."cn= +0010: 6D 79 65 76 65 6E 74 32 2C 64 63 3D 69 65 2C 64 myevent2,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 82 02 0B 30 81 FD 04 12 6A 61 76 61 53 65 72 69 ...0....javaSeri +0040: 61 6C 69 7A 65 64 44 61 74 61 31 81 E6 04 81 E3 alizedData1..... +0050: AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74 ....sr..java.awt +0060: 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65 .event.ActionEve +0070: 6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09 nt...zX./+...I.. +0080: 6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E modifiersJ..when +0090: 4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64 L..actionCommand +00A0: 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 t..Ljava/lang/St +00B0: 72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77 ring;xr..java.aw +00C0: 74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF t.AWTEvent..-... +00D0: 8A C3 02 00 03 5A 00 08 63 6F 6E 73 75 6D 65 64 .....Z..consumed +00E0: 49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02 I..id[..bdatat.. +00F0: 5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E [Bxr..java.util. +0100: 45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18 EventObjectL..N. +0110: 6D 7D A8 02 00 00 78 70 00 00 00 00 02 70 00 00 m.....xp.....p.. +0120: 00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C ..........t..Hel +0130: 6C 6F 32 30 45 04 0B 6F 62 6A 65 63 74 43 6C 61 lo20E..objectCla +0140: 73 73 31 36 04 03 74 6F 70 04 0D 6A 61 76 61 43 ss16..top..javaC +0150: 6F 6E 74 61 69 6E 65 72 04 0A 6A 61 76 61 4F 62 ontainer..javaOb +0160: 6A 65 63 74 04 14 6A 61 76 61 53 65 72 69 61 6C ject..javaSerial +0170: 69 7A 65 64 4F 62 6A 65 63 74 30 81 80 04 0E 6A izedObject0....j +0180: 61 76 61 43 6C 61 73 73 4E 61 6D 65 73 31 6E 04 avaClassNames1n. +0190: 1A 6A 61 76 61 2E 61 77 74 2E 65 76 65 6E 74 2E .java.awt.event. +01A0: 41 63 74 69 6F 6E 45 76 65 6E 74 04 11 6A 61 76 ActionEvent..jav +01B0: 61 2E 61 77 74 2E 41 57 54 45 76 65 6E 74 04 15 a.awt.AWTEvent.. +01C0: 6A 61 76 61 2E 75 74 69 6C 2E 45 76 65 6E 74 4F java.util.EventO +01D0: 62 6A 65 63 74 04 10 6A 61 76 61 2E 6C 61 6E 67 bject..java.lang +01E0: 2E 4F 62 6A 65 63 74 04 14 6A 61 76 61 2E 69 6F .Object..java.io +01F0: 2E 53 65 72 69 61 6C 69 7A 61 62 6C 65 30 2D 04 .Serializable0-. +0200: 0D 6A 61 76 61 43 6C 61 73 73 4E 61 6D 65 31 1C .javaClassName1. +0210: 04 1A 6A 61 76 61 2E 61 77 74 2E 65 76 65 6E 74 ..java.awt.event +0220: 2E 41 63 74 69 6F 6E 45 76 65 6E 74 30 10 04 02 .ActionEvent0... +0230: 63 6E 31 0A 04 08 6D 79 65 76 65 6E 74 32 A0 1B cn1...myevent2.. +0240: 30 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 0...2.16.840.1.1 +0250: 31 33 37 33 30 2E 33 2E 34 2E 32 13730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 3 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 03 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP SearchRequest: +# +# 0 99: SEQUENCE { +# 2 1: INTEGER 4 +# 5 65: [APPLICATION 3] { +# 7 33: OCTET STRING 'cn=myevent,dc=ie,dc=oracle,dc=com' +# 42 1: ENUMERATED 0 +# 45 1: ENUMERATED 0 +# 48 1: INTEGER 0 +# 51 1: INTEGER 0 +# 54 1: BOOLEAN FALSE +# 57 11: [7] 'objectClass' +# 70 0: SEQUENCE {} +# : } +# 72 27: [0] { +# 74 25: SEQUENCE { +# 76 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 63 02 01 04 63 41 04 21 63 6E 3D 6D 79 65 76 0c...cA.!cn=myev +0010: 65 6E 74 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 ent,dc=ie,dc=ora +0020: 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 0A 01 03 cle,dc=com...... +0030: 02 01 00 02 01 00 01 01 00 87 0B 6F 62 6A 65 63 ...........objec +0040: 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 17 32 2E tClass0...0...2. +0050: 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 16.840.1.113730. +0060: 33 2E 34 2E 32 3.4.2 + +# LDAP SearchResultEntry: +# +# 0 568: SEQUENCE { +# 4 1: INTEGER 4 +# 7 561: [APPLICATION 4] { +# 11 33: OCTET STRING 'cn=myevent,dc=ie,dc=oracle,dc=com' +# 46 522: SEQUENCE { +# 50 15: SEQUENCE { +# 52 2: OCTET STRING 'cn' +# 56 9: SET { +# 58 7: OCTET STRING 'myevent' +# : } +# : } +# 67 128: SEQUENCE { +# 70 14: OCTET STRING 'javaClassNames' +# 86 110: SET { +# 88 26: OCTET STRING 'java.awt.event.ActionEvent' +# 116 17: OCTET STRING 'java.awt.AWTEvent' +# 135 21: OCTET STRING 'java.util.EventObject' +# 158 16: OCTET STRING 'java.lang.Object' +# 176 20: OCTET STRING 'java.io.Serializable' +# : } +# : } +# 198 45: SEQUENCE { +# 200 13: OCTET STRING 'javaClassName' +# 215 28: SET { +# 217 26: OCTET STRING 'java.awt.event.ActionEvent' +# : } +# : } +# 245 69: SEQUENCE { +# 247 11: OCTET STRING 'objectClass' +# 260 54: SET { +# 262 10: OCTET STRING 'javaObject' +# 274 3: OCTET STRING 'top' +# 279 20: OCTET STRING 'javaSerializedObject' +# 301 13: OCTET STRING 'javaContainer' +# : } +# : } +# 316 253: SEQUENCE { +# 319 18: OCTET STRING 'javaSerializedData' +# 339 230: SET { +# 342 227: OCTET STRING +# : AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74 +# : 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65 +# : 6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09 +# : 6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E +# : 4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64 +# : 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 +# : 72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77 +# : 74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF +# : 8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64 +# : 49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02 +# : 5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E +# : 45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18 +# : 6D 7D A8 02 00 00 78 70 00 00 00 00 01 70 00 00 +# : 00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C +# : 6C 6F 31 +# : } +# : } +# : } +# : } +# : } +# +0000: 30 82 02 38 02 01 04 64 82 02 31 04 21 63 6E 3D 0..8...d..1.!cn= +0010: 6D 79 65 76 65 6E 74 2C 64 63 3D 69 65 2C 64 63 myevent,dc=ie,dc +0020: 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 82 =oracle,dc=com0. +0030: 02 0A 30 0F 04 02 63 6E 31 09 04 07 6D 79 65 76 ..0...cn1...myev +0040: 65 6E 74 30 81 80 04 0E 6A 61 76 61 43 6C 61 73 ent0....javaClas +0050: 73 4E 61 6D 65 73 31 6E 04 1A 6A 61 76 61 2E 61 sNames1n..java.a +0060: 77 74 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 wt.event.ActionE +0070: 76 65 6E 74 04 11 6A 61 76 61 2E 61 77 74 2E 41 vent..java.awt.A +0080: 57 54 45 76 65 6E 74 04 15 6A 61 76 61 2E 75 74 WTEvent..java.ut +0090: 69 6C 2E 45 76 65 6E 74 4F 62 6A 65 63 74 04 10 il.EventObject.. +00A0: 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 java.lang.Object +00B0: 04 14 6A 61 76 61 2E 69 6F 2E 53 65 72 69 61 6C ..java.io.Serial +00C0: 69 7A 61 62 6C 65 30 2D 04 0D 6A 61 76 61 43 6C izable0-..javaCl +00D0: 61 73 73 4E 61 6D 65 31 1C 04 1A 6A 61 76 61 2E assName1...java. +00E0: 61 77 74 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E awt.event.Action +00F0: 45 76 65 6E 74 30 45 04 0B 6F 62 6A 65 63 74 43 Event0E..objectC +0100: 6C 61 73 73 31 36 04 0A 6A 61 76 61 4F 62 6A 65 lass16..javaObje +0110: 63 74 04 03 74 6F 70 04 14 6A 61 76 61 53 65 72 ct..top..javaSer +0120: 69 61 6C 69 7A 65 64 4F 62 6A 65 63 74 04 0D 6A ializedObject..j +0130: 61 76 61 43 6F 6E 74 61 69 6E 65 72 30 81 FD 04 avaContainer0... +0140: 12 6A 61 76 61 53 65 72 69 61 6C 69 7A 65 64 44 .javaSerializedD +0150: 61 74 61 31 81 E6 04 81 E3 AC ED 00 05 73 72 00 ata1.........sr. +0160: 1A 6A 61 76 61 2E 61 77 74 2E 65 76 65 6E 74 2E .java.awt.event. +0170: 41 63 74 69 6F 6E 45 76 65 6E 74 95 8A DA 7A 58 ActionEvent...zX +0180: 11 2F 2B 02 00 03 49 00 09 6D 6F 64 69 66 69 65 ./+...I..modifie +0190: 72 73 4A 00 04 77 68 65 6E 4C 00 0D 61 63 74 69 rsJ..whenL..acti +01A0: 6F 6E 43 6F 6D 6D 61 6E 64 74 00 12 4C 6A 61 76 onCommandt..Ljav +01B0: 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B 78 72 a/lang/String;xr +01C0: 00 11 6A 61 76 61 2E 61 77 74 2E 41 57 54 45 76 ..java.awt.AWTEv +01D0: 65 6E 74 E6 AB 2D E1 18 DF 8A C3 02 00 03 5A 00 ent..-........Z. +01E0: 08 63 6F 6E 73 75 6D 65 64 49 00 02 69 64 5B 00 .consumedI..id[. +01F0: 05 62 64 61 74 61 74 00 02 5B 42 78 72 00 15 6A .bdatat..[Bxr..j +0200: 61 76 61 2E 75 74 69 6C 2E 45 76 65 6E 74 4F 62 ava.util.EventOb +0210: 6A 65 63 74 4C 8D 09 4E 18 6D 7D A8 02 00 00 78 jectL..N.m.....x +0220: 70 00 00 00 00 01 70 00 00 00 00 00 00 00 00 00 p.....p......... +0230: 00 00 00 74 00 06 48 65 6C 6C 6F 31 ...t..Hello1 + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 4 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 04 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP SearchRequest: +# +# 0 100: SEQUENCE { +# 2 1: INTEGER 5 +# 5 66: [APPLICATION 3] { +# 7 34: OCTET STRING 'cn=myevent2,dc=ie,dc=oracle,dc=com' +# 43 1: ENUMERATED 0 +# 46 1: ENUMERATED 0 +# 49 1: INTEGER 0 +# 52 1: INTEGER 0 +# 55 1: BOOLEAN FALSE +# 58 11: [7] 'objectClass' +# 71 0: SEQUENCE {} +# : } +# 73 27: [0] { +# 75 25: SEQUENCE { +# 77 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 64 02 01 05 63 42 04 22 63 6E 3D 6D 79 65 76 0d...cB."cn=myev +0010: 65 6E 74 32 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 ent2,dc=ie,dc=or +0020: 61 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 0A 01 acle,dc=com..... +0030: 03 02 01 00 02 01 00 01 01 00 87 0B 6F 62 6A 65 ............obje +0040: 63 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 17 32 ctClass0...0...2 +0050: 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 .16.840.1.113730 +0060: 2E 33 2E 34 2E 32 .3.4.2 + +# LDAP SearchResultEntry: +# +# 0 570: SEQUENCE { +# 4 1: INTEGER 5 +# 7 563: [APPLICATION 4] { +# 11 34: OCTET STRING 'cn=myevent2,dc=ie,dc=oracle,dc=com' +# 47 523: SEQUENCE { +# 51 16: SEQUENCE { +# 53 2: OCTET STRING 'cn' +# 57 10: SET { +# 59 8: OCTET STRING 'myevent2' +# : } +# : } +# 69 128: SEQUENCE { +# 72 14: OCTET STRING 'javaClassNames' +# 88 110: SET { +# 90 26: OCTET STRING 'java.awt.event.ActionEvent' +# 118 17: OCTET STRING 'java.awt.AWTEvent' +# 137 21: OCTET STRING 'java.util.EventObject' +# 160 16: OCTET STRING 'java.lang.Object' +# 178 20: OCTET STRING 'java.io.Serializable' +# : } +# : } +# 200 45: SEQUENCE { +# 202 13: OCTET STRING 'javaClassName' +# 217 28: SET { +# 219 26: OCTET STRING 'java.awt.event.ActionEvent' +# : } +# : } +# 247 69: SEQUENCE { +# 249 11: OCTET STRING 'objectClass' +# 262 54: SET { +# 264 10: OCTET STRING 'javaObject' +# 276 3: OCTET STRING 'top' +# 281 20: OCTET STRING 'javaSerializedObject' +# 303 13: OCTET STRING 'javaContainer' +# : } +# : } +# 318 253: SEQUENCE { +# 321 18: OCTET STRING 'javaSerializedData' +# 341 230: SET { +# 344 227: OCTET STRING +# : AC ED 00 05 73 72 00 1A 6A 61 76 61 2E 61 77 74 +# : 2E 65 76 65 6E 74 2E 41 63 74 69 6F 6E 45 76 65 +# : 6E 74 95 8A DA 7A 58 11 2F 2B 02 00 03 49 00 09 +# : 6D 6F 64 69 66 69 65 72 73 4A 00 04 77 68 65 6E +# : 4C 00 0D 61 63 74 69 6F 6E 43 6F 6D 6D 61 6E 64 +# : 74 00 12 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 +# : 72 69 6E 67 3B 78 72 00 11 6A 61 76 61 2E 61 77 +# : 74 2E 41 57 54 45 76 65 6E 74 E6 AB 2D E1 18 DF +# : 8A C3 02 00 03 5A 20 08 63 6F 6E 73 75 6D 65 64 +# : 49 00 02 69 64 5B 00 05 62 64 61 74 61 74 00 02 +# : 5B 42 78 72 00 15 6A 61 76 61 2E 75 74 69 6C 2E +# : 45 76 65 6E 74 4F 62 6A 65 63 74 4C 8D 09 4E 18 +# : 6D 7D A8 02 00 00 78 70 00 00 00 00 02 70 00 00 +# : 00 00 00 00 00 00 00 00 00 00 74 00 06 48 65 6C +# : 6C 6F 32 +# : } +# : } +# : } +# : } +# : } +# +0000: 30 82 02 3A 02 01 05 64 82 02 33 04 22 63 6E 3D 0..:...d..3."cn= +0010: 6D 79 65 76 65 6E 74 32 2C 64 63 3D 69 65 2C 64 myevent2,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 82 02 0B 30 10 04 02 63 6E 31 0A 04 08 6D 79 65 ...0...cn1...mye +0040: 76 65 6E 74 32 30 81 80 04 0E 6A 61 76 61 43 6C vent20....javaCl +0050: 61 73 73 4E 61 6D 65 73 31 6E 04 1A 6A 61 76 61 assNames1n..java +0060: 2E 61 77 74 2E 65 76 65 6E 74 2E 41 63 74 69 6F .awt.event.Actio +0070: 6E 45 76 65 6E 74 04 11 6A 61 76 61 2E 61 77 74 nEvent..java.awt +0080: 2E 41 57 54 45 76 65 6E 74 04 15 6A 61 76 61 2E .AWTEvent..java. +0090: 75 74 69 6C 2E 45 76 65 6E 74 4F 62 6A 65 63 74 util.EventObject +00A0: 04 10 6A 61 76 61 2E 6C 61 6E 67 2E 4F 62 6A 65 ..java.lang.Obje +00B0: 63 74 04 14 6A 61 76 61 2E 69 6F 2E 53 65 72 69 ct..java.io.Seri +00C0: 61 6C 69 7A 61 62 6C 65 30 2D 04 0D 6A 61 76 61 alizable0-..java +00D0: 43 6C 61 73 73 4E 61 6D 65 31 1C 04 1A 6A 61 76 ClassName1...jav +00E0: 61 2E 61 77 74 2E 65 76 65 6E 74 2E 41 63 74 69 a.awt.event.Acti +00F0: 6F 6E 45 76 65 6E 74 30 45 04 0B 6F 62 6A 65 63 onEvent0E..objec +0100: 74 43 6C 61 73 73 31 36 04 0A 6A 61 76 61 4F 62 tClass16..javaOb +0110: 6A 65 63 74 04 03 74 6F 70 04 14 6A 61 76 61 53 ject..top..javaS +0120: 65 72 69 61 6C 69 7A 65 64 4F 62 6A 65 63 74 04 erializedObject. +0130: 0D 6A 61 76 61 43 6F 6E 74 61 69 6E 65 72 30 81 .javaContainer0. +0140: FD 04 12 6A 61 76 61 53 65 72 69 61 6C 69 7A 65 ...javaSerialize +0150: 64 44 61 74 61 31 81 E6 04 81 E3 AC ED 00 05 73 dData1.........s +0160: 72 00 1A 6A 61 76 61 2E 61 77 74 2E 65 76 65 6E r..java.awt.even +0170: 74 2E 41 63 74 69 6F 6E 45 76 65 6E 74 95 8A DA t.ActionEvent... +0180: 7A 58 11 2F 2B 02 00 03 49 00 09 6D 6F 64 69 66 zX./+...I..modif +0190: 69 65 72 73 4A 00 04 77 68 65 6E 4C 00 0D 61 63 iersJ..whenL..ac +01A0: 74 69 6F 6E 43 6F 6D 6D 61 6E 64 74 00 12 4C 6A tionCommandt..Lj +01B0: 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 6E 67 3B ava/lang/String; +01C0: 78 72 00 11 6A 61 76 61 2E 61 77 74 2E 41 57 54 xr..java.awt.AWT +01D0: 45 76 65 6E 74 E6 AB 2D E1 18 DF 8A C3 02 00 03 Event..-........ +01E0: 5A 00 08 63 6F 6E 73 75 6D 65 64 49 00 02 69 64 Z..consumedI..id +01F0: 5B 00 05 62 64 61 74 61 74 00 02 5B 42 78 72 00 [..bdatat..[Bxr. +0200: 15 6A 61 76 61 2E 75 74 69 6C 2E 45 76 65 6E 74 .java.util.Event +0210: 4F 62 6A 65 63 74 4C 8D 09 4E 18 6D 7D A8 02 00 ObjectL..N.m.... +0220: 00 78 70 00 00 00 00 02 70 00 00 00 00 00 00 00 .xp.....p....... +0230: 00 00 00 00 00 74 00 06 48 65 6C 6C 6F 32 .....t..Hello2 + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 5 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 05 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP DeleteRequest: +# +# 0 67: SEQUENCE { +# 2 1: INTEGER 6 +# 5 33: [APPLICATION 10] 'cn=myevent,dc=ie,dc=oracle,dc=com' +# 40 27: [0] { +# 42 25: SEQUENCE { +# 44 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 43 02 01 06 4A 21 63 6E 3D 6D 79 65 76 65 6E 0C...J!cn=myeven +0010: 74 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 63 6C t,dc=ie,dc=oracl +0020: 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 17 32 2E e,dc=com..0...2. +0030: 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 16.840.1.113730. +0040: 33 2E 34 2E 32 3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 6 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 06 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP DeleteRequest: +# +# 0 68: SEQUENCE { +# 2 1: INTEGER 7 +# 5 34: [APPLICATION 10] 'cn=myevent2,dc=ie,dc=oracle,dc=com' +# 41 27: [0] { +# 43 25: SEQUENCE { +# 45 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 44 02 01 07 4A 22 63 6E 3D 6D 79 65 76 65 6E 0D...J"cn=myeven +0010: 74 32 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 63 t2,dc=ie,dc=orac +0020: 6C 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 17 32 le,dc=com..0...2 +0030: 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 .16.840.1.113730 +0040: 2E 33 2E 34 2E 32 .3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 7 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 07 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 8 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 08 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 + diff --git a/jdk/test/javax/naming/module/src/test/test/StorePerson.java b/jdk/test/javax/naming/module/src/test/test/StorePerson.java new file mode 100644 index 00000000000..4b6e174625f --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StorePerson.java @@ -0,0 +1,198 @@ +/* + * 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. + */ + +/** + * Demonstrate Java object storage and retrieval using an LDAP directory. + * The Person object and its associated object and state factory is supplied by + * a third-party module. As the Person object does not implement + * javax.naming.Referenceable, the classname of its state and object factory + * must be specified to the JNDI initial context. + */ + +package test; + +import java.net.*; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; + +import org.example.person.Person; + +public class StorePerson { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + "/src/test/test/StorePerson.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: StorePerson \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java StorePerson ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the StorePerson.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Store Person objects in the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + // Specify the factory classname explicitly + env.put(Context.STATE_FACTORIES, "org.example.person.PersonFactory"); + env.put(Context.OBJECT_FACTORIES, "org.example.person.PersonFactory"); + + System.out.println("StorePerson: connecting to " + ldapUri); + DirContext ctx = new InitialDirContext(env); + Person person = null; + String name = "John Smith"; + String dn = "cn=" + name; + + try { + person = new Person(name, "Smith"); + person.setMailAddress("jsmith@smith.com"); + ctx.bind(dn, person); + System.out.println("StorePerson: created entry '" + dn + "'"); + } catch (NameAlreadyBoundException e) { + System.err.println("StorePerson: entry '" + dn + + "' already exists"); + cleanup(ctx, (String)null); + return; + } + + name = "Jill Smyth"; + String dn2 = "cn=" + name; + Person person2 = new Person(name, "Smyth"); + person2.setMailAddress("jsmyth@smith.com"); + + try { + ctx.bind(dn2, person2); + System.out.println("StorePerson: created entry '" + dn2 + "'"); + } catch (NameAlreadyBoundException e) { + System.err.println("StorePerson: entry '" + dn2 + + "' already exists"); + cleanup(ctx, dn); + return; + } + + /* + * Retrieve Person objects from the LDAP directory + */ + + try { + Person person3 = (Person) ctx.lookup(dn); + System.out.println("StorePerson: retrieved object: " + person3); + if (person.getAttributes().equals(person3.getAttributes())) { + System.out.println( + "StorePerson: retrieved person matches original"); + } else { + System.out.println( + "StorePerson: retrieved person does NOT match original"); + } + } catch (NamingException e) { + System.err.println("StorePerson: error retrieving entry '" + + dn + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn, dn2); + return; + } + + try { + Person person4 = (Person) ctx.lookup(dn2); + System.out.println("StorePerson: retrieved object: " + person4); + if (person2.getAttributes().equals(person4.getAttributes())) { + System.out.println( + "StorePerson: retrieved person matches original"); + } else { + System.out.println( + "StorePerson: retrieved person does NOT match original"); + } + } catch (NamingException e) { + System.err.println("StorePerson: error retrieving entry '" + + dn2 + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn, dn2); + return; + } + + cleanup(ctx, dn, dn2); + return; + } + + /* + * Remove objects from the LDAP directory + */ + private static void cleanup(DirContext ctx, String... dns) + throws NamingException { + + for (String dn : dns) { + try { + ctx.destroySubcontext(dn); + System.out.println("StorePerson: removed entry '" + dn + "'"); + } catch (NamingException e) { + System.err.println("StorePerson: error removing entry '" + dn + + "' " + e); + } + } + ctx.close(); + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/StorePerson.ldap b/jdk/test/javax/naming/module/src/test/test/StorePerson.ldap new file mode 100644 index 00000000000..c4de6aba756 --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StorePerson.ldap @@ -0,0 +1,456 @@ +# +# 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. +# + +################################################################################ +# Capture file for StorePerson.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the StorePerson application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 0: OCTET STRING +# 12 0: [0] +# : } +# : } +# +0000: 30 0C 02 01 01 60 07 02 01 03 04 00 80 00 0....`........ + +# LDAP BindResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........ + +# LDAP AddRequest: +# +# 0 183: SEQUENCE { +# 3 1: INTEGER 2 +# 6 148: [APPLICATION 8] { +# 9 36: OCTET STRING 'cn=John Smith,dc=ie,dc=oracle,dc=com' +# 47 108: SEQUENCE { +# 49 26: SEQUENCE { +# 51 4: OCTET STRING 'mail' +# 57 18: SET { +# 59 16: OCTET STRING 'jsmith@smith.com' +# : } +# : } +# 77 43: SEQUENCE { +# 79 11: OCTET STRING 'objectClass' +# 92 28: SET { +# 94 3: OCTET STRING 'top' +# 99 6: OCTET STRING 'person' +# 107 13: OCTET STRING 'inetOrgPerson' +# : } +# : } +# 122 13: SEQUENCE { +# 124 2: OCTET STRING 73 6E +# 128 7: SET { +# 130 5: OCTET STRING 'Smith' +# : } +# : } +# 137 18: SEQUENCE { +# 139 2: OCTET STRING 63 6E +# 143 12: SET { +# 145 10: OCTET STRING 'John Smith' +# : } +# : } +# : } +# : } +# 157 27: [0] { +# 159 25: SEQUENCE { +# 161 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 81 B7 02 01 02 68 81 94 04 24 63 6E 3D 4A 6F 0.....h...$cn=Jo +0010: 68 6E 20 53 6D 69 74 68 2C 64 63 3D 69 65 2C 64 hn Smith,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 6C 30 1A 04 04 6D 61 69 6C 31 12 04 10 6A 73 6D l0...mail1...jsm +0040: 69 74 68 40 73 6D 69 74 68 2E 63 6F 6D 30 2B 04 ith@smith.com0+. +0050: 0B 6F 62 6A 65 63 74 43 6C 61 73 73 31 1C 04 03 .objectClass1... +0060: 74 6F 70 04 06 70 65 72 73 6F 6E 04 0D 69 6E 65 top..person..ine +0070: 74 4F 72 67 50 65 72 73 6F 6E 30 0D 04 02 73 6E tOrgPerson0...sn +0080: 31 07 04 05 53 6D 69 74 68 30 12 04 02 63 6E 31 1...Smith0...cn1 +0090: 0C 04 0A 4A 6F 68 6E 20 53 6D 69 74 68 A0 1B 30 ...John Smith..0 +00A0: 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 ...2.16.840.1.11 +00B0: 33 37 33 30 2E 33 2E 34 2E 32 3730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 2 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 02 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP AddRequest: +# +# 0 183: SEQUENCE { +# 3 1: INTEGER 3 +# 6 148: [APPLICATION 8] { +# 9 36: OCTET STRING 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com' +# 47 108: SEQUENCE { +# 49 26: SEQUENCE { +# 51 4: OCTET STRING 'mail' +# 57 18: SET { +# 59 16: OCTET STRING 'jsmyth@smith.com' +# : } +# : } +# 77 43: SEQUENCE { +# 79 11: OCTET STRING 'objectClass' +# 92 28: SET { +# 94 3: OCTET STRING 'top' +# 99 6: OCTET STRING 'person' +# 107 13: OCTET STRING 'inetOrgPerson' +# : } +# : } +# 122 13: SEQUENCE { +# 124 2: OCTET STRING 73 6E +# 128 7: SET { +# 130 5: OCTET STRING 'Smyth' +# : } +# : } +# 137 18: SEQUENCE { +# 139 2: OCTET STRING 63 6E +# 143 12: SET { +# 145 10: OCTET STRING 'Jill Smyth' +# : } +# : } +# : } +# : } +# 157 27: [0] { +# 159 25: SEQUENCE { +# 161 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 81 B7 02 01 03 68 81 94 04 24 63 6E 3D 4A 69 0.....h...$cn=Ji +0010: 6C 6C 20 53 6D 79 74 68 2C 64 63 3D 69 65 2C 64 ll Smyth,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 6C 30 1A 04 04 6D 61 69 6C 31 12 04 10 6A 73 6D l0...mail1...jsm +0040: 79 74 68 40 73 6D 69 74 68 2E 63 6F 6D 30 2B 04 yth@smith.com0+. +0050: 0B 6F 62 6A 65 63 74 43 6C 61 73 73 31 1C 04 03 .objectClass1... +0060: 74 6F 70 04 06 70 65 72 73 6F 6E 04 0D 69 6E 65 top..person..ine +0070: 74 4F 72 67 50 65 72 73 6F 6E 30 0D 04 02 73 6E tOrgPerson0...sn +0080: 31 07 04 05 53 6D 79 74 68 30 12 04 02 63 6E 31 1...Smyth0...cn1 +0090: 0C 04 0A 4A 69 6C 6C 20 53 6D 79 74 68 A0 1B 30 ...Jill Smyth..0 +00A0: 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 ...2.16.840.1.11 +00B0: 33 37 33 30 2E 33 2E 34 2E 32 3730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 3 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 03 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP SearchRequest: +# +# 0 102: SEQUENCE { +# 2 1: INTEGER 4 +# 5 68: [APPLICATION 3] { +# 7 36: OCTET STRING 'cn=John Smith,dc=ie,dc=oracle,dc=com' +# 45 1: ENUMERATED 0 +# 48 1: ENUMERATED 3 +# 51 1: INTEGER 0 +# 54 1: INTEGER 0 +# 57 1: BOOLEAN FALSE +# 60 11: [7] 'objectClass' +# 73 0: SEQUENCE {} +# : } +# 75 27: [0] { +# 77 25: SEQUENCE { +# 79 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 66 02 01 04 63 44 04 24 63 6E 3D 4A 6F 68 6E 0f...cD.$cn=John +0010: 20 53 6D 69 74 68 2C 64 63 3D 69 65 2C 64 63 3D Smith,dc=ie,dc= +0020: 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 oracle,dc=com... +0030: 0A 01 03 02 01 00 02 01 00 01 01 00 87 0B 6F 62 ..............ob +0040: 6A 65 63 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 jectClass0...0.. +0050: 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 .2.16.840.1.1137 +0060: 33 30 2E 33 2E 34 2E 32 30.3.4.2 + +# LDAP SearchResultEntry: +# +# 0 154: SEQUENCE { +# 3 1: INTEGER 4 +# 6 148: [APPLICATION 4] { +# 9 36: OCTET STRING 'cn=John Smith,dc=ie,dc=oracle,dc=com' +# 47 108: SEQUENCE { +# 49 26: SEQUENCE { +# 51 4: OCTET STRING 'mail' +# 57 18: SET { +# 59 16: OCTET STRING 'jsmith@smith.com' +# : } +# : } +# 77 43: SEQUENCE { +# 79 11: OCTET STRING 'objectClass' +# 92 28: SET { +# 94 3: OCTET STRING 'top' +# 99 6: OCTET STRING 'person' +# 107 13: OCTET STRING 'inetOrgPerson' +# : } +# : } +# 122 13: SEQUENCE { +# 124 2: OCTET STRING 73 6E +# 128 7: SET { +# 130 5: OCTET STRING 'Smith' +# : } +# : } +# 137 18: SEQUENCE { +# 139 2: OCTET STRING 63 6E +# 143 12: SET { +# 145 10: OCTET STRING 'John Smith' +# : } +# : } +# : } +# : } +# : } +# +0000: 30 81 9A 02 01 04 64 81 94 04 24 63 6E 3D 4A 6F 0.....d...$cn=Jo +0010: 68 6E 20 53 6D 69 74 68 2C 64 63 3D 69 65 2C 64 hn Smith,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 6C 30 1A 04 04 6D 61 69 6C 31 12 04 10 6A 73 6D l0...mail1...jsm +0040: 69 74 68 40 73 6D 69 74 68 2E 63 6F 6D 30 2B 04 ith@smith.com0+. +0050: 0B 6F 62 6A 65 63 74 43 6C 61 73 73 31 1C 04 03 .objectClass1... +0060: 74 6F 70 04 06 70 65 72 73 6F 6E 04 0D 69 6E 65 top..person..ine +0070: 74 4F 72 67 50 65 72 73 6F 6E 30 0D 04 02 73 6E tOrgPerson0...sn +0080: 31 07 04 05 53 6D 69 74 68 30 12 04 02 63 6E 31 1...Smith0...cn1 +0090: 0C 04 0A 4A 6F 68 6E 20 53 6D 69 74 68 ...John Smith + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 4 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 04 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP SearchRequest: +# +# 0 102: SEQUENCE { +# 2 1: INTEGER 5 +# 5 68: [APPLICATION 3] { +# 7 36: OCTET STRING 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com' +# 45 1: ENUMERATED 0 +# 48 1: ENUMERATED 3 +# 51 1: INTEGER 0 +# 54 1: INTEGER 0 +# 57 1: BOOLEAN FALSE +# 60 11: [7] 'objectClass' +# 73 0: SEQUENCE {} +# : } +# 75 27: [0] { +# 77 25: SEQUENCE { +# 79 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 66 02 01 05 63 44 04 24 63 6E 3D 4A 69 6C 6C 0f...cD.$cn=Jill +0010: 20 53 6D 79 74 68 2C 64 63 3D 69 65 2C 64 63 3D Smyth,dc=ie,dc= +0020: 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 oracle,dc=com... +0030: 0A 01 03 02 01 00 02 01 00 01 01 00 87 0B 6F 62 ..............ob +0040: 6A 65 63 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 jectClass0...0.. +0050: 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 .2.16.840.1.1137 +0060: 33 30 2E 33 2E 34 2E 32 30.3.4.2 + +# LDAP SearchResultEntry: +# +# 0 154: SEQUENCE { +# 3 1: INTEGER 5 +# 6 148: [APPLICATION 4] { +# 9 36: OCTET STRING 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com' +# 47 108: SEQUENCE { +# 49 26: SEQUENCE { +# 51 4: OCTET STRING 'mail' +# 57 18: SET { +# 59 16: OCTET STRING 'jsmyth@smith.com' +# : } +# : } +# 77 43: SEQUENCE { +# 79 11: OCTET STRING 'objectClass' +# 92 28: SET { +# 94 3: OCTET STRING 'top' +# 99 6: OCTET STRING 'person' +# 107 13: OCTET STRING 'inetOrgPerson' +# : } +# : } +# 122 13: SEQUENCE { +# 124 2: OCTET STRING 73 6E +# 128 7: SET { +# 130 5: OCTET STRING 'Smyth' +# : } +# : } +# 137 18: SEQUENCE { +# 139 2: OCTET STRING 63 6E +# 143 12: SET { +# 145 10: OCTET STRING 'Jill Smyth' +# : } +# : } +# : } +# : } +# : } +# +0000: 30 81 9A 02 01 05 64 81 94 04 24 63 6E 3D 4A 69 0.....d...$cn=Ji +0010: 6C 6C 20 53 6D 79 74 68 2C 64 63 3D 69 65 2C 64 ll Smyth,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 6C 30 1A 04 04 6D 61 69 6C 31 12 04 10 6A 73 6D l0...mail1...jsm +0040: 79 74 68 40 73 6D 69 74 68 2E 63 6F 6D 30 2B 04 yth@smith.com0+. +0050: 0B 6F 62 6A 65 63 74 43 6C 61 73 73 31 1C 04 03 .objectClass1... +0060: 74 6F 70 04 06 70 65 72 73 6F 6E 04 0D 69 6E 65 top..person..ine +0070: 74 4F 72 67 50 65 72 73 6F 6E 30 0D 04 02 73 6E tOrgPerson0...sn +0080: 31 07 04 05 53 6D 79 74 68 30 12 04 02 63 6E 31 1...Smyth0...cn1 +0090: 0C 04 0A 4A 69 6C 6C 20 53 6D 79 74 68 ...Jill Smyth + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 5 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 05 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP DeleteRequest: +# +# 0 70: SEQUENCE { +# 2 1: INTEGER 6 +# 5 36: [APPLICATION 10] 'cn=John Smith,dc=ie,dc=oracle,dc=com' +# 43 27: [0] { +# 45 25: SEQUENCE { +# 47 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 46 02 01 06 4A 24 63 6E 3D 4A 6F 68 6E 20 53 0F...J$cn=John S +0010: 6D 69 74 68 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 mith,dc=ie,dc=or +0020: 61 63 6C 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 acle,dc=com..0.. +0030: 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 .2.16.840.1.1137 +0040: 33 30 2E 33 2E 34 2E 32 30.3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 6 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 06 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP DeleteRequest: +# +# 0 70: SEQUENCE { +# 2 1: INTEGER 7 +# 5 36: [APPLICATION 10] 'cn=Jill Smyth,dc=ie,dc=oracle,dc=com' +# 43 27: [0] { +# 45 25: SEQUENCE { +# 47 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 46 02 01 07 4A 24 63 6E 3D 4A 69 6C 6C 20 53 0F...J$cn=Jill S +0010: 6D 79 74 68 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 myth,dc=ie,dc=or +0020: 61 63 6C 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 acle,dc=com..0.. +0030: 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 .2.16.840.1.1137 +0040: 33 30 2E 33 2E 34 2E 32 30.3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 7 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 07 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 8 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 08 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 + diff --git a/jdk/test/javax/naming/module/src/test/test/StoreRemote.java b/jdk/test/javax/naming/module/src/test/test/StoreRemote.java new file mode 100644 index 00000000000..95dea1bd327 --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StoreRemote.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +/** + * Demonstrate Java Remote object storage and retrieval using an LDAP directory. + * The RMI object is supplied by a third-party module. + */ + +package test; + +import java.io.*; +import java.net.*; +import java.rmi.Remote; +import java.rmi.server.UnicastRemoteObject; +import java.util.*; +import javax.naming.*; +import javax.naming.directory.*; + +import org.example.hello.*; + +public class StoreRemote { + + // LDAP capture file + private static final String LDAP_CAPTURE_FILE = + System.getProperty("test.src") + "/src/test/test/StoreRemote.ldap"; + // LDAPServer socket + private static ServerSocket serverSocket; + + public static void main(String[] args) throws Exception { + + /* + * Process arguments + */ + + int argc = args.length; + if ((argc < 1) || + ((argc == 1) && (args[0].equalsIgnoreCase("-help")))) { + + System.err.println("\nUsage: StoreRemote \n"); + System.err.println(" is the LDAP URL of the parent entry\n"); + System.err.println("example:"); + System.err.println(" java StoreRemote ldap://oasis/o=airius.com"); + return; + } + + /* + * Launch the LDAP server with the StoreRemote.ldap capture file + */ + + serverSocket = new ServerSocket(0); + new Thread(new Runnable() { + @Override + public void run() { + try { + new LDAPServer(serverSocket, LDAP_CAPTURE_FILE); + } catch (Exception e) { + System.out.println("ERROR: unable to launch LDAP server"); + e.printStackTrace(); + } + } + }).start(); + + /* + * Store a Remote object in the LDAP directory + */ + + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + URI ldapUri = new URI(args[0]); + if (ldapUri.getPort() == -1) { + ldapUri = new URI(ldapUri.getScheme(), null, ldapUri.getHost(), + serverSocket.getLocalPort(), ldapUri.getPath(), null, null); + } + env.put(Context.PROVIDER_URL, ldapUri.toString()); + if (args[args.length - 1].equalsIgnoreCase("-trace")) { + env.put("com.sun.jndi.ldap.trace.ber", System.out); + } + + System.out.println("StoreRemote: connecting to " + ldapUri); + DirContext ctx = new InitialDirContext(env); + String dn = "cn=myremote"; + + try { + Hello hello = new HelloImpl(); + ctx.bind(dn, hello); + System.out.println("StoreRemote: created entry '" + dn + "'"); + + // Explicitly release the RMI object + UnicastRemoteObject.unexportObject(hello, true); + + } catch (NameAlreadyBoundException e) { + System.err.println("StoreRemote: entry '" + dn + + "' already exists"); + cleanup(ctx, (String)null); + return; + } + + /* + * Retrieve the Remote object from the LDAP directory + */ + + try { + Hello obj = (Hello) ctx.lookup(dn); + System.out.println("StoreRemote: retrieved object: " + obj); + System.out.println("StoreRemote: calling Hello.sayHello()...\n" + + obj.sayHello()); + + // Explicitly release the RMI object + UnicastRemoteObject.unexportObject(obj, true); + + } catch (NamingException e) { + System.err.println("StoreRemote: error retrieving entry '" + + dn + "' " + e); + e.printStackTrace(); + cleanup(ctx, dn); + return; + } + + cleanup(ctx, dn); + } + + /* + * Remove objects from the LDAP directory + */ + private static void cleanup(DirContext ctx, String... dns) + throws NamingException { + + for (String dn : dns) { + try { + ctx.destroySubcontext(dn); + System.out.println("StoreRemote: removed entry '" + dn + "'"); + } catch (NamingException e) { + System.err.println("StoreRemote: error removing entry '" + dn + + "' " + e); + } + } + ctx.close(); + } +} diff --git a/jdk/test/javax/naming/module/src/test/test/StoreRemote.ldap b/jdk/test/javax/naming/module/src/test/test/StoreRemote.ldap new file mode 100644 index 00000000000..f5c8ea8db51 --- /dev/null +++ b/jdk/test/javax/naming/module/src/test/test/StoreRemote.ldap @@ -0,0 +1,411 @@ +# +# 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. +# + +################################################################################ +# Capture file for StoreRemote.java +# +# NOTE: This hexadecimal dump of LDAP protocol messages was generated by +# running the StoreRemote application program against a real LDAP +# server and setting the JNDI/LDAP environment property: +# com.sun.jndi.ldap.trace.ber to activate LDAP message tracing. +# +# (The ASN.1 annotations were generated separately by the dumpasn1 +# utility and added only for clarity.) +# +################################################################################ + +# LDAP BindRequest: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 0] { +# 7 1: INTEGER 3 +# 10 0: OCTET STRING +# 12 0: [0] +# : } +# : } +# +0000: 30 0C 02 01 01 60 07 02 01 03 04 00 80 00 0....`........ + +# LDAP BindResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 1 +# 5 7: [APPLICATION 1] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 01 61 07 0A 01 00 04 00 04 00 0....a........ + +# LDAP AddRequest: +# +# 0 791: SEQUENCE { +# 4 1: INTEGER 2 +# 7 755: [APPLICATION 8] { +# 11 34: OCTET STRING 'cn=myremote,dc=ie,dc=oracle,dc=com' +# 47 715: SEQUENCE { +# 51 344: SEQUENCE { +# 55 18: OCTET STRING 'javaSerializedData' +# 75 320: SET { +# 79 316: OCTET STRING +# : AC ED 00 05 73 72 00 1B 6F 72 67 2E 65 78 61 6D +# : 70 6C 65 2E 68 65 6C 6C 6F 2E 48 65 6C 6C 6F 49 +# : 6D 70 6C A9 56 08 D1 0C 92 18 98 02 00 00 78 72 +# : 00 23 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65 +# : 72 2E 55 6E 69 63 61 73 74 52 65 6D 6F 74 65 4F +# : 62 6A 65 63 74 45 09 12 15 F5 E2 7E 31 02 00 03 +# : 49 00 04 70 6F 72 74 4C 00 03 63 73 66 74 00 28 +# : 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65 72 +# : 2F 52 4D 49 43 6C 69 65 6E 74 53 6F 63 6B 65 74 +# : 46 61 63 74 6F 72 79 3B 4C 00 03 73 73 66 74 00 +# : 28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65 +# : 72 2F 52 4D 49 53 65 72 76 65 72 53 6F 63 6B 65 +# : 74 46 61 63 74 6F 72 79 3B 78 72 00 1C 6A 61 76 +# : 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 6D +# : 6F 74 65 53 65 72 76 65 72 C7 19 07 12 68 F3 39 +# : FB 02 00 00 78 72 00 1C 6A 61 76 61 2E 72 6D 69 +# : 2E 73 65 72 76 65 72 2E 52 65 6D 6F 74 65 4F 62 +# : 6A 65 63 74 D3 61 B4 91 0C 61 33 1E 03 00 00 78 +# : 70 77 12 00 10 55 6E 69 63 61 73 74 53 65 72 76 +# : 65 72 52 65 66 78 00 00 00 00 70 70 +# : } +# : } +# 399 69: SEQUENCE { +# 401 11: OCTET STRING 'objectClass' +# 414 54: SET { +# 416 3: OCTET STRING 'top' +# 421 13: OCTET STRING 'javaContainer' +# 436 10: OCTET STRING 'javaObject' +# 448 20: OCTET STRING 'javaSerializedObject' +# : } +# : } +# 470 227: SEQUENCE { +# 473 14: OCTET STRING 'javaClassNames' +# 489 208: SET { +# 492 27: OCTET STRING 'org.example.hello.HelloImpl' +# 521 35: OCTET STRING 'java.rmi.server.UnicastRemoteObject' +# 558 28: OCTET STRING 'java.rmi.server.RemoteServer' +# 588 28: OCTET STRING 'java.rmi.server.RemoteObject' +# 618 16: OCTET STRING 'java.lang.Object' +# 636 15: OCTET STRING 'java.rmi.Remote' +# 653 20: OCTET STRING 'java.io.Serializable' +# 675 23: OCTET STRING 'org.example.hello.Hello' +# : } +# : } +# 700 46: SEQUENCE { +# 702 13: OCTET STRING 'javaClassName' +# 717 29: SET { +# 719 27: OCTET STRING 'org.example.hello.HelloImpl' +# : } +# : } +# 748 16: SEQUENCE { +# 750 2: OCTET STRING 63 6E +# 754 10: SET { +# 756 8: OCTET STRING 'myremote' +# : } +# : } +# : } +# : } +# 766 27: [0] { +# 768 25: SEQUENCE { +# 770 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 82 03 17 02 01 02 68 82 02 F3 04 22 63 6E 3D 0......h...."cn= +0010: 6D 79 72 65 6D 6F 74 65 2C 64 63 3D 69 65 2C 64 myremote,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 82 02 CB 30 82 01 58 04 12 6A 61 76 61 53 65 72 ...0..X..javaSer +0040: 69 61 6C 69 7A 65 64 44 61 74 61 31 82 01 40 04 ializedData1..@. +0050: 82 01 3C AC ED 00 05 73 72 00 1B 6F 72 67 2E 65 ..<....sr..org.e +0060: 78 61 6D 70 6C 65 2E 68 65 6C 6C 6F 2E 48 65 6C xample.hello.Hel +0070: 6C 6F 49 6D 70 6C A9 56 08 D1 0C 92 18 98 02 00 loImpl.V........ +0080: 00 78 72 00 23 6A 61 76 61 2E 72 6D 69 2E 73 65 .xr.#java.rmi.se +0090: 72 76 65 72 2E 55 6E 69 63 61 73 74 52 65 6D 6F rver.UnicastRemo +00A0: 74 65 4F 62 6A 65 63 74 45 09 12 15 F5 E2 7E 31 teObjectE......1 +00B0: 02 00 03 49 00 04 70 6F 72 74 4C 00 03 63 73 66 ...I..portL..csf +00C0: 74 00 28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 t.(Ljava/rmi/ser +00D0: 76 65 72 2F 52 4D 49 43 6C 69 65 6E 74 53 6F 63 ver/RMIClientSoc +00E0: 6B 65 74 46 61 63 74 6F 72 79 3B 4C 00 03 73 73 ketFactory;L..ss +00F0: 66 74 00 28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 ft.(Ljava/rmi/se +0100: 72 76 65 72 2F 52 4D 49 53 65 72 76 65 72 53 6F rver/RMIServerSo +0110: 63 6B 65 74 46 61 63 74 6F 72 79 3B 78 72 00 1C cketFactory;xr.. +0120: 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E java.rmi.server. +0130: 52 65 6D 6F 74 65 53 65 72 76 65 72 C7 19 07 12 RemoteServer.... +0140: 68 F3 39 FB 02 00 00 78 72 00 1C 6A 61 76 61 2E h.9....xr..java. +0150: 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 6D 6F 74 rmi.server.Remot +0160: 65 4F 62 6A 65 63 74 D3 61 B4 91 0C 61 33 1E 03 eObject.a...a3.. +0170: 00 00 78 70 77 12 00 10 55 6E 69 63 61 73 74 53 ..xpw...UnicastS +0180: 65 72 76 65 72 52 65 66 78 00 00 00 00 70 70 30 erverRefx....pp0 +0190: 45 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 31 36 E..objectClass16 +01A0: 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F 6E 74 61 ..top..javaConta +01B0: 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A 65 63 74 iner..javaObject +01C0: 04 14 6A 61 76 61 53 65 72 69 61 6C 69 7A 65 64 ..javaSerialized +01D0: 4F 62 6A 65 63 74 30 81 E3 04 0E 6A 61 76 61 43 Object0....javaC +01E0: 6C 61 73 73 4E 61 6D 65 73 31 81 D0 04 1B 6F 72 lassNames1....or +01F0: 67 2E 65 78 61 6D 70 6C 65 2E 68 65 6C 6C 6F 2E g.example.hello. +0200: 48 65 6C 6C 6F 49 6D 70 6C 04 23 6A 61 76 61 2E HelloImpl.#java. +0210: 72 6D 69 2E 73 65 72 76 65 72 2E 55 6E 69 63 61 rmi.server.Unica +0220: 73 74 52 65 6D 6F 74 65 4F 62 6A 65 63 74 04 1C stRemoteObject.. +0230: 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E java.rmi.server. +0240: 52 65 6D 6F 74 65 53 65 72 76 65 72 04 1C 6A 61 RemoteServer..ja +0250: 76 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 va.rmi.server.Re +0260: 6D 6F 74 65 4F 62 6A 65 63 74 04 10 6A 61 76 61 moteObject..java +0270: 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 04 0F 6A 61 .lang.Object..ja +0280: 76 61 2E 72 6D 69 2E 52 65 6D 6F 74 65 04 14 6A va.rmi.Remote..j +0290: 61 76 61 2E 69 6F 2E 53 65 72 69 61 6C 69 7A 61 ava.io.Serializa +02A0: 62 6C 65 04 17 6F 72 67 2E 65 78 61 6D 70 6C 65 ble..org.example +02B0: 2E 68 65 6C 6C 6F 2E 48 65 6C 6C 6F 30 2E 04 0D .hello.Hello0... +02C0: 6A 61 76 61 43 6C 61 73 73 4E 61 6D 65 31 1D 04 javaClassName1.. +02D0: 1B 6F 72 67 2E 65 78 61 6D 70 6C 65 2E 68 65 6C .org.example.hel +02E0: 6C 6F 2E 48 65 6C 6C 6F 49 6D 70 6C 30 10 04 02 lo.HelloImpl0... +02F0: 63 6E 31 0A 04 08 6D 79 72 65 6D 6F 74 65 A0 1B cn1...myremote.. +0300: 30 19 04 17 32 2E 31 36 2E 38 34 30 2E 31 2E 31 0...2.16.840.1.1 +0310: 31 33 37 33 30 2E 33 2E 34 2E 32 13730.3.4.2 + +# LDAP AddResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 2 +# 5 7: [APPLICATION 9] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 02 69 07 0A 01 00 04 00 04 00 0....i........ + +# LDAP SearchRequest: +# +# 0 100: SEQUENCE { +# 2 1: INTEGER 3 +# 5 66: [APPLICATION 3] { +# 7 34: OCTET STRING 'cn=myremote,dc=ie,dc=oracle,dc=com' +# 43 1: ENUMERATED 0 +# 46 1: ENUMERATED 3 +# 49 1: INTEGER 0 +# 52 1: INTEGER 0 +# 55 1: BOOLEAN FALSE +# 58 11: [7] 'objectClass' +# 71 0: SEQUENCE {} +# : } +# 73 27: [0] { +# 75 25: SEQUENCE { +# 77 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 64 02 01 03 63 42 04 22 63 6E 3D 6D 79 72 65 0d...cB."cn=myre +0010: 6D 6F 74 65 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 mote,dc=ie,dc=or +0020: 61 63 6C 65 2C 64 63 3D 63 6F 6D 0A 01 00 0A 01 acle,dc=com..... +0030: 03 02 01 00 02 01 00 01 01 00 87 0B 6F 62 6A 65 ............obje +0040: 63 74 43 6C 61 73 73 30 00 A0 1B 30 19 04 17 32 ctClass0...0...2 +0050: 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 .16.840.1.113730 +0060: 2E 33 2E 34 2E 32 .3.4.2 + +# LDAP SearchResultEntry: +# +# +# 0 762: SEQUENCE { +# 4 1: INTEGER 3 +# 7 755: [APPLICATION 4] { +# 11 34: OCTET STRING 'cn=myremote,dc=ie,dc=oracle,dc=com' +# 47 715: SEQUENCE { +# 51 344: SEQUENCE { +# 55 18: OCTET STRING 'javaSerializedData' +# 75 320: SET { +# 79 316: OCTET STRING +# : AC ED 00 05 73 72 00 1B 6F 72 67 2E 65 78 61 6D +# : 70 6C 65 2E 68 65 6C 6C 6F 2E 48 65 6C 6C 6F 49 +# : 6D 70 6C A9 56 08 D1 0C 92 18 98 02 00 00 78 72 +# : 00 23 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65 +# : 72 2E 55 6E 69 63 61 73 74 52 65 6D 6F 74 65 4F +# : 62 6A 65 63 74 45 09 12 15 F5 E2 7E 31 02 00 03 +# : 49 00 04 70 6F 72 74 4C 00 03 63 73 66 74 00 28 +# : 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65 72 +# : 2F 52 4D 49 43 6C 69 65 6E 74 53 6F 63 6B 65 74 +# : 46 61 63 74 6F 72 79 3B 4C 00 03 73 73 66 74 00 +# : 28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 76 65 +# : 72 2F 52 4D 49 53 65 72 76 65 72 53 6F 63 6B 65 +# : 74 46 61 63 74 6F 72 79 3B 78 72 00 1C 6A 61 76 +# : 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 6D +# : 6F 74 65 53 65 72 76 65 72 C7 19 07 12 68 F3 39 +# : FB 02 00 00 78 72 00 1C 6A 61 76 61 2E 72 6D 69 +# : 2E 73 65 72 76 65 72 2E 52 65 6D 6F 74 65 4F 62 +# : 6A 65 63 74 D3 61 B4 91 0C 61 33 1E 03 00 00 78 +# : 70 77 12 00 10 55 6E 69 63 61 73 74 53 65 72 76 +# : 65 72 52 65 66 78 00 00 00 00 70 70 +# : } +# : } +# 399 69: SEQUENCE { +# 401 11: OCTET STRING 'objectClass' +# 414 54: SET { +# 416 3: OCTET STRING 'top' +# 421 13: OCTET STRING 'javaContainer' +# 436 10: OCTET STRING 'javaObject' +# 448 20: OCTET STRING 'javaSerializedObject' +# : } +# : } +# 470 227: SEQUENCE { +# 473 14: OCTET STRING 'javaClassNames' +# 489 208: SET { +# 492 27: OCTET STRING 'org.example.hello.HelloImpl' +# 521 35: OCTET STRING 'java.rmi.server.UnicastRemoteObject' +# 558 28: OCTET STRING 'java.rmi.server.RemoteServer' +# 588 28: OCTET STRING 'java.rmi.server.RemoteObject' +# 618 16: OCTET STRING 'java.lang.Object' +# 636 15: OCTET STRING 'java.rmi.Remote' +# 653 20: OCTET STRING 'java.io.Serializable' +# 675 23: OCTET STRING 'org.example.hello.Hello' +# : } +# : } +# 700 46: SEQUENCE { +# 702 13: OCTET STRING 'javaClassName' +# 717 29: SET { +# 719 27: OCTET STRING 'org.example.hello.HelloImpl' +# : } +# : } +# 748 16: SEQUENCE { +# 750 2: OCTET STRING 63 6E +# 754 10: SET { +# 756 8: OCTET STRING 'myremote' +# : } +# : } +# : } +# : } +# : } +# +0000: 30 82 02 FA 02 01 03 64 82 02 F3 04 22 63 6E 3D 0......d...."cn= +0010: 6D 79 72 65 6D 6F 74 65 2C 64 63 3D 69 65 2C 64 myremote,dc=ie,d +0020: 63 3D 6F 72 61 63 6C 65 2C 64 63 3D 63 6F 6D 30 c=oracle,dc=com0 +0030: 82 02 CB 30 82 01 58 04 12 6A 61 76 61 53 65 72 ...0..X..javaSer +0040: 69 61 6C 69 7A 65 64 44 61 74 61 31 82 01 40 04 ializedData1..@. +0050: 82 01 3C AC ED 00 05 73 72 00 1B 6F 72 67 2E 65 ..<....sr..org.e +0060: 78 61 6D 70 6C 65 2E 68 65 6C 6C 6F 2E 48 65 6C xample.hello.Hel +0070: 6C 6F 49 6D 70 6C A9 56 08 D1 0C 92 18 98 02 00 loImpl.V........ +0080: 00 78 72 00 23 6A 61 76 61 2E 72 6D 69 2E 73 65 .xr.#java.rmi.se +0090: 72 76 65 72 2E 55 6E 69 63 61 73 74 52 65 6D 6F rver.UnicastRemo +00A0: 74 65 4F 62 6A 65 63 74 45 09 12 15 F5 E2 7E 31 teObjectE......1 +00B0: 02 00 03 49 00 04 70 6F 72 74 4C 00 03 63 73 66 ...I..portL..csf +00C0: 74 00 28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 72 t.(Ljava/rmi/ser +00D0: 76 65 72 2F 52 4D 49 43 6C 69 65 6E 74 53 6F 63 ver/RMIClientSoc +00E0: 6B 65 74 46 61 63 74 6F 72 79 3B 4C 00 03 73 73 ketFactory;L..ss +00F0: 66 74 00 28 4C 6A 61 76 61 2F 72 6D 69 2F 73 65 ft.(Ljava/rmi/se +0100: 72 76 65 72 2F 52 4D 49 53 65 72 76 65 72 53 6F rver/RMIServerSo +0110: 63 6B 65 74 46 61 63 74 6F 72 79 3B 78 72 00 1C cketFactory;xr.. +0120: 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E java.rmi.server. +0130: 52 65 6D 6F 74 65 53 65 72 76 65 72 C7 19 07 12 RemoteServer.... +0140: 68 F3 39 FB 02 00 00 78 72 00 1C 6A 61 76 61 2E h.9....xr..java. +0150: 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 6D 6F 74 rmi.server.Remot +0160: 65 4F 62 6A 65 63 74 D3 61 B4 91 0C 61 33 1E 03 eObject.a...a3.. +0170: 00 00 78 70 77 12 00 10 55 6E 69 63 61 73 74 53 ..xpw...UnicastS +0180: 65 72 76 65 72 52 65 66 78 00 00 00 00 70 70 30 erverRefx....pp0 +0190: 45 04 0B 6F 62 6A 65 63 74 43 6C 61 73 73 31 36 E..objectClass16 +01A0: 04 03 74 6F 70 04 0D 6A 61 76 61 43 6F 6E 74 61 ..top..javaConta +01B0: 69 6E 65 72 04 0A 6A 61 76 61 4F 62 6A 65 63 74 iner..javaObject +01C0: 04 14 6A 61 76 61 53 65 72 69 61 6C 69 7A 65 64 ..javaSerialized +01D0: 4F 62 6A 65 63 74 30 81 E3 04 0E 6A 61 76 61 43 Object0....javaC +01E0: 6C 61 73 73 4E 61 6D 65 73 31 81 D0 04 1B 6F 72 lassNames1....or +01F0: 67 2E 65 78 61 6D 70 6C 65 2E 68 65 6C 6C 6F 2E g.example.hello. +0200: 48 65 6C 6C 6F 49 6D 70 6C 04 23 6A 61 76 61 2E HelloImpl.#java. +0210: 72 6D 69 2E 73 65 72 76 65 72 2E 55 6E 69 63 61 rmi.server.Unica +0220: 73 74 52 65 6D 6F 74 65 4F 62 6A 65 63 74 04 1C stRemoteObject.. +0230: 6A 61 76 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E java.rmi.server. +0240: 52 65 6D 6F 74 65 53 65 72 76 65 72 04 1C 6A 61 RemoteServer..ja +0250: 76 61 2E 72 6D 69 2E 73 65 72 76 65 72 2E 52 65 va.rmi.server.Re +0260: 6D 6F 74 65 4F 62 6A 65 63 74 04 10 6A 61 76 61 moteObject..java +0270: 2E 6C 61 6E 67 2E 4F 62 6A 65 63 74 04 0F 6A 61 .lang.Object..ja +0280: 76 61 2E 72 6D 69 2E 52 65 6D 6F 74 65 04 14 6A va.rmi.Remote..j +0290: 61 76 61 2E 69 6F 2E 53 65 72 69 61 6C 69 7A 61 ava.io.Serializa +02A0: 62 6C 65 04 17 6F 72 67 2E 65 78 61 6D 70 6C 65 ble..org.example +02B0: 2E 68 65 6C 6C 6F 2E 48 65 6C 6C 6F 30 2E 04 0D .hello.Hello0... +02C0: 6A 61 76 61 43 6C 61 73 73 4E 61 6D 65 31 1D 04 javaClassName1.. +02D0: 1B 6F 72 67 2E 65 78 61 6D 70 6C 65 2E 68 65 6C .org.example.hel +02E0: 6C 6F 2E 48 65 6C 6C 6F 49 6D 70 6C 30 10 04 02 lo.HelloImpl0... +02F0: 63 6E 31 0A 04 08 6D 79 72 65 6D 6F 74 65 cn1...myremote + +# LDAP SearchResultDone: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 3 +# 5 7: [APPLICATION 5] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 03 65 07 0A 01 00 04 00 04 00 0....e........ + +# LDAP DeleteRequest: +# +# 0 68: SEQUENCE { +# 2 1: INTEGER 4 +# 5 34: [APPLICATION 10] 'cn=myremote,dc=ie,dc=oracle,dc=com' +# 41 27: [0] { +# 43 25: SEQUENCE { +# 45 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 44 02 01 04 4A 22 63 6E 3D 6D 79 72 65 6D 6F 0D...J"cn=myremo +0010: 74 65 2C 64 63 3D 69 65 2C 64 63 3D 6F 72 61 63 te,dc=ie,dc=orac +0020: 6C 65 2C 64 63 3D 63 6F 6D A0 1B 30 19 04 17 32 le,dc=com..0...2 +0030: 2E 31 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 .16.840.1.113730 +0040: 2E 33 2E 34 2E 32 .3.4.2 + +# LDAP DeleteResponse: +# +# 0 12: SEQUENCE { +# 2 1: INTEGER 4 +# 5 7: [APPLICATION 11] { +# 7 1: ENUMERATED 0 +# 10 0: OCTET STRING +# 12 0: OCTET STRING +# : } +# : } +# +0000: 30 0C 02 01 04 6B 07 0A 01 00 04 00 04 00 0....k........ + +# LDAP UnbindRequest: +# +# 0 34: SEQUENCE { +# 2 1: INTEGER 5 +# 5 0: [APPLICATION 2] +# 7 27: [0] { +# 9 25: SEQUENCE { +# 11 23: OCTET STRING '2.16.840.1.113730.3.4.2' +# : } +# : } +# : } +# +0000: 30 22 02 01 05 42 00 A0 1B 30 19 04 17 32 2E 31 0"...B...0...2.1 +0010: 36 2E 38 34 30 2E 31 2E 31 31 33 37 33 30 2E 33 6.840.1.113730.3 +0020: 2E 34 2E 32 .4.2 diff --git a/jdk/test/javax/net/ssl/Stapling/TEST.properties b/jdk/test/javax/net/ssl/Stapling/TEST.properties new file mode 100644 index 00000000000..f4117a3ced2 --- /dev/null +++ b/jdk/test/javax/net/ssl/Stapling/TEST.properties @@ -0,0 +1,5 @@ +modules = \ + java.base/sun.security.provider.certpath \ + java.base/sun.security.util \ + java.base/sun.security.validator \ + java.base/sun.security.x509 diff --git a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java index d7f0d38cdee..fd5ec86e4ef 100644 --- a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -101,9 +101,6 @@ public class SSLSocketSSLEngineTemplate { private static final boolean debug = false; private final SSLContext sslc; private SSLEngine serverEngine; // server-side SSLEngine - private SSLSocket sslSocket; // client-side socket - private ServerSocket serverSocket; // server-side Socket, generates the... - private Socket socket; // server-side socket that will read private final byte[] serverMsg = "Hi there Client, I'm a Server.".getBytes(); @@ -217,132 +214,128 @@ public class SSLSocketSSLEngineTemplate { private void runTest(boolean direct) throws Exception { boolean serverClose = direct; - serverSocket = new ServerSocket(); - serverSocket.setReuseAddress(false); - serverSocket.bind(null); - int port = serverSocket.getLocalPort(); - Thread thread = createClientThread(port, serverClose); + // generates the server-side Socket + try (ServerSocket serverSocket = new ServerSocket()) { + serverSocket.setReuseAddress(false); + serverSocket.bind(null); + int port = serverSocket.getLocalPort(); + Thread thread = createClientThread(port, serverClose); - socket = serverSocket.accept(); - socket.setSoTimeout(500); - serverSocket.close(); + createSSLEngine(); + createBuffers(direct); - createSSLEngine(); - createBuffers(direct); + // server-side socket that will read + try (Socket socket = serverSocket.accept()) { + socket.setSoTimeout(500); - try { - boolean closed = false; - // will try to read one more time in case client message - // is fragmented to multiple pieces - boolean retry = true; + boolean closed = false; + // will try to read one more time in case client message + // is fragmented to multiple pieces + boolean retry = true; - InputStream is = socket.getInputStream(); - OutputStream os = socket.getOutputStream(); + InputStream is = socket.getInputStream(); + OutputStream os = socket.getOutputStream(); - SSLEngineResult serverResult; // results from last operation + SSLEngineResult serverResult; // results from last operation - /* - * Examining the SSLEngineResults could be much more involved, - * and may alter the overall flow of the application. - * - * For example, if we received a BUFFER_OVERFLOW when trying - * to write to the output pipe, we could reallocate a larger - * pipe, but instead we wait for the peer to drain it. - */ - byte[] inbound = new byte[8192]; - byte[] outbound = new byte[8192]; + /* + * Examining the SSLEngineResults could be much more involved, + * and may alter the overall flow of the application. + * + * For example, if we received a BUFFER_OVERFLOW when trying + * to write to the output pipe, we could reallocate a larger + * pipe, but instead we wait for the peer to drain it. + */ + byte[] inbound = new byte[8192]; + byte[] outbound = new byte[8192]; - while (!isEngineClosed(serverEngine)) { - int len; + while (!isEngineClosed(serverEngine)) { + int len; - // Inbound data - log("================"); + // Inbound data + log("================"); - // Read from the Client side. - try { - len = is.read(inbound); - if (len == -1) { - throw new Exception("Unexpected EOF"); - } - cTOs.put(inbound, 0, len); - } catch (SocketTimeoutException ste) { - // swallow. Nothing yet, probably waiting on us. - } - - cTOs.flip(); - - serverResult = serverEngine.unwrap(cTOs, serverIn); - log("server unwrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); - cTOs.compact(); - - // Outbound data - log("----"); - - serverResult = serverEngine.wrap(serverOut, sTOc); - log("server wrap: ", serverResult); - runDelegatedTasks(serverResult, serverEngine); - - sTOc.flip(); - - if ((len = sTOc.remaining()) != 0) { - sTOc.get(outbound, 0, len); - os.write(outbound, 0, len); - // Give the other side a chance to process - } - - sTOc.compact(); - - if (!closed && (serverOut.remaining() == 0)) { - closed = true; - - /* - * We'll alternate initiatating the shutdown. - * When the server initiates, it will take one more - * loop, but tests the orderly shutdown. - */ - if (serverClose) { - serverEngine.closeOutbound(); - } - serverIn.flip(); - - /* - * A sanity check to ensure we got what was sent. - */ - if (serverIn.remaining() != clientMsg.length) { - if (retry && serverIn.remaining() < clientMsg.length) { - log("Need to read more from client"); - retry = false; - continue; - } else { - throw new Exception("Client: Data length error"); + // Read from the Client side. + try { + len = is.read(inbound); + if (len == -1) { + throw new Exception("Unexpected EOF"); } + cTOs.put(inbound, 0, len); + } catch (SocketTimeoutException ste) { + // swallow. Nothing yet, probably waiting on us. } - for (int i = 0; i < clientMsg.length; i++) { - if (clientMsg[i] != serverIn.get()) { - throw new Exception("Client: Data content error"); - } + cTOs.flip(); + + serverResult = serverEngine.unwrap(cTOs, serverIn); + log("server unwrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + cTOs.compact(); + + // Outbound data + log("----"); + + serverResult = serverEngine.wrap(serverOut, sTOc); + log("server wrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + + sTOc.flip(); + + if ((len = sTOc.remaining()) != 0) { + sTOc.get(outbound, 0, len); + os.write(outbound, 0, len); + // Give the other side a chance to process } - serverIn.compact(); + + sTOc.compact(); + + if (!closed && (serverOut.remaining() == 0)) { + closed = true; + + /* + * We'll alternate initiatating the shutdown. + * When the server initiates, it will take one more + * loop, but tests the orderly shutdown. + */ + if (serverClose) { + serverEngine.closeOutbound(); + } + serverIn.flip(); + + /* + * A sanity check to ensure we got what was sent. + */ + if (serverIn.remaining() != clientMsg.length) { + if (retry && + serverIn.remaining() < clientMsg.length) { + log("Need to read more from client"); + retry = false; + continue; + } else { + throw new Exception( + "Client: Data length error"); + } + } + + for (int i = 0; i < clientMsg.length; i++) { + if (clientMsg[i] != serverIn.get()) { + throw new Exception( + "Client: Data content error"); + } + } + serverIn.compact(); + } + } + } catch (Exception e) { + serverException = e; + } finally { + // Wait for the client to join up with us. + if (thread != null) { + thread.join(); } } - } catch (Exception e) { - serverException = e; } finally { - if (socket != null) { - socket.close(); - } - - // Wait for the client to join up with us. - if (thread != null) { - thread.join(); - } - - if (sslSocket != null) { - sslSocket.close(); - } - if (serverException != null) { if (clientException != null) { serverException.initCause(clientException); @@ -369,11 +362,9 @@ public class SSLSocketSSLEngineTemplate { @Override public void run() { - try { - Thread.sleep(1000); // Give server time to finish setup. - - sslSocket = (SSLSocket) sslc.getSocketFactory(). - createSocket("localhost", port); + // client-side socket + try (SSLSocket sslSocket = (SSLSocket)sslc.getSocketFactory(). + createSocket("localhost", port)) { OutputStream os = sslSocket.getOutputStream(); InputStream is = sslSocket.getInputStream(); diff --git a/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java b/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java index 920f4056267..12dfcaacae5 100644 --- a/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/jdk/test/javax/net/ssl/templates/SSLSocketTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -85,26 +85,26 @@ public class SSLSocketTemplate { */ void doServerSide() throws Exception { SSLServerSocketFactory sslssf = - (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); - SSLServerSocket sslServerSocket = - (SSLServerSocket) sslssf.createServerSocket(serverPort); + (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); + try (SSLServerSocket sslServerSocket = + (SSLServerSocket)sslssf.createServerSocket(serverPort)) { - serverPort = sslServerSocket.getLocalPort(); + serverPort = sslServerSocket.getLocalPort(); - /* - * Signal Client, we're ready for his connect. - */ - serverReady = true; + /* + * Signal Client, we're ready for his connect. + */ + serverReady = true; - SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); + try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) { + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - sslIS.read(); - sslOS.write(85); - sslOS.flush(); - - sslSocket.close(); + sslIS.read(); + sslOS.write(85); + sslOS.flush(); + } + } } /* @@ -123,18 +123,17 @@ public class SSLSocketTemplate { } SSLSocketFactory sslsf = - (SSLSocketFactory) SSLSocketFactory.getDefault(); - SSLSocket sslSocket = (SSLSocket) - sslsf.createSocket("localhost", serverPort); + (SSLSocketFactory)SSLSocketFactory.getDefault(); + try (SSLSocket sslSocket = + (SSLSocket)sslsf.createSocket("localhost", serverPort)) { - InputStream sslIS = sslSocket.getInputStream(); - OutputStream sslOS = sslSocket.getOutputStream(); + InputStream sslIS = sslSocket.getInputStream(); + OutputStream sslOS = sslSocket.getOutputStream(); - sslOS.write(280); - sslOS.flush(); - sslIS.read(); - - sslSocket.close(); + sslOS.write(280); + sslOS.flush(); + sslIS.read(); + } } /* diff --git a/jdk/test/javax/security/auth/login/modules/JaasClient.java b/jdk/test/javax/security/auth/login/modules/JaasClient.java new file mode 100644 index 00000000000..6f1ef403224 --- /dev/null +++ b/jdk/test/javax/security/auth/login/modules/JaasClient.java @@ -0,0 +1,103 @@ +/* + * 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 client; + +import java.io.IOException; +import java.security.Principal; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; +import javax.security.auth.login.LoginContext; +import com.sun.security.auth.UnixPrincipal; + +/** + * JAAS client which will try to authenticate a user through a custom JAAS LOGIN + * Module. + */ +public class JaasClient { + + private static final String USER_NAME = "testUser"; + private static final String PASSWORD = "testPassword"; + private static final String LOGIN_CONTEXT = "ModularLoginConf"; + + public static void main(String[] args) { + try { + LoginContext lc = new LoginContext(LOGIN_CONTEXT, + new MyCallbackHandler()); + lc.login(); + checkPrincipal(lc, true); + lc.logout(); + checkPrincipal(lc, false); + } catch (LoginException le) { + throw new RuntimeException(le); + } + System.out.println("Test passed."); + + } + + /* + * Check context for principal of the test user. + */ + private static void checkPrincipal(LoginContext loginContext, + boolean principalShouldExist) { + if (!principalShouldExist) { + if (loginContext.getSubject().getPrincipals().size() != 0) { + throw new RuntimeException("Test failed. Principal was not " + + "cleared."); + } + return; + } + for (Principal p : loginContext.getSubject().getPrincipals()) { + if (p instanceof UnixPrincipal + && USER_NAME.equals(p.getName())) { + //Proper principal was found, return. + return; + } + } + throw new RuntimeException("Test failed. UnixPrincipal " + + USER_NAME + " expected."); + + } + + private static class MyCallbackHandler implements CallbackHandler { + + @Override + public void handle(Callback[] callbacks) throws IOException, + UnsupportedCallbackException { + for (Callback callback : callbacks) { + if (callback instanceof NameCallback) { + ((NameCallback) callback).setName(USER_NAME); + } else if (callback instanceof PasswordCallback) { + ((PasswordCallback) callback).setPassword( + PASSWORD.toCharArray()); + } else { + throw new UnsupportedCallbackException(callback); + } + } + } + } + +} diff --git a/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java b/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java new file mode 100644 index 00000000000..d662d0e14be --- /dev/null +++ b/jdk/test/javax/security/auth/login/modules/JaasModularClientTest.java @@ -0,0 +1,292 @@ +/* + * 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. + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Arrays; +import java.io.IOException; +import java.lang.module.ModuleDescriptor; +import java.util.ArrayList; +import jdk.testlibrary.ProcessTools; +import jdk.testlibrary.OutputAnalyzer; +import org.testng.annotations.BeforeTest; + +/** + * @test + * @bug 8078813 + * @library /lib/testlibrary + * @library /java/security/modules + * @build CompilerUtils JarUtils + * @summary Test custom JAAS module with all possible modular option. The test + * includes different combination of JAAS client/login modules + * interaction with or without service description. + * @run testng JaasModularClientTest + */ +public class JaasModularClientTest extends ModularTest { + + private static final Path S_SRC = SRC.resolve("TestLoginModule.java"); + private static final String S_PKG = "login"; + private static final String S_JAR_NAME = S_PKG + JAR_EXTN; + private static final String S_DESCR_JAR_NAME = S_PKG + DESCRIPTOR + + JAR_EXTN; + private static final String MS_JAR_NAME = MODULAR + S_PKG + JAR_EXTN; + private static final String MS_DESCR_JAR_NAME = MODULAR + S_PKG + DESCRIPTOR + + JAR_EXTN; + + private static final Path C_SRC = SRC.resolve("JaasClient.java"); + private static final String C_PKG = "client"; + private static final String C_JAR_NAME = C_PKG + JAR_EXTN; + private static final String MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME = MODULAR + + C_PKG + AUTO + JAR_EXTN; + private static final String MC_JAR_NAME = MODULAR + C_PKG + JAR_EXTN; + + private static final Path BUILD_DIR = Paths.get(".").resolve("build"); + private static final Path COMPILE_DIR = BUILD_DIR.resolve("bin"); + private static final Path S_BUILD_DIR = COMPILE_DIR.resolve(S_PKG); + private static final Path S_WITH_META_DESCR_BUILD_DIR = COMPILE_DIR.resolve( + S_PKG + DESCRIPTOR); + private static final Path C_BUILD_DIR = COMPILE_DIR.resolve(C_PKG); + private static final Path M_BASE_PATH = BUILD_DIR.resolve("mbase"); + private static final Path ARTIFACTS_DIR = BUILD_DIR.resolve("artifacts"); + + private static final Path S_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(S_PKG); + private static final Path S_JAR = S_ARTIFACTS_DIR.resolve(S_JAR_NAME); + private static final Path S_WITH_DESCRIPTOR_JAR = S_ARTIFACTS_DIR.resolve( + S_DESCR_JAR_NAME); + private static final Path MS_JAR = S_ARTIFACTS_DIR.resolve(MS_JAR_NAME); + private static final Path MS_WITH_DESCR_JAR = S_ARTIFACTS_DIR.resolve( + MS_DESCR_JAR_NAME); + + private static final Path C_ARTIFACTS_DIR = ARTIFACTS_DIR.resolve(C_PKG); + private static final Path C_JAR = C_ARTIFACTS_DIR.resolve(C_JAR_NAME); + private static final Path MC_JAR = C_ARTIFACTS_DIR.resolve(MC_JAR_NAME); + private static final Path MC_DEPENDS_ON_AUTO_SERVICE_JAR = C_ARTIFACTS_DIR + .resolve(MC_DEPENDS_ON_AUTO_SERVICE_JAR_NAME); + + private static final String MAIN = C_PKG + ".JaasClient"; + private static final String S_INTERFACE + = "javax.security.auth.spi.LoginModule"; + private static final String S_IMPL = S_PKG + ".TestLoginModule"; + private static final List M_REQUIRED = Arrays.asList("java.base", + "jdk.security.auth"); + private static final Path META_DESCR_PATH = Paths.get("META-INF") + .resolve("services").resolve(S_INTERFACE); + private static final Path S_META_DESCR_FPATH = S_WITH_META_DESCR_BUILD_DIR + .resolve(META_DESCR_PATH); + + private static final boolean WITH_S_DESCR = true; + private static final boolean WITHOUT_S_DESCR = false; + private static final String LOGIN_MODULE_NOT_FOUND_MSG + = "No LoginModule found"; + private static final String NO_FAILURE = null; + private static final Map VM_ARGS = new LinkedHashMap<>(); + + /** + * Generates Test specific input parameters. + */ + @Override + public Object[][] getTestInput() { + + List> params = new ArrayList<>(); + String[] args = new String[]{}; + //PARAMETER ORDERS - + //client Module Type, Service Module Type, + //Service META Descriptor Required, + //Expected Failure message, mechanism used to find the provider + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.EXPLICIT, + WITHOUT_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.AUTO, + WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.EXPLICIT, MODULE_TYPE.UNNAMED, + WITHOUT_S_DESCR, NO_FAILURE, args)); + + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.EXPLICIT, + WITHOUT_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.AUTO, + WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.AUTO, MODULE_TYPE.UNNAMED, + WITHOUT_S_DESCR, NO_FAILURE, args)); + + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.EXPLICIT, + WITHOUT_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.AUTO, + WITHOUT_S_DESCR, LOGIN_MODULE_NOT_FOUND_MSG, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED, + WITH_S_DESCR, NO_FAILURE, args)); + params.add(Arrays.asList(MODULE_TYPE.UNNAMED, MODULE_TYPE.UNNAMED, + WITHOUT_S_DESCR, NO_FAILURE, args)); + return params.stream().map(p -> p.toArray()).toArray(Object[][]::new); + } + + /** + * Pre-compile and generate the artifacts required to run this test before + * running each test cases. + */ + @BeforeTest + public void buildArtifacts() { + + boolean done = true; + try { + VM_ARGS.put("-Duser.language=", "en"); + VM_ARGS.put("-Duser.region", "US"); + VM_ARGS.put("-Djava.security.auth.login.config=", SRC.resolve( + "jaas.conf").toFile().getCanonicalPath()); + + done = CompilerUtils.compile(S_SRC, S_BUILD_DIR); + done &= CompilerUtils.compile(S_SRC, S_WITH_META_DESCR_BUILD_DIR); + done &= createMetaInfServiceDescriptor(S_META_DESCR_FPATH, S_IMPL); + //Generate regular/modular jars with(out) META-INF + //service descriptor + generateJar(true, MODULE_TYPE.EXPLICIT, MS_JAR, S_BUILD_DIR, false); + generateJar(true, MODULE_TYPE.EXPLICIT, MS_WITH_DESCR_JAR, + S_WITH_META_DESCR_BUILD_DIR, false); + generateJar(true, MODULE_TYPE.UNNAMED, S_JAR, S_BUILD_DIR, false); + generateJar(true, MODULE_TYPE.UNNAMED, S_WITH_DESCRIPTOR_JAR, + S_WITH_META_DESCR_BUILD_DIR, false); + //Generate regular/modular(depends on explicit/auto service) + //jars for client + done &= CompilerUtils.compile(C_SRC, C_BUILD_DIR); + generateJar(false, MODULE_TYPE.EXPLICIT, MC_JAR, C_BUILD_DIR, true); + generateJar(false, MODULE_TYPE.EXPLICIT, + MC_DEPENDS_ON_AUTO_SERVICE_JAR, C_BUILD_DIR, false); + generateJar(false, MODULE_TYPE.UNNAMED, C_JAR, C_BUILD_DIR, false); + System.out.format("%nArtifacts generated successfully? %s", done); + if (!done) { + throw new RuntimeException("Artifact generation failed"); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Generate modular/regular jar based on module type for this test. + */ + private void generateJar(boolean isService, MODULE_TYPE moduleType, + Path jar, Path compilePath, boolean depends) throws IOException { + + ModuleDescriptor mDescriptor = null; + if (isService) { + mDescriptor = generateModuleDescriptor(isService, moduleType, S_PKG, + S_PKG, S_INTERFACE, S_IMPL, null, M_REQUIRED, depends); + } else { + mDescriptor = generateModuleDescriptor(isService, moduleType, C_PKG, + C_PKG, S_INTERFACE, null, S_PKG, M_REQUIRED, depends); + } + generateJar(mDescriptor, jar, compilePath); + } + + /** + * Holds Logic for the test client. This method will get called with each + * test parameter. + */ + @Override + public OutputAnalyzer executeTestClient(MODULE_TYPE cModuleType, + Path cJarPath, MODULE_TYPE sModuletype, Path sJarPath, + String... args) throws Exception { + + OutputAnalyzer output = null; + try { + //For automated/explicit module type copy the corresponding + //jars to module base folder, which will be considered as + //module base path during execution. + if (!(cModuleType == MODULE_TYPE.UNNAMED + && sModuletype == MODULE_TYPE.UNNAMED)) { + copyJarsToModuleBase(cModuleType, cJarPath, M_BASE_PATH); + copyJarsToModuleBase(sModuletype, sJarPath, M_BASE_PATH); + } + + System.out.format("%nExecuting java client with required" + + " custom service in class/module path."); + String mName = getModuleName(cModuleType, cJarPath, + C_PKG); + Path cmBasePath = (cModuleType != MODULE_TYPE.UNNAMED + || sModuletype != MODULE_TYPE.UNNAMED) ? M_BASE_PATH : null; + String cPath = buildClassPath(cModuleType, cJarPath, sModuletype, + sJarPath); + output = ProcessTools.executeTestJava( + getJavaCommand(cmBasePath, cPath, mName, MAIN, VM_ARGS, + args)).outputTo(System.out).errorTo(System.out); + } finally { + //clean module path so that the modulepath can hold only + //the required jars for next run. + cleanModuleBasePath(M_BASE_PATH); + System.out.println("--------------------------------------------"); + } + return output; + } + + /** + * Decide the pre-generated client/service jar path for each test case + * based on client/service module type. + */ + @Override + public Path findJarPath(boolean service, MODULE_TYPE moduleType, + boolean addMetaDesc, boolean dependsOnServiceModule) { + if (service) { + if (moduleType == MODULE_TYPE.EXPLICIT) { + if (addMetaDesc) { + return MS_WITH_DESCR_JAR; + } else { + return MS_JAR; + } + } else { + if (addMetaDesc) { + return S_WITH_DESCRIPTOR_JAR; + } else { + return S_JAR; + } + } + } else { + if (moduleType == MODULE_TYPE.EXPLICIT) { + if (dependsOnServiceModule) { + return MC_JAR; + } else { + return MC_DEPENDS_ON_AUTO_SERVICE_JAR; + } + } else { + return C_JAR; + } + } + } + +} diff --git a/jdk/test/javax/security/auth/login/modules/TEST.properties b/jdk/test/javax/security/auth/login/modules/TEST.properties new file mode 100644 index 00000000000..348c11904cf --- /dev/null +++ b/jdk/test/javax/security/auth/login/modules/TEST.properties @@ -0,0 +1 @@ +modules java.base/jdk.internal.module diff --git a/jdk/test/javax/security/auth/login/modules/TestLoginModule.java b/jdk/test/javax/security/auth/login/modules/TestLoginModule.java new file mode 100644 index 00000000000..166dda902e1 --- /dev/null +++ b/jdk/test/javax/security/auth/login/modules/TestLoginModule.java @@ -0,0 +1,140 @@ +/* + * 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 login; + +import java.io.IOException; +import java.util.Map; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; +import com.sun.security.auth.UnixPrincipal; + +/** + * Custom JAAS login module which will be loaded through Java LoginContext when + * it is bundled by Strict/Auto/Unnamed modules. + */ +public class TestLoginModule implements LoginModule { + + private static final String USER_NAME = "testUser"; + private static final String PASSWORD = "testPassword"; + private Subject subject; + private CallbackHandler callbackHandler; + private UnixPrincipal userPrincipal; + private String username; + private String password; + private boolean succeeded = false; + private boolean commitSucceeded = false; + + @Override + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + + this.subject = subject; + this.callbackHandler = callbackHandler; + System.out.println(String.format( + "'%s' login module initialized", this.getClass())); + } + + /* + * Authenticate the user by prompting for a username and password. + */ + @Override + public boolean login() throws LoginException { + if (callbackHandler == null) { + throw new LoginException("No CallbackHandler available"); + } + + Callback[] callbacks = new Callback[2]; + callbacks[0] = new NameCallback("Username: "); + callbacks[1] = new PasswordCallback("Password: ", false); + + try { + callbackHandler.handle(callbacks); + username = ((NameCallback) callbacks[0]).getName(); + password = new String(((PasswordCallback) callbacks[1]) + .getPassword()); + System.out.println(String.format("'%s' login module found username" + + " as '%s' and password as '%s'", this.getClass(), + username, password)); + if (username.equals(USER_NAME) + && password.equals(PASSWORD)) { + System.out.println(String.format("'%s' login module " + + "authentication done successfully", this.getClass())); + succeeded = true; + return true; + } + throw new IllegalArgumentException("Incorrect username/password!"); + } catch (IOException | UnsupportedCallbackException e) { + throw new LoginException("Login failed: " + e.getMessage()); + } + } + + @Override + public boolean commit() throws LoginException { + if (succeeded == false) { + return false; + } + userPrincipal = new UnixPrincipal(username); + if (!subject.getPrincipals().contains(userPrincipal)) { + subject.getPrincipals().add(userPrincipal); + } + System.out.println(String.format("'%s' login module authentication " + + "committed", this.getClass())); + password = null; + commitSucceeded = true; + return true; + } + + @Override + public boolean abort() throws LoginException { + if (succeeded == false) { + return false; + } + System.out.println(String.format( + "'%s' login module aborted", this.getClass())); + clearState(); + return true; + } + + @Override + public boolean logout() throws LoginException { + clearState(); + System.out.println(String.format( + "'%s' login module logout completed", this.getClass())); + return true; + } + + private void clearState() { + if (commitSucceeded) { + subject.getPrincipals().remove(userPrincipal); + } + username = null; + password = null; + userPrincipal = null; + } +} diff --git a/jdk/test/javax/security/auth/login/modules/jaas.conf b/jdk/test/javax/security/auth/login/modules/jaas.conf new file mode 100644 index 00000000000..c4b536e782c --- /dev/null +++ b/jdk/test/javax/security/auth/login/modules/jaas.conf @@ -0,0 +1,3 @@ +ModularLoginConf { + login.TestLoginModule required; +}; diff --git a/jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java b/jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java new file mode 100644 index 00000000000..e32e7723db5 --- /dev/null +++ b/jdk/test/javax/sound/sampled/AudioInputStream/FrameLengthAfterConversion.java @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileWriter; +import javax.sound.sampled.spi.FormatConversionProvider; + +import static java.util.ServiceLoader.load; +import static javax.sound.sampled.AudioFileFormat.Type.AIFC; +import static javax.sound.sampled.AudioFileFormat.Type.AIFF; +import static javax.sound.sampled.AudioFileFormat.Type.AU; +import static javax.sound.sampled.AudioFileFormat.Type.SND; +import static javax.sound.sampled.AudioFileFormat.Type.WAVE; +import static javax.sound.sampled.AudioSystem.NOT_SPECIFIED; + +/** + * @test + * @bug 8038139 + */ +public final class FrameLengthAfterConversion { + + /** + * We will try to use all formats, in this case all our providers will be + * covered by supported/unsupported formats. + */ + private static final List formats = new ArrayList<>(23000); + + private static final AudioFormat.Encoding[] encodings = { + AudioFormat.Encoding.ALAW, AudioFormat.Encoding.ULAW, + AudioFormat.Encoding.PCM_SIGNED, AudioFormat.Encoding.PCM_UNSIGNED, + AudioFormat.Encoding.PCM_FLOAT, new AudioFormat.Encoding("Test") + }; + + private static final int[] sampleBits = { + 1, 4, 8, 11, 16, 20, 24, 32 + }; + + private static final int[] channels = { + 1, 2, 3, 4, 5 + }; + + private static final AudioFileFormat.Type[] types = { + WAVE, AU, AIFF, AIFC, SND, + new AudioFileFormat.Type("TestName", "TestExt") + }; + + private static final int FRAME_LENGTH = 10; + + static { + for (final int sampleSize : sampleBits) { + for (final int channel : channels) { + for (final AudioFormat.Encoding enc : encodings) { + final int frameSize = ((sampleSize + 7) / 8) * channel; + formats.add(new AudioFormat(enc, 44100, sampleSize, channel, + frameSize, 44100, true)); + formats.add(new AudioFormat(enc, 44100, sampleSize, channel, + frameSize, 44100, false)); + } + } + } + } + + public static void main(final String[] args) { + for (final FormatConversionProvider fcp : load( + FormatConversionProvider.class)) { + System.out.println("fcp = " + fcp); + for (final AudioFormat from : formats) { + for (final AudioFormat to : formats) { + testAfterConversion(fcp, to, getStream(from, true)); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToStream(afw, type, getStream(from, true)); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToFile(afw, type, getStream(from, true)); + } + } + } + + for (final AudioFileWriter afw : load(AudioFileWriter.class)) { + System.out.println("afw = " + afw); + for (final AudioFileFormat.Type type : types) { + for (final AudioFormat from : formats) { + testAfterSaveToFile(afw, type, getStream(from, false)); + } + } + } + } + + /** + * Verifies the frame length after the stream was saved/read to/from + * stream. + */ + private static void testAfterSaveToStream(final AudioFileWriter afw, + final AudioFileFormat.Type type, + final AudioInputStream ais) { + try { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + afw.write(ais, type, out); + final InputStream input = new ByteArrayInputStream( + out.toByteArray()); + validate(AudioSystem.getAudioInputStream(input).getFrameLength()); + } catch (IllegalArgumentException | UnsupportedAudioFileException + | IOException ignored) { + } + } + + /** + * Verifies the frame length after the stream was saved/read to/from file. + */ + private static void testAfterSaveToFile(final AudioFileWriter afw, + final AudioFileFormat.Type type, + AudioInputStream ais) { + try { + final File temp = File.createTempFile("sound", ".tmp"); + temp.deleteOnExit(); + afw.write(ais, type, temp); + ais = AudioSystem.getAudioInputStream(temp); + final long frameLength = ais.getFrameLength(); + ais.close(); + temp.delete(); + validate(frameLength); + } catch (IllegalArgumentException | UnsupportedAudioFileException + | IOException ignored) { + } + } + + /** + * Verifies the frame length after the stream was converted to other + * stream. + * + * @see FormatConversionProvider#getAudioInputStream(AudioFormat, + * AudioInputStream) + */ + private static void testAfterConversion(final FormatConversionProvider fcp, + final AudioFormat to, + final AudioInputStream ais) { + if (fcp.isConversionSupported(to, ais.getFormat())) { + validate(fcp.getAudioInputStream(to, ais).getFrameLength()); + } + } + + /** + * Throws an exception if the frameLength is specified and is not equal to + * the gold value. + */ + private static void validate(final long frameLength) { + if (frameLength != FRAME_LENGTH) { + System.err.println("Expected: " + FRAME_LENGTH); + System.err.println("Actual: " + frameLength); + throw new RuntimeException(); + } + } + + private static AudioInputStream getStream(final AudioFormat format, + final boolean frameLength) { + final int dataSize = FRAME_LENGTH * format.getFrameSize(); + final InputStream in = new ByteArrayInputStream(new byte[dataSize]); + if (frameLength) { + return new AudioInputStream(in, format, FRAME_LENGTH); + } else { + return new AudioInputStream(in, format, NOT_SPECIFIED); + } + } +} diff --git a/jdk/test/javax/swing/JComboBox/8080972/TestBasicComboBoxEditor.java b/jdk/test/javax/swing/JComboBox/8080972/TestBasicComboBoxEditor.java new file mode 100644 index 00000000000..205aecc9d87 --- /dev/null +++ b/jdk/test/javax/swing/JComboBox/8080972/TestBasicComboBoxEditor.java @@ -0,0 +1,73 @@ +/* + * 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. + */ +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.plaf.basic.BasicComboBoxEditor; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestBasicComboBoxEditor { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestBasicComboBoxEditor::testBasicComboBoxEditor); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestBasicComboBoxEditor::testBasicComboBoxEditor); + } + + private static void testBasicComboBoxEditor() { + + BasicComboBoxEditor comboBoxEditor = new BasicComboBoxEditor(); + comboBoxEditor.setItem(new UserComboBoxEditorType("100")); + + JTextField editor = (JTextField) comboBoxEditor.getEditorComponent(); + editor.setText("200"); + UserComboBoxEditorType item = (UserComboBoxEditorType) comboBoxEditor.getItem(); + + if (!item.str.equals("200")) { + throw new RuntimeException("Wrong itme value!"); + } + } + + public static class UserComboBoxEditorType { + + String str; + + public UserComboBoxEditorType(String str) { + this.str = str; + } + + public static UserComboBoxEditorType valueOf(String str) { + return new UserComboBoxEditorType(str); + } + + @Override + public String toString() { + return "UserComboBoxEditorType: " + str; + } + } +} diff --git a/jdk/test/javax/swing/JEditorPane/8080972/TestJEditor.java b/jdk/test/javax/swing/JEditorPane/8080972/TestJEditor.java new file mode 100644 index 00000000000..7e12100ff00 --- /dev/null +++ b/jdk/test/javax/swing/JEditorPane/8080972/TestJEditor.java @@ -0,0 +1,115 @@ +/* + * 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. + */ +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import javax.swing.Action; +import javax.swing.JEditorPane; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import javax.swing.text.ViewFactory; + +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ +public class TestJEditor { + + public static void main(String[] args) throws Exception { + + SwingUtilities.invokeAndWait(TestJEditor::testJEditorPane); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestJEditor::testJEditorPane); + } + + private static void testJEditorPane() { + + try { + + JEditorPane.registerEditorKitForContentType("text/html", UserEditorKit.class.getName()); + EditorKit editorKit = JEditorPane.createEditorKitForContentType("text/html"); + + if (!(editorKit instanceof UserEditorKit)) { + throw new RuntimeException("Editor kit is not UserEditorKit!"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static class UserEditorKit extends EditorKit { + + @Override + public String getContentType() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public ViewFactory getViewFactory() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Action[] getActions() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Caret createCaret() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Document createDefaultDocument() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void read(InputStream in, Document doc, int pos) throws IOException, BadLocationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void write(OutputStream out, Document doc, int pos, int len) throws IOException, BadLocationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public void write(Writer out, Document doc, int pos, int len) throws IOException, BadLocationException { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java b/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java new file mode 100644 index 00000000000..0892b5e2090 --- /dev/null +++ b/jdk/test/javax/swing/JFileChooser/ShellFolderQueries/ShellFolderQueriesTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8081722 + * @summary Provide public API for file hierarchy provided by + * sun.awt.shell.ShellFolder + * @author Semyon Sadetsky + * @run main ShellFolderQueriesTest + */ + +import sun.awt.OSInfo; + +import javax.swing.filechooser.FileSystemView; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +public class ShellFolderQueriesTest { + static final String HOME = System.getProperty("user.home"); + static final FileSystemView fsv = FileSystemView.getFileSystemView(); + + + static String scriptBeg = + "set WshShell = WScript.CreateObject(\"WScript.Shell\")\n" + + "set oShellLink = WshShell.CreateShortcut(\"shortcut.lnk\")\n" + + "oShellLink.TargetPath = \""; + static String scriptEnd = "\"\noShellLink.WindowStyle = 1\noShellLink.Save"; + + public static void main(String[] args) throws Exception { + if(OSInfo.getOSType() == OSInfo.OSType.WINDOWS) { + testGet(); + testLink(); + } else { + testGet(); + } + System.out.println("ok"); + } + + private static void testLink() throws IOException, InterruptedException { + // Create and execute VBS script to create a link + File file = createVbsScript(scriptBeg + HOME + scriptEnd); + Runtime.getRuntime().exec("cscript " + file.getName(), null, + file.getParentFile()).waitFor(); + file.delete(); + + File link = new File(file.getParentFile(), "shortcut.lnk"); + if (!fsv.isLink(link)) { + link.delete(); + throw new RuntimeException("Link is not detected"); + } + + File location = fsv.getLinkLocation(link); + if (!location.getAbsolutePath().equals(HOME)) { + link.delete(); + throw new RuntimeException("Link location " + location + + " is wrong"); + } + link.delete(); + + + link = File.createTempFile("test", ".tst"); + + if (fsv.isLink(link)) { + link.delete(); + throw new RuntimeException("File is not a link"); + } + + try { + location = fsv.getLinkLocation(link); + if (location != null) { + link.delete(); + throw new RuntimeException("Not a link, should return null"); + } + } + catch (FileNotFoundException e) { + } + link.delete(); + } + + private static File createVbsScript(String script) throws IOException { + File file = File.createTempFile("test", ".vbs"); + file.deleteOnExit(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(script.getBytes()); + fos.close(); + return file; + } + + private static void testGet() { + File[] files = fsv.getChooserComboBoxFiles(); + for (File file : files) { + if (fsv.isLink(file)) { + throw new RuntimeException( + "Link shouldn't be in FileChooser combobox, " + + file.getPath()); + } + } + } +} diff --git a/jdk/test/javax/swing/JFormattedTextField/8080972/TestDefaultFormatter.java b/jdk/test/javax/swing/JFormattedTextField/8080972/TestDefaultFormatter.java new file mode 100644 index 00000000000..eabb0265c95 --- /dev/null +++ b/jdk/test/javax/swing/JFormattedTextField/8080972/TestDefaultFormatter.java @@ -0,0 +1,75 @@ +/* + * 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. + */ +import java.text.ParseException; +import javax.swing.SwingUtilities; +import javax.swing.text.DefaultFormatter; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestDefaultFormatter { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestDefaultFormatter::testDefaultFormatter); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestDefaultFormatter::testDefaultFormatter); + } + private static void testDefaultFormatter() { + testDefaultFormatter(new DefaultFormatter() { + }); + testDefaultFormatter(new DefaultFormatter()); + } + + private static void testDefaultFormatter(DefaultFormatter formatter ) { + try { + System.out.println("formatter: " + formatter.getClass()); + formatter.setValueClass(UserValueClass.class); + UserValueClass userValue = (UserValueClass) formatter.stringToValue("test"); + + if (!userValue.str.equals("test")) { + throw new RuntimeException("String value is wrong!"); + } + } catch (ParseException ex) { + throw new RuntimeException(ex); + } + + } + + public static class UserValueClass { + + String str; + + public UserValueClass(String str) { + this.str = str; + } + + @Override + public String toString() { + return "UserValueClass: " + str; + } + } +} diff --git a/jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java b/jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java new file mode 100644 index 00000000000..4ff95c5bc30 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + * @bug 8146321 + * @summary verifies JInternalFrame Icon and ImageIcon + * @library ../../regtesthelpers + * @build Util + * @run main JInternalFrameIconTest + */ +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +public class JInternalFrameIconTest { + + private static JFrame frame; + private static JDesktopPane desktopPane; + private static JInternalFrame internalFrame; + private static ImageIcon titleImageIcon; + private static Icon titleIcon; + private static BufferedImage imageIconImage; + private static BufferedImage iconImage; + + private static Robot robot; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.delay(2000); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName()); + } + + } + + private static void executeCase(String lookAndFeelString) throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + createImageIconUI(lookAndFeelString); + robot.delay(1000); + getImageIconBufferedImage(); + robot.waitForIdle(); + cleanUp(); + robot.waitForIdle(); + + createIconUI(lookAndFeelString); + robot.delay(1000); + getIconBufferedImage(); + robot.waitForIdle(); + cleanUp(); + robot.waitForIdle(); + testIfSame(); + robot.waitForIdle(); + } + + } + + private static void createImageIconUI(final String lookAndFeelString) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + desktopPane = new JDesktopPane(); + internalFrame = new JInternalFrame(); + frame = new JFrame(); + internalFrame.setTitle(lookAndFeelString); + titleImageIcon = new ImageIcon() { + @Override + public int getIconWidth() { + return 16; + } + + @Override + public int getIconHeight() { + return 16; + } + + @Override + public void paintIcon( + Component c, Graphics g, int x, int y) { + g.setColor(java.awt.Color.black); + g.fillRect(x, y, 16, 16); + } + }; + internalFrame.setFrameIcon(titleImageIcon); + internalFrame.setSize(500, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(desktopPane, "Center"); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void createIconUI(final String lookAndFeelString) + throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + desktopPane = new JDesktopPane(); + internalFrame = new JInternalFrame(); + frame = new JFrame(); + internalFrame.setTitle(lookAndFeelString); + titleIcon = new Icon() { + @Override + public int getIconWidth() { + return 16; + } + + @Override + public int getIconHeight() { + return 16; + } + + @Override + public void paintIcon( + Component c, Graphics g, int x, int y) { + g.setColor(java.awt.Color.black); + g.fillRect(x, y, 16, 16); + } + }; + internalFrame.setFrameIcon(titleIcon); + internalFrame.setSize(500, 200); + internalFrame.setVisible(true); + desktopPane.add(internalFrame); + + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.getContentPane().setLayout(new BorderLayout()); + frame.getContentPane().add(desktopPane, "Center"); + frame.setSize(500, 500); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + frame.toFront(); + } + }); + } + + private static void getImageIconBufferedImage() throws Exception { + Point point = internalFrame.getLocationOnScreen(); + Rectangle rect = internalFrame.getBounds(); + Rectangle captureRect = new Rectangle( + point.x + internalFrame.getInsets().left, + point.y, + rect.width, + internalFrame.getInsets().top); + imageIconImage + = robot.createScreenCapture(captureRect); + } + + private static void getIconBufferedImage() throws Exception { + Point point = internalFrame.getLocationOnScreen(); + Rectangle rect = internalFrame.getBounds(); + Rectangle captureRect = new Rectangle( + point.x + internalFrame.getInsets().left, + point.y, + rect.width, + internalFrame.getInsets().top); + iconImage + = robot.createScreenCapture(captureRect); + } + + private static void testIfSame() throws Exception { + if (!bufferedImagesEqual(imageIconImage, iconImage)) { + System.err.println("ERROR: icon and imageIcon not same."); + } else { + System.out.println("SUCCESS: icon and imageIcon same."); + } + } + + private static boolean bufferedImagesEqual( + BufferedImage bufferedImage1, BufferedImage bufferedImage2) { + boolean flag = true; + + if (bufferedImage1.getWidth() == bufferedImage2.getWidth() + && bufferedImage1.getHeight() == bufferedImage2.getHeight()) { + final int colorTolerance = 25; + final int mismatchTolerance = (int) (0.1 + * bufferedImage1.getWidth() * bufferedImage1.getHeight()); + int mismatchCounter = 0; + for (int x = 0; x < bufferedImage1.getWidth(); x++) { + for (int y = 0; y < bufferedImage1.getHeight(); y++) { + + int color1 = bufferedImage1.getRGB(x, y); + int red1 = (color1 >> 16) & 0x000000FF; + int green1 = (color1 >> 8) & 0x000000FF; + int blue1 = (color1) & 0x000000FF; + + int color2 = bufferedImage2.getRGB(x, y); + int red2 = (color2 >> 16) & 0x000000FF; + int green2 = (color2 >> 8) & 0x000000FF; + int blue2 = (color2) & 0x000000FF; + if (red1 != red2 || green1 != green2 || blue1 != blue2) { + ++mismatchCounter; + if ((Math.abs(red1 - red2) > colorTolerance) + || (Math.abs(green1 - green2) > colorTolerance) + || (Math.abs(blue1 - blue2) > colorTolerance)) { + + flag = false; + } + } + } + } + if (mismatchCounter > mismatchTolerance) { + flag = false; + } + } else { + System.err.println("ERROR: size is different"); + flag = false; + } + return flag; + } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } +} diff --git a/jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java b/jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java new file mode 100644 index 00000000000..2a6d7f998a9 --- /dev/null +++ b/jdk/test/javax/swing/JInternalFrame/NormalBoundsTest.java @@ -0,0 +1,301 @@ +/* + * 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 7126823 + @summary Verify NormalBounds upon iconify/deiconify sequence + @run main NormalBoundsTest + */ +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.beans.PropertyVetoException; +import javax.swing.JDesktopPane; +import javax.swing.JFrame; +import javax.swing.JInternalFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.WindowConstants; + +public class NormalBoundsTest { + + private static JFrame mainFrame; + private static JInternalFrame internalFrame; + private static Rectangle bounds; + + private static void createUI(String lookAndFeelString) { + internalFrame = new JInternalFrame("Internal", true, true, true, true); + internalFrame.setDefaultCloseOperation( + WindowConstants.DO_NOTHING_ON_CLOSE); + internalFrame.setSize(200, 200); + + JDesktopPane desktopPane = new JDesktopPane(); + desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE); + desktopPane.add(internalFrame); + + mainFrame = new JFrame(lookAndFeelString); + mainFrame.setSize(640, 480); + mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + mainFrame.setContentPane(desktopPane); + + mainFrame.setVisible(true); + internalFrame.setVisible(true); + + } + + private static int signWOZero(int i) { + return (i > 0) ? 1 : -1; + } + + private static void mouseMove(Robot robot, Point startPt, Point endPt) { + int dx = endPt.x - startPt.x; + int dy = endPt.y - startPt.y; + + int ax = Math.abs(dx) * 2; + int ay = Math.abs(dy) * 2; + + int sx = signWOZero(dx); + int sy = signWOZero(dy); + + int x = startPt.x; + int y = startPt.y; + + int d = 0; + + if (ax > ay) { + d = ay - ax / 2; + while (true) { + robot.mouseMove(x, y); + robot.delay(50); + + if (x == endPt.x) { + return; + } + if (d >= 0) { + y = y + sy; + d = d - ax; + } + x = x + sx; + d = d + ay; + } + } else { + d = ax - ay / 2; + while (true) { + robot.mouseMove(x, y); + robot.delay(50); + + if (y == endPt.y) { + return; + } + if (d >= 0) { + x = x + sx; + d = d - ay; + } + y = y + sy; + d = d + ax; + } + } + } + + private static void drag(Robot r, Point startPt, Point endPt, int button) { + if (!(button == InputEvent.BUTTON1_MASK + || button == InputEvent.BUTTON2_MASK + || button == InputEvent.BUTTON3_MASK)) { + throw new IllegalArgumentException("invalid mouse button"); + } + + r.mouseMove(startPt.x, startPt.y); + r.mousePress(button); + try { + mouseMove(r, startPt, endPt); + } finally { + r.mouseRelease(button); + } + } + + private static boolean tryLookAndFeel(String lookAndFeelString) { + try { + UIManager.setLookAndFeel(lookAndFeelString); + return true; + } catch (UnsupportedLookAndFeelException | ClassNotFoundException | + InstantiationException | IllegalAccessException e) { + return false; + } + } + + public static void executeTest(Robot robot) throws Exception { + + // Iconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(true); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Iconize InternalFrame Failed"); + } + } + }); + robot.waitForIdle(); + + // Deiconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(false); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Deiconize InternalFrame" + + " Failed"); + } + } + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + Point loc = internalFrame.getLocationOnScreen(); + // Drag Frame + drag(robot, + new Point((int) loc.x + 80, (int) loc.y + 12), + new Point((int) loc.x + 100, (int) loc.y + 40), + InputEvent.BUTTON1_MASK); + } + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + bounds = internalFrame.getBounds(); + if (!internalFrame.getNormalBounds().equals(bounds)) { + mainFrame.dispose(); + throw new RuntimeException("Invalid NormalBounds"); + } + } + }); + robot.waitForIdle(); + + // Regression Test Bug ID: 4424247 + // Maximize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setMaximum(true); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Maximize InternalFrame Failed"); + } + } + }); + robot.waitForIdle(); + + // Iconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(true); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Iconize InternalFrame Failed"); + } + } + }); + robot.waitForIdle(); + + // DeIconize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setIcon(false); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("DeIcoize InternalFrame " + + " Failed"); + } + } + }); + robot.waitForIdle(); + + // Restore/Undo Maximize JInternalFrame + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + internalFrame.setMaximum(false); + } catch (PropertyVetoException ex) { + mainFrame.dispose(); + throw new RuntimeException("Restore InternalFrame " + + " Failed"); + } + } + }); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + if (!internalFrame.getBounds().equals(bounds)) { + mainFrame.dispose(); + throw new RuntimeException("Regression Test Failed"); + } + } + }); + robot.waitForIdle(); + + mainFrame.dispose(); + } + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + String lookAndFeelString = lookAndFeelItem.getClassName(); + if (tryLookAndFeel(lookAndFeelString)) { + // create UI + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createUI(lookAndFeelString); + } + }); + + robot.waitForIdle(); + executeTest(robot); + } else { + throw new RuntimeException("Setting Look and Feel Failed"); + } + } + + } +} diff --git a/jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java b/jdk/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java similarity index 78% rename from jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java rename to jdk/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java index 4e5d23149ab..b8120b9e910 100644 --- a/jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java +++ b/jdk/test/javax/swing/JScrollPane/HorizontalMouseWheelOnShiftPressed/HorizontalMouseWheelOnShiftPressed.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -20,6 +20,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + import java.awt.BorderLayout; import java.awt.Point; import java.awt.Robot; @@ -29,24 +30,25 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.SwingUtilities; -import javax.swing.UIManager; + import jdk.testlibrary.OSInfo; /** * @test - * @bug 8033000 + * @bug 8033000 8147994 * @author Alexander Scherbatiy * @summary No Horizontal Mouse Wheel Support In BasicScrollPaneUI * @library ../../../../lib/testlibrary * @build jdk.testlibrary.OSInfo - * @run main bug8033000 + * @run main HorizontalMouseWheelOnShiftPressed */ -public class bug8033000 { +public class HorizontalMouseWheelOnShiftPressed { private static JScrollPane scrollPane; private static JTextArea textArea; private static Point point; private static final int delta; + private static JFrame frame; static { delta = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ? -30 : 30; @@ -57,9 +59,17 @@ public class bug8033000 { Robot robot = new Robot(); robot.setAutoDelay(50); - SwingUtilities.invokeAndWait(bug8033000::createAndShowGUI); + SwingUtilities.invokeAndWait( + HorizontalMouseWheelOnShiftPressed::createAndShowGUI); robot.waitForIdle(); + try { + test(robot); + } finally { + frame.dispose(); + } + } + private static void test(Robot robot) throws Exception { SwingUtilities.invokeAndWait(() -> { Point locationOnScreen = scrollPane.getLocationOnScreen(); point = new Point( @@ -75,7 +85,7 @@ public class bug8033000 { robot.waitForIdle(); robot.mouseWheel(delta); robot.waitForIdle(); - checkScrollPane(true); + checkScrollPane(true, false); // vertical scroll bar is enabled + shift initScrollPane(true, false); @@ -84,14 +94,14 @@ public class bug8033000 { robot.mouseWheel(delta); robot.keyRelease(KeyEvent.VK_SHIFT); robot.waitForIdle(); - checkScrollPane(true); + checkScrollPane(false, false); // horizontal scroll bar is enabled initScrollPane(false, true); robot.waitForIdle(); robot.mouseWheel(delta); robot.waitForIdle(); - checkScrollPane(false); + checkScrollPane(false, true); // horizontal scroll bar is enabled + shift initScrollPane(false, true); @@ -100,14 +110,14 @@ public class bug8033000 { robot.mouseWheel(delta); robot.keyRelease(KeyEvent.VK_SHIFT); robot.waitForIdle(); - checkScrollPane(false); + checkScrollPane(false, true); // both scroll bars are enabled initScrollPane(true, true); robot.waitForIdle(); robot.mouseWheel(delta); robot.waitForIdle(); - checkScrollPane(true); + checkScrollPane(true, false); // both scroll bars are enabled + shift initScrollPane(true, true); @@ -116,7 +126,7 @@ public class bug8033000 { robot.mouseWheel(delta); robot.keyRelease(KeyEvent.VK_SHIFT); robot.waitForIdle(); - checkScrollPane(false); + checkScrollPane(false, true); } static void initScrollPane(boolean vVisible, boolean hVisible) throws Exception { @@ -131,17 +141,25 @@ public class bug8033000 { }); } - static void checkScrollPane(boolean verticalScrolled) throws Exception { + static void checkScrollPane(boolean verticalScrolled, + boolean horizontalScrolled) throws Exception { SwingUtilities.invokeAndWait(() -> { if (verticalScrolled) { - if (scrollPane.getVerticalScrollBar().getValue() == 0 - || scrollPane.getHorizontalScrollBar().getValue() != 0) { + if (scrollPane.getVerticalScrollBar().getValue() == 0) { throw new RuntimeException("Wrong vertical scrolling!"); } + } else{ + if (scrollPane.getVerticalScrollBar().getValue() != 0) { + throw new RuntimeException("Wrong vertical scrolling!"); + } + } + if (horizontalScrolled) { + if (scrollPane.getHorizontalScrollBar().getValue() == 0) { + throw new RuntimeException("Wrong horizontal scrolling!"); + } } else { - if (scrollPane.getVerticalScrollBar().getValue() != 0 - || scrollPane.getHorizontalScrollBar().getValue() == 0) { + if (scrollPane.getHorizontalScrollBar().getValue() != 0) { throw new RuntimeException("Wrong horizontal scrolling!"); } } @@ -149,9 +167,10 @@ public class bug8033000 { } static void createAndShowGUI() { - JFrame frame = new JFrame(); + frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 300); + frame.setLocationRelativeTo(null); textArea = new JTextArea("Hello World!"); scrollPane = new JScrollPane(textArea); JPanel panel = new JPanel(new BorderLayout()); diff --git a/jdk/test/javax/swing/JTable/8080972/TestJTableCellEditor.java b/jdk/test/javax/swing/JTable/8080972/TestJTableCellEditor.java new file mode 100644 index 00000000000..592044a4ea3 --- /dev/null +++ b/jdk/test/javax/swing/JTable/8080972/TestJTableCellEditor.java @@ -0,0 +1,90 @@ +/* + * 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. + */ +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableCellEditor; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestJTableCellEditor { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestJTableCellEditor::testJTableCellEditor); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestJTableCellEditor::testJTableCellEditor); + } + + private static void testJTableCellEditor() { + + final Class cls = UserEditor.class; + + JTable table = new JTable(new AbstractTableModel() { + public int getRowCount() { + return 0; + } + + public int getColumnCount() { + return 1; + } + + public Object getValueAt(int r, int c) { + return "Some Value"; + } + + public Class getColumnClass(int c) { + return cls; + } + }); + + TableCellEditor editor = table.getDefaultEditor(Object.class); + editor.getTableCellEditorComponent(table, + UserEditor.TEST_VALUE, false, 0, 0); + editor.stopCellEditing(); + Object obj = editor.getCellEditorValue(); + + if (obj == null) { + throw new RuntimeException("Editor object is null!"); + } + + if (!UserEditor.TEST_VALUE.equals(((UserEditor) obj).value)) { + throw new RuntimeException("Value is incorrect!"); + } + } + + public static class UserEditor { + + private static final String TEST_VALUE = "Test Value"; + + private final String value; + + public UserEditor(String value) { + this.value = value; + } + } +} diff --git a/jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java b/jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java new file mode 100644 index 00000000000..54ac5fd2619 --- /dev/null +++ b/jdk/test/javax/swing/JTableHeader/8020039/TableHeaderRendererExceptionTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.swing.UIManager; +import javax.swing.table.JTableHeader; + +/** + * @test + * @summary Tests whether getTableCellRendererComponent() method handles + * null table parameter + * @bug 8020039 + * @run main TableHeaderRendererExceptionTest + */ +public class TableHeaderRendererExceptionTest { + + public static void main(String[] args) throws Throwable { + //Execute test for all supported look and feels + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + String lookAndFeelString = lookAndFeelItem.getClassName(); + + UIManager.setLookAndFeel(lookAndFeelString); + + // Test getTableCellRendererComponent method by passing null table + JTableHeader header = new JTableHeader(); + + header.getDefaultRenderer().getTableCellRendererComponent(null, + " test ", true, true, -1, 0); + } + } +} diff --git a/jdk/test/javax/swing/UIDefaults/8080972/TestProxyLazyValue.java b/jdk/test/javax/swing/UIDefaults/8080972/TestProxyLazyValue.java new file mode 100644 index 00000000000..e36dba28540 --- /dev/null +++ b/jdk/test/javax/swing/UIDefaults/8080972/TestProxyLazyValue.java @@ -0,0 +1,156 @@ +/* + * 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. + */ +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestProxyLazyValue { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestProxyLazyValue::testUserProxyLazyValue); + SwingUtilities.invokeAndWait(TestProxyLazyValue::testProxyLazyValue); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestProxyLazyValue::testUserProxyLazyValue); + SwingUtilities.invokeAndWait(TestProxyLazyValue::testProxyLazyValue); + } + + private static void testUserProxyLazyValue() { + + Object obj = new UserProxyLazyValue( + UserLazyClass.class.getName()).createValue(null); + + if (!(obj instanceof UserLazyClass)) { + throw new RuntimeException("Object is not UserLazyClass!"); + } + + obj = new UserProxyLazyValue(UserLazyClass.class.getName(), + new Object[]{UserLazyClass.CONSTRUCTOR_ARG}).createValue(null); + + if (!(obj instanceof UserLazyClass)) { + throw new RuntimeException("Object is not UserLazyClass!"); + } + + if (((UserLazyClass) obj).arg != UserLazyClass.CONSTRUCTOR_ARG) { + throw new RuntimeException("Constructt argument is wrong!"); + } + + obj = new UserProxyLazyValue(UserLazyClass.class.getName(), + "method1").createValue(null); + + if (!UserLazyClass.RESULT_1.equals(obj)) { + throw new RuntimeException("Result is wrong!"); + } + + obj = new UserProxyLazyValue(UserLazyClass.class.getName(), + "method2", new Object[]{UserLazyClass.RESULT_2}).createValue(null); + + if (!UserLazyClass.RESULT_2.equals(obj)) { + throw new RuntimeException("Result is wrong!"); + } + } + + private static void testProxyLazyValue() { + + Object obj = new UIDefaults.ProxyLazyValue( + UserLazyClass.class.getName()).createValue(null); + + if (!(obj instanceof UserLazyClass)) { + throw new RuntimeException("Object is not UserLazyClass!"); + } + + obj = new UIDefaults.ProxyLazyValue(UserLazyClass.class.getName(), + new Object[]{UserLazyClass.CONSTRUCTOR_ARG}).createValue(null); + + if (!(obj instanceof UserLazyClass)) { + throw new RuntimeException("Object is not UserLazyClass!"); + } + + if (((UserLazyClass) obj).arg != UserLazyClass.CONSTRUCTOR_ARG) { + throw new RuntimeException("Constructt argument is wrong!"); + } + + obj = new UIDefaults.ProxyLazyValue(UserLazyClass.class.getName(), + "method1").createValue(null); + + if (!UserLazyClass.RESULT_1.equals(obj)) { + throw new RuntimeException("Result is wrong!"); + } + + obj = new UIDefaults.ProxyLazyValue(UserLazyClass.class.getName(), + "method2", new Object[]{UserLazyClass.RESULT_2}).createValue(null); + + if (!UserLazyClass.RESULT_2.equals(obj)) { + throw new RuntimeException("Result is wrong!"); + } + } + + public static class UserLazyClass { + + static final int CONSTRUCTOR_ARG = 100; + static final String RESULT_1 = "1"; + static final String RESULT_2 = "2"; + + int arg; + + public UserLazyClass() { + } + + public UserLazyClass(int arg) { + this.arg = arg; + } + + public static String method1() { + return RESULT_1; + } + + public static String method2(String arg) { + return arg; + } + } + + public static class UserProxyLazyValue extends UIDefaults.ProxyLazyValue { + + public UserProxyLazyValue(String className) { + super(className); + } + + public UserProxyLazyValue(String className, Object[] constructorArgs) { + super(className, constructorArgs); + } + + public UserProxyLazyValue(String className, String methodName) { + super(className, methodName); + } + + public UserProxyLazyValue(String className, String methodName, + Object[] methodArgs) { + super(className, methodName, methodArgs); + } + } +} diff --git a/jdk/test/javax/swing/dnd/8080972/TestTransferHandler.java b/jdk/test/javax/swing/dnd/8080972/TestTransferHandler.java new file mode 100644 index 00000000000..a7cf675c482 --- /dev/null +++ b/jdk/test/javax/swing/dnd/8080972/TestTransferHandler.java @@ -0,0 +1,99 @@ +/* + * 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. + */ +import java.awt.Color; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.TransferHandler; +import java.awt.datatransfer.*; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestTransferHandler { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestTransferHandler::testTransferHandler); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestTransferHandler::testTransferHandler); + } + + private static void testTransferHandler() { + try { + TransferHandler transferHandler = new TransferHandler("userColor"); + UserJComponent comp = new UserJComponent(); + + final String colorType = DataFlavor.javaJVMLocalObjectMimeType + + ";class=java.awt.Color"; + final DataFlavor colorFlavor = new DataFlavor(colorType); + + Transferable transferable = new Transferable() { + + public DataFlavor[] getTransferDataFlavors() { + return new DataFlavor[]{colorFlavor}; + + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + return true; + } + + public Object getTransferData(DataFlavor flavor) { + return UserJComponent.TEST_COLOR; + } + + }; + + transferHandler.importData(comp, transferable); + + if (!UserJComponent.TEST_COLOR.equals(comp.color)) { + throw new RuntimeException("Wrong color!"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static class UserJComponent extends JComponent { + + public static final Color USER_COLOR = new Color(10, 20, 30); + public static final Color TEST_COLOR = new Color(15, 25, 35); + + Color color = USER_COLOR; + + public UserJComponent() { + + } + + public Color getUserColor() { + return color; + } + + public void setUserColor(Color color) { + this.color = color; + } + } +} diff --git a/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java b/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java index 0ef16996cf5..71a2e6f4b58 100644 --- a/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java +++ b/jdk/test/javax/swing/plaf/gtk/crash/RenderBadPictureCrash.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,16 +23,15 @@ /* @test - @bug 8056151 + @bug 8056151 8131751 @summary Switching to GTK L&F on-the-fly leads to X Window System error RenderBadPicture @run main/othervm -Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel -Dsun.java2d.xrender=T RenderBadPictureCrash */ - import java.awt.Color; +import java.awt.GraphicsDevice; import java.lang.reflect.InvocationTargetException; import javax.swing.JFrame; import javax.swing.SwingUtilities; - import javax.swing.UIManager; public class RenderBadPictureCrash { @@ -41,7 +40,10 @@ public class RenderBadPictureCrash { SwingUtilities.invokeAndWait(() -> { JFrame f = new JFrame(); f.setUndecorated(true); - f.setBackground(new Color(0, 0, 0, 0)); + GraphicsDevice gd = f.getGraphicsConfiguration().getDevice(); + if (gd.isWindowTranslucencySupported(GraphicsDevice.WindowTranslucency.PERPIXEL_TRANSLUCENT)) { + f.setBackground(new Color(0, 0, 0, 0)); + } f.setSize(200, 300); f.setVisible(true); diff --git a/jdk/test/javax/swing/plaf/nimbus/8080972/TestAbstractRegionPainter.java b/jdk/test/javax/swing/plaf/nimbus/8080972/TestAbstractRegionPainter.java new file mode 100644 index 00000000000..f2b18724d23 --- /dev/null +++ b/jdk/test/javax/swing/plaf/nimbus/8080972/TestAbstractRegionPainter.java @@ -0,0 +1,97 @@ +/* + * 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. + */ +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.plaf.nimbus.AbstractRegionPainter; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestAbstractRegionPainter { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestAbstractRegionPainter::testAbstractRegionPainter); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestAbstractRegionPainter::testAbstractRegionPainter); + } + + private static void testAbstractRegionPainter() { + UserAbstractRegionPainter painter = new UserAbstractRegionPainter(); + + JComponent userComponent = new UserJComponent(); + + Color color = painter.getUserComponentColor(userComponent, "UserColor", + Color.yellow, 0, 0, 0); + + if (!UserJComponent.USER_COLOR.equals(color)) { + throw new RuntimeException("Wrong color: " + color); + } + } + + public static class UserJComponent extends JComponent { + + public static final Color USER_COLOR = new Color(10, 20, 30); + public static final Color TEST_COLOR = new Color(15, 25, 35); + + Color color = USER_COLOR; + + public UserJComponent() { + + } + + public Color getUserColor() { + return color; + } + + public void setUserColor(Color color) { + this.color = color; + } + } + + public static class UserAbstractRegionPainter extends AbstractRegionPainter { + + public Color getUserComponentColor(JComponent c, String property, + Color defaultColor, + float saturationOffset, + float brightnessOffset, + int alphaOffset) { + return getComponentColor(c, property, defaultColor, saturationOffset, brightnessOffset, alphaOffset); + } + + @Override + protected AbstractRegionPainter.PaintContext getPaintContext() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + protected void doPaint(Graphics2D g, JComponent c, int width, int height, Object[] extendedCacheKeys) { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/jdk/test/javax/swing/text/View/8080972/TestObjectView.java b/jdk/test/javax/swing/text/View/8080972/TestObjectView.java new file mode 100644 index 00000000000..772447ed250 --- /dev/null +++ b/jdk/test/javax/swing/text/View/8080972/TestObjectView.java @@ -0,0 +1,196 @@ +/* + * 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. + */ +import java.awt.Color; +import java.awt.Component; +import java.util.Enumeration; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.html.HTML; +import javax.swing.text.html.ObjectView; +/* + * @test + * @bug 8080972 + * @summary Audit Core Reflection in module java.desktop for places that will + * require changes to work with modules + * @author Alexander Scherbatiy + */ + +public class TestObjectView { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(TestObjectView::testObjectView); + System.setSecurityManager(new SecurityManager()); + SwingUtilities.invokeAndWait(TestObjectView::testObjectView); + } + + private static void testObjectView() { + + UserObjectView objectView = new UserObjectView(new UserElement()); + + Component comp = objectView.createComponent(); + + if (!(comp instanceof UserJComponent)) { + throw new RuntimeException("Component is not UserJComponent!"); + } + } + public static class UserJComponent extends JComponent { + + public static final Color USER_COLOR = new Color(10, 20, 30); + public static final Color TEST_COLOR = new Color(15, 25, 35); + + Color color = USER_COLOR; + + public UserJComponent() { + + } + + public Color getUserColor() { + System.out.println("[user component] get user color"); + return color; + } + + public void setUserColor(Color color) { + System.out.println("[user component] set user color"); + this.color = color; + } + + } + + public static class UserObjectView extends ObjectView { + + public UserObjectView(Element elem) { + super(elem); + } + + @Override + public Component createComponent() { + return super.createComponent(); + } + } + + public static class UserElement implements Element { + + @Override + public Document getDocument() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Element getParentElement() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public String getName() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AttributeSet getAttributes() { + return new AttributeSet() { + + @Override + public int getAttributeCount() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isDefined(Object attrName) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isEqual(AttributeSet attr) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AttributeSet copyAttributes() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Object getAttribute(Object key) { + if (key.equals(HTML.Attribute.CLASSID)) { + return UserJComponent.class.getName(); + } + + return null; + } + + @Override + public Enumeration getAttributeNames() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean containsAttribute(Object name, Object value) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean containsAttributes(AttributeSet attributes) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public AttributeSet getResolveParent() { + throw new UnsupportedOperationException("Not supported yet."); + } + }; + } + + @Override + public int getStartOffset() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getEndOffset() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getElementIndex(int offset) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public int getElementCount() { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public Element getElement(int index) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public boolean isLeaf() { + throw new UnsupportedOperationException("Not supported yet."); + } + } +} diff --git a/jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java b/jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java new file mode 100644 index 00000000000..37b817d0b4d --- /dev/null +++ b/jdk/test/javax/xml/bind/xjc/8145039/JaxbMarshallTest.java @@ -0,0 +1,158 @@ +/* + * 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 8145039 + * @summary Check that marshalling of xjc generated class doesn't throw + * ClassCast exception. + * @modules javax.xml.bind + * @library /lib/testlibrary + * @run testng/othervm JaxbMarshallTest + */ + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import java.util.Arrays; +import java.util.List; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import jdk.testlibrary.JDKToolLauncher; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +public class JaxbMarshallTest { + + @BeforeTest + public void setUp() throws IOException { + // Create test directory inside scratch + testWorkDir = Paths.get(System.getProperty("user.dir", ".")); + // Save its URL + testWorkDirUrl = testWorkDir.toUri().toURL(); + // Get test source directory path + testSrcDir = Paths.get(System.getProperty("test.src", ".")); + // Get path of xjc result folder + xjcResultDir = testWorkDir.resolve(TEST_PACKAGE); + // Copy schema document file to scratch directory + Files.copy(testSrcDir.resolve(XSD_FILENAME), testWorkDir.resolve(XSD_FILENAME), REPLACE_EXISTING); + } + + + /* + * Test does the following steps to reproduce problem reported by 8145039: + * 1. Copy test schema to JTREG scratch folder + * 2. Run xjc on test schema file + * 3. Compile generated java files with test javac + * 4. Marshall the new list instance to ensure that + * ClassCastException is not thrown + */ + @Test + public void marshallClassCastExceptionTest() throws Exception { + JAXBContext jaxbContext; + Marshaller marshaller; + URLClassLoader jaxbContextClassLoader; + // Generate java classes by xjc + runXjc(XSD_FILENAME); + // Compile xjc generated java files + compileXjcGeneratedClasses(); + + // Create JAXB context based on xjc generated package. + // Need to create URL class loader ot make compiled classes discoverable + // by JAXB context + jaxbContextClassLoader = URLClassLoader.newInstance(new URL[] {testWorkDirUrl}); + jaxbContext = JAXBContext.newInstance( TEST_PACKAGE, jaxbContextClassLoader); + + // Create instance of Xjc generated data type. + // Java classes were compiled during the test execution hence reflection + // is needed here + Class classLongListClass = jaxbContextClassLoader.loadClass(TEST_CLASS); + Object objectLongListClass = classLongListClass.newInstance(); + // Get 'getIn' method object + Method getInMethod = classLongListClass.getMethod( GET_LIST_METHOD, (Class [])null ); + // Invoke 'getIn' method + List inList = (List)getInMethod.invoke(objectLongListClass); + // Add values into the jaxb object list + inList.add(Long.valueOf(0)); + inList.add(Long.valueOf(43)); + inList.add(Long.valueOf(1000000123)); + + // Marshall constructed complex type variable to standard output. + // In case of failure the ClassCastException will be thrown + marshaller = jaxbContext.createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + marshaller.marshal(objectLongListClass, System.out); + } + + // Compile schema file into java classes definitions + void runXjc(String xsdFileName) throws Exception { + // Prepare process builder to run schemagen tool and save its output + JDKToolLauncher xjcLauncher = JDKToolLauncher.createUsingTestJDK("xjc"); + xjcLauncher.addToolArg(xsdFileName); + System.out.println("Executing xjc command: " + Arrays.asList(xjcLauncher.getCommand())); + ProcessBuilder pb = new ProcessBuilder(xjcLauncher.getCommand()); + // Set xjc work directory with the input java file + pb.directory(testWorkDir.toFile()); + pb.inheritIO(); + Process p = pb.start(); + p.waitFor(); + p.destroy(); + } + + // Compile java classes with javac tool + void compileXjcGeneratedClasses() throws Exception { + JDKToolLauncher javacLauncher = JDKToolLauncher.createUsingTestJDK("javac"); + javacLauncher.addToolArg(xjcResultDir.resolve("ObjectFactory.java").toString()); + javacLauncher.addToolArg(xjcResultDir.resolve("TypesLongList.java").toString()); + javacLauncher.addToolArg(xjcResultDir.resolve("package-info.java").toString()); + System.out.println("Compiling xjc generated classes: " + Arrays.asList(javacLauncher.getCommand())); + ProcessBuilder pb = new ProcessBuilder(javacLauncher.getCommand()); + pb.inheritIO(); + pb.directory(testWorkDir.toFile()); + Process p = pb.start(); + p.waitFor(); + p.destroy(); + } + + // Test schema filename + static final String XSD_FILENAME = "testSchema.xsd"; + // Package of java classes generated by xjc + static final String TEST_PACKAGE = "testns_package"; + // Name of generated java class + static final String TEST_CLASS = TEST_PACKAGE+".TypesLongList"; + // Method to get the list from xjc generated class + static final String GET_LIST_METHOD = "getIn"; + // Test working directory + Path testWorkDir; + // Test working directory URL + URL testWorkDirUrl; + // Directory with test src + Path testSrcDir; + // Directory with java files generated by xjc + Path xjcResultDir; +} diff --git a/jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd b/jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd new file mode 100644 index 00000000000..f625d0607d0 --- /dev/null +++ b/jdk/test/javax/xml/bind/xjc/8145039/testSchema.xsd @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java index 8d74fd27b7b..daa9451acf1 100644 --- a/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java +++ b/jdk/test/javax/xml/jaxp/Encodings/CheckEncodingPropertiesFile.java @@ -39,6 +39,7 @@ import com.sun.org.apache.xml.internal.serializer.EncodingInfo; import com.sun.org.apache.xml.internal.serializer.Encodings; import java.io.InputStreamReader; +import java.lang.reflect.Module; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.ArrayList; @@ -61,7 +62,8 @@ public class CheckEncodingPropertiesFile { public static void main(String[] args) throws Exception { Properties props = new Properties(); - try (InputStreamReader is = new InputStreamReader(ClassLoader.getSystemResourceAsStream(ENCODINGS_FILE))) { + Module xmlModule = EncodingInfo.class.getModule(); + try (InputStreamReader is = new InputStreamReader(xmlModule.getResourceAsStream(ENCODINGS_FILE))) { props.load(is); } @@ -71,7 +73,7 @@ public class CheckEncodingPropertiesFile { // Check that the content of the Encodings.properties included in // the tested build image matches the content of the file in the source // jaxp tree of the jdk forest. - throw new RuntimeException("UTF8 key missing in " + ClassLoader.getSystemResource(ENCODINGS_FILE)); + throw new RuntimeException("UTF8 key missing in " + ENCODINGS_FILE); } //printAllCharsets(); diff --git a/jdk/test/javax/xml/jaxp/common/8035437/run.sh b/jdk/test/javax/xml/jaxp/common/8035437/run.sh index 413edebcd27..2ebe7ce4296 100644 --- a/jdk/test/javax/xml/jaxp/common/8035437/run.sh +++ b/jdk/test/javax/xml/jaxp/common/8035437/run.sh @@ -28,17 +28,18 @@ # @summary Tests that java.lang.AbstractMethodError is not thrown when # serializing improper version of DocumentImpl class. -mkdir -p exec compile +mkdir -p exec/java.xml compile/java.xml $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - -d compile $TESTSRC/Document.java $TESTSRC/Node.java || exit 1 + -d compile/java.xml -Xmodule:java.xml $TESTSRC/Document.java $TESTSRC/Node.java || exit 1 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - -Xbootclasspath/p:compile -d exec $TESTSRC/DocumentImpl.java || exit 1 + -d exec/java.xml -Xpatch:compile -Xmodule:java.xml $TESTSRC/DocumentImpl.java || exit 2 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - $TESTSRC/AbstractMethodErrorTest.java -d exec || exit 1 + $TESTSRC/AbstractMethodErrorTest.java -d exec || exit 3 -$TESTJAVA/bin/java ${TESTVMOPTS} -Xbootclasspath/p:exec -cp exec AbstractMethodErrorTest || exit 1 +$TESTJAVA/bin/java ${TESTVMOPTS} -Xpatch:exec -cp exec AbstractMethodErrorTest || exit 4 exit 0 + diff --git a/jdk/test/javax/xml/soap/XmlTest.java b/jdk/test/javax/xml/soap/XmlTest.java new file mode 100644 index 00000000000..fedd52d59da --- /dev/null +++ b/jdk/test/javax/xml/soap/XmlTest.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +import javax.xml.soap.AttachmentPart; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.Name; +import javax.xml.soap.SOAPEnvelope; +import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; +import javax.xml.transform.stream.StreamSource; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Iterator; + +/* + * @test + * @summary tests JAF DataHandler can be instantiated; test serialize and + * deserialize SOAP message containing xml attachment + */ +public class XmlTest { + + public void test() throws Exception { + + File file = new File("message.xml"); + file.deleteOnExit(); + + MessageFactory mf = MessageFactory.newInstance(); + SOAPMessage msg = createMessage(mf); + + // Save the soap message to file + try (FileOutputStream sentFile = new FileOutputStream(file)) { + msg.writeTo(sentFile); + } + + // See if we get the image object back + try (FileInputStream fin = new FileInputStream(file)) { + SOAPMessage newMsg = mf.createMessage(msg.getMimeHeaders(), fin); + + newMsg.writeTo(new ByteArrayOutputStream()); + + Iterator i = newMsg.getAttachments(); + while (i.hasNext()) { + AttachmentPart att = (AttachmentPart) i.next(); + Object obj = att.getContent(); + if (!(obj instanceof StreamSource)) { + fail("Got incorrect attachment type [" + obj.getClass() + "], " + + "expected [javax.xml.transform.stream.StreamSource]"); + } + } + } + + } + + private SOAPMessage createMessage(MessageFactory mf) throws SOAPException, IOException { + SOAPMessage msg = mf.createMessage(); + SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope(); + Name name = envelope.createName("hello", "ex", "http://example.com"); + envelope.getBody().addChildElement(name).addTextNode("THERE!"); + + String s = "THERE!"; + + AttachmentPart ap = msg.createAttachmentPart( + new StreamSource(new ByteArrayInputStream(s.getBytes())), + "text/xml" + ); + msg.addAttachmentPart(ap); + msg.saveChanges(); + + return msg; + } + + private void fail(String s) { + throw new RuntimeException(s); + } + + public static void main(String[] args) throws Exception { + new XmlTest().test(); + } + +} diff --git a/jdk/test/jdk/asm/AsmSanity.java b/jdk/test/jdk/asm/AsmSanity.java index 0ae1cadc437..8f9cc3caf53 100644 --- a/jdk/test/jdk/asm/AsmSanity.java +++ b/jdk/test/jdk/asm/AsmSanity.java @@ -32,7 +32,7 @@ * - Verify that if user code is compiled without ct.sym, it can't access asm classes * at runtime when a security manager is in use. * - * @compile/fail AsmSanity.java + * @modules java.base/jdk.internal.org.objectweb.asm * * @compile -XDignore.symbol.file=true AsmSanity.java * @run main/othervm AsmSanity @@ -44,11 +44,6 @@ // Verify that the expected asm pkgs are present import jdk.internal.org.objectweb.asm.*; -import jdk.internal.org.objectweb.asm.commons.*; -import jdk.internal.org.objectweb.asm.signature.*; -import jdk.internal.org.objectweb.asm.tree.*; -import jdk.internal.org.objectweb.asm.tree.analysis.*; -import jdk.internal.org.objectweb.asm.util.*; // Verify that we can actually run some of the asm code. public class AsmSanity { diff --git a/jdk/test/jdk/internal/jimage/ExecutableTest.java b/jdk/test/jdk/internal/jimage/ExecutableTest.java deleted file mode 100644 index b65230bb092..00000000000 --- a/jdk/test/jdk/internal/jimage/ExecutableTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015 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 - * 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.DirectoryStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.attribute.PosixFilePermission; -import static java.nio.file.attribute.PosixFilePermission.*; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -/* - * @test - * @bug 8132475 - * @summary Check that the executables in the current JDK image - * are executable by all users. - * @run main ExecutableTest - * @author Volker Simonis - */ - -public class ExecutableTest { - - // The bin/ directory may contain non-executable files (see 8132704) - private static final String[] exclude = { "jmc.ini" }; - private static final Set excludeSet = - new HashSet(Arrays.asList(exclude)); - - public static void main(String args[]) throws Throwable { - String JAVA_HOME = System.getProperty("java.home"); - Path binPath = Paths.get(JAVA_HOME, "bin"); - DirectoryStream stream = Files.newDirectoryStream(binPath); - EnumSet execPerms = - EnumSet.of(GROUP_EXECUTE, OTHERS_EXECUTE, OWNER_EXECUTE); - for (Path entry : stream) { - if (excludeSet.contains(entry.getFileName().toString())) continue; - if (Files.isRegularFile(entry)) { - if (!Files.isExecutable(entry)) { - throw new Error(entry + " is not executable!"); - } - try { - Set perm = Files.getPosixFilePermissions(entry); - if (!perm.containsAll(execPerms)) { - throw new Error(entry + " has not all executable permissions!\n" + - "Should have: " + execPerms + "\nbut has: " + perm); - } - } catch (UnsupportedOperationException e) {} - } - } - } -} diff --git a/jdk/test/jdk/internal/jimage/JImageReadTest.java b/jdk/test/jdk/internal/jimage/JImageReadTest.java index b840d1444e9..feb31a53e2e 100644 --- a/jdk/test/jdk/internal/jimage/JImageReadTest.java +++ b/jdk/test/jdk/internal/jimage/JImageReadTest.java @@ -23,20 +23,23 @@ /* * @test - * @modules java.base/jdk.internal.jimage - * @run testng JImageReadTest * @summary Unit test for libjimage JIMAGE_Open/Read/Close + * @modules java.base/jdk.internal.jimage */ import java.io.File; -import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Arrays; import jdk.internal.jimage.BasicImageReader; -import jdk.internal.jimage.ImageNativeSubstrate; +import jdk.internal.jimage.ImageReader; +import jdk.internal.jimage.ImageLocation; import org.testng.annotations.DataProvider; import org.testng.annotations.Optional; @@ -49,9 +52,7 @@ import org.testng.TestNG; public class JImageReadTest { static String javaHome = System.getProperty("java.home"); - static String imageFile = javaHome + File.separator + "lib" - + File.separator + "modules" + File.separator - + "bootmodules.jimage"; + static Path imageFile = Paths.get(javaHome, "lib", "modules"); @DataProvider(name="classes") static Object[][] loadClasses() { @@ -66,16 +67,6 @@ public class JImageReadTest { }; } - - @DataProvider(name="packages") - static Object[][] loadPackages() { - return new Object[][] { - {"java.base", "java/lang"}, - {"java.base", "java/io"}, - {"java.logging", "java/util/logging"}, - }; - } - /** * Test a class is correctly accessible from the image in a module. * @@ -86,60 +77,46 @@ public class JImageReadTest { @Test(dataProvider="classes") public static void test1_ReadClasses(String moduleName, String className) throws Exception { final int classMagic = 0xCAFEBABE; - final long NOT_FOUND = 0L; - if (!(new File(imageFile)).exists()) { + if (!Files.exists(imageFile)) { System.out.printf("Test skipped; no jimage file"); return; } - long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile); - Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle); + BasicImageReader reader = BasicImageReader.open(imageFile); + Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile); - long[] sizeArray = new long[1]; - long locationHandle = - ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle, - moduleName, "9.0", className, sizeArray); - long size = sizeArray[0]; - System.out.printf("reading: module: %s, path: %s, handle: %16x, " + - "location: %d, size: %d%n", - moduleName, className, jimageHandle, locationHandle, size); + ImageLocation location = reader.findLocation(moduleName, className); + + if (location != null && !location.verify("/" + moduleName + "/" + className)) { + location = null; + } + + long size = location != null ? location.getUncompressedSize() : 0; + + System.out.printf("reading: module: %s, path: %s, size: %d%n", + moduleName, className, size); if (moduleName.contains("NOSUCH") || className.contains("NOSUCH")) { - Assert.assertEquals(locationHandle, NOT_FOUND, + Assert.assertTrue(location == null, "location found for non-existing module: " + moduleName + ", or class: " + className); return; // no more to test for non-existing class } else { - Assert.assertTrue(locationHandle != NOT_FOUND, "location not found: " + className); + Assert.assertTrue(location != null, "location not found: " + className); Assert.assertTrue(size > 0, "size of should be > 0: " + className); } // positive: read whole class - ByteBuffer buffer = ByteBuffer.allocate((int)size); - long actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle, - locationHandle, buffer.array(), size); - Assert.assertEquals(actual, size, "bytes read not equal bytes requested"); + ByteBuffer buffer = reader.getResourceBuffer(location); + Assert.assertTrue(buffer != null, "bytes read not equal bytes requested"); if (className.endsWith(".class")) { int m = buffer.getInt(); Assert.assertEquals(m, classMagic, "Classfile has bad magic number"); } - // Read less than the size of the artifact - buffer.rewind(); - Arrays.fill(buffer.array(), (byte)0xc0); - long sizeExpected = size - 10; - actual = ImageNativeSubstrate.JIMAGE_GetResource(jimageHandle, - locationHandle, buffer.array(), sizeExpected); - Assert.assertEquals(actual, sizeExpected, "bytes read not equal bytes requested"); - - if (className.endsWith(".class")) { - int m1 = buffer.getInt(); - Assert.assertEquals(m1, classMagic, "Read operation succeeded but has bad magic number"); - } - - ImageNativeSubstrate.JIMAGE_Close(jimageHandle); + reader.close(); } /** @@ -149,63 +126,37 @@ public class JImageReadTest { */ @Test static void test2_ImageResources() throws IOException { - if (!(new File(imageFile)).exists()) { + if (!Files.exists(imageFile)) { System.out.printf("Test skipped; no jimage file"); return; } - long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile); - Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle); + BasicImageReader reader = BasicImageReader.open(imageFile); + Assert.assertTrue(reader != null, "JIMAGE_Open failed: " + imageFile); - String[] names = new String[4096]; - int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, - names); + String[] names = reader.getEntryNames(); // Repeat with count available - names = new String[max + 1]; - int count = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, - names); + int count = names.length; + System.out.printf(" count: %d, a class: %s\n", count, names[0]); + int minEntryCount = 16000; - Assert.assertTrue(max > minEntryCount, - "missing entries, should be more than " + minEntryCount + - ", reported: " + count); - Assert.assertTrue(count == max, + Assert.assertTrue(minEntryCount < count, "unexpected count of entries, count: " + count - + ", max: " + max); + + ", min: " + minEntryCount); for (int i = 0; i < count; i++) { checkFullName(names[i]); } - ImageNativeSubstrate.JIMAGE_Close(jimageHandle); + reader.close(); } - /** - * Tests that a package exists and correctly mapped to the module. - * - * @param moduleName the module name - * @param packageName the package name - * @throws IOException thrown if an error occurs - */ - @Test(dataProvider="packages") - static void test3_PackageToModule(String moduleName, String packageName) throws IOException { - if (!(new File(imageFile)).exists()) { - System.out.printf("Test skipped; no jimage file"); + static void checkFullName(String path) { + if (path.startsWith("/packages") || path.startsWith("/modules")) { return; } - long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile); - Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle); - - String result = ImageNativeSubstrate.JIMAGE_PackageToModule(jimageHandle, packageName); - System.out.printf(" package: %s, module: %s%n", packageName, result); - Assert.assertEquals(result, moduleName, "wrong module for package: " + packageName); - - ImageNativeSubstrate.JIMAGE_Close(jimageHandle); - } - - - static void checkFullName(String path) { int next = 0; String m = null; String p = null; @@ -241,8 +192,8 @@ public class JImageReadTest { * from the BasicImageReader they are ignored. */ @Test - static void test4_verifyNames() { - if (!(new File(imageFile)).exists()) { + static void test3_verifyNames() { + if (!Files.exists(imageFile)) { System.out.printf("Test skipped; no jimage file"); return; } @@ -271,9 +222,6 @@ public class JImageReadTest { System.out.printf("native name count: %d, modCount: %d, pkgCount: %d, otherCount: %d%n", names.length, modCount, pkgCount, otherCount); - Assert.assertEquals(modCount, 0, "JIMAGE_ResourceIterator should not return any '/modules' paths"); - Assert.assertEquals(pkgCount, 0, "JIMAGE_ResourceIterator should not return any '/packages' paths"); - // Sort and merge the two arrays. Every name should appear exactly twice. Arrays.sort(names); Arrays.sort(nativeNames); @@ -336,21 +284,13 @@ public class JImageReadTest { */ static String[] JIMAGE_Names() throws IOException { - long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile); - Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle); + BasicImageReader reader = BasicImageReader.open(imageFile); + Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile); - String[] names = new String[50000]; - int max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names); + String[] names = reader.getEntryNames(); - if (max > names.length) { - // Not all names fit, repeat with correct size - names = new String[max]; - max = ImageNativeSubstrate.JIMAGE_Resources(jimageHandle, names); - } else { - names = Arrays.copyOf(names, max); - } + reader.close(); - ImageNativeSubstrate.JIMAGE_Close(jimageHandle); return names; } @@ -366,24 +306,55 @@ public class JImageReadTest { System.out.printf(" %s: %d names%n", fname, names.length); } - @Test - static void test5_nameTooLong() throws IOException { + //@Test + static void test4_nameTooLong() throws IOException { long[] size = new long[1]; String moduleName = "FictiousModuleName"; String className = String.format("A%09999d", 1); - long jimageHandle = ImageNativeSubstrate.JIMAGE_Open(imageFile); - Assert.assertTrue(jimageHandle != 0, "JIMAGE_Open failed: id: " + jimageHandle); + BasicImageReader reader = BasicImageReader.open(imageFile); + Assert.assertNotNull(reader, "JIMAGE_Open failed: " + imageFile); - long locationHandle = - ImageNativeSubstrate.JIMAGE_FindResource(jimageHandle, - moduleName, "9.0", className, size); + String name = "/" + moduleName + "/" + className; + ImageLocation location = reader.findLocation(name); - Assert.assertEquals(0, locationHandle, "Too long name should have failed"); + if (location != null && !location.verify(name)) { + location = null; + } + Assert.assertTrue(location == null, "Too long name should have failed"); - ImageNativeSubstrate.JIMAGE_Close(jimageHandle); + reader.close(); } + /** + * Verify that the ImageReader returned by ImageReader.open has the + * the requested endianness or fails with an IOException if not. + */ + @Test + static void test5_imageReaderEndianness() throws IOException { + ImageReader nativeReader = ImageReader.open(imageFile); + Assert.assertEquals(nativeReader.getByteOrder(), ByteOrder.nativeOrder()); + + try { + ImageReader leReader = ImageReader.open(imageFile, ByteOrder.LITTLE_ENDIAN); + Assert.assertEquals(leReader.getByteOrder(), ByteOrder.LITTLE_ENDIAN); + leReader.close(); + } catch (IOException io) { + // IOException expected if LITTLE_ENDIAN not the nativeOrder() + Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.LITTLE_ENDIAN); + } + + try { + ImageReader beReader = ImageReader.open(imageFile, ByteOrder.BIG_ENDIAN); + Assert.assertEquals(beReader.getByteOrder(), ByteOrder.BIG_ENDIAN); + beReader.close(); + } catch (IOException io) { + // IOException expected if LITTLE_ENDIAN not the nativeOrder() + Assert.assertNotEquals(ByteOrder.nativeOrder(), ByteOrder.BIG_ENDIAN); + } + + nativeReader.close(); + } // main method to run standalone from jtreg @Test(enabled=false) diff --git a/jdk/test/jdk/internal/jimage/TEST.properties b/jdk/test/jdk/internal/jimage/TEST.properties new file mode 100644 index 00000000000..db4e960f214 --- /dev/null +++ b/jdk/test/jdk/internal/jimage/TEST.properties @@ -0,0 +1,7 @@ +# This file identifies root(s) of the test-ng hierarchy. + +TestNG.dirs = . + +modules=java.base/jdk.internal.jimage + +javatest.maxOutputSize = 2500000 diff --git a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java index f9b03cecc23..46f919e0a12 100644 --- a/jdk/test/jdk/internal/jline/console/StripAnsiTest.java +++ b/jdk/test/jdk/internal/jline/console/StripAnsiTest.java @@ -23,14 +23,16 @@ /** * @test - * @bug 8080679 - * @modules jdk.internal.le/jdk.internal.jline.console + * @bug 8080679 8131913 + * @modules jdk.internal.le/jdk.internal.jline + * jdk.internal.le/jdk.internal.jline.console * @summary Verify ConsoleReader.stripAnsi strips escape sequences from its input correctly. */ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.lang.reflect.Method; +import jdk.internal.jline.UnsupportedTerminal; import jdk.internal.jline.console.ConsoleReader; public class StripAnsiTest { @@ -41,7 +43,7 @@ public class StripAnsiTest { void run() throws Exception { ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); ByteArrayOutputStream out = new ByteArrayOutputStream(); - ConsoleReader reader = new ConsoleReader(in, out); + ConsoleReader reader = new ConsoleReader(in, out, new UnsupportedTerminal()); String withAnsi = "0\033[s1\033[2J2\033[37;4m3"; String expected = "0123"; diff --git a/jdk/test/jdk/internal/jrtfs/Basic.java b/jdk/test/jdk/internal/jrtfs/Basic.java index 5b99a5cf83f..0af30c5e2f7 100644 --- a/jdk/test/jdk/internal/jrtfs/Basic.java +++ b/jdk/test/jdk/internal/jrtfs/Basic.java @@ -28,8 +28,10 @@ */ import java.io.InputStream; +import java.io.IOException; import java.io.DataInputStream; import java.nio.file.DirectoryStream; +import java.nio.file.InvalidPathException; import java.nio.file.Files; import java.nio.file.FileSystem; import java.nio.file.FileSystems; @@ -38,16 +40,20 @@ import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.net.URI; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.stream.Stream; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertFalse; @@ -57,6 +63,34 @@ import static org.testng.Assert.assertFalse; public class Basic { + private FileSystem theFileSystem; + private FileSystem fs; + + @BeforeClass + public void setup() { + try { + theFileSystem = FileSystems.getFileSystem(URI.create("jrt:/")); + Map env = new HashMap<>(); + // set java.home property to be underlying java.home + // so that jrt-fs.jar loading is exercised. + env.put("java.home", System.getProperty("java.home")); + fs = FileSystems.newFileSystem(URI.create("jrt:/"), env); + } catch (IOException ioExp) { + throw new RuntimeException(ioExp); + } + } + + @AfterClass + public void tearDown() { + try { + fs.close(); + } catch (Exception ignored) {} + } + + private FileSystem selectFileSystem(boolean theDefault) { + return theDefault? theFileSystem : fs; + } + // Checks that the given FileSystem is a jrt file system. private void checkFileSystem(FileSystem fs) { assertTrue(fs.provider().getScheme().equalsIgnoreCase("jrt")); @@ -95,17 +129,32 @@ public class Basic { } } + @Test + public void testNewFileSystemWithJavaHome() throws Exception { + Map env = new HashMap<>(); + // set java.home property to be underlying java.home + // so that jrt-fs.jar loading is exercised. + env.put("java.home", System.getProperty("java.home")); + try (FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), env)) { + checkFileSystem(fs); + // jrt-fs.jar classes are loaded by another (non-boot) loader in this case + assertNotNull(fs.provider().getClass().getClassLoader()); + } + } + @DataProvider(name = "knownClassFiles") private Object[][] knownClassFiles() { return new Object[][] { - { "/modules/java.base/java/lang/Object.class" }, - { "modules/java.base/java/lang/Object.class" }, + { "/modules/java.base/java/lang/Object.class", true }, + { "modules/java.base/java/lang/Object.class", true }, + { "/modules/java.base/java/lang/Object.class", false }, + { "modules/java.base/java/lang/Object.class", false }, }; } @Test(dataProvider = "knownClassFiles") - public void testKnownClassFiles(String path) throws Exception { - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + public void testKnownClassFiles(String path, boolean theDefault) throws Exception { + FileSystem fs = selectFileSystem(theDefault); Path classFile = fs.getPath(path); assertTrue(Files.isRegularFile(classFile)); @@ -121,25 +170,38 @@ public class Basic { @DataProvider(name = "knownDirectories") private Object[][] knownDirectories() { return new Object[][] { - { "/" }, - { "." }, - { "./" }, - { "/." }, - { "/./" }, - { "/modules/java.base/.." }, - { "/modules/java.base/../" }, - { "/modules/java.base/../." }, - { "/modules/java.base" }, - { "/modules/java.base/java/lang" }, - { "modules/java.base/java/lang" }, - { "/modules/java.base/java/lang/" }, - { "modules/java.base/java/lang/" } + { "/", true }, + { "." , true }, + { "./", true }, + { "/.", true }, + { "/./", true }, + { "/modules/java.base/..", true }, + { "/modules/java.base/../", true }, + { "/modules/java.base/../.", true }, + { "/modules/java.base", true }, + { "/modules/java.base/java/lang", true }, + { "modules/java.base/java/lang", true }, + { "/modules/java.base/java/lang/", true }, + { "modules/java.base/java/lang/", true }, + { "/", false }, + { "." , false }, + { "./", false }, + { "/.", false }, + { "/./", false }, + { "/modules/java.base/..", false }, + { "/modules/java.base/../", false }, + { "/modules/java.base/../.", false }, + { "/modules/java.base", false }, + { "/modules/java.base/java/lang", false }, + { "modules/java.base/java/lang", false }, + { "/modules/java.base/java/lang/", false }, + { "modules/java.base/java/lang/", false }, }; } @Test(dataProvider = "knownDirectories") - public void testKnownDirectories(String path) throws Exception { - FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + public void testKnownDirectories(String path, boolean theDefault) throws Exception { + FileSystem fs = selectFileSystem(theDefault); Path dir = fs.getPath(path); assertTrue(Files.isDirectory(dir)); @@ -383,6 +445,8 @@ public class Basic { { "/modules/java.base/packages.offsets" }, { "/modules/java.instrument/packages.offsets" }, { "/modules/jdk.zipfs/packages.offsets" }, + { "/modules/java.base/_the.java.base.vardeps" }, + { "/modules/java.base/_the.java.base_batch" }, { "/java/lang" }, { "/java/util" }, }; @@ -568,48 +632,55 @@ public class Basic { } @Test - public void testPackagesSubDirList() throws Exception { + public void invalidPathTest() { FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - String pathName = "/packages/javax.annotation"; - Path path = fs.getPath(pathName); - boolean seenJavaCompiler = false, seenAnnotationsCommon = false; - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (Path p : stream) { - String str = p.toString(); - if (str.equals(pathName + "/java.compiler")) { - seenJavaCompiler = true; - } else if (str.equals(pathName + "/java.annotations.common")) { - seenAnnotationsCommon = true; - } - } + InvalidPathException ipe = null; + try { + boolean res = Files.exists(fs.getPath("/packages/\ud834\udd7b")); + assertFalse(res); + return; + } catch (InvalidPathException e) { + ipe = e; } - assertTrue(seenJavaCompiler); - assertTrue(seenAnnotationsCommon); + assertTrue(ipe != null); } - @Test - public void testRootDirList() throws Exception { + @DataProvider(name="packagesLinkedDirs") + private Object[][] packagesLinkedDirs() { + return new Object[][] { + { "/packages/java.lang/java.base/java/lang/ref" }, + { "/./packages/java.lang/java.base/java/lang/ref" }, + { "packages/java.lang/java.base/java/lang/ref" }, + { "/packages/../packages/java.lang/java.base/java/lang/ref" }, + { "/packages/java.lang/java.base/java/util/zip" }, + { "/./packages/java.lang/java.base/java/util/zip" }, + { "packages/java.lang/java.base/java/util/zip" }, + { "/packages/../packages/java.lang/java.base/java/util/zip" }, + { "/packages/com.oracle/java.xml.ws/com" }, + { "/./packages/com.oracle/java.xml.ws/com" }, + { "packages/com.oracle/java.xml.ws/com" }, + { "/packages/../packages/com.oracle/java.xml.ws/com" } + }; + } + + // @bug 8141521: jrt file system's DirectoryStream reports child paths + // with wrong paths for directories under /packages + @Test(dataProvider = "packagesLinkedDirs") + public void dirStreamPackagesDirTest(String dirName) throws IOException { FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); - Path path = fs.getPath("/"); - // check /packages and /modules are not repeated - // and seen once. - boolean packages = false, modules = false; - try (DirectoryStream stream = Files.newDirectoryStream(path)) { - for (Path p : stream) { - String str = p.toString(); - switch (str) { - case "/packages": - assertFalse(packages, "/packages repeated"); - packages = true; - break; - case "/modules": - assertFalse(modules, "/modules repeated"); - modules = true; - break; + Path path = fs.getPath(dirName); + + int childCount = 0, dirPrefixOkayCount = 0; + try (DirectoryStream dirStream = Files.newDirectoryStream(path)) { + for (Path child : dirStream) { + childCount++; + if (child.toString().startsWith(dirName)) { + dirPrefixOkayCount++; } } } - assertTrue(packages, "/packages missing in / list!"); - assertTrue(modules, "/modules missing in / list!"); + + assertTrue(childCount != 0); + assertEquals(dirPrefixOkayCount, childCount); } } diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java new file mode 100644 index 00000000000..65e2b587388 --- /dev/null +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyCommon.java @@ -0,0 +1,607 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +/** + * Helper class to support testing of Unsafe.copyMemory and Unsafe.copySwapMemory + */ +public class CopyCommon { + private static final boolean DEBUG = Boolean.getBoolean("CopyCommon.DEBUG"); + + public static final long KB = 1024; + public static final long MB = KB * 1024; + public static final long GB = MB * 1024; + + static final int SMALL_COPY_SIZE = 32; + static final int BASE_ALIGNMENT = 16; + + protected static final Unsafe UNSAFE; + + static { + try { + Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); + f.setAccessible(true); + UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); + } catch (Exception e) { + throw new RuntimeException("Unable to get Unsafe instance.", e); + } + } + + static long alignDown(long value, long alignment) { + return value & ~(alignment - 1); + } + + static long alignUp(long value, long alignment) { + return (value + alignment - 1) & ~(alignment - 1); + } + + static boolean isAligned(long value, long alignment) { + return value == alignDown(value, alignment); + } + + CopyCommon() { + } + + /** + * Generate verification data for a given offset + * + * The verification data is used to verify that the correct bytes + * have indeed been copied and byte swapped. + * + * The data is generated based on the offset (in bytes) into the + * source buffer. For a native buffer the offset is relative to + * the base pointer. For a heap array it is relative to the + * address of the first array element. + * + * This method will return the result of doing an elementSize byte + * read starting at offset (in bytes). + * + * @param offset offset into buffer + * @param elemSize size (in bytes) of the element + * + * @return the verification data, only the least significant + * elemSize*8 bits are set, zero extended + */ + private long getVerificationDataForOffset(long offset, long elemSize) { + byte[] bytes = new byte[(int)elemSize]; + + for (long i = 0; i < elemSize; i++) { + bytes[(int)i] = (byte)(offset + i); + } + + long o = UNSAFE.arrayBaseOffset(byte[].class); + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); + case 8: return UNSAFE.getLongUnaligned(bytes, o); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Verify byte swapped data + * + * @param ptr the data to verify + * @param srcOffset the srcOffset (in bytes) from which the copy started, + * used as key to regenerate the verification data + * @param dstOffset the offset (in bytes) in the array at which to start + * the verification, relative to the first element in the array + * @param size size (in bytes) of data to to verify + * @param elemSize size (in bytes) of the individual array elements + * + * @throws RuntimeException if an error is found + */ + private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { + for (long offset = 0; offset < size; offset += elemSize) { + long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); + long expected = byteSwap(expectedUnswapped, elemSize); + + long actual = getArrayElem(ptr, dstOffset + offset, elemSize); + + if (expected != actual) { + throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + + " dstOffset: 0x" + Long.toHexString(dstOffset) + + " size: 0x" + Long.toHexString(size) + + " offset: 0x" + Long.toHexString(offset) + + " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + /** + * Initialize an array with verification friendly data + * + * @param ptr pointer to the data to initialize + * @param size size (in bytes) of the data + * @param elemSize size (in bytes) of the individual elements + */ + private void initVerificationData(GenericPointer ptr, long size, long elemSize) { + for (long offset = 0; offset < size; offset++) { + byte data = (byte)getVerificationDataForOffset(offset, 1); + + if (ptr.isOnHeap()) { + UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); + } else { + UNSAFE.putByte(ptr.getOffset() + offset, data); + } + } + } + + /** + * Allocate a primitive array + * + * @param size size (in bytes) of all the array elements (elemSize * length) + * @param elemSize the size of the array elements + * + * @return a newly allocated primitive array + */ + Object allocArray(long size, long elemSize) { + int length = (int)(size / elemSize); + + switch ((int)elemSize) { + case 1: return new byte[length]; + case 2: return new short[length]; + case 4: return new int[length]; + case 8: return new long[length]; + default: + throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the value of a primitive array entry + * + * @param ptr pointer to the data + * @param offset offset (in bytes) of the array element, relative to the first element in the array + * + * @return the array element, as an unsigned long + */ + private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { + if (ptr.isOnHeap()) { + Object o = ptr.getObject(); + int index = (int)(offset / elemSize); + + if (o instanceof short[]) { + short[] arr = (short[])o; + return Short.toUnsignedLong(arr[index]); + } else if (o instanceof int[]) { + int[] arr = (int[])o; + return Integer.toUnsignedLong(arr[index]); + } else if (o instanceof long[]) { + long[] arr = (long[])o; + return arr[index]; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } else { + long addr = ptr.getOffset() + offset; + + switch ((int)elemSize) { + case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); + case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); + case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); + case 8: return UNSAFE.getLongUnaligned(null, addr); + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + } + + private void putValue(long addr, long elemSize, long value) { + switch ((int)elemSize) { + case 1: UNSAFE.putByte(addr, (byte)value); break; + case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; + case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; + case 8: UNSAFE.putLongUnaligned(null, addr, value); break; + default: throw new IllegalArgumentException("Invalid element size: " + elemSize); + } + } + + /** + * Get the size of the elements for an array + * + * @param o a primitive heap array + * + * @return the size (in bytes) of the individual array elements + */ + private long getArrayElemSize(Object o) { + if (o instanceof short[]) { + return 2; + } else if (o instanceof int[]) { + return 4; + } else if (o instanceof long[]) { + return 8; + } else { + throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); + } + } + + /** + * Byte swap a value + * + * @param value the value to swap, only the bytes*8 least significant bits are used + * @param size size (in bytes) of the value + * + * @return the byte swapped value in the bytes*8 least significant bits + */ + private long byteSwap(long value, long size) { + switch ((int)size) { + case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); + case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); + case 8: return Long.reverseBytes(value); + default: throw new IllegalArgumentException("Invalid element size: " + size); + } + } + + /** + * Verify data which has *not* been byte swapped + * + * @param ptr the data to verify + * @param startOffset the offset (in bytes) at which to start the verification + * @param size size (in bytes) of the data to verify + * + * @throws RuntimeException if an error is found + */ + private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { + for (long i = 0; i < size; i++) { + byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); + + byte actual; + if (ptr.isOnHeap()) { + actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); + } else { + actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); + } + + if (expected != actual) { + throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + + " srcOffset: 0x" + Long.toHexString(srcOffset) + + " size: 0x" + Long.toHexString(size) + + " i: 0x" + Long.toHexString(i) + + " expected: 0x" + Long.toHexString(expected) + + " != actual: 0x" + Long.toHexString(actual)); + } + } + } + + + /** + * Copy and byte swap data from the source to the destination + * + * This method will pre-populate the whole source and destination + * buffers with verification friendly data. It will then copy data + * to fill part of the destination buffer with data from the + * source, optionally byte swapping the copied elements on the + * fly. Some space (padding) will be left before and after the + * data in the destination buffer, which should not be + * touched/overwritten by the copy call. + * + * Note: Both source and destination buffers will be overwritten! + * + * @param src source buffer to copy from + * @param srcOffset the offset (in bytes) in the source buffer, relative to + * the first array element, at which to start reading data + * @param dst destination buffer to copy to + * @param dstOffset the offset (in bytes) in the destination + * buffer, relative to the first array element, at which to + * start writing data + * @param bufSize the size (in bytes) of the src and dst arrays + * @param copyBytes the size (in bytes) of the copy to perform, + * must be a multiple of elemSize + * @param elemSize the size (in bytes) of the elements + * @param swap true if elements should be byte swapped + * + * @throws RuntimeException if an error is found + */ + void testCopyGeneric(GenericPointer src, long srcOffset, + GenericPointer dst, long dstOffset, + long bufSize, long copyBytes, long elemSize, boolean swap) { + if (swap) { + if (!isAligned(copyBytes, elemSize)) { + throw new IllegalArgumentException( + "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")"); + } + if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")"); + } + if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")"); + } + } + + if (srcOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + if (dstOffset + copyBytes > bufSize) { + throw new IllegalArgumentException( + "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); + } + + // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) + initVerificationData(src, bufSize, elemSize); + if (!src.equals(dst)) { + initVerificationData(dst, bufSize, elemSize); + } + + if (DEBUG) { + System.out.println("===before==="); + for (int offset = 0; offset < bufSize; offset += elemSize) { + long srcValue = getArrayElem(src, offset, elemSize); + long dstValue = getArrayElem(dst, offset, elemSize); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + if (swap) { + // Copy & swap data into the middle of the destination buffer + UNSAFE.copySwapMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes, + elemSize); + } else { + // Copy & swap data into the middle of the destination buffer + UNSAFE.copyMemory(src.getObject(), + src.getOffset() + srcOffset, + dst.getObject(), + dst.getOffset() + dstOffset, + copyBytes); + } + + if (DEBUG) { + System.out.println("===after==="); + for (int offset = 0; offset < bufSize; offset += elemSize) { + long srcValue = getArrayElem(src, offset, elemSize); + long dstValue = getArrayElem(dst, offset, elemSize); + + System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + + " src=0x" + Long.toHexString(srcValue) + + " dst=0x" + Long.toHexString(dstValue)); + } + } + + // Verify the the front padding is unchanged + verifyUnswappedData(dst, 0, 0, dstOffset); + + if (swap) { + // Verify swapped data + verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize); + } else { + // Verify copied/unswapped data + verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); + } + + // Verify that the back padding is unchanged + long frontAndCopyBytes = dstOffset + copyBytes; + long trailingBytes = bufSize - frontAndCopyBytes; + verifyUnswappedData(dst, frontAndCopyBytes, frontAndCopyBytes, trailingBytes); + } + + /** + * Test various configurations of copying and optionally swapping data + * + * @param src the source buffer to copy from + * @param dst the destination buffer to copy to + * @param size size (in bytes) of the buffers + * @param elemSize size (in bytes) of the individual elements + * + * @throws RuntimeException if an error is found + */ + public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize, boolean swap) { + // offset in source from which to start reading data + for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { + + // offset in destination at which to start writing data + for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { + + // number of bytes to copy + long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); + for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { + try { + testCopyGeneric(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize, swap); + } catch (RuntimeException e) { + // Wrap the exception in another exception to catch the relevant configuration data + throw new RuntimeException("testBufferPair: " + + "src=" + src + + " dst=" + dst + + " elemSize=0x" + Long.toHexString(elemSize) + + " copyBytes=0x" + Long.toHexString(copyBytes) + + " srcOffset=0x" + Long.toHexString(srcOffset) + + " dstOffset=0x" + Long.toHexString(dstOffset) + + " swap=" + swap, + e); + } + } + } + } + } + + /** + * Test copying between various permutations of buffers + * + * @param buffers buffers to permute (src x dst) + * @param size size (in bytes) of buffers + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize, boolean swap) { + System.out.println("testPermuteBuffers(buffers, " + size + ", " + elemSize + ", " + swap + ")"); + for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { + for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { + testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize, swap); + } + } + } + + /** + * Test copying of a specific element size + * + * @param size size (in bytes) of buffers to allocate + * @param elemSize size (in bytes) of individual elements + * + * @throws RuntimeException if an error is found + */ + private void testElemSize(long size, long elemSize, boolean swap) { + long buf1Raw = 0; + long buf2Raw = 0; + + try { + buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); + + buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); + + GenericPointer[] buffers = { + new GenericPointer(buf1), + new GenericPointer(buf2), + new GenericPointer(allocArray(size, elemSize)), + new GenericPointer(allocArray(size, elemSize)) + }; + + testPermuteBuffers(buffers, size, elemSize, swap); + } finally { + if (buf1Raw != 0) { + UNSAFE.freeMemory(buf1Raw); + } + if (buf2Raw != 0) { + UNSAFE.freeMemory(buf2Raw); + } + } + } + + /** + * Verify that small copies work + */ + void testSmallCopy(boolean swap) { + int smallBufSize = SMALL_COPY_SIZE; + int minElemSize = swap ? 2 : 1; + int maxElemSize = swap ? 8 : 1; + + // Test various element types and heap/native combinations + for (long elemSize = minElemSize; elemSize <= maxElemSize; elemSize <<= 1) { + testElemSize(smallBufSize, elemSize, swap); + } + } + + + /** + * Verify that large copies work + */ + void testLargeCopy(boolean swap) { + long size = 2 * GB + 8; + long bufRaw = 0; + + // Check that a large native copy succeeds + try { + try { + bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); + } catch (OutOfMemoryError e) { + // Accept failure, skip test + return; + } + + long buf = alignUp(bufRaw, BASE_ALIGNMENT); + + if (swap) { + UNSAFE.copySwapMemory(null, buf, null, buf, size, 8); + } else { + UNSAFE.copyMemory(null, buf, null, buf, size); + } + } catch (Exception e) { + throw new RuntimeException("copy of large buffer failed (swap=" + swap + ")"); + } finally { + if (bufRaw != 0) { + UNSAFE.freeMemory(bufRaw); + } + } + } + + /** + * Helper class to represent a "pointer" - either a heap array or + * a pointer to a native buffer. + * + * In the case of a native pointer, the Object is null and the offset is + * the absolute address of the native buffer. + * + * In the case of a heap object, the Object is a primitive array, and + * the offset will be set to the base offset to the first element, meaning + * the object and the offset together form a double-register pointer. + */ + static class GenericPointer { + private final Object o; + private final long offset; + + private GenericPointer(Object o, long offset) { + this.o = o; + this.offset = offset; + } + + public String toString() { + return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof GenericPointer)) { + return false; + } + + GenericPointer otherp = (GenericPointer)other; + + return o == otherp.o && offset == otherp.offset; + } + + GenericPointer(Object o) { + this(o, UNSAFE.arrayBaseOffset(o.getClass())); + } + + GenericPointer(long offset) { + this(null, offset); + } + + public boolean isOnHeap() { + return o != null; + } + + public Object getObject() { + return o; + } + + public long getOffset() { + return offset; + } + } +} diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java index c87bb1b6895..d4879e603f1 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopyMemory.java @@ -29,492 +29,18 @@ import java.lang.reflect.Field; * @summary Test Unsafe.copyMemory * @modules java.base/jdk.internal.misc */ -public class CopyMemory { - private static final boolean DEBUG = Boolean.getBoolean("CopyMemory.DEBUG"); - - public static final long KB = 1024; - public static final long MB = KB * 1024; - public static final long GB = MB * 1024; - - private static final Unsafe UNSAFE; - private static final int SMALL_COPY_SIZE = 32; - private static final int BASE_ALIGNMENT = 16; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } - - private static long alignDown(long value, long alignment) { - return value & ~(alignment - 1); - } - - private static long alignUp(long value, long alignment) { - return (value + alignment - 1) & ~(alignment - 1); - } - - private static boolean isAligned(long value, long alignment) { - return value == alignDown(value, alignment); - } - +public class CopyMemory extends CopyCommon { private CopyMemory() { } - /** - * Generate verification data for a given offset - * - * The verification data is used to verify that the correct bytes - * have indeed been copied and byte swapped. - * - * The data is generated based on the offset (in bytes) into the - * source buffer. For a native buffer the offset is relative to - * the base pointer. For a heap array it is relative to the - * address of the first array element. - * - * This method will return the result of doing an elementSize byte - * read starting at offset (in bytes). - * - * @param offset offset into buffer - * @param elemSize size (in bytes) of the element - * - * @return the verification data, only the least significant - * elemSize*8 bits are set, zero extended - */ - private long getVerificationDataForOffset(long offset, long elemSize) { - byte[] bytes = new byte[(int)elemSize]; - - for (long i = 0; i < elemSize; i++) { - bytes[(int)i] = (byte)(offset + i); - } - - long o = UNSAFE.arrayBaseOffset(byte[].class); - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); - case 8: return UNSAFE.getLongUnaligned(bytes, o); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Verify byte swapped data - * - * @param ptr the data to verify - * @param srcOffset the srcOffset (in bytes) from which the copy started, - * used as key to regenerate the verification data - * @param dstOffset the offset (in bytes) in the array at which to start - * the verification, relative to the first element in the array - * @param size size (in bytes) of data to to verify - * @param elemSize size (in bytes) of the individual array elements - * - * @throws RuntimeException if an error is found - */ - private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { - for (long offset = 0; offset < size; offset += elemSize) { - long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); - long expected = byteSwap(expectedUnswapped, elemSize); - - long actual = getArrayElem(ptr, dstOffset + offset, elemSize); - - if (expected != actual) { - throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + - " dstOffset: 0x" + Long.toHexString(dstOffset) + - " size: 0x" + Long.toHexString(size) + - " offset: 0x" + Long.toHexString(offset) + - " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - /** - * Initialize an array with verification friendly data - * - * @param ptr pointer to the data to initialize - * @param size size (in bytes) of the data - * @param elemSize size (in bytes) of the individual elements - */ - private void initVerificationData(GenericPointer ptr, long size, long elemSize) { - for (long offset = 0; offset < size; offset++) { - byte data = (byte)getVerificationDataForOffset(offset, 1); - - if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); - } else { - UNSAFE.putByte(ptr.getOffset() + offset, data); - } - } - } - - /** - * Allocate a primitive array - * - * @param size size (in bytes) of all the array elements (elemSize * length) - * @param elemSize the size of the array elements - * - * @return a newly allocated primitive array - */ - Object allocArray(long size, long elemSize) { - int length = (int)(size / elemSize); - - switch ((int)elemSize) { - case 1: return new byte[length]; - case 2: return new short[length]; - case 4: return new int[length]; - case 8: return new long[length]; - default: - throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the value of a primitive array entry - * - * @param ptr pointer to the data - * @param offset offset (in bytes) of the array element, relative to the first element in the array - * - * @return the array element, as an unsigned long - */ - private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { - if (ptr.isOnHeap()) { - Object o = ptr.getObject(); - int index = (int)(offset / elemSize); - - if (o instanceof short[]) { - short[] arr = (short[])o; - return Short.toUnsignedLong(arr[index]); - } else if (o instanceof int[]) { - int[] arr = (int[])o; - return Integer.toUnsignedLong(arr[index]); - } else if (o instanceof long[]) { - long[] arr = (long[])o; - return arr[index]; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } else { - long addr = ptr.getOffset() + offset; - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); - case 8: return UNSAFE.getLongUnaligned(null, addr); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - } - - private void putValue(long addr, long elemSize, long value) { - switch ((int)elemSize) { - case 1: UNSAFE.putByte(addr, (byte)value); break; - case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; - case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; - case 8: UNSAFE.putLongUnaligned(null, addr, value); break; - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the size of the elements for an array - * - * @param o a primitive heap array - * - * @return the size (in bytes) of the individual array elements - */ - private long getArrayElemSize(Object o) { - if (o instanceof short[]) { - return 2; - } else if (o instanceof int[]) { - return 4; - } else if (o instanceof long[]) { - return 8; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } - - /** - * Byte swap a value - * - * @param value the value to swap, only the bytes*8 least significant bits are used - * @param size size (in bytes) of the value - * - * @return the byte swapped value in the bytes*8 least significant bits - */ - private long byteSwap(long value, long size) { - switch ((int)size) { - case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); - case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); - case 8: return Long.reverseBytes(value); - default: throw new IllegalArgumentException("Invalid element size: " + size); - } - } - - /** - * Verify data which has *not* been byte swapped - * - * @param ptr the data to verify - * @param startOffset the offset (in bytes) at which to start the verification - * @param size size (in bytes) of the data to verify - * - * @throws RuntimeException if an error is found - */ - private void verifyUnswappedData(GenericPointer ptr, long startOffset, long srcOffset, long size) { - for (long i = 0; i < size; i++) { - byte expected = (byte)getVerificationDataForOffset(srcOffset + i, 1); - - byte actual; - if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + startOffset + i); - } else { - actual = UNSAFE.getByte(ptr.getOffset() + startOffset + i); - } - - if (expected != actual) { - throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + - " srcOffset: 0x" + Long.toHexString(srcOffset) + - " size: 0x" + Long.toHexString(size) + - " i: 0x" + Long.toHexString(i) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - - /** - * Copy and byte swap data from the source to the destination - * - * This method will pre-populate the whole source and destination - * buffers with verification friendly data. It will then use - * copypMemory to fill part of the destination buffer with - * data from the source. Some space (padding) will be - * left before and after the data in the destination buffer, which - * should not be touched/overwritten by the copy call. - * - * Note: Both source and destination buffers will be overwritten! - * - * @param src source buffer to copy from - * @param srcOffset the offset (in bytes) in the source buffer, relative to - * the first array element, at which to start reading data - * @param dst destination buffer to copy to - * @param dstOffset the offset (in bytes) in the destination - * buffer, relative to the first array element, at which to - * start writing data - * @param bufSize the size (in bytes) of the src and dst arrays - * @param copyBytes the size (in bytes) of the copy to perform, - * must be a multiple of elemSize - * - * @throws RuntimeException if an error is found - */ - private void testCopy(GenericPointer src, long srcOffset, - GenericPointer dst, long dstOffset, - long bufSize, long copyBytes) { - if (srcOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - if (dstOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - - // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) - initVerificationData(src, bufSize, 1); - if (!src.equals(dst)) { - initVerificationData(dst, bufSize, 1); - } - - if (DEBUG) { - System.out.println("===before==="); - for (int offset = 0; offset < bufSize; offset++) { - long srcValue = getArrayElem(src, offset, 1); - long dstValue = getArrayElem(dst, offset, 1); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Copy & swap data into the middle of the destination buffer - UNSAFE.copyMemory(src.getObject(), - src.getOffset() + srcOffset, - dst.getObject(), - dst.getOffset() + dstOffset, - copyBytes); - - if (DEBUG) { - System.out.println("===after==="); - for (int offset = 0; offset < bufSize; offset++) { - long srcValue = getArrayElem(src, offset, 1); - long dstValue = getArrayElem(dst, offset, 1); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Verify the the front padding is unchanged - verifyUnswappedData(dst, 0, 0, dstOffset); - - // Verify copied data - verifyUnswappedData(dst, dstOffset, srcOffset, copyBytes); - - // Verify that the back back padding is unchanged - long frontAndDataBytes = dstOffset + copyBytes; - long trailingBytes = bufSize - frontAndDataBytes; - verifyUnswappedData(dst, frontAndDataBytes, frontAndDataBytes, trailingBytes); - } - - /** - * Test various configurations copying from one buffer to the other - * - * @param src the source buffer to copy from - * @param dst the destination buffer to copy to - * @param size size (in bytes) of the buffers - * @param elemSize size (in bytes) of the individual elements - * - * @throws RuntimeException if an error is found - */ - public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { - // offset in source from which to start reading data - for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { - - // offset in destination at which to start writing data - for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { - - // number of bytes to copy - long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); - for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { - try { - testCopy(src, srcOffset, dst, dstOffset, size, copyBytes); - } catch (RuntimeException e) { - // Wrap the exception in another exception to catch the relevant configuration data - throw new RuntimeException("testBufferPair: " + - "src=" + src + - " dst=" + dst + - " elemSize=0x" + Long.toHexString(elemSize) + - " copyBytes=0x" + Long.toHexString(copyBytes) + - " srcOffset=0x" + Long.toHexString(srcOffset) + - " dstOffset=0x" + Long.toHexString(dstOffset), - e); - } - } - } - } - } - - /** - * Test copying between various permutations of buffers - * - * @param buffers buffers to permute (src x dst) - * @param size size (in bytes) of buffers - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { - for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { - for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { - testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); - } - } - } - - /** - * Test copying of a specific element size - * - * @param size size (in bytes) of buffers to allocate - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - private void testElemSize(long size, long elemSize) { - long buf1Raw = 0; - long buf2Raw = 0; - - try { - buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); - - buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); - - GenericPointer[] buffers = { - new GenericPointer(buf1), - new GenericPointer(buf2), - new GenericPointer(allocArray(size, elemSize)), - new GenericPointer(allocArray(size, elemSize)) - }; - - testPermuteBuffers(buffers, size, elemSize); - } finally { - if (buf1Raw != 0) { - UNSAFE.freeMemory(buf1Raw); - } - if (buf2Raw != 0) { - UNSAFE.freeMemory(buf2Raw); - } - } - } - - /** - * Verify that small copies work - */ - private void testSmallCopy() { - int smallBufSize = SMALL_COPY_SIZE; - - testElemSize(smallBufSize, 1); - } - - - /** - * Verify that large copies work - */ - private void testLargeCopy() { - long size = 2 * GB + 8; - long bufRaw = 0; - - // Check that a large native copy succeeds - try { - try { - bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - } catch (OutOfMemoryError e) { - // Accept failure, skip test - return; - } - - long buf = alignUp(bufRaw, BASE_ALIGNMENT); - - UNSAFE.copyMemory(null, buf, null, buf, size); - } catch (Exception e) { - throw new RuntimeException("copyMemory of large buffer failed"); - } finally { - if (bufRaw != 0) { - UNSAFE.freeMemory(bufRaw); - } - } - } - /** * Run positive tests * * @throws RuntimeException if an error is found */ private void testPositive() { - testSmallCopy(); - testLargeCopy(); + testSmallCopy(false); + testLargeCopy(false); } /** @@ -527,7 +53,7 @@ public class CopyMemory { try { bufRaw = UNSAFE.allocateMemory(1024); - long buf = alignUp(bufRaw, BASE_ALIGNMENT); + long buf = CopyCommon.alignUp(bufRaw, CopyCommon.BASE_ALIGNMENT); short[] arr = new short[16]; // Check illegal sizes @@ -609,59 +135,4 @@ public class CopyMemory { CopyMemory cs = new CopyMemory(); cs.test(); } - - /** - * Helper class to represent a "pointer" - either a heap array or - * a pointer to a native buffer. - * - * In the case of a native pointer, the Object is null and the offset is - * the absolute address of the native buffer. - * - * In the case of a heap object, the Object is a primitive array, and - * the offset will be set to the base offset to the first element, meaning - * the object and the offset together form a double-register pointer. - */ - static class GenericPointer { - private final Object o; - private final long offset; - - private GenericPointer(Object o, long offset) { - this.o = o; - this.offset = offset; - } - - public String toString() { - return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; - } - - public boolean equals(Object other) { - if (!(other instanceof GenericPointer)) { - return false; - } - - GenericPointer otherp = (GenericPointer)other; - - return o == otherp.o && offset == otherp.offset; - } - - GenericPointer(Object o) { - this(o, UNSAFE.arrayBaseOffset(o.getClass())); - } - - GenericPointer(long offset) { - this(null, offset); - } - - public boolean isOnHeap() { - return o != null; - } - - public Object getObject() { - return o; - } - - public long getOffset() { - return offset; - } - } } diff --git a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java index bb94c200765..4cbd8b709d2 100644 --- a/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java +++ b/jdk/test/jdk/internal/misc/Unsafe/CopySwap.java @@ -29,507 +29,18 @@ import java.lang.reflect.Field; * @summary Test Unsafe.copySwapMemory * @modules java.base/jdk.internal.misc */ -public class CopySwap { - private static final boolean DEBUG = Boolean.getBoolean("CopySwap.DEBUG"); - - public static final long KB = 1024; - public static final long MB = KB * 1024; - public static final long GB = MB * 1024; - - private static final Unsafe UNSAFE; - private static final int SMALL_COPY_SIZE = 32; - private static final int BASE_ALIGNMENT = 16; - - static { - try { - Field f = jdk.internal.misc.Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - UNSAFE = (jdk.internal.misc.Unsafe) f.get(null); - } catch (Exception e) { - throw new RuntimeException("Unable to get Unsafe instance.", e); - } - } - - private static long alignDown(long value, long alignment) { - return value & ~(alignment - 1); - } - - private static long alignUp(long value, long alignment) { - return (value + alignment - 1) & ~(alignment - 1); - } - - private static boolean isAligned(long value, long alignment) { - return value == alignDown(value, alignment); - } - +public class CopySwap extends CopyCommon { private CopySwap() { } - /** - * Generate verification data for a given offset - * - * The verification data is used to verify that the correct bytes - * have indeed been copied and byte swapped. - * - * The data is generated based on the offset (in bytes) into the - * source buffer. For a native buffer the offset is relative to - * the base pointer. For a heap array it is relative to the - * address of the first array element. - * - * This method will return the result of doing an elementSize byte - * read starting at offset (in bytes). - * - * @param offset offset into buffer - * @param elemSize size (in bytes) of the element - * - * @return the verification data, only the least significant - * elemSize*8 bits are set, zero extended - */ - private long getVerificationDataForOffset(long offset, long elemSize) { - byte[] bytes = new byte[(int)elemSize]; - - for (long i = 0; i < elemSize; i++) { - bytes[(int)i] = (byte)(offset + i); - } - - long o = UNSAFE.arrayBaseOffset(byte[].class); - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(bytes, o)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(bytes, o)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(bytes, o)); - case 8: return UNSAFE.getLongUnaligned(bytes, o); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Verify byte swapped data - * - * @param ptr the data to verify - * @param srcOffset the srcOffset (in bytes) from which the copy started, - * used as key to regenerate the verification data - * @param dstOffset the offset (in bytes) in the array at which to start - * the verification, relative to the first element in the array - * @param size size (in bytes) of data to to verify - * @param elemSize size (in bytes) of the individual array elements - * - * @throws RuntimeException if an error is found - */ - private void verifySwappedData(GenericPointer ptr, long srcOffset, long dstOffset, long size, long elemSize) { - for (long offset = 0; offset < size; offset += elemSize) { - long expectedUnswapped = getVerificationDataForOffset(srcOffset + offset, elemSize); - long expected = byteSwap(expectedUnswapped, elemSize); - - long actual = getArrayElem(ptr, dstOffset + offset, elemSize); - - if (expected != actual) { - throw new RuntimeException("srcOffset: 0x" + Long.toHexString(srcOffset) + - " dstOffset: 0x" + Long.toHexString(dstOffset) + - " size: 0x" + Long.toHexString(size) + - " offset: 0x" + Long.toHexString(offset) + - " expectedUnswapped: 0x" + Long.toHexString(expectedUnswapped) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - /** - * Initialize an array with verification friendly data - * - * @param ptr pointer to the data to initialize - * @param size size (in bytes) of the data - * @param elemSize size (in bytes) of the individual elements - */ - private void initVerificationData(GenericPointer ptr, long size, long elemSize) { - for (long offset = 0; offset < size; offset++) { - byte data = (byte)getVerificationDataForOffset(offset, 1); - - if (ptr.isOnHeap()) { - UNSAFE.putByte(ptr.getObject(), ptr.getOffset() + offset, data); - } else { - UNSAFE.putByte(ptr.getOffset() + offset, data); - } - } - } - - /** - * Allocate a primitive array - * - * @param size size (in bytes) of all the array elements (elemSize * length) - * @param elemSize the size of the array elements - * - * @return a newly allocated primitive array - */ - Object allocArray(long size, long elemSize) { - int length = (int)(size / elemSize); - - switch ((int)elemSize) { - case 2: return new short[length]; - case 4: return new int[length]; - case 8: return new long[length]; - default: - throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the value of a primitive array entry - * - * @param ptr pointer to the data - * @param offset offset (in bytes) of the array element, relative to the first element in the array - * - * @return the array element, as an unsigned long - */ - private long getArrayElem(GenericPointer ptr, long offset, long elemSize) { - if (ptr.isOnHeap()) { - Object o = ptr.getObject(); - int index = (int)(offset / elemSize); - - if (o instanceof short[]) { - short[] arr = (short[])o; - return Short.toUnsignedLong(arr[index]); - } else if (o instanceof int[]) { - int[] arr = (int[])o; - return Integer.toUnsignedLong(arr[index]); - } else if (o instanceof long[]) { - long[] arr = (long[])o; - return arr[index]; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } else { - long addr = ptr.getOffset() + offset; - - switch ((int)elemSize) { - case 1: return Byte.toUnsignedLong(UNSAFE.getByte(addr)); - case 2: return Short.toUnsignedLong(UNSAFE.getShortUnaligned(null, addr)); - case 4: return Integer.toUnsignedLong(UNSAFE.getIntUnaligned(null, addr)); - case 8: return UNSAFE.getLongUnaligned(null, addr); - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - } - - private void putValue(long addr, long elemSize, long value) { - switch ((int)elemSize) { - case 1: UNSAFE.putByte(addr, (byte)value); break; - case 2: UNSAFE.putShortUnaligned(null, addr, (short)value); break; - case 4: UNSAFE.putIntUnaligned(null, addr, (int)value); break; - case 8: UNSAFE.putLongUnaligned(null, addr, value); break; - default: throw new IllegalArgumentException("Invalid element size: " + elemSize); - } - } - - /** - * Get the size of the elements for an array - * - * @param o a primitive heap array - * - * @return the size (in bytes) of the individual array elements - */ - private long getArrayElemSize(Object o) { - if (o instanceof short[]) { - return 2; - } else if (o instanceof int[]) { - return 4; - } else if (o instanceof long[]) { - return 8; - } else { - throw new IllegalArgumentException("Invalid object type: " + o.getClass().getName()); - } - } - - /** - * Byte swap a value - * - * @param value the value to swap, only the bytes*8 least significant bits are used - * @param size size (in bytes) of the value - * - * @return the byte swapped value in the bytes*8 least significant bits - */ - private long byteSwap(long value, long size) { - switch ((int)size) { - case 2: return Short.toUnsignedLong(Short.reverseBytes((short)value)); - case 4: return Integer.toUnsignedLong(Integer.reverseBytes((int)value)); - case 8: return Long.reverseBytes(value); - default: throw new IllegalArgumentException("Invalid element size: " + size); - } - } - - /** - * Verify data in a heap array which has *not* been byte swapped - * - * @param ptr the data to verify - * @param startOffset the offset (in bytes) at which to start the verification - * @param size size (in bytes) of the data to verify - * - * @throws RuntimeException if an error is found - */ - private void verifyUnswappedData(GenericPointer ptr, long startOffset, long size) { - for (long elemOffset = startOffset; elemOffset < startOffset + size; elemOffset++) { - byte expected = (byte)getVerificationDataForOffset(elemOffset, 1); - - byte actual; - if (ptr.isOnHeap()) { - actual = UNSAFE.getByte(ptr.getObject(), ptr.getOffset() + elemOffset); - } else { - actual = UNSAFE.getByte(ptr.getOffset() + elemOffset); - } - - if (expected != actual) { - throw new RuntimeException("startOffset: 0x" + Long.toHexString(startOffset) + - " size: 0x" + Long.toHexString(size) + - " elemOffset: 0x" + Long.toHexString(elemOffset) + - " expected: 0x" + Long.toHexString(expected) + - " != actual: 0x" + Long.toHexString(actual)); - } - } - } - - - /** - * Copy and byte swap data from the source to the destination - * - * This method will pre-populate the whole source and destination - * buffers with verification friendly data. It will then use - * copySwapMemory to fill part of the destination buffer with - * swapped data from the source. Some space (padding) will be - * left before and after the data in the destination buffer, which - * should not be touched/overwritten by the copy call. - * - * Note: Both source and destination buffers will be overwritten! - * - * @param src source buffer to copy from - * @param srcOffset the offset (in bytes) in the source buffer, relative to - * the first array element, at which to start reading data - * @param dst destination buffer to copy to - * @param dstOffset the offset (in bytes) in the destination - * buffer, relative to the first array element, at which to - * start writing data - * @param bufSize the size (in bytes) of the src and dst arrays - * @param copyBytes the size (in bytes) of the copy to perform, - * must be a multiple of elemSize - * @param elemSize the size (in bytes) of the elements to byte swap - * - * @throws RuntimeException if an error is found - */ - private void testCopySwap(GenericPointer src, long srcOffset, - GenericPointer dst, long dstOffset, - long bufSize, long copyBytes, long elemSize) { - if (!isAligned(copyBytes, elemSize)) { - throw new IllegalArgumentException( - "copyBytes (" + copyBytes + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (src.isOnHeap() && !isAligned(srcOffset, elemSize)) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (dst.isOnHeap() && !isAligned(dstOffset, elemSize)) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") must be a multiple of elemSize (" + elemSize + ")"); - } - if (srcOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "srcOffset (" + srcOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - if (dstOffset + copyBytes > bufSize) { - throw new IllegalArgumentException( - "dstOffset (" + dstOffset + ") + copyBytes (" + copyBytes + ") > bufSize (" + bufSize + ")"); - } - - // Initialize the whole source buffer with a verification friendly pattern (no 0x00 bytes) - initVerificationData(src, bufSize, elemSize); - if (!src.equals(dst)) { - initVerificationData(dst, bufSize, elemSize); - } - - if (DEBUG) { - System.out.println("===before==="); - for (int offset = 0; offset < bufSize; offset += elemSize) { - long srcValue = getArrayElem(src, offset, elemSize); - long dstValue = getArrayElem(dst, offset, elemSize); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Copy & swap data into the middle of the destination buffer - UNSAFE.copySwapMemory(src.getObject(), - src.getOffset() + srcOffset, - dst.getObject(), - dst.getOffset() + dstOffset, - copyBytes, - elemSize); - - if (DEBUG) { - System.out.println("===after==="); - for (int offset = 0; offset < bufSize; offset += elemSize) { - long srcValue = getArrayElem(src, offset, elemSize); - long dstValue = getArrayElem(dst, offset, elemSize); - - System.out.println("offs=0x" + Long.toHexString(Integer.toUnsignedLong(offset)) + - " src=0x" + Long.toHexString(srcValue) + - " dst=0x" + Long.toHexString(dstValue)); - } - } - - // Verify the the front padding is unchanged - verifyUnswappedData(dst, 0, dstOffset); - - // Verify swapped data - verifySwappedData(dst, srcOffset, dstOffset, copyBytes, elemSize); - - // Verify that the back back padding is unchanged - long frontAndDataBytes = dstOffset + copyBytes; - long trailingBytes = bufSize - frontAndDataBytes; - verifyUnswappedData(dst, frontAndDataBytes, trailingBytes); - } - - /** - * Test various configurations copy-swapping from one buffer to the other - * - * @param src the source buffer to copy from - * @param dst the destination buffer to copy to - * @param size size (in bytes) of the buffers - * @param elemSize size (in bytes) of the individual elements - * - * @throws RuntimeException if an error is found - */ - public void testBufferPair(GenericPointer src, GenericPointer dst, long size, long elemSize) { - // offset in source from which to start reading data - for (long srcOffset = 0; srcOffset < size; srcOffset += (src.isOnHeap() ? elemSize : 1)) { - - // offset in destination at which to start writing data - for (int dstOffset = 0; dstOffset < size; dstOffset += (dst.isOnHeap() ? elemSize : 1)) { - - // number of bytes to copy - long maxCopyBytes = Math.min(size - srcOffset, size - dstOffset); - for (long copyBytes = 0; copyBytes < maxCopyBytes; copyBytes += elemSize) { - try { - testCopySwap(src, srcOffset, dst, dstOffset, size, copyBytes, elemSize); - } catch (RuntimeException e) { - // Wrap the exception in another exception to catch the relevant configuration data - throw new RuntimeException("testBufferPair: " + - "src=" + src + - " dst=" + dst + - " elemSize=0x" + Long.toHexString(elemSize) + - " copyBytes=0x" + Long.toHexString(copyBytes) + - " srcOffset=0x" + Long.toHexString(srcOffset) + - " dstOffset=0x" + Long.toHexString(dstOffset), - e); - } - } - } - } - } - - /** - * Test copying between various permutations of buffers - * - * @param buffers buffers to permute (src x dst) - * @param size size (in bytes) of buffers - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - public void testPermuteBuffers(GenericPointer[] buffers, long size, long elemSize) { - for (int srcIndex = 0; srcIndex < buffers.length; srcIndex++) { - for (int dstIndex = 0; dstIndex < buffers.length; dstIndex++) { - testBufferPair(buffers[srcIndex], buffers[dstIndex], size, elemSize); - } - } - } - - /** - * Test copying of a specific element size - * - * @param size size (in bytes) of buffers to allocate - * @param elemSize size (in bytes) of individual elements - * - * @throws RuntimeException if an error is found - */ - private void testElemSize(long size, long elemSize) { - long buf1Raw = 0; - long buf2Raw = 0; - - try { - buf1Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf1 = alignUp(buf1Raw, BASE_ALIGNMENT); - - buf2Raw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - long buf2 = alignUp(buf2Raw, BASE_ALIGNMENT); - - GenericPointer[] buffers = { - new GenericPointer(buf1), - new GenericPointer(buf2), - new GenericPointer(allocArray(size, elemSize)), - new GenericPointer(allocArray(size, elemSize)) - }; - - testPermuteBuffers(buffers, size, elemSize); - } finally { - if (buf1Raw != 0) { - UNSAFE.freeMemory(buf1Raw); - } - if (buf2Raw != 0) { - UNSAFE.freeMemory(buf2Raw); - } - } - } - - /** - * Verify that small copy swaps work - */ - private void testSmallCopy() { - int smallBufSize = SMALL_COPY_SIZE; - - // Test various element types and heap/native combinations - for (long elemSize = 2; elemSize <= 8; elemSize <<= 1) { - testElemSize(smallBufSize, elemSize); - } - } - - - /** - * Verify that large copy swaps work - */ - private void testLargeCopy() { - long size = 2 * GB + 8; - long bufRaw = 0; - - // Check that a large native copy succeeds - try { - try { - bufRaw = UNSAFE.allocateMemory(size + BASE_ALIGNMENT); - } catch (OutOfMemoryError e) { - // Accept failure, skip test - return; - } - - long buf = alignUp(bufRaw, BASE_ALIGNMENT); - - UNSAFE.copySwapMemory(null, buf, null, buf, size, 8); - } catch (Exception e) { - throw new RuntimeException("copySwapMemory of large buffer failed"); - } finally { - if (bufRaw != 0) { - UNSAFE.freeMemory(bufRaw); - } - } - } - /** * Run positive tests * * @throws RuntimeException if an error is found */ private void testPositive() { - testSmallCopy(); - testLargeCopy(); + testSmallCopy(true); + testLargeCopy(true); } /** @@ -542,7 +53,7 @@ public class CopySwap { try { bufRaw = UNSAFE.allocateMemory(1024); - long buf = alignUp(bufRaw, BASE_ALIGNMENT); + long buf = CopyCommon.alignUp(bufRaw, CopyCommon.BASE_ALIGNMENT); short[] arr = new short[16]; // Check various illegal element sizes @@ -637,59 +148,4 @@ public class CopySwap { CopySwap cs = new CopySwap(); cs.test(); } - - /** - * Helper class to represent a "pointer" - either a heap array or - * a pointer to a native buffer. - * - * In the case of a native pointer, the Object is null and the offset is - * the absolute address of the native buffer. - * - * In the case of a heap object, the Object is a primitive array, and - * the offset will be set to the base offset to the first element, meaning - * the object and the offset together form a double-register pointer. - */ - static class GenericPointer { - private final Object o; - private final long offset; - - private GenericPointer(Object o, long offset) { - this.o = o; - this.offset = offset; - } - - public String toString() { - return "GenericPointer(o={" + o + "}, offset=0x" + Long.toHexString(offset) + ")"; - } - - public boolean equals(Object other) { - if (!(other instanceof GenericPointer)) { - return false; - } - - GenericPointer otherp = (GenericPointer)other; - - return o == otherp.o && offset == otherp.offset; - } - - GenericPointer(Object o) { - this(o, UNSAFE.arrayBaseOffset(o.getClass())); - } - - GenericPointer(long offset) { - this(null, offset); - } - - public boolean isOnHeap() { - return o != null; - } - - public Object getObject() { - return o; - } - - public long getOffset() { - return offset; - } - } } diff --git a/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java b/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java index 994cee3f896..a4296eccbf0 100644 --- a/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java +++ b/jdk/test/jdk/internal/ref/Cleaner/ExitOnThrow.java @@ -25,6 +25,7 @@ * @test * @bug 4954921 8009259 * @library /test/lib/share/classes + * @modules java.base/jdk.internal.ref * @build jdk.test.lib.* * @build jdk.test.lib.process.* * @run main ExitOnThrow diff --git a/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java new file mode 100644 index 00000000000..6594a5ca449 --- /dev/null +++ b/jdk/test/jdk/modules/etc/VerifyModuleDelegation.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @summary Verify the defining class loader of each module never delegates + * to its child class loader. Also sanity check java.compact2 + * requires. + * @run testng VerifyModuleDelegation + */ + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.lang.reflect.Layer; +import java.util.Set; + +import static java.lang.module.ModuleDescriptor.Requires.Modifier.*; + +import org.testng.annotations.*; + +import static org.testng.Assert.*; + +public class VerifyModuleDelegation { + private static final String JAVA_BASE = "java.base"; + private static final String JAVA_COMPACT1 = "java.compact1"; + private static final String JAVA_COMPACT2 = "java.compact2"; + + private static final ModuleDescriptor BASE + = new ModuleDescriptor.Builder(JAVA_BASE).build(); + + private static final ModuleDescriptor COMPACT2 + = new ModuleDescriptor.Builder(JAVA_COMPACT2) + .requires(MANDATED, JAVA_BASE) + .requires(PUBLIC, JAVA_COMPACT1) + .requires(PUBLIC, "java.rmi") + .requires(PUBLIC, "java.sql") + .requires(PUBLIC, "java.xml") + .build(); + + private static final Set MREFS + = ModuleFinder.ofSystem().findAll(); + + private void check(ModuleDescriptor md, ModuleDescriptor ref) { + assertTrue(md.requires().size() == ref.requires().size()); + assertTrue(md.requires().containsAll(ref.requires())); + } + + @Test + public void checkJavaBase() { + ModuleDescriptor md = + MREFS.stream().map(ModuleReference::descriptor) + .filter(d -> d.name().equals(JAVA_BASE)) + .findFirst().orElseThrow(Error::new); + + check(md, BASE); + } + @Test + public void checkCompact2() { + ModuleDescriptor md = + MREFS.stream().map(ModuleReference::descriptor) + .filter(d -> d.name().equals(JAVA_COMPACT2)) + .findFirst().orElseThrow(Error::new); + check(md, COMPACT2); + } + + @Test + public void checkLoaderDelegation() { + Layer boot = Layer.boot(); + MREFS.stream().map(ModuleReference::descriptor) + .forEach(md -> md.requires().stream().forEach(req -> + { + // check if M requires D and D's loader must be either the + // same or an ancestor of M's loader + ClassLoader loader1 = boot.findLoader(md.name()); + ClassLoader loader2 = boot.findLoader(req.name()); + if (loader1 != loader2 && !isAncestor(loader2, loader1)) { + throw new Error(md.name() + " can't delegate to " + + "find classes from " + req.name()); + } + })); + } + + // Returns true if p is an ancestor of cl i.e. class loader 'p' can + // be found in the cl's delegation chain + private static boolean isAncestor(ClassLoader p, ClassLoader cl) { + if (p != null && cl == null) { + return false; + } + ClassLoader acl = cl; + do { + acl = acl.getParent(); + if (p == acl) { + return true; + } + } while (acl != null); + return false; + } +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/RunWithAutomaticModules.java b/jdk/test/jdk/modules/scenarios/automaticmodules/RunWithAutomaticModules.java new file mode 100644 index 00000000000..4d1ebcf322d --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/RunWithAutomaticModules.java @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build RunWithAutomaticModules CompilerUtils JarUtils + * jdk.testlibrary.ProcessTools + * @run testng RunWithAutomaticModules + * @summary Runs tests that make use of automatic modules + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class RunWithAutomaticModules { + + 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 CLASSES_DIR = Paths.get("classes"); + private static final Path MODS_DIR = Paths.get("mods"); + + /** + * Basic test that consists of 3 modules: + * + * basictest - the test itself + * httpserver - a JAR file (automatic module) with a dummy HTTP server + * logging - a JAR file (automatic module) with a dummy logging library + * + * The test runs the dummy HTTP server and checks that has the expected + * reads and exported packages. + * + * The HTTP server uses the logging library. + */ + + public void testBasic() throws Exception { + boolean compiled; + + Path loggingSrc = SRC_DIR.resolve("logging"); + Path loggingClasses = CLASSES_DIR.resolve("logging"); + + Path httpServerSrc = SRC_DIR.resolve("httpserver"); + Path httpServerClasses = CLASSES_DIR.resolve("httpserver"); + + String testModule = "basictest"; + String mainClass = "test.Main"; + + + // compile + create mods/logging-1.0.jar + + compiled = CompilerUtils.compile(loggingSrc, loggingClasses); + assertTrue(compiled); + + JarUtils.createJarFile(MODS_DIR.resolve("logging-1.0.jar"), + loggingClasses); + + + // compile + create mods/httpserver-9.0.0.jar + + compiled = CompilerUtils.compile(httpServerSrc, + httpServerClasses, + "-cp", loggingClasses.toString()); + assertTrue(compiled); + + JarUtils.createJarFile(MODS_DIR.resolve("httpserver-9.0.0.jar"), + httpServerClasses); + + + // compile basictest to mods/basictest + + compiled = CompilerUtils + .compile(SRC_DIR.resolve(testModule), + MODS_DIR.resolve(testModule), + "-mp", MODS_DIR.toString()); + assertTrue(compiled); + + + // launch the test. Need -addmods because nothing explicitly depends on logging + + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "logging", + "-m", testModule + "/" + mainClass) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + + /** + * Test using a JAR file with a service provider as an automatic module. + * + * The consists of 2 modules: + * + * sptest - the test itself + * bananascript - a JAR file (automatic module) with a dummy ScriptEngineFactory + * + * The test uses ServiceLoader to locate and load ScriptEngineFactory + * implementations. It checks that bananascript is located. + */ + + public void testServiceProvider() throws Exception { + boolean compiled; + + Path providerSrc = SRC_DIR.resolve("bananascript"); + Path providerClasses = CLASSES_DIR.resolve("bananascript"); + + String testModule = "sptest"; + String mainClass = "test.Main"; + + + // create mods/bananascript-0.9.jar + + compiled = CompilerUtils.compile(providerSrc, providerClasses); + assertTrue(compiled); + + String config = "META-INF/services/javax.script.ScriptEngineFactory"; + Path services = providerClasses.resolve(config).getParent(); + Files.createDirectories(services); + Files.copy(providerSrc.resolve(config), providerClasses.resolve(config)); + + JarUtils.createJarFile(MODS_DIR.resolve("bananascript-0.9.jar"), providerClasses); + + + // compile sptest to mods/sptest + + compiled = CompilerUtils + .compile(SRC_DIR.resolve(testModule), + MODS_DIR.resolve(testModule), + "-mp", MODS_DIR.toString()); + + assertTrue(compiled); + + + // launch the test + + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-m", testModule + "/" + mainClass) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/META-INF/services/javax.script.ScriptEngineFactory b/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 00000000000..02241bb2843 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1,2 @@ +# Our test script engine factory +org.banana.BananaScriptEngineFactory diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScript.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScript.java new file mode 100644 index 00000000000..ddaf1e1043e --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScript.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package org.banana; + +import java.io.Reader; +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class BananaScript implements ScriptEngine { + + @Override + public Object eval(String script, ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader) { + throw new RuntimeException(); + } + + @Override + public Object eval(String script, Bindings n) { + throw new RuntimeException(); + } + + @Override + public Object eval(Reader reader , Bindings n) { + throw new RuntimeException(); + } + @Override + public void put(String key, Object value) { + throw new RuntimeException(); + } + + @Override + public Object get(String key) { + throw new RuntimeException(); + } + + @Override + public Bindings getBindings(int scope) { + throw new RuntimeException(); + } + + @Override + public void setBindings(Bindings bindings, int scope) { + throw new RuntimeException(); + } + + @Override + public Bindings createBindings() { + throw new RuntimeException(); + } + + @Override + public ScriptContext getContext() { + throw new RuntimeException(); + } + + @Override + public void setContext(ScriptContext context) { + throw new RuntimeException(); + } + + @Override + public ScriptEngineFactory getFactory() { + throw new RuntimeException(); + } +} + diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScriptEngineFactory.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScriptEngineFactory.java new file mode 100644 index 00000000000..443415c1706 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/bananascript/org/banana/BananaScriptEngineFactory.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package org.banana; + +import java.util.Arrays; +import java.util.List; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +public class BananaScriptEngineFactory implements ScriptEngineFactory { + + @Override + public String getEngineName() { + return "BananaScriptEngine"; + } + + @Override + public String getEngineVersion() { + return "1.0"; + } + + @Override + public List getExtensions() { + return Arrays.asList("banana"); + } + + @Override + public List getMimeTypes() { + return Arrays.asList("application/x-bananascript"); + } + + @Override + public List getNames() { + return Arrays.asList("BananaScript"); + } + + @Override + public String getLanguageName() { + return "BananaScript"; + } + + @Override + public String getLanguageVersion() { + return "1.0"; + } + + @Override + public Object getParameter(String key) { + return null; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) { + throw new RuntimeException(); + } + + @Override + public String getOutputStatement(String toDisplay) { + throw new RuntimeException(); + } + + @Override + public String getProgram(String... statements) { + throw new RuntimeException(); + } + + @Override + public ScriptEngine getScriptEngine() { + return new BananaScript(); + } +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/basictest/module-info.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/basictest/module-info.java new file mode 100644 index 00000000000..0bc9bd62560 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/basictest/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module basictest { + requires httpserver; // automatic module +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java new file mode 100644 index 00000000000..01d8283a4b3 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/basictest/test/Main.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package test; + +import java.lang.reflect.Layer; +import java.lang.reflect.Module; + +import http.HttpServer; + +/** + * Basic test using automatic modules. + */ + +public class Main { + public static void main(String[] args) throws Exception { + + Module httpModule = HttpServer.class.getModule(); + + // automatic modules are named + assertTrue(httpModule.isNamed()); + + // and read all unnamed modules + ClassLoader cl; + cl = ClassLoader.getPlatformClassLoader(); + assertTrue(httpModule.canRead(cl.getUnnamedModule())); + cl = ClassLoader.getSystemClassLoader(); + assertTrue(httpModule.canRead(cl.getUnnamedModule())); + + // and read all modules in the boot Layer + Layer layer = Layer.boot(); + layer.modules().forEach(m -> assertTrue(httpModule.canRead(m))); + + // run code in the automatic modue, ensures access is allowed + HttpServer http = HttpServer.create(80); + http.start(); + } + + static void assertTrue(boolean e) { + if (!e) + throw new RuntimeException(); + } +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/HttpServer.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/HttpServer.java new file mode 100644 index 00000000000..eadb55d561e --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/HttpServer.java @@ -0,0 +1,60 @@ +/* + * 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 http; + +import java.util.Iterator; +import java.util.ServiceLoader; + +import http.spi.HttpServerProvider; +import logging.Logger; + +/** + * A do-nothing HTTP server + */ + +public class HttpServer { + private final int port; + private final Logger logger; + + protected HttpServer(int port) { + this.port = port; + this.logger = new Logger(); + } + + public static HttpServer create(int port) { + ServiceLoader sl + = ServiceLoader.load(HttpServerProvider.class); + Iterator iterator = sl.iterator(); + if (iterator.hasNext()) { + HttpServerProvider provider = iterator.next(); + return provider.createHttpServer(port); + } else { + return new HttpServer(port) { }; + } + } + + public void start() { + logger.log("Start HTTP server on port " + port); + } +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/spi/HttpServerProvider.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/spi/HttpServerProvider.java new file mode 100644 index 00000000000..b2966ae531c --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/httpserver/http/spi/HttpServerProvider.java @@ -0,0 +1,33 @@ +/* + * 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 http.spi; + +import http.HttpServer; + +public abstract class HttpServerProvider { + + protected HttpServerProvider() { } + + public abstract HttpServer createHttpServer(int port); +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/logging/logging/Logger.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/logging/logging/Logger.java new file mode 100644 index 00000000000..d0673c3bb57 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/logging/logging/Logger.java @@ -0,0 +1,36 @@ +/* + * 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 logging; + +/** + * A simple logger. + */ + +public class Logger { + public Logger() { } + + public void log(String msg) { + System.out.println(msg); + } +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/module-info.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/module-info.java new file mode 100644 index 00000000000..ce3c72d3739 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module sptest { + requires java.scripting; + uses javax.script.ScriptEngineFactory; +} diff --git a/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java new file mode 100644 index 00000000000..05ff04d6700 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/automaticmodules/src/sptest/test/Main.java @@ -0,0 +1,83 @@ +/* + * 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 test; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires; +import java.lang.module.ModuleDescriptor.Provides; +import java.lang.reflect.Layer; +import java.lang.reflect.Module; +import java.util.Map; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; +import java.util.stream.Collectors; +import javax.script.ScriptEngineFactory; + +/** + * Test that the automatic module "bananascript" is in the boot Layer and + * it behaves as a service provider. + */ + +public class Main { + + public static void main(String[] args) throws Exception { + + Optional om = Layer.boot().findModule("bananascript"); + assertTrue(om.isPresent()); + + ModuleDescriptor descriptor = om.get().getDescriptor(); + + // requires java.base + Set requires + = descriptor.requires().stream() + .map(Requires::name) + .collect(Collectors.toSet()); + assertTrue(requires.size() == 1); + assertTrue(requires.contains("java.base")); + + // uses ScriptEngineFactory + Map provides = descriptor.provides(); + assertTrue(provides.size() == 1); + String sn = ScriptEngineFactory.class.getName(); + assertTrue(provides.containsKey(sn)); + + // Check that it is iterated over with ServiceLoader + ServiceLoader sl + = ServiceLoader.load(ScriptEngineFactory.class); + boolean found = false; + for (ScriptEngineFactory factory : sl) { + String name = factory.getEngineName(); + System.out.println(name); + if (name.equals("BananaScriptEngine")) + found = true; + } + assertTrue(found); + } + + static void assertTrue(boolean e) { + if (!e) + throw new RuntimeException(); + } +} diff --git a/jdk/test/jdk/modules/scenarios/container/ContainerTest.java b/jdk/test/jdk/modules/scenarios/container/ContainerTest.java new file mode 100644 index 00000000000..36a7ac2c219 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/ContainerTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.jartool/sun.tools.jar + * jdk.compiler + * @build ContainerTest CompilerUtils jdk.testlibrary.* + * @run testng ContainerTest + * @summary Starts a simple container that uses dynamic configurations + * and launches two applications in the same VM + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class ContainerTest { + + 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"); + + private static final Path MLIB_DIR = Paths.get("mlib"); + private static final Path APPLIB_DIR = Paths.get("applib"); + + private static final String CONTAINER_MODULE = "container"; + private static final String CONTAINER_MAIN_CLASS = "container.Main"; + + + /** + * Creates the container module in mlib/container@1.0.jmod + */ + void buildContainer() throws Exception { + + Path src = SRC_DIR.resolve(CONTAINER_MODULE); + Path output = MODS_DIR.resolve(CONTAINER_MODULE); + + boolean compiled = CompilerUtils.compile(src, output); + assertTrue(compiled); + + // jar --create ... + Path mlib = Files.createDirectories(MLIB_DIR); + String classes = output.toString(); + String jar = mlib.resolve(CONTAINER_MODULE + "@1.0.jar").toString(); + String[] args = { + "--create", + "--file=" + jar, + "--main-class=" + CONTAINER_MAIN_CLASS, + "-C", classes, "." + }; + boolean success + = new sun.tools.jar.Main(System.out, System.out, "jar") + .run(args); + assertTrue(success); + } + + /** + * Creates app1 and its bundled libraries in applib. + */ + void buildApp1() throws Exception { + Path dir = Files.createDirectories(APPLIB_DIR); + + // app1 uses its own copy of JAX-WS + boolean compiled + = CompilerUtils.compile(SRC_DIR.resolve("java.xml.ws"), + dir.resolve("java.xml.ws")); + assertTrue(compiled); + + compiled = CompilerUtils.compile(SRC_DIR.resolve("app1"), + dir.resolve("app1"), + "-upgrademodulepath", dir.toString()); + assertTrue(compiled); + } + + /** + * Creates app2 and its bundled libraries in applib. + */ + void buildApp2() throws Exception { + Path dir = Files.createDirectories(APPLIB_DIR); + + // app2 uses JAX-RS + boolean compiled + = CompilerUtils.compile(SRC_DIR.resolve("java.ws.rs"), + dir.resolve("java.ws.rs")); + assertTrue(compiled); + + compiled = CompilerUtils.compile(SRC_DIR.resolve("app2"), + dir.resolve("app2"), + "-mp", dir.toString()); + assertTrue(compiled); + } + + + @BeforeTest + public void setup() throws Exception { + buildContainer(); + buildApp1(); + buildApp2(); + } + + /** + * Launches the container + */ + public void testContainer() throws Exception { + + int exitValue + = executeTestJava("-mp", MLIB_DIR.toString(), + "-m", CONTAINER_MODULE) + .outputTo(System.out) + .errorTo(System.err) + .getExitValue(); + + assertTrue(exitValue == 0); + } + +} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg3/Interface1Pkg3.java b/jdk/test/jdk/modules/scenarios/container/src/app1/app1/Main.java similarity index 70% rename from langtools/test/com/sun/javadoc/testProfiles/pkg3/Interface1Pkg3.java rename to jdk/test/jdk/modules/scenarios/container/src/app1/app1/Main.java index 09db1afb478..fb47af124db 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg3/Interface1Pkg3.java +++ b/jdk/test/jdk/modules/scenarios/container/src/app1/app1/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,28 +21,20 @@ * questions. */ -package pkg3; +package app1; -/** - * A sample interface. - * - * @author Bhavesh Patel - */ -public interface Interface1Pkg3 { +import javax.xml.ws.WebService; - /** - * A test method. - * - * @param a blah. - * @param b blah. - */ - void method1(int a, int b); +public class Main { - /** - * Another test method. - * - * @param c blah. - */ - void method2(int c); + static void trace(Class c) { + System.out.format("%s loaded by %s\n", c, c.getClassLoader()); + } + public static void main(String[] args) throws Exception { + trace(Main.class); + + WebService ws = new WebService(); + trace(ws.getClass()); + } } diff --git a/jdk/test/jdk/modules/scenarios/container/src/app1/module-info.java b/jdk/test/jdk/modules/scenarios/container/src/app1/module-info.java new file mode 100644 index 00000000000..c11441fffc7 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/app1/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +module app1 { + requires java.base; + requires java.xml.ws; + exports app1; +} diff --git a/langtools/test/com/sun/javadoc/testProfiles/pkg1/Interface1Pkg1.java b/jdk/test/jdk/modules/scenarios/container/src/app2/app2/Main.java similarity index 71% rename from langtools/test/com/sun/javadoc/testProfiles/pkg1/Interface1Pkg1.java rename to jdk/test/jdk/modules/scenarios/container/src/app2/app2/Main.java index e2a4337ee08..519e6644134 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/pkg1/Interface1Pkg1.java +++ b/jdk/test/jdk/modules/scenarios/container/src/app2/app2/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,28 +21,20 @@ * questions. */ -package pkg1; +package app2; -/** - * A sample interface. - * - * @author Bhavesh Patel - */ -public interface Interface1Pkg1 { +import javax.ws.rs.Client; - /** - * A test method. - * - * @param a blah. - * @param b blah. - */ - void method1(int a, int b); +public class Main { - /** - * Another test method. - * - * @param c blah. - */ - void method2(int c); + static void trace(Class c) { + System.out.format("%s loaded by %s\n", c, c.getClassLoader()); + } + public static void main(String[] args) throws Exception { + trace(Main.class); + + Client c = new Client(); + trace(c.getClass()); + } } diff --git a/jdk/test/jdk/modules/scenarios/container/src/app2/module-info.java b/jdk/test/jdk/modules/scenarios/container/src/app2/module-info.java new file mode 100644 index 00000000000..8a766fe97b3 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/app2/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +module app2 { + requires java.base; + requires java.ws.rs; + exports app2; +} 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 new file mode 100644 index 00000000000..4c86c6e549c --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/container/container/Main.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package container; + +import java.io.File; +import java.lang.module.Configuration; +import java.lang.module.ModuleFinder; +import java.lang.module.ResolvedModule; +import java.lang.reflect.Layer; +import java.lang.reflect.Method; +import java.lang.reflect.Module; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Set; + +/** + * Exercises dynamic configuration. + */ + +public class Main { + + public static void main(String[] args) throws Exception { + + System.out.println("Boot layer"); + Layer.boot() + .modules() + .stream() + .map(Module::getName) + .sorted() + .forEach(System.out::println); + + // "start" two applications in their own layers + start("applib", "app1", "app1.Main"); + start("applib", "app2", "app2.Main"); + } + + static void start(String appModulePath, + String appModuleName, + String appMainClass) throws Exception { + + System.out.format("Starting %s/%s ...%n", appModuleName, appMainClass); + + String[] dirs = appModulePath.split(File.pathSeparator); + Path[] paths = new Path[dirs.length]; + int i = 0; + for (String dir: dirs) { + paths[i++] = Paths.get(dir); + } + + ModuleFinder finder = ModuleFinder.of(paths); + + Configuration cf = Layer.boot().configuration() + .resolveRequiresAndUses(finder, + ModuleFinder.empty(), + Set.of(appModuleName)); + + System.out.println("Resolved"); + cf.modules().stream() + .map(ResolvedModule::name) + .sorted() + .forEach(mn -> System.out.format(" %s%n", mn)); + + // reify the configuration as a Layer + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl); + + // invoke application main method + ClassLoader loader = layer.findLoader(appModuleName); + Class c = loader.loadClass(appMainClass); + Main.class.getModule().addReads(c.getModule()); + Method mainMethod = c.getMethod("main", String[].class); + + // set TCCL as that is the EE thing to do + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(loader); + mainMethod.invoke(null, (Object)new String[0]); + } finally { + Thread.currentThread().setContextClassLoader(tccl); + } + + System.out.println(); + } +} diff --git a/jdk/test/jdk/modules/scenarios/container/src/container/module-info.java b/jdk/test/jdk/modules/scenarios/container/src/container/module-info.java new file mode 100644 index 00000000000..ea0cf50c04b --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/container/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ +module container { + requires java.se; +} diff --git a/jdk/test/jdk/modules/scenarios/container/src/java.ws.rs/javax/ws/rs/Client.java b/jdk/test/jdk/modules/scenarios/container/src/java.ws.rs/javax/ws/rs/Client.java new file mode 100644 index 00000000000..12fdcd1029b --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/java.ws.rs/javax/ws/rs/Client.java @@ -0,0 +1,28 @@ +/* + * 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. + */ +package javax.ws.rs; + +public class Client { + public Client() { } +} + diff --git a/jdk/test/jdk/modules/scenarios/container/src/java.ws.rs/module-info.java b/jdk/test/jdk/modules/scenarios/container/src/java.ws.rs/module-info.java new file mode 100644 index 00000000000..96177847678 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/java.ws.rs/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +module java.ws.rs { + requires java.base; + + exports javax.ws.rs; +} diff --git a/jdk/test/jdk/modules/scenarios/container/src/java.xml.ws/javax/xml/ws/WebService.java b/jdk/test/jdk/modules/scenarios/container/src/java.xml.ws/javax/xml/ws/WebService.java new file mode 100644 index 00000000000..82149bc4bdf --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/java.xml.ws/javax/xml/ws/WebService.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +package javax.xml.ws; + +public class WebService { + public WebService() { } +} diff --git a/jdk/test/jdk/modules/scenarios/container/src/java.xml.ws/module-info.java b/jdk/test/jdk/modules/scenarios/container/src/java.xml.ws/module-info.java new file mode 100644 index 00000000000..775df769da5 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/container/src/java.xml.ws/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ +module java.xml.ws { + requires java.base; + + exports javax.xml.ws; +} diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/OverlappingPackagesTest.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/OverlappingPackagesTest.java new file mode 100644 index 00000000000..826e282326a --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/OverlappingPackagesTest.java @@ -0,0 +1,125 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build OverlappingPackagesTest CompilerUtils jdk.testlibrary.* + * @run testng OverlappingPackagesTest + * @summary Basic test to ensure that startup fails if two or more modules + * in the boot Layer have the same package + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +@Test +public class OverlappingPackagesTest { + + 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", "test"); + + + /** + * Compiles all modules used by the test + */ + @BeforeTest + public void compileAll() throws Exception { + for (String mn : modules) { + Path src = SRC_DIR.resolve(mn); + Path mods = MODS_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(src, mods)); + } + Path srcMisc = SRC_DIR.resolve("misc"); + Path modsMisc = MODS_DIR.resolve("misc"); + assertTrue(CompilerUtils.compile(srcMisc.resolve("sun") + .resolve("misc") + .resolve("Unsafe.java"), + modsMisc, + "-Xmodule:java.base")); + assertTrue(CompilerUtils.compile(srcMisc.resolve("module-info.java"), + modsMisc)); + } + + /** + * Sanity check that the test runs without error. + */ + public void testNoOverlappingPackages() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-m", "test/test.Main") + .outputTo(System.out) + .errorTo(System.err) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Run the test with "-addmods misc", the misc module has package + * sun.misc and so should overlap with the base module. + */ + public void testOverlapWithBaseModule() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "misc", + "-m", "test/test.Main") + .outputTo(System.out) + .errorTo(System.err) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + /** + * Run the test with "-addmods m1,m2". Both modules have package p. + */ + public void testOverlap() throws Exception { + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "m1,m2", + "-m", "test/test.Main") + .outputTo(System.out) + .errorTo(System.err) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + +} diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m1/module-info.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m1/module-info.java new file mode 100644 index 00000000000..967d5535675 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m1/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m1 { +} diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m1/p/C1.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m1/p/C1.java new file mode 100644 index 00000000000..a68906e99d2 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m1/p/C1.java @@ -0,0 +1,26 @@ +/* + * 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 p; + +public class C1 { } diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m2/module-info.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m2/module-info.java new file mode 100644 index 00000000000..b0fadc62198 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m2/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m2 { +} diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m2/p/C2.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m2/p/C2.java new file mode 100644 index 00000000000..141d012d07d --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/m2/p/C2.java @@ -0,0 +1,26 @@ +/* + * 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 p; + +public class C2 { } diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/misc/module-info.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/misc/module-info.java new file mode 100644 index 00000000000..65cc15d749b --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/misc/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module misc { + exports sun.misc; +} + diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/misc/sun/misc/Unsafe.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/misc/sun/misc/Unsafe.java new file mode 100644 index 00000000000..135652ea9b7 --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/misc/sun/misc/Unsafe.java @@ -0,0 +1,32 @@ +/* + * 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 sun.misc; + +public class Unsafe { + private Unsafe() { } + + public static long getLong(long address) { + return 0L; + } +} diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/test/module-info.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/test/module-info.java new file mode 100644 index 00000000000..62b1d4d786a --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/test/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module test { +} + diff --git a/jdk/test/jdk/modules/scenarios/overlappingpackages/src/test/test/Main.java b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/test/test/Main.java new file mode 100644 index 00000000000..cdf8907806a --- /dev/null +++ b/jdk/test/jdk/modules/scenarios/overlappingpackages/src/test/test/Main.java @@ -0,0 +1,28 @@ +/* + * 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 test; + +public class Main { + public static void main(String[] args) { } +} diff --git a/jdk/test/lib/testlibrary/CompilerUtils.java b/jdk/test/lib/testlibrary/CompilerUtils.java new file mode 100644 index 00000000000..91ca9181340 --- /dev/null +++ b/jdk/test/lib/testlibrary/CompilerUtils.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +import javax.tools.JavaCompiler; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * This class consists exclusively of static utility methods for invoking the + * java compiler. + */ + +public final class CompilerUtils { + private CompilerUtils() { } + + /** + * Compile all the java sources in {@code /**} to + * {@code /**}. The destination directory will be created if + * it doesn't exist. + * + * All warnings/errors emitted by the compiler are output to System.out/err. + * + * @return true if the compilation is successful + * + * @throws IOException if there is an I/O error scanning the source tree or + * creating the destination directory + */ + public static boolean compile(Path source, Path destination, String ... options) + throws IOException + { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null); + + List sources + = Files.find(source, Integer.MAX_VALUE, + (file, attrs) -> (file.toString().endsWith(".java"))) + .collect(Collectors.toList()); + + Files.createDirectories(destination); + jfm.setLocation(StandardLocation.CLASS_PATH, Collections.EMPTY_LIST); + jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, + Arrays.asList(destination)); + + List opts = Arrays.asList(options); + JavaCompiler.CompilationTask task + = compiler.getTask(null, jfm, null, opts, null, + jfm.getJavaFileObjectsFromPaths(sources)); + + return task.call(); + } +} diff --git a/jdk/test/lib/testlibrary/JarUtils.java b/jdk/test/lib/testlibrary/JarUtils.java new file mode 100644 index 00000000000..94905ccffed --- /dev/null +++ b/jdk/test/lib/testlibrary/JarUtils.java @@ -0,0 +1,179 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.IOException; +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.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * This class consists exclusively of static utility methods that are useful + * for creating and manipulating JAR files. + */ + +public final class JarUtils { + private JarUtils() { } + + /** + * Creates a JAR file. + * + * Equivalent to {@code jar cf -C file...} + * + * The input files are resolved against the given directory. Any input + * files that are directories are processed recursively. + */ + public static void createJarFile(Path jarfile, Path dir, Path... file) + throws IOException + { + // create the target directory + Path parent = jarfile.getParent(); + if (parent != null) + Files.createDirectories(parent); + + List entries = new ArrayList<>(); + for (Path entry : file) { + Files.find(dir.resolve(entry), Integer.MAX_VALUE, + (p, attrs) -> attrs.isRegularFile()) + .map(e -> dir.relativize(e)) + .forEach(entries::add); + } + + try (OutputStream out = Files.newOutputStream(jarfile); + JarOutputStream jos = new JarOutputStream(out)) + { + for (Path entry : entries) { + String name = toJarEntryName(entry); + jos.putNextEntry(new JarEntry(name)); + Files.copy(dir.resolve(entry), jos); + } + } + } + + /** + * Creates a JAR file. + * + * Equivalent to {@code jar cf -C file...} + * + * The input files are resolved against the given directory. Any input + * files that are directories are processed recursively. + */ + public static void createJarFile(Path jarfile, Path dir, String... input) + throws IOException + { + Path[] paths = Stream.of(input).map(Paths::get).toArray(Path[]::new); + createJarFile(jarfile, dir, paths); + } + + /** + * Creates a JAR file from the contents of a directory. + * + * Equivalent to {@code jar cf -C .} + */ + public static void createJarFile(Path jarfile, Path dir) throws IOException { + createJarFile(jarfile, dir, Paths.get(".")); + } + + /** + * Update a JAR file. + * + * Equivalent to {@code jar uf -C file...} + * + * The input files are resolved against the given directory. Any input + * files that are directories are processed recursively. + */ + public static void updateJarFile(Path jarfile, Path dir, Path... file) + throws IOException + { + List entries = new ArrayList<>(); + for (Path entry : file) { + Files.find(dir.resolve(entry), Integer.MAX_VALUE, + (p, attrs) -> attrs.isRegularFile()) + .map(e -> dir.relativize(e)) + .forEach(entries::add); + } + + Set names = entries.stream() + .map(JarUtils::toJarEntryName) + .collect(Collectors.toSet()); + + Path tmpfile = Files.createTempFile("jar", "jar"); + + try (OutputStream out = Files.newOutputStream(tmpfile); + JarOutputStream jos = new JarOutputStream(out)) + { + // copy existing entries from the original JAR file + try (JarFile jf = new JarFile(jarfile.toString())) { + Enumeration jentries = jf.entries(); + while (jentries.hasMoreElements()) { + JarEntry jentry = jentries.nextElement(); + if (!names.contains(jentry.getName())) { + jos.putNextEntry(jentry); + jf.getInputStream(jentry).transferTo(jos); + } + } + } + + // add the new entries + for (Path entry : entries) { + String name = toJarEntryName(entry); + jos.putNextEntry(new JarEntry(name)); + Files.copy(dir.resolve(entry), jos); + } + } + + // replace the original JAR file + Files.move(tmpfile, jarfile, StandardCopyOption.REPLACE_EXISTING); + } + + /** + * Update a JAR file. + * + * Equivalent to {@code jar uf -C .} + */ + public static void updateJarFile(Path jarfile, Path dir) throws IOException { + updateJarFile(jarfile, dir, Paths.get(".")); + } + + + /** + * Map a file path to the equivalent name in a JAR file + */ + private static String toJarEntryName(Path file) { + Path normalized = file.normalize(); + return normalized.subpath(0, normalized.getNameCount()) // drop root + .toString() + .replace(File.separatorChar, '/'); + } +} diff --git a/jdk/test/lib/testlibrary/ModuleUtils.java b/jdk/test/lib/testlibrary/ModuleUtils.java new file mode 100644 index 00000000000..c227464da1a --- /dev/null +++ b/jdk/test/lib/testlibrary/ModuleUtils.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReader; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Supplier; + + +/** + * This class consists exclusively of static utility methods that are useful + * for creating tests for modules. + */ + +public final class ModuleUtils { + private ModuleUtils() { } + + + /** + * Returns a ModuleFinder that finds modules with the given module + * descriptors. + */ + static ModuleFinder finderOf(ModuleDescriptor... descriptors) { + + // Create a ModuleReference for each module + Map namesToReference = new HashMap<>(); + + for (ModuleDescriptor descriptor : descriptors) { + String name = descriptor.name(); + + URI uri = URI.create("module:/" + name); + + Supplier supplier = () -> { + throw new UnsupportedOperationException(); + }; + + ModuleReference mref = new ModuleReference(descriptor, uri, supplier); + + namesToReference.put(name, mref); + } + + return new ModuleFinder() { + @Override + public Optional find(String name) { + Objects.requireNonNull(name); + return Optional.ofNullable(namesToReference.get(name)); + } + @Override + public Set findAll() { + return new HashSet<>(namesToReference.values()); + } + }; + } + +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java index 58ef07a710c..839c3228294 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java @@ -26,6 +26,7 @@ package jdk.testlibrary; import static jdk.testlibrary.Asserts.*; import java.io.IOException; +import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; @@ -422,6 +423,28 @@ public final class OutputAnalyzer { return output == null ? exitValue : output.getExitValue(); } + + /** + * Print the stdout buffer to the given {@code PrintStream}. + * + * @return this OutputAnalyzer + */ + public OutputAnalyzer outputTo(PrintStream out) { + out.println(getStdout()); + return this; + } + + /** + * Print the stderr buffer to the given {@code PrintStream}. + * + * @return this OutputAnalyzer + */ + public OutputAnalyzer errorTo(PrintStream out) { + out.println(getStderr()); + return this; + } + + /** * Get the contents of the output buffer (stdout and stderr) as list of strings. * Output will be split by system property 'line.separator'. diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java index 6842de26bd4..35cffc1c994 100644 --- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java @@ -340,23 +340,30 @@ public final class ProcessTools { } /** - * Executes a test jvm process, waits for it to finish and returns the process output. - * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added. + * Executes a test java process, waits for it to finish and returns the process output. + * The default options from jtreg, test.vm.opts and test.java.opts, are added. * The java from the test.jdk is used to execute the command. * * The command line will be like: * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds * - * The jvm process will have exited before this method returns. + * The java process will have exited before this method returns. * * @param cmds User specifed arguments. * @return The output from the process. */ - public static OutputAnalyzer executeTestJvm(String... cmds) throws Exception { - ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds)); + public static OutputAnalyzer executeTestJava(String... options) throws Exception { + ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(options)); return executeProcess(pb); } + /** + * @deprecated Use executeTestJava instead + */ + public static OutputAnalyzer executeTestJvm(String... options) throws Exception { + return executeTestJava(options); + } + /** * Executes a process, waits for it to finish and returns the process output. * The process will have exited before this method returns. diff --git a/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java b/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java index fc905968496..69b39bfb7e7 100644 --- a/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java +++ b/jdk/test/sun/awt/shell/ShellFolderMemoryLeak.java @@ -93,6 +93,7 @@ public class ShellFolderMemoryLeak { String command = javaPath + File.separator + "bin" + File.separator + "java -Xmx256M" + arg1 + " -cp " + classPathDir + + " -XaddExports:java.desktop/sun.awt.shell=ALL-UNNAMED" + " ShellFolderMemoryLeak " + arg2; process = Runtime.getRuntime().exec(command); BufferedReader input = null; diff --git a/jdk/test/sun/java2d/marlin/CrashNaNTest.java b/jdk/test/sun/java2d/marlin/CrashNaNTest.java new file mode 100644 index 00000000000..01e32dd6c11 --- /dev/null +++ b/jdk/test/sun/java2d/marlin/CrashNaNTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.geom.Path2D; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import static java.lang.Double.NaN; +import java.util.Locale; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import javax.imageio.ImageIO; + +/** + * @test + * @bug 8149338 + * @summary Verifies that Marlin supports NaN coordinates and no JVM crash happens ! + * @run main CrashNaNTest + */ +public class CrashNaNTest { + + static final boolean SAVE_IMAGE = false; + + public static void main(String argv[]) { + Locale.setDefault(Locale.US); + + // initialize j.u.l Looger: + final Logger log = Logger.getLogger("sun.java2d.marlin"); + log.addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + Throwable th = record.getThrown(); + // detect any Throwable: + if (th != null) { + System.out.println("Test failed:\n" + record.getMessage()); + th.printStackTrace(System.out); + + throw new RuntimeException("Test failed: ", th); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); + + // enable Marlin logging & internal checks: + System.setProperty("sun.java2d.renderer.log", "true"); + System.setProperty("sun.java2d.renderer.useLogger", "true"); + System.setProperty("sun.java2d.renderer.doChecks", "true"); + + final int width = 400; + final int height = 400; + + final BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = (Graphics2D) image.getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g2d.setBackground(Color.WHITE); + g2d.clearRect(0, 0, width, height); + + final Path2D.Double path = new Path2D.Double(); + path.moveTo(30, 30); + path.lineTo(100, 100); + + for (int i = 0; i < 20000; i++) { + path.lineTo(110 + 0.01 * i, 110); + path.lineTo(111 + 0.01 * i, 100); + } + + path.lineTo(NaN, 200); + path.lineTo(200, 200); + path.lineTo(200, NaN); + path.lineTo(300, 300); + path.lineTo(NaN, NaN); + path.lineTo(100, 100); + path.closePath(); + + final Path2D.Double path2 = new Path2D.Double(); + path2.moveTo(0,0); + path2.lineTo(width,height); + path2.lineTo(10, 10); + path2.closePath(); + + for (int i = 0; i < 1; i++) { + final long start = System.nanoTime(); + g2d.setColor(Color.BLUE); + g2d.fill(path); + + g2d.fill(path2); + + final long time = System.nanoTime() - start; + System.out.println("paint: duration= " + (1e-6 * time) + " ms."); + } + + if (SAVE_IMAGE) { + try { + final File file = new File("CrashNaNTest.png"); + System.out.println("Writing file: " + + file.getAbsolutePath()); + ImageIO.write(image, "PNG", file); + } catch (IOException ex) { + System.out.println("Writing file failure:"); + ex.printStackTrace(); + } + } + } finally { + g2d.dispose(); + } + } +} diff --git a/jdk/test/sun/java2d/marlin/CrashPaintTest.java b/jdk/test/sun/java2d/marlin/CrashPaintTest.java new file mode 100644 index 00000000000..cf710bc83a5 --- /dev/null +++ b/jdk/test/sun/java2d/marlin/CrashPaintTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.logging.Handler; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import javax.imageio.ImageIO; + +/** + * @test + * @bug 8148886 + * @summary Verifies that Marlin supports reentrant operations (ThreadLocal) + * like in custom Paint or custom Composite + * @run main CrashPaintTest + */ +public class CrashPaintTest { + + static final boolean SAVE_IMAGE = false; + + public static void main(String argv[]) { + Locale.setDefault(Locale.US); + + // initialize j.u.l Looger: + final Logger log = Logger.getLogger("sun.java2d.marlin"); + log.addHandler(new Handler() { + @Override + public void publish(LogRecord record) { + Throwable th = record.getThrown(); + // detect any Throwable: + if (th != null) { + System.out.println("Test failed:\n" + record.getMessage()); + th.printStackTrace(System.out); + + throw new RuntimeException("Test failed: ", th); + } + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + } + }); + + // enable Marlin logging & internal checks: + System.setProperty("sun.java2d.renderer.log", "true"); + System.setProperty("sun.java2d.renderer.useLogger", "true"); + System.setProperty("sun.java2d.renderer.doChecks", "true"); + + // Force using thread-local storage: + System.setProperty("sun.java2d.renderer.useThreadLocal", "true"); + // Force smaller pixelsize to force using array caches: + System.setProperty("sun.java2d.renderer.pixelsize", "256"); + + final int width = 300; + final int height = 300; + + final BufferedImage image = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB); + + final Graphics2D g2d = (Graphics2D) image.getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g2d.setBackground(Color.WHITE); + g2d.clearRect(0, 0, width, height); + + final Ellipse2D.Double ellipse + = new Ellipse2D.Double(0, 0, width, height); + + final Paint paint = new CustomPaint(100); + + for (int i = 0; i < 20; i++) { + final long start = System.nanoTime(); + g2d.setPaint(paint); + g2d.fill(ellipse); + + g2d.setColor(Color.GREEN); + g2d.draw(ellipse); + + final long time = System.nanoTime() - start; + System.out.println("paint: duration= " + (1e-6 * time) + " ms."); + } + + if (SAVE_IMAGE) { + try { + final File file = new File("CrashPaintTest.png"); + System.out.println("Writing file: " + + file.getAbsolutePath()); + ImageIO.write(image, "PNG", file); + } catch (IOException ex) { + System.out.println("Writing file failure:"); + ex.printStackTrace(); + } + } + + // Check image on few pixels: + final Raster raster = image.getData(); + + // 170, 175 = blue + checkPixel(raster, 170, 175, Color.BLUE.getRGB()); + // 50, 50 = blue + checkPixel(raster, 50, 50, Color.BLUE.getRGB()); + + // 190, 110 = pink + checkPixel(raster, 190, 110, Color.PINK.getRGB()); + // 280, 210 = pink + checkPixel(raster, 280, 210, Color.PINK.getRGB()); + + } finally { + g2d.dispose(); + } + } + + private static void checkPixel(final Raster raster, + final int x, final int y, + final int expected) { + + final int[] rgb = (int[]) raster.getDataElements(x, y, null); + + if (rgb[0] != expected) { + throw new IllegalStateException("bad pixel at (" + x + ", " + y + + ") = " + rgb[0] + " expected: " + expected); + } + } + + private static class CustomPaint extends TexturePaint { + private int size; + + CustomPaint(final int size) { + super(new BufferedImage(size, size, + BufferedImage.TYPE_INT_ARGB), + new Rectangle2D.Double(0, 0, size, size) + ); + this.size = size; + } + + @Override + public PaintContext createContext(ColorModel cm, + Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform at, + RenderingHints hints) { + + // Fill bufferedImage using + final Graphics2D g2d = (Graphics2D) getImage().getGraphics(); + try { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.setBackground(Color.PINK); + g2d.clearRect(0, 0, size, size); + + g2d.setColor(Color.BLUE); + g2d.drawRect(0, 0, size, size); + + g2d.fillOval(size / 10, size / 10, + size * 8 / 10, size * 8 / 10); + + } finally { + g2d.dispose(); + } + + return super.createContext(cm, deviceBounds, userBounds, at, hints); + } + } +} diff --git a/jdk/test/sun/java2d/marlin/TextClipErrorTest.java b/jdk/test/sun/java2d/marlin/TextClipErrorTest.java index efce137256c..c6d42ceb305 100644 --- a/jdk/test/sun/java2d/marlin/TextClipErrorTest.java +++ b/jdk/test/sun/java2d/marlin/TextClipErrorTest.java @@ -69,24 +69,12 @@ public class TextClipErrorTest { @Override public void publish(LogRecord record) { Throwable th = record.getThrown(); - // detect potential Throwable thrown by XxxArrayCache.check(): - if (th != null && th.getClass() == Throwable.class) { - StackTraceElement[] stackElements = th.getStackTrace(); + // detect any Throwable: + if (th != null) { + System.out.println("Test failed:\n" + record.getMessage()); + th.printStackTrace(System.out); - for (int i = 0; i < stackElements.length; i++) { - StackTraceElement e = stackElements[i]; - - if (e.getClassName().startsWith("sun.java2d.marlin") - && e.getClassName().contains("ArrayCache") - && "check".equals(e.getMethodName())) - { - System.out.println("Test failed:\n" - + record.getMessage()); - th.printStackTrace(System.out); - - throw new RuntimeException("Test failed: ", th); - } - } + throw new RuntimeException("Test failed: ", th); } } diff --git a/jdk/test/sun/management/StackTraceElementCompositeData/CompatibilityTest.java b/jdk/test/sun/management/StackTraceElementCompositeData/CompatibilityTest.java new file mode 100644 index 00000000000..00789c89d59 --- /dev/null +++ b/jdk/test/sun/management/StackTraceElementCompositeData/CompatibilityTest.java @@ -0,0 +1,72 @@ + +import java.util.HashMap; +import java.util.Map; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import sun.management.StackTraceElementCompositeData; + +import org.testng.annotations.*; +import static org.testng.Assert.*; + +/* + * @test + * @bug 8139587 + * @summary Check backward compatibility of StackTraceElementCompositeData + * @modules java.management/sun.management + * @run testng CompatibilityTest + * @author Jaroslav Bachorik + */ + +public class CompatibilityTest { + private static CompositeType compositeTypeV6; + private static Map itemsV6; + private static CompositeData compositeDataV6; + + @BeforeClass + public static void setup() throws Exception { + compositeTypeV6 = new CompositeType( + StackTraceElement.class.getName(), + "StackTraceElement", + new String[]{ + "className", "methodName", "fileName", "nativeMethod", "lineNumber" + }, + new String[]{ + "className", "methodName", "fileName", "nativeMethod", "lineNumber" + }, + new OpenType[]{ + SimpleType.STRING, + SimpleType.STRING, + SimpleType.STRING, + SimpleType.BOOLEAN, + SimpleType.INTEGER + } + ); + + itemsV6 = new HashMap<>(); + itemsV6.put("className", "MyClass"); + itemsV6.put("methodName", "myMethod"); + itemsV6.put("fileName", "MyClass.java"); + itemsV6.put("nativeMethod", false); + itemsV6.put("lineNumber", 123); + + compositeDataV6 = new CompositeDataSupport(compositeTypeV6, itemsV6); + } + + @Test + public void testV6Compatibility() throws Exception { + StackTraceElement ste = StackTraceElementCompositeData.from(compositeDataV6); + + assertNotNull(ste); + assertEquals(ste.getClassName(), "MyClass"); + assertEquals(ste.getMethodName(), "myMethod"); + assertEquals(ste.getFileName(), "MyClass.java"); + assertEquals(ste.isNativeMethod(), false); + assertEquals(ste.getLineNumber(), 123); + + assertNull(ste.getModuleName()); + assertNull(ste.getModuleVersion()); + } +} \ No newline at end of file diff --git a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java index 5e61420ddeb..75f3cdbba08 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/CustomLauncherTest.java @@ -150,6 +150,7 @@ public class CustomLauncherTest { ProcessBuilder client = ProcessTools.createJavaProcessBuilder( "-cp", TEST_CLASSPATH, + "-XaddExports:java.management/sun.management=ALL-UNNAMED", "TestManager", String.valueOf(serverPrc.getPid()), port.get(), diff --git a/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java b/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java index a34424935f0..2dd35555af1 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java +++ b/jdk/test/sun/management/jmxremote/bootstrap/LocalManagementTest.java @@ -131,6 +131,7 @@ public class LocalManagementTest { ProcessBuilder client = ProcessTools.createJavaProcessBuilder( "-cp", TEST_CLASSPATH, + "-XaddExports:java.management/sun.management=ALL-UNNAMED", "TestManager", String.valueOf(serverPrc.getPid()), port.get(), diff --git a/jdk/test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh b/jdk/test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh index 2e3fac89fb0..5efd6e2400e 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh +++ b/jdk/test/sun/management/jmxremote/bootstrap/RmiBootstrapTest.sh @@ -51,6 +51,9 @@ chmod -R 777 ${TESTCLASSES}/ssl DEBUGOPTIONS="" export DEBUGOPTIONS +EXTRAOPTIONS="-XaddExports:java.management/sun.management=ALL-UNNAMED,java.management/sun.management.jmxremote=ALL-UNNAMED" +export EXTRAOPTIONS + # Call the common generic test # # No need to since bug 4267864 is now fixed. @@ -58,7 +61,7 @@ export DEBUGOPTIONS echo ------------------------------------------------------------- echo Launching test for `basename $0 .sh` echo ------------------------------------------------------------- -sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${TESTCLASS} +sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${EXTRAOPTIONS} ${TESTCLASS} result=$? restoreFilePermissions `ls ${TESTSRC}/*_test*.in` exit $result diff --git a/jdk/test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh b/jdk/test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh index ee68781b585..16db84cb5d1 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh +++ b/jdk/test/sun/management/jmxremote/bootstrap/RmiSslBootstrapTest.sh @@ -49,12 +49,15 @@ chmod -R 777 ${TESTCLASSES}/ssl DEBUGOPTIONS="" export DEBUGOPTIONS +EXTRAOPTIONS="-XaddExports:java.management/sun.management=ALL-UNNAMED,java.management/sun.management.jmxremote=ALL-UNNAMED" +export EXTRAOPTIONS + # Call the common generic test # echo ------------------------------------------------------------- echo Launching test for `basename $0 .sh` echo ------------------------------------------------------------- -sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${TESTCLASS} \ +sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${EXTRAOPTIONS} ${TESTCLASS} \ ${TESTCLASSES}/management_ssltest*.properties result=$? restoreFilePermissions `ls ${TESTSRC}/*_ssltest*.in` diff --git a/jdk/test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh b/jdk/test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh index a6d10631cdd..86ab964c85f 100644 --- a/jdk/test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh +++ b/jdk/test/sun/management/jmxremote/bootstrap/RmiSslNoKeyStoreTest.sh @@ -48,12 +48,15 @@ chmod -R 777 ${TESTCLASSES}/ssl DEBUGOPTIONS="" export DEBUGOPTIONS +EXTRAOPTIONS="-XaddExports:java.management/sun.management=ALL-UNNAMED,java.management/sun.management.jmxremote=ALL-UNNAMED" +export EXTRAOPTIONS + # Call the common generic test # echo ------------------------------------------------------------- echo Launching test for `basename $0 .sh` echo ------------------------------------------------------------- -sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${TESTCLASS} \ +sh ${TESTSRC}/../RunTest.sh ${DEBUGOPTIONS} ${EXTRAOPTIONS} ${TESTCLASS} \ ${TESTCLASSES}/management_ssltest*.properties result=$? restoreFilePermissions `ls ${TESTSRC}/*_ssltest*.in` diff --git a/jdk/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java b/jdk/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java index bbdf3c0add6..e7545558621 100644 --- a/jdk/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java +++ b/jdk/test/sun/management/jmxremote/startstop/JMXStatusPerfCountersTest.java @@ -42,6 +42,7 @@ import jdk.testlibrary.ProcessTools; * in the related performance counters. * @key intermittent * @library /lib/testlibrary + * @modules java.management/sun.management * @build jdk.testlibrary.* PortAllocator TestApp ManagementAgentJcmd * @run testng/othervm -XX:+UsePerfData JMXStatusPerfCountersTest */ diff --git a/jdk/test/sun/net/idn/TestStringPrep.java b/jdk/test/sun/net/idn/TestStringPrep.java index 20b4f5d3659..493d4bff041 100644 --- a/jdk/test/sun/net/idn/TestStringPrep.java +++ b/jdk/test/sun/net/idn/TestStringPrep.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /* * @test * @summary Unit test for sun.net.idn.Punycode - * @bug 4737170 + * @bug 4737170 8060097 * @modules java.base/sun.net.idn java.base/sun.text.normalizer * @library . * @compile -XDignore.symbol.file TestStringPrep.java NFS4StringPrep.java @@ -41,6 +41,7 @@ import java.text.ParseException; import java.io.InputStream; +import java.util.Locale; import sun.net.idn.StringPrep; import sun.text.normalizer.UCharacterIterator; @@ -209,7 +210,7 @@ public class TestStringPrep { src = "THISISATEST"; byte[] dest = NFS4StringPrep.cs_prepare(src.getBytes("UTF-8"), false); String destStr = new String(dest, "UTF-8"); - if(!src.toLowerCase().equals(destStr)){ + if(!src.toLowerCase(Locale.ROOT).equals(destStr)){ fail("Did not get expected output. Expected: "+ prettify(src)+ " Got: " + prettify(destStr)); } @@ -231,7 +232,8 @@ public class TestStringPrep { } public static void TestNamePrepConformance() throws Exception { - InputStream stream = StringPrep.class.getResourceAsStream("uidna.spp"); + InputStream stream = StringPrep.class.getModule() + .getResourceAsStream("sun/net/idn/uidna.spp"); StringPrep namePrep = new StringPrep(stream); stream.close(); int i; @@ -274,7 +276,7 @@ public class TestStringPrep { private static String hex(char ch) { StringBuffer result = new StringBuffer(); - String foo = Integer.toString(ch,16).toUpperCase(); + String foo = Integer.toString(ch,16).toUpperCase(Locale.ROOT); for (int i = foo.length(); i < 4; ++i) { result.append('0'); } diff --git a/jdk/test/sun/net/util/IPAddressUtilTest.java b/jdk/test/sun/net/util/IPAddressUtilTest.java index 8c35ac726e1..8e4b6a243e3 100644 --- a/jdk/test/sun/net/util/IPAddressUtilTest.java +++ b/jdk/test/sun/net/util/IPAddressUtilTest.java @@ -25,6 +25,7 @@ * @test * @bug 8087190 * @summary Exercise the sun.net.util.IPAddressUtil class + * @modules java.base/sun.net.util */ import sun.net.util.*; diff --git a/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh b/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh index 1b7cf984e8b..c3b45f10a64 100644 --- a/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh +++ b/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxy.sh @@ -28,6 +28,7 @@ # @test # @bug 4423074 # @summary Need to rebase all the duplicated classes from Merlin +# @modules java.base/sun.net.www HOSTNAME=`uname -n` OS=`uname -s` @@ -50,9 +51,12 @@ case "$OS" in ;; esac -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ +EXTRAOPTS="-XaddExports:java.base/sun.net.www=ALL-UNNAMED" + +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . \ ${TESTSRC}${FS}OriginServer.java \ ${TESTSRC}${FS}ProxyTunnelServer.java \ ${TESTSRC}${FS}PostThruProxy.java -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} PostThruProxy ${HOSTNAME} ${TESTSRC} +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} \ + PostThruProxy ${HOSTNAME} ${TESTSRC} exit diff --git a/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh b/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh index fd24c76a475..79b99f0478e 100644 --- a/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh +++ b/jdk/test/sun/net/www/protocol/https/HttpsURLConnection/PostThruProxyWithAuth.sh @@ -28,6 +28,7 @@ # @test # @bug 4423074 # @summary Need to rebase all the duplicated classes from Merlin +# @modules java.base/sun.net.www HOSTNAME=`uname -n` OS=`uname -s` @@ -50,8 +51,11 @@ case "$OS" in ;; esac -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}OriginServer.java \ +EXTRAOPTS="-XaddExports:java.base/sun.net.www=ALL-UNNAMED" +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} \ + -d . ${TESTSRC}${FS}OriginServer.java \ ${TESTSRC}${FS}ProxyTunnelServer.java \ ${TESTSRC}${FS}PostThruProxyWithAuth.java -${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} PostThruProxyWithAuth ${HOSTNAME} ${TESTSRC} +${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} \ + PostThruProxyWithAuth ${HOSTNAME} ${TESTSRC} exit diff --git a/jdk/test/sun/net/www/protocol/jrt/Basic.java b/jdk/test/sun/net/www/protocol/jrt/Basic.java index 82d15fc197e..0f0492c9b39 100644 --- a/jdk/test/sun/net/www/protocol/jrt/Basic.java +++ b/jdk/test/sun/net/www/protocol/jrt/Basic.java @@ -38,26 +38,6 @@ import static org.testng.Assert.*; public class Basic { - @DataProvider(name = "resources") - public Object[][] resources() { - Object[][] data = { - { "java/lang/Object.class", "jrt:/java.base/java/lang/Object.class" }, - { "java/awt/Component.class", "jrt:/java.desktop/java/awt/Component.class" }, - { "jdk/internal/DoesNotExist", null }, - }; - return data; - } - - @Test(dataProvider = "resources") - public void testResources(String name, String expectedUrlString) throws Exception { - URL url = ClassLoader.getSystemResource(name); - if (url == null) { - assertTrue(expectedUrlString == null); - } else { - assertEquals(url.toString(), expectedUrlString); - } - } - @DataProvider(name = "urls") public Object[][] urls() { Object[][] data = { diff --git a/jdk/test/sun/net/www/protocol/jrt/OtherResources.java b/jdk/test/sun/net/www/protocol/jrt/OtherResources.java new file mode 100644 index 00000000000..9717d4dd4c2 --- /dev/null +++ b/jdk/test/sun/net/www/protocol/jrt/OtherResources.java @@ -0,0 +1,47 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; + +/** + * Access a jrt:/ resource in an observable module that is not in the boot + * layer and hence not known to the built-in class loaders. + */ + +public class OtherResources { + public static void main(String[] args) throws IOException { + + // check that java.desktop is not in the set of readable modules + try { + Class.forName("java.awt.Component"); + throw new RuntimeException("Need to run with -limitmods java.base"); + } catch (ClassNotFoundException expected) { } + + // access resource in the java.desktop module + URL url = new URL("jrt:/java.desktop/java/awt/Component.class"); + URLConnection uc = url.openConnection(); + System.out.println(uc.getInputStream()); + } +} diff --git a/jdk/test/sun/net/www/protocol/jrt/WithSecurityManager.java b/jdk/test/sun/net/www/protocol/jrt/WithSecurityManager.java index 58678d7bc3c..97f1105fde8 100644 --- a/jdk/test/sun/net/www/protocol/jrt/WithSecurityManager.java +++ b/jdk/test/sun/net/www/protocol/jrt/WithSecurityManager.java @@ -29,6 +29,8 @@ */ import java.io.InputStream; +import java.io.IOException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -36,8 +38,8 @@ import java.nio.file.Paths; public class WithSecurityManager { public static void main(String[] args) throws Exception { String home = System.getProperty("java.home"); - Path bootmodules = Paths.get(home, "lib", "modules", "bootmodules.jimage"); - if (Files.notExists(bootmodules)) { + Path modules = Paths.get(home, "lib", "modules"); + if (!Files.isRegularFile(modules)) { System.out.println("This runtime is not jimage, test skipped"); return; } @@ -55,7 +57,13 @@ public class WithSecurityManager { System.setSecurityManager(new SecurityManager()); - InputStream in = ClassLoader.getSystemResourceAsStream("java/lang/Object.class"); + InputStream in = null; + URL url = new URL("jrt:/java.base/java/lang/Object.class"); + if (url != null) { + try { + in = url.openStream(); + } catch (IOException ignore) { } + } if (in == null && allow) throw new RuntimeException("access expected"); if (in != null && !allow) diff --git a/jdk/test/sun/security/krb5/config/dns.sh b/jdk/test/sun/net/www/protocol/jrt/other_resources.sh similarity index 62% rename from jdk/test/sun/security/krb5/config/dns.sh rename to jdk/test/sun/net/www/protocol/jrt/other_resources.sh index 698f57879d5..260891cf519 100644 --- a/jdk/test/sun/security/krb5/config/dns.sh +++ b/jdk/test/sun/net/www/protocol/jrt/other_resources.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -22,23 +22,24 @@ # # @test -# @bug 8002344 -# @summary Krb5LoginModule config class does not return proper KDC list from DNS -# +# @build OtherResources +# @run shell other_resources.sh +# @summary Access a jrt:/ resource in an observable module that is not in +# the boot layer and hence not known to the built-in class loaders. This +# test is a shell test because the run tag doesn't support -limitmods. -env +set -e -if [ "${TESTJAVA}" = "" ] ; then - JAVAC_CMD=`which javac` - TESTJAVA=`dirname $JAVAC_CMD`/.. +if [ -z "$TESTJAVA" ]; then + if [ $# -lt 1 ]; then exit 1; fi + TESTJAVA="$1"; shift COMPILEJAVA="${TESTJAVA}" + TESTSRC="`pwd`" + TESTCLASSES="`pwd`" fi -if [ "${TESTSRC}" = "" ] ; then - TESTSRC="." -fi +JAVA="$TESTJAVA/bin/java ${TESTVMOPTS}" +$JAVA -limitmods java.base -cp $TESTCLASSES OtherResources -$COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \ - ${TESTSRC}/NamingManager.java ${TESTSRC}/DNS.java -$TESTJAVA/bin/java ${TESTVMOPTS} -Xbootclasspath/p:. DNS +exit 0 diff --git a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh index b6337096320..b6d0ddad6f6 100644 --- a/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh +++ b/jdk/test/sun/reflect/Reflection/GetCallerClassTest.sh @@ -55,14 +55,16 @@ BCP=${TESTCLASSES}/bcp rm -rf ${BCP} mkdir ${BCP} +EXTRAOPTS="-XaddExports:java.base/sun.reflect=ALL-UNNAMED" + # Compile GetCallerClass in bootclasspath -${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \ +${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} ${EXTRAOPTS} \ -XDignore.symbol.file \ -d ${BCP} ${TESTSRC}/GetCallerClass.java || exit 1 -${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} \ - -XDignore.symbol.file -Xbootclasspath/a:${BCP} \ +${COMPILEJAVA}/bin/javac ${TESTTOOLVMOPTS} ${EXTRAOPTS} \ + -XDignore.symbol.file -cp ${BCP} \ -d ${TESTCLASSES} ${TESTSRC}/GetCallerClassTest.java || exit 2 -${TESTJAVA}/bin/java ${TESTVMOPTS} -Xbootclasspath/a:${BCP} \ +${TESTJAVA}/bin/java ${TESTVMOPTS} ${EXTRAOPTS} -Xbootclasspath/a:${BCP} \ -cp ${TESTCLASSES} GetCallerClassTest || exit 3 diff --git a/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java b/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java index 3ede807577d..fab27c6fe91 100644 --- a/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java +++ b/jdk/test/sun/reflect/constantPool/ConstantPoolTest.java @@ -25,7 +25,8 @@ * @test * @bug 8141615 * @summary Tests new public methods at sun.reflect.ConstantPool - * @modules java.base/sun.reflect + * @modules java.base/jdk.internal.misc + * java.base/sun.reflect * @library /lib/testlibrary * @compile ConstantPoolTestDummy.jasm * @run main sun.reflect.constantPool.ConstantPoolTest diff --git a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java index eab963b1d8d..36414cc087b 100644 --- a/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java +++ b/jdk/test/sun/rmi/runtime/Log/6409194/NoConsoleOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -66,9 +66,13 @@ public class NoConsoleOutput { // We instantiate a JavaVM that should not produce any console output // (neither on standard output, nor on standard err streams). - JavaVM vm = new JavaVM(DoRMIStuff.class.getName(), - "-Djava.util.logging.config.file=" + loggingPropertiesFile, - "", out, err); + JavaVM vm = new JavaVM( + DoRMIStuff.class.getName(), + "-XaddExports:java.rmi/sun.rmi.registry=ALL-UNNAMED," + + "java.rmi/sun.rmi.server=ALL-UNNAMED,java.rmi/sun.rmi.transport=ALL-UNNAMED," + + "java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED" + + " -Djava.util.logging.config.file=" + + loggingPropertiesFile, "", out, err); vm.execute(); /* diff --git a/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java b/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java index 5d69d998eb9..c6f5cf28c87 100644 --- a/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java +++ b/jdk/test/sun/security/jca/PreferredProviderNegativeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,55 +21,52 @@ * questions. */ -/** - * @test - * @bug 8076359 8133151 - * @summary Test for jdk.security.provider.preferred security property - * @requires os.name == "SunOS" - * @run main/othervm PreferredProviderNegativeTest preJCESet AES:OracleUcrypto false - * @run main/othervm PreferredProviderNegativeTest preJCESet AES:SunNegative true - * @run main/othervm PreferredProviderNegativeTest afterJCESet AES:SunJGSS - * @run main/othervm PreferredProviderNegativeTest afterJCESet AES:SunECNegative - * @run main/othervm PreferredProviderNegativeTest invalidAlg AESNegative:SunJCE - */ - import java.security.Security; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +/** + * @test + * @bug 8076359 8133151 8150512 + * @summary Test for jdk.security.provider.preferred security property + * @run main/othervm PreferredProviderNegativeTest preSet AES false + * @run main/othervm PreferredProviderNegativeTest preSet AES:SunNegative true + * @run main/othervm PreferredProviderNegativeTest afterSet AES:SunJGSS + * @run main/othervm PreferredProviderNegativeTest afterSet AES:SunECNegative + * @run main/othervm PreferredProviderNegativeTest invalidAlg AESInvalid:SunJCE + */ public class PreferredProviderNegativeTest { + static final String SEC_PREF_PROP = "jdk.security.provider.preferred"; + /* * Test security property could be set by valid and invalid provider * before JCE was loaded */ public static void preJCESet(String value, boolean negativeProvider) throws NoSuchAlgorithmException, NoSuchPaddingException { - Security.setProperty("jdk.security.provider.preferred", value); - if (!Security.getProperty("jdk.security.provider.preferred") - .equals(value)) { - throw new RuntimeException( - "Test Failed:The property wasn't set"); + Security.setProperty(SEC_PREF_PROP, value); + + if (!Security.getProperty(SEC_PREF_PROP).equals(value)) { + throw new RuntimeException("Test Failed:The property wasn't set"); } String[] arrays = value.split(":"); Cipher cipher = Cipher.getInstance(arrays[0]); - if (negativeProvider) { if (cipher.getProvider().getName().equals(arrays[1])) { throw new RuntimeException( - "Test Failed:The provider shouldn't be set"); + "Test Failed:The provider shouldn't be set."); } } else { if (!cipher.getProvider().getName().equals(arrays[1])) { - throw new RuntimeException( - "Test Faild:The provider could be set " - + "by valid provider "); + throw new RuntimeException("Test Faild:The provider could be " + + "set by valid provider."); } } - System.out.println("Test Pass"); + System.out.println("Test Pass."); } /* @@ -81,10 +78,10 @@ public class PreferredProviderNegativeTest { String[] arrays = value.split(":"); Cipher cipher = Cipher.getInstance(arrays[0]); - Security.setProperty("jdk.security.provider.preferred", value); + Security.setProperty(SEC_PREF_PROP, value); if (!cipher.getProvider().getName().equals("SunJCE")) { - throw new RuntimeException( - "Test Failed:The security property can't be updated after JCE load."); + throw new RuntimeException("Test Failed:The security property can't" + + " be updated after JCE load."); } System.out.println("Test Pass"); } @@ -94,10 +91,11 @@ public class PreferredProviderNegativeTest { String[] arrays = value.split(":"); try { - Security.setProperty("jdk.security.provider.preferred", value); + Security.setProperty(SEC_PREF_PROP, value); Cipher.getInstance(arrays[0]); } catch (NoSuchAlgorithmException e) { - System.out.println("Test Pass:Got NoSuchAlgorithmException as expired"); + System.out.println( + "Test Pass:Got NoSuchAlgorithmException as expired"); return; } throw new RuntimeException( @@ -106,15 +104,25 @@ public class PreferredProviderNegativeTest { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException { - boolean negativeProvider; if (args.length >= 2) { switch (args[0]) { - case "preJCESet": - negativeProvider = Boolean.valueOf(args[2]); - PreferredProviderNegativeTest.preJCESet(args[1], negativeProvider); + case "preSet": + boolean negativeProvider = Boolean.valueOf(args[2]); + boolean solaris = System.getProperty("os.name") + .toLowerCase().contains("sun"); + String value = args[1]; + if (args[1].split(":").length < 2) { + if (solaris) { + value += ":OracleUcrypto"; + } else { + value += ":SunJCE"; + } + } + PreferredProviderNegativeTest.preJCESet( + value, negativeProvider); break; - case "afterJCESet": + case "afterSet": PreferredProviderNegativeTest.afterJCESet(args[1]); break; case "invalidAlg": @@ -127,4 +135,3 @@ public class PreferredProviderNegativeTest { } } } - diff --git a/jdk/test/sun/security/jca/PreferredProviderTest.java b/jdk/test/sun/security/jca/PreferredProviderTest.java index b7eace2d90e..56aa4a0210e 100644 --- a/jdk/test/sun/security/jca/PreferredProviderTest.java +++ b/jdk/test/sun/security/jca/PreferredProviderTest.java @@ -21,97 +21,131 @@ * questions. */ -/** - * @test - * @bug 8076359 8133151 8145344 - * @summary Test the value for new jdk.security.provider.preferred security property - * @requires os.name == "SunOS" - */ - -import java.security.KeyFactory; import java.security.MessageDigest; +import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.Security; +import java.security.Provider; import java.util.Arrays; import java.util.List; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +/** + * @test + * @bug 8076359 8133151 8145344 8150512 + * @summary Test the value for new jdk.security.provider.preferred + * security property + */ public class PreferredProviderTest { - private static final List SPARC_DATA = Arrays.asList( - new DataTuple("SHA1", "SUN"), new DataTuple("SHA-1", "SUN"), - new DataTuple("SHA-224", "SUN"), new DataTuple("SHA-256", "SUN"), - new DataTuple("SHA-384", "SUN"), new DataTuple("SHA-512", "SUN")); - private static final List X86_DATA = Arrays - .asList(new DataTuple("RSA", "SunRsaSign")); - - public void RunTest(String type) + public void RunTest(String type, String os) throws NoSuchAlgorithmException, NoSuchPaddingException { - String preferredProvider = Security - .getProperty("jdk.security.provider.preferred"); + String actualProvider = null; - if (type.equals("sparcv9")) { - if (!preferredProvider.equals( - "AES:SunJCE, SHA1:SUN, SHA-224:SUN, SHA-256:SUN, SHA-384:SUN, SHA-512:SUN")) { - throw new RuntimeException( - "Test Failed: wrong jdk.security.provider.preferred " - + "value on solaris-sparcv9"); - } - for (DataTuple dataTuple : SPARC_DATA) { - MessageDigest md = MessageDigest - .getInstance(dataTuple.algorithm); - actualProvider = md.getProvider().getName(); - if (!actualProvider.equals(dataTuple.provider)) { - throw new RuntimeException(String.format( - "Test Failed:Got wrong " - + "provider from Solaris-sparcv9 platform," - + "Expected Provider: %s, Returned Provider: %s", - dataTuple.provider, actualProvider)); - } - } - } else if (type.equals("amd64")) { - if (!preferredProvider.equals("AES:SunJCE, RSA:SunRsaSign")) { - throw new RuntimeException( - "Test Failed: wrong jdk.security.provider.preferred " - + "value on solaris-x86"); - } - for (DataTuple dataTuple : X86_DATA) { - KeyFactory keyFactory = KeyFactory - .getInstance(dataTuple.algorithm); - actualProvider = keyFactory.getProvider().getName(); - if (!actualProvider.equals(dataTuple.provider)) { - throw new RuntimeException(String.format( - "Test Failed:Got wrong " - + "provider from Solaris-x86 platform," - + "Expected Provider: %s, Returned Provider: %s", - dataTuple.provider, actualProvider)); - } - } + boolean solaris = os.contains("sun"); + String preferredProp + = "AES/GCM/NoPadding:SunJCE, MessageDigest.SHA-256:SUN"; + System.out.printf("%nExecuting test for the platform '%s'%n", os); + if (!solaris) { + //For other platform it will try to set the preferred algorithm and + //Provider and verify the usage of it. + Security.setProperty( + "jdk.security.provider.preferred", preferredProp); + verifyPreferredProviderProperty(os, type, preferredProp); + + verifyDigestProvider(os, type, Arrays.asList( + new DataTuple("SHA-256", "SUN"))); } else { - throw new RuntimeException("Test Failed: wrong platform value"); + //For solaris the preferred algorithm/provider is already set in + //java.security file which will be verified. + switch (type) { + case "sparcv9": + preferredProp = "AES:SunJCE, SHA1:SUN, SHA-224:SUN," + + " SHA-256:SUN, SHA-384:SUN, SHA-512:SUN"; + verifyPreferredProviderProperty(os, type, preferredProp); + + verifyDigestProvider(os, type, Arrays.asList( + new DataTuple("SHA1", "SUN"), + new DataTuple("SHA-1", "SUN"), + new DataTuple("SHA-224", "SUN"), + new DataTuple("SHA-256", "SUN"), + new DataTuple("SHA-384", "SUN"), + new DataTuple("SHA-512", "SUN"))); + break; + case "amd64": + preferredProp = "AES:SunJCE, RSA:SunRsaSign"; + verifyPreferredProviderProperty(os, type, preferredProp); + + verifyKeyFactoryProvider(os, type, Arrays.asList( + new DataTuple("RSA", "SunRsaSign"))); + break; + } + verifyDigestProvider(os, type, Arrays.asList( + new DataTuple("MD5", "OracleUcrypto"))); } Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); actualProvider = cipher.getProvider().getName(); if (!actualProvider.equals("SunJCE")) { - throw new RuntimeException(String.format( - "Test Failed:Got wrong provider from Solaris-%s platform, " - + "Expected Provider: SunJCE, Returned Provider: %s", - type, actualProvider)); + throw new RuntimeException(String.format("Test Failed:Got wrong " + + "provider from %s-%s platform, Expected Provider: SunJCE," + + " Returned Provider: %s", os, type, actualProvider)); } + } - MessageDigest md = MessageDigest.getInstance("MD5"); - actualProvider = md.getProvider().getName(); - if (!actualProvider.equals("OracleUcrypto")) { + private static void verifyPreferredProviderProperty(String os, String arch, + String preferred) { + String preferredProvider + = Security.getProperty("jdk.security.provider.preferred"); + if (!preferredProvider.equals(preferred)) { throw new RuntimeException(String.format( - "Test Failed:Got wrong provider from Solaris-%s platform," - + "Expected Provider: OracleUcrypto, Returned Provider: %s", - type, actualProvider)); + "Test Failed: wrong jdk.security.provider.preferred value " + + "on %s-%s", os, arch)); + } + System.out.println( + "Preferred provider security property verification complete."); + } + + private static void verifyDigestProvider(String os, String arch, + List algoProviders) throws NoSuchAlgorithmException { + for (DataTuple dataTuple : algoProviders) { + System.out.printf( + "Verifying MessageDigest for '%s'%n", dataTuple.algorithm); + MessageDigest md = MessageDigest.getInstance(dataTuple.algorithm); + matchProvider(md.getProvider(), dataTuple.provider, + dataTuple.algorithm, os, arch); + } + System.out.println( + "Preferred MessageDigest algorithm verification successful."); + } + + private static void verifyKeyFactoryProvider(String os, String arch, + List algoProviders) throws NoSuchAlgorithmException { + for (DataTuple dataTuple : algoProviders) { + System.out.printf( + "Verifying KeyFactory for '%s'%n", dataTuple.algorithm); + KeyFactory kf = KeyFactory.getInstance(dataTuple.algorithm); + matchProvider(kf.getProvider(), dataTuple.provider, + dataTuple.algorithm, os, arch); + } + System.out.println( + "Preferred KeyFactory algorithm verification successful."); + } + + private static void matchProvider(Provider provider, String expected, + String algo, String os, String arch) { + if (!provider.getName().equals(expected)) { + throw new RuntimeException(String.format( + "Test Failed:Got wrong provider from %s-%s platform, " + + "for algorithm %s. Expected Provider: %s," + + " Returned Provider: %s", os, arch, algo, + expected, provider.getName())); } } private static class DataTuple { + private final String provider; private final String algorithm; @@ -123,10 +157,9 @@ public class PreferredProviderTest { public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException { - - String arch = System.getProperty("os.arch"); + String os = System.getProperty("os.name").toLowerCase(); + String arch = System.getProperty("os.arch").toLowerCase(); PreferredProviderTest pp = new PreferredProviderTest(); - pp.RunTest(arch); + pp.RunTest(arch, os); } } - diff --git a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java index 96245002874..101f4d785d4 100644 --- a/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java +++ b/jdk/test/sun/security/krb5/auto/HttpNegotiateServer.java @@ -24,6 +24,14 @@ /* * @test * @bug 6578647 6829283 + * @modules java.base/sun.net.spi.nameservice + * java.base/sun.security.util + * java.security.jgss/sun.security.jgss + * java.security.jgss/sun.security.krb5 + * java.security.jgss/sun.security.krb5.internal + * java.security.jgss/sun.security.krb5.internal.ccache + * java.security.jgss/sun.security.krb5.internal.crypto + * java.security.jgss/sun.security.krb5.internal.ktab * @run main/othervm HttpNegotiateServer * @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication() * @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one diff --git a/jdk/test/sun/security/krb5/auto/MaxRetries.java b/jdk/test/sun/security/krb5/auto/MaxRetries.java index 5c5da91653f..d23cd1043b5 100644 --- a/jdk/test/sun/security/krb5/auto/MaxRetries.java +++ b/jdk/test/sun/security/krb5/auto/MaxRetries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 6844193 + * @key intermittent * @compile -XDignore.symbol.file MaxRetries.java * @run main/othervm/timeout=300 MaxRetries * @summary support max_retries in krb5.conf diff --git a/jdk/test/sun/security/krb5/auto/Unreachable.java b/jdk/test/sun/security/krb5/auto/Unreachable.java index 52339786a9f..b010b54837e 100644 --- a/jdk/test/sun/security/krb5/auto/Unreachable.java +++ b/jdk/test/sun/security/krb5/auto/Unreachable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ /* * @test * @bug 7162687 + * @key intermittent * @summary enhance KDC server availability detection * @compile -XDignore.symbol.file Unreachable.java * @run main/othervm/timeout=10 Unreachable diff --git a/jdk/test/sun/security/krb5/config/ConfPlusProp.java b/jdk/test/sun/security/krb5/config/ConfPlusProp.java index 2376d02d46a..b7dc4924fc8 100644 --- a/jdk/test/sun/security/krb5/config/ConfPlusProp.java +++ b/jdk/test/sun/security/krb5/config/ConfPlusProp.java @@ -25,6 +25,7 @@ * @bug 6857795 * @bug 6858589 * @bug 6972005 + * @modules java.security.jgss/sun.security.krb5 * @compile -XDignore.symbol.file ConfPlusProp.java * @run main/othervm ConfPlusProp * @summary krb5.conf ignored if system properties on realm and kdc are provided diff --git a/jdk/test/sun/security/krb5/config/DNS.java b/jdk/test/sun/security/krb5/config/DNS.java index 7171441dcb4..da143e59fe9 100644 --- a/jdk/test/sun/security/krb5/config/DNS.java +++ b/jdk/test/sun/security/krb5/config/DNS.java @@ -21,7 +21,14 @@ * questions. */ -// See dns.sh. +/* + * @test + * @bug 8002344 + * @summary Krb5LoginModule config class does not return proper KDC list from DNS + * @modules java.security.jgss/sun.security.krb5 + * @build java.naming/javax.naming.spi.NamingManager + * @run main/othervm DNS + */ import sun.security.krb5.Config; import sun.security.krb5.KrbException; diff --git a/jdk/test/sun/security/krb5/config/NamingManager.java b/jdk/test/sun/security/krb5/config/java.naming/javax/naming/spi/NamingManager.java similarity index 100% rename from jdk/test/sun/security/krb5/config/NamingManager.java rename to jdk/test/sun/security/krb5/config/java.naming/javax/naming/spi/NamingManager.java diff --git a/jdk/test/sun/security/krb5/tools/ktcheck.sh b/jdk/test/sun/security/krb5/tools/ktcheck.sh index ba279851b6e..48a01a78e6b 100644 --- a/jdk/test/sun/security/krb5/tools/ktcheck.sh +++ b/jdk/test/sun/security/krb5/tools/ktcheck.sh @@ -24,6 +24,9 @@ # @test # @bug 6950546 # @summary "ktab -d name etype" to "ktab -d name [-e etype] [kvno | all | old]" +# @modules java.security.jgss/sun.security.krb5.internal.ktab +# java.security.jgss/sun.security.krb5 +# @compile KtabCheck.java # @run shell ktcheck.sh # @@ -54,11 +57,12 @@ esac KEYTAB=ktab.tmp rm $KEYTAB -${TESTJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}KtabCheck.java EXTRA_OPTIONS="-Djava.security.krb5.conf=${TESTSRC}${FS}onlythree.conf" KTAB="${TESTJAVA}${FS}bin${FS}ktab -J${EXTRA_OPTIONS} -k $KEYTAB -f" -CHECK="${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRA_OPTIONS} KtabCheck $KEYTAB" +CHECK="${TESTJAVA}${FS}bin${FS}java -cp ${TESTCLASSES} ${TESTVMOPTS} ${EXTRA_OPTIONS} \ + -XaddExports:java.security.jgss/sun.security.krb5.internal.ktab=ALL-UNNAMED,java.security.jgss/sun.security.krb5=ALL-UNNAMED \ + KtabCheck $KEYTAB" echo ${EXTRA_OPTIONS} diff --git a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.java b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.java index ac3c2ffcf37..7d3b42d61f1 100644 --- a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.java +++ b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.java @@ -21,8 +21,12 @@ * questions. */ -/** - * @see IsSunMSCAPIAvailable.sh +/* + * @test + * @bug 6318171 6931562 + * @requires os.family == "windows" + * @modules jdk.crypto.mscapi/sun.security.mscapi + * @run main/othervm IsSunMSCAPIAvailable */ import java.security.Provider; diff --git a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh b/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh deleted file mode 100644 index accf1bf4e43..00000000000 --- a/jdk/test/sun/security/mscapi/IsSunMSCAPIAvailable.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -# -# Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - - -# @test -# @bug 6318171 6931562 -# @requires os.family == "windows" -# @run shell IsSunMSCAPIAvailable.sh -# @summary Basic test of the Microsoft CryptoAPI provider. - -OS=`uname -s` -case "$OS" in - Windows* | CYGWIN* ) - - # 'uname -m' does not give us enough information - - # should rely on $PROCESSOR_IDENTIFIER (as is done in Defs-windows.gmk), - # but JTREG does not pass this env variable when executing a shell script. - # - # execute test program - rely on it to exit if platform unsupported - - ${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}\\IsSunMSCAPIAvailable.java - ${TESTJAVA}/bin/java ${TESTVMOPTS} IsSunMSCAPIAvailable - exit - ;; - - * ) - echo "This test is not intended for '$OS' - passing test" - exit 0 - ;; -esac - diff --git a/jdk/test/sun/security/mscapi/PublicKeyInterop.sh b/jdk/test/sun/security/mscapi/PublicKeyInterop.sh index 0f0fba5227f..5110a4b50c5 100644 --- a/jdk/test/sun/security/mscapi/PublicKeyInterop.sh +++ b/jdk/test/sun/security/mscapi/PublicKeyInterop.sh @@ -25,7 +25,6 @@ # @test # @bug 6888925 -# @modules java.base/sun.security.util # @requires os.family == "windows" # @run shell PublicKeyInterop.sh # @summary SunMSCAPI's Cipher can't use RSA public keys obtained from other @@ -62,9 +61,11 @@ case "$OS" in -noprompt echo - echo "Running the test..." - ${TESTJAVA}/bin/javac ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . ${TESTSRC}\\PublicKeyInterop.java - ${TESTJAVA}/bin/java ${TESTVMOPTS} PublicKeyInterop + echo "Running the test..." + ${TESTJAVA}/bin/javac -XaddExports:java.base/sun.security.util=ALL-UNNAMED \ + ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . ${TESTSRC}\\PublicKeyInterop.java + ${TESTJAVA}/bin/java -XaddExports:java.base/sun.security.util=ALL-UNNAMED \ + ${TESTVMOPTS} PublicKeyInterop rc=$? diff --git a/jdk/test/sun/security/mscapi/ShortRSAKey1024.sh b/jdk/test/sun/security/mscapi/ShortRSAKey1024.sh index 4c2bf166dfe..091f3d9ba34 100644 --- a/jdk/test/sun/security/mscapi/ShortRSAKey1024.sh +++ b/jdk/test/sun/security/mscapi/ShortRSAKey1024.sh @@ -88,9 +88,11 @@ case "$OS" in echo echo "Running the test..." - ${TESTJAVA}${FS}bin${FS}javac ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . \ + ${TESTJAVA}${FS}bin${FS}javac -XaddExports:java.base/sun.security.util=ALL-UNNAMED \ + ${TESTTOOLVMOPTS} ${TESTJAVACOPTS} -d . \ ${TESTSRC}${FS}ShortRSAKeyWithinTLS.java - ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ShortRSAKeyWithinTLS 7106773.$BITS $BITS \ + ${TESTJAVA}${FS}bin${FS}java -XaddExports:java.base/sun.security.util=ALL-UNNAMED \ + ${TESTVMOPTS} ShortRSAKeyWithinTLS 7106773.$BITS $BITS \ TLSv1.2 TLS_DHE_RSA_WITH_AES_128_CBC_SHA rc=$? diff --git a/jdk/test/sun/security/mscapi/SignatureOffsets.java b/jdk/test/sun/security/mscapi/SignatureOffsets.java index 4c710396840..128cc00ca04 100644 --- a/jdk/test/sun/security/mscapi/SignatureOffsets.java +++ b/jdk/test/sun/security/mscapi/SignatureOffsets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,7 @@ import java.security.SignatureException; /* * @test * @bug 8050374 - * @key randomness + * @key randomness intermittent * @summary This test validates signature verification * Signature.verify(byte[], int, int). The test uses RandomFactory to * get random set of clear text data to sign. After the signature diff --git a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java index 1ee0f5bb069..0013bd86e03 100644 --- a/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java +++ b/jdk/test/sun/security/mscapi/SmallPrimeExponentP.java @@ -32,6 +32,7 @@ import java.security.interfaces.RSAPrivateCrtKey; /* * @test * @bug 8023546 + * @key intermittent * @modules java.base/sun.security.x509 * java.base/sun.security.tools.keytool * @summary sun/security/mscapi/ShortRSAKey1024.sh fails intermittently diff --git a/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh b/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh index f889417d228..a99a5916e53 100644 --- a/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh +++ b/jdk/test/sun/security/pkcs11/KeyStore/ClientAuth.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 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 @@ -126,7 +126,7 @@ ${CHMOD} +w ${TESTCLASSES}${FS}key3.db # compile test ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ - -classpath ${TESTSRC}${FS}..${PS}${TESTSRC}${FS}loader.jar \ + -classpath ${TESTSRC} \ -d ${TESTCLASSES} \ ${TESTSRC}${FS}ClientAuth.java \ ${TESTSRC}${FS}..${FS}PKCS11Test.java @@ -134,7 +134,7 @@ ${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ # run test echo "Run ClientAuth ..." ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \ - -classpath ${TESTCLASSES}${PS}${TESTSRC}${FS}loader.jar \ + -classpath ${TESTCLASSES} \ -DDIR=${TESTSRC}${FS}ClientAuthData${FS} \ -DCUSTOM_DB_DIR=${TESTCLASSES} \ -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}ClientAuthData${FS}p11-nss.txt \ @@ -155,7 +155,7 @@ fi # run test with specified TLS protocol and cipher suite echo "Run ClientAuth TLSv1.2 TLS_DHE_RSA_WITH_AES_128_CBC_SHA" ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} \ - -classpath ${TESTCLASSES}${PS}${TESTSRC}${FS}loader.jar \ + -classpath ${TESTCLASSES} \ -DDIR=${TESTSRC}${FS}ClientAuthData${FS} \ -DCUSTOM_DB_DIR=${TESTCLASSES} \ -DCUSTOM_P11_CONFIG=${TESTSRC}${FS}ClientAuthData${FS}p11-nss.txt \ diff --git a/jdk/test/sun/security/pkcs11/Provider/Login.policy b/jdk/test/sun/security/pkcs11/Provider/Login.policy index 7fee2f88e03..a386103f315 100644 --- a/jdk/test/sun/security/pkcs11/Provider/Login.policy +++ b/jdk/test/sun/security/pkcs11/Provider/Login.policy @@ -1,6 +1,7 @@ grant { permission java.util.PropertyPermission "*", "read, write"; permission java.lang.RuntimePermission "loadLibrary.*"; + permission java.lang.RuntimePermission "accessClassInPackage.apple.*"; permission java.lang.RuntimePermission "accessClassInPackage.sun.*"; permission java.lang.RuntimePermission "getProtectionDomain"; permission java.security.SecurityPermission "putProviderProperty.*"; diff --git a/jdk/test/sun/security/provider/PolicyFile/Modules.java b/jdk/test/sun/security/provider/PolicyFile/Modules.java new file mode 100644 index 00000000000..5cd7f3dca58 --- /dev/null +++ b/jdk/test/sun/security/provider/PolicyFile/Modules.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8047771 + * @summary check permissions and principals from various modules + * @run main/othervm/java.security.policy==modules.policy Modules + */ + +import java.security.AccessController; +import java.security.Permission; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import javax.security.auth.Subject; + +public class Modules { + + private final static Permission[] perms = new Permission[] { + // java.base module + new java.io.SerializablePermission("enableSubstitution"), + new java.lang.reflect.ReflectPermission("suppressAccessChecks"), + new java.nio.file.LinkPermission("hard"), + new javax.net.ssl.SSLPermission("getSSLSessionContext"), + new javax.security.auth.AuthPermission("doAsPrivileged"), + new javax.security.auth.PrivateCredentialPermission("* * \"*\"", + "read"), + // java.base module (@jdk.Exported Permissions) + new jdk.net.NetworkPermission("setOption.SO_FLOW_SLA"), + // java.desktop module + new java.awt.AWTPermission("createRobot"), + new javax.sound.sampled.AudioPermission("play"), + // java.logging module + new java.util.logging.LoggingPermission("control", ""), + // java.management module + new java.lang.management.ManagementPermission("control"), + new javax.management.MBeanPermission("*", "getAttribute"), + new javax.management.MBeanServerPermission("createMBeanServer"), + new javax.management.MBeanTrustPermission("register"), + new javax.management.remote.SubjectDelegationPermission("*"), + // java.security.jgss module + new javax.security.auth.kerberos.DelegationPermission("\"*\" \"*\""), + new javax.security.auth.kerberos.ServicePermission("*", "accept"), + // java.sql module + new java.sql.SQLPermission("setLog"), + // java.xml.bind module + new javax.xml.bind.JAXBPermission("setDatatypeConverter"), + // java.xml.ws module + new javax.xml.ws.WebServicePermission("publishEndpoint"), + // java.smartcardio module + new javax.smartcardio.CardPermission("*", "*"), + // jdk.attach module (@jdk.Exported Permissions) + new com.sun.tools.attach.AttachPermission("attachVirtualMachine"), + // jdk.jdi module (@jdk.Exported Permissions) + new com.sun.jdi.JDIPermission("virtualMachineManager"), + // jdk.security.jgss module (@jdk.Exported Permissions) + new com.sun.security.jgss.InquireSecContextPermission("*"), + }; + + private final static Principal[] princs = new Principal[] { + // java.base module + new javax.security.auth.x500.X500Principal("CN=Duke"), + // java.management module + new javax.management.remote.JMXPrincipal("Duke"), + // java.security.jgss module + new javax.security.auth.kerberos.KerberosPrincipal("duke@openjdk.org"), + new com.sun.security.auth.UserPrincipal("Duke"), + new com.sun.security.auth.NTDomainPrincipal("openjdk.org"), + new com.sun.security.auth.NTSid( + "S-1-5-21-3623811015-3361044348-30300820-1013"), + new com.sun.security.auth.NTUserPrincipal("Duke"), + new com.sun.security.auth.UnixNumericUserPrincipal("0"), + new com.sun.security.auth.UnixPrincipal("duke"), + }; + + public static void main(String[] args) throws Exception { + + for (Permission perm : perms) { + AccessController.checkPermission(perm); + } + + Permission princPerm = new java.util.PropertyPermission("user.home", + "read"); + Set princSet = new HashSet<>(Arrays.asList(princs)); + Subject subject = new Subject(true, princSet, Collections.emptySet(), + Collections.emptySet()); + PrivilegedAction pa = () -> { + AccessController.checkPermission(princPerm); + return null; + }; + Subject.doAsPrivileged(subject, pa, null); + } +} diff --git a/jdk/test/sun/security/provider/PolicyFile/modules.policy b/jdk/test/sun/security/provider/PolicyFile/modules.policy new file mode 100644 index 00000000000..4a52fc379c6 --- /dev/null +++ b/jdk/test/sun/security/provider/PolicyFile/modules.policy @@ -0,0 +1,67 @@ +grant { + // java.base module + permission java.io.SerializablePermission "enableSubstitution"; + permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; + permission java.nio.file.LinkPermission "hard"; + permission javax.net.ssl.SSLPermission "getSSLSessionContext"; + permission javax.security.auth.AuthPermission "doAsPrivileged"; + permission javax.security.auth.PrivateCredentialPermission "* * \"*\"", + "read"; + // java.base module (@jdk.Exported Permissions) + permission jdk.net.NetworkPermission "setOption.SO_FLOW_SLA"; + // java.desktop module + permission java.awt.AWTPermission "createRobot"; + permission javax.sound.sampled.AudioPermission "play"; + // java.logging module + permission java.util.logging.LoggingPermission "control", ""; + // java.management module + permission java.lang.management.ManagementPermission "control"; + permission javax.management.MBeanPermission "*", "getAttribute"; + permission javax.management.MBeanServerPermission "createMBeanServer"; + permission javax.management.MBeanTrustPermission "register"; + permission javax.management.remote.SubjectDelegationPermission "*"; + // java.security.jgss module + permission javax.security.auth.kerberos.DelegationPermission "\"*\" \"*\""; + permission javax.security.auth.kerberos.ServicePermission "*", "accept"; + // java.sql module + permission java.sql.SQLPermission "setLog"; + // javax.xml.bind module + permission javax.xml.bind.JAXBPermission "setDatatypeConverter"; + // javax.xml.ws module + permission javax.xml.ws.WebServicePermission "publishEndpoint"; + // java.smartcardio module + permission javax.smartcardio.CardPermission "*", "*"; + // jdk.attach module (@jdk.Exported Permissions) + permission com.sun.tools.attach.AttachPermission "attachVirtualMachine"; + // jdk.jdi module (@jdk.Exported Permissions) + permission com.sun.jdi.JDIPermission "virtualMachineManager"; + // jdk.security.jgss module (@jdk.Exported Permissions) + permission com.sun.security.jgss.InquireSecContextPermission "*"; +}; + +grant + // java.base module + principal javax.security.auth.x500.X500Principal "CN=Duke", + // java.management module + principal javax.management.remote.JMXPrincipal "Duke", + // java.security.jgss module + principal javax.security.auth.kerberos.KerberosPrincipal "duke@openjdk.org", + // jdk.security.auth module (@jdk.Exported Principals) + principal com.sun.security.auth.UserPrincipal "Duke", + principal com.sun.security.auth.NTDomainPrincipal "openjdk.org", + principal com.sun.security.auth.NTSid + "S-1-5-21-3623811015-3361044348-30300820-1013", + principal com.sun.security.auth.NTUserPrincipal "Duke", + principal com.sun.security.auth.UnixNumericUserPrincipal "0", + principal com.sun.security.auth.UnixPrincipal "duke" { + permission java.util.PropertyPermission "user.home", "read"; +}; + +grant + // java.security.jgss module + principal javax.security.auth.kerberos.KerberosPrincipal "duke@openjdk.org" +{ + // test that ${{self}} expansion works + permission javax.security.auth.kerberos.ServicePermission "${{self}}", + "accept"; +}; diff --git a/jdk/test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java b/jdk/test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java index f9dde0f3e3a..1a29c280ee4 100644 --- a/jdk/test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java +++ b/jdk/test/sun/security/provider/certpath/OCSP/OCSPSingleExtensions.java @@ -26,16 +26,16 @@ * @bug 8074064 * @summary OCSPResponse.SingleResponse objects do not parse singleExtensions * @modules java.base/sun.security.x509 - * @run main/othervm sun.security.provider.certpath.OCSPSingleExtensions + * java.base/sun.security.provider.certpath + * @run main/othervm OCSPSingleExtensions */ -package sun.security.provider.certpath; - import java.io.*; import java.util.*; import java.security.cert.*; import sun.security.x509.SerialNumber; +import sun.security.provider.certpath.*; /* * Tester note: diff --git a/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java b/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java new file mode 100644 index 00000000000..fd7ae8fa3c9 --- /dev/null +++ b/jdk/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java @@ -0,0 +1,183 @@ +/* + * 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. + */ + +// +// SunJSSE does not support dynamic system properties, no way to re-use +// system properties in samevm/agentvm mode. +// + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; + +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +/* + * @test + * @bug 8149169 + * @summary Test for BufferOverflowException during read from SSLSocket when + * large packet is coming from server after server initiated handshake + * @run main/othervm LargePacketAfterHandshakeTest + */ +public class LargePacketAfterHandshakeTest { + static String pathToStores = "../../../../javax/net/ssl/etc"; + static String keyStoreFile = "keystore"; + static String trustStoreFile = "truststore"; + static String passwd = "passphrase"; + + volatile static int serverport = -1; + volatile static boolean serverReady = false; + volatile static boolean clientDone = false; + volatile static Exception serverException = null; + + public static void runServer() { + try { + System.out.println("Server: Started server thread."); + SSLServerSocketFactory ssf = + (SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); + SSLServerSocket s = (SSLServerSocket)ssf.createServerSocket(0); + serverport = s.getLocalPort(); + System.out.println("Server: Started, listening on port " + + serverport + "."); + serverReady = true; + SSLSocket c = (SSLSocket)s.accept(); + s.close(); + System.out.println( + "Server: Accepted client connection and closed server socket."); + BufferedReader r = new BufferedReader( + new InputStreamReader(c.getInputStream())); + BufferedWriter w = new BufferedWriter( + new OutputStreamWriter(c.getOutputStream())); + String echostring = r.readLine(); + System.out.println("Server: Read " + echostring.length() + + " chars of input data."); + c.startHandshake(); + System.out.println("Server: Kicked new handshake."); + w.write(echostring); + w.newLine(); + w.flush(); + System.out.println("Server: Echoed " + echostring.length() + + " chars of input data."); + while (!clientDone) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + System.out.println("Server: Caught InterruptedException."); + } + } + r.close(); + w.close(); + c.close(); + System.out.println( + "Server: Closed streams and client socket, exiting."); + } catch (Exception e) { + System.out.println("Server: Caught Exception."); + e.printStackTrace(); + serverReady = true; + serverException = e; + } + } + + public static void runClient() throws IOException { + try { + SSLSocketFactory f = + (SSLSocketFactory)SSLSocketFactory.getDefault(); + System.out.println("Client: Initialized."); + while (!serverReady) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + System.out.println("Client: Caught InterruptedException."); + } + } + SSLSocket c = (SSLSocket)f.createSocket("localhost", serverport); + BufferedWriter w = new BufferedWriter( + new OutputStreamWriter(c.getOutputStream())); + BufferedReader r = new BufferedReader( + new InputStreamReader(c.getInputStream())); + System.out.println("Client: Connected."); + String echoPattern = "Otto"; + StringBuilder echoBuilder = + new StringBuilder(4500 + echoPattern.length()); + while (echoBuilder.length() < 4500) { + echoBuilder.append(echoPattern); + } + String echostring = echoBuilder.toString(); + w.write(echostring); + w.newLine(); + w.flush(); + System.out.println("Client: Sent " + echostring.length() + + " chars of data."); + String echoresponse = r.readLine(); + clientDone = true; + System.out.println("Client: Read " + echoresponse.length() + + " chars of data."); + w.close(); + r.close(); + c.close(); + System.out.println("Client: Closed streams and socket, exiting."); + } catch (IOException e) { + System.out.println("Client: Caught Exception."); + e.printStackTrace(); + clientDone = true; + throw e; + } + } + + public static void main(String[] args) throws Exception { + String keyFilename = System.getProperty("test.src", "./") + "/" + + pathToStores + "/" + keyStoreFile; + String trustFilename = System.getProperty("test.src", "./") + "/" + + pathToStores + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + Thread serverThread = new Thread() { + @Override + public void run() { + runServer(); + } + }; + serverThread.start(); + runClient(); + while (serverThread.isAlive()) { + try { + serverThread.join(); + } catch (InterruptedException e) { + System.out.println("Main: Caught InterruptedException " + + " waiting for server Thread."); + } + } + if (serverException != null) { + throw serverException; + } + } +} diff --git a/jdk/test/sun/security/ssl/StatusStapling/TEST.properties b/jdk/test/sun/security/ssl/StatusStapling/TEST.properties index 72f8b4cfd43..41268dd3645 100644 --- a/jdk/test/sun/security/ssl/StatusStapling/TEST.properties +++ b/jdk/test/sun/security/ssl/StatusStapling/TEST.properties @@ -1 +1,6 @@ +modules = \ + java.base/sun.security.provider.certpath \ + java.base/sun.security.util \ + java.base/sun.security.x509 \ + java.base/sun.security.ssl bootclasspath.dirs=. diff --git a/jdk/test/sun/security/ssl/StatusStapling/TestRun.java b/jdk/test/sun/security/ssl/StatusStapling/TestRun.java new file mode 100644 index 00000000000..ce6e6f1de4d --- /dev/null +++ b/jdk/test/sun/security/ssl/StatusStapling/TestRun.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8046321 + * @library ../../../../java/security/testlibrary + * @build CertificateBuilder SimpleOCSPServer + * @run main/othervm java.base/sun.security.ssl.CertStatusReqExtensionTests + * @run main/othervm java.base/sun.security.ssl.CertStatusReqItemV2Tests + * @run main/othervm java.base/sun.security.ssl.CertStatusReqListV2ExtensionTests + * @run main/othervm java.base/sun.security.ssl.OCSPStatusRequestTests + * @run main/othervm -Djavax.net.debug=ssl:respmgr java.base/sun.security.ssl.StatusResponseManagerTests + * @summary OCSP Stapling for TLS + */ + diff --git a/jdk/test/sun/security/ssl/StatusStapling/BogusStatusRequest.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/BogusStatusRequest.java similarity index 100% rename from jdk/test/sun/security/ssl/StatusStapling/BogusStatusRequest.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/BogusStatusRequest.java diff --git a/jdk/test/sun/security/ssl/StatusStapling/CertStatusReqExtensionTests.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqExtensionTests.java similarity index 98% rename from jdk/test/sun/security/ssl/StatusStapling/CertStatusReqExtensionTests.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqExtensionTests.java index 4d79876768d..da7030eccf8 100644 --- a/jdk/test/sun/security/ssl/StatusStapling/CertStatusReqExtensionTests.java +++ b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqExtensionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,6 @@ package sun.security.ssl; -/* - * @test - * @bug 8046321 - * @summary OCSP Stapling for TLS (CertStatusReqExtension tests) - * @build CertStatusReqExtensionTests BogusStatusRequest TestCase TestUtils - * @run main/othervm sun.security.ssl.CertStatusReqExtensionTests - */ - import java.io.IOException; import java.util.*; import java.nio.ByteBuffer; diff --git a/jdk/test/sun/security/ssl/StatusStapling/CertStatusReqItemV2Tests.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqItemV2Tests.java similarity index 98% rename from jdk/test/sun/security/ssl/StatusStapling/CertStatusReqItemV2Tests.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqItemV2Tests.java index 1238d5e5c6a..0ff275bf50c 100644 --- a/jdk/test/sun/security/ssl/StatusStapling/CertStatusReqItemV2Tests.java +++ b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqItemV2Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,6 @@ package sun.security.ssl; -/* - * @test - * @bug 8046321 - * @summary OCSP Stapling for TLS (CertStatusReqItemv2 tests) - * @build CertStatusReqItemV2Tests BogusStatusRequest TestCase TestUtils - * @run main/othervm sun.security.ssl.CertStatusReqItemV2Tests - */ - import java.security.cert.*; import java.util.*; import java.nio.ByteBuffer; diff --git a/jdk/test/sun/security/ssl/StatusStapling/CertStatusReqListV2ExtensionTests.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqListV2ExtensionTests.java similarity index 98% rename from jdk/test/sun/security/ssl/StatusStapling/CertStatusReqListV2ExtensionTests.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqListV2ExtensionTests.java index b8c8013bd94..5884ee3049d 100644 --- a/jdk/test/sun/security/ssl/StatusStapling/CertStatusReqListV2ExtensionTests.java +++ b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/CertStatusReqListV2ExtensionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,6 @@ package sun.security.ssl; -/* - * @test - * @bug 8046321 - * @summary OCSP Stapling for TLS (CertStatusReqListV2Extension tests) - * @build CertStatusReqListV2ExtensionTests TestCase TestUtils - * @run main/othervm sun.security.ssl.CertStatusReqListV2ExtensionTests - */ - import java.io.IOException; import java.util.*; import java.nio.ByteBuffer; diff --git a/jdk/test/sun/security/ssl/StatusStapling/OCSPStatusRequestTests.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/OCSPStatusRequestTests.java similarity index 98% rename from jdk/test/sun/security/ssl/StatusStapling/OCSPStatusRequestTests.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/OCSPStatusRequestTests.java index eb610672d75..85de96d9c5d 100644 --- a/jdk/test/sun/security/ssl/StatusStapling/OCSPStatusRequestTests.java +++ b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/OCSPStatusRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,14 +23,6 @@ package sun.security.ssl; -/* - * @test - * @bug 8046321 - * @summary OCSP Stapling for TLS (OCSPStatusRequestTests tests) - * @build OCSPStatusRequestTests TestCase TestUtils - * @run main/othervm sun.security.ssl.OCSPStatusRequestTests - */ - import java.security.cert.*; import java.util.*; import java.nio.ByteBuffer; diff --git a/jdk/test/sun/security/ssl/StatusStapling/StatusResponseManagerTests.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/StatusResponseManagerTests.java similarity index 97% rename from jdk/test/sun/security/ssl/StatusStapling/StatusResponseManagerTests.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/StatusResponseManagerTests.java index 198657e7c0b..7e0202e5fd8 100644 --- a/jdk/test/sun/security/ssl/StatusStapling/StatusResponseManagerTests.java +++ b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/StatusResponseManagerTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,17 +23,6 @@ package sun.security.ssl; -/* - * @test - * @bug 8046321 - * @summary OCSP Stapling for TLS (StatusResponseManager tests) - * @library ../../../../java/security/testlibrary - * @build CertificateBuilder SimpleOCSPServer - * @build StatusResponseManagerTests TestCase TestUtils - * @run main/othervm -Djavax.net.debug=ssl:respmgr - * sun.security.ssl.StatusResponseManagerTests - */ - import java.io.IOException; import java.math.BigInteger; import java.security.cert.*; diff --git a/jdk/test/sun/security/ssl/StatusStapling/TestCase.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestCase.java similarity index 100% rename from jdk/test/sun/security/ssl/StatusStapling/TestCase.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestCase.java diff --git a/jdk/test/sun/security/ssl/StatusStapling/TestUtils.java b/jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestUtils.java similarity index 100% rename from jdk/test/sun/security/ssl/StatusStapling/TestUtils.java rename to jdk/test/sun/security/ssl/StatusStapling/java.base/sun/security/ssl/TestUtils.java diff --git a/jdk/test/sun/security/tools/jarsigner/ts.sh b/jdk/test/sun/security/tools/jarsigner/ts.sh index 6dabe06c696..9b7bd89af1d 100644 --- a/jdk/test/sun/security/tools/jarsigner/ts.sh +++ b/jdk/test/sun/security/tools/jarsigner/ts.sh @@ -24,6 +24,11 @@ # @test # @bug 6543842 6543440 6939248 8009636 8024302 # @summary checking response of timestamp +# @modules java.base/sun.misc +# java.base/sun.security.pkcs +# java.base/sun.security.timestamp +# java.base/sun.security.x509 +# java.base/sun.security.util # # @run shell/timeout=600 ts.sh @@ -90,6 +95,7 @@ $KT -alias tsbad3 -certreq | \ $KT -alias ca -gencert -ext eku:critical=cs | \ $KT -alias tsbad3 -importcert -$JAVAC -d . ${TESTSRC}/TimestampCheck.java -$JAVA ${TESTVMOPTS} "-Dtest.tool.vm.opts=${TESTTOOLVMOPTS}" TimestampCheck +EXTRAOPTS="-XaddExports:java.base/sun.misc=ALL-UNNAMED,java.base/sun.security.pkcs=ALL-UNNAMED,java.base/sun.security.timestamp=ALL-UNNAMED,java.base/sun.security.x509=ALL-UNNAMED,java.base/sun.security.util=ALL-UNNAMED" +$JAVAC ${EXTRAOPTS} -d . ${TESTSRC}/TimestampCheck.java +$JAVA ${TESTVMOPTS} ${EXTRAOPTS} "-Dtest.tool.vm.opts=${TESTTOOLVMOPTS}" TimestampCheck diff --git a/jdk/test/sun/security/tools/keytool/autotest.sh b/jdk/test/sun/security/tools/keytool/autotest.sh index 655c8865527..d798f7a811e 100644 --- a/jdk/test/sun/security/tools/keytool/autotest.sh +++ b/jdk/test/sun/security/tools/keytool/autotest.sh @@ -100,7 +100,9 @@ fi echo "Using NSS lib at $LIBNAME" -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . -XDignore.symbol.file \ +EXTRAOPTS="-XaddExports:java.base/sun.security.tools.keytool=ALL-UNNAMED,java.base/sun.security.util=ALL-UNNAMED,java.base/sun.security.x509=ALL-UNNAMED" + +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file \ ${TESTSRC}${FS}KeyToolTest.java || exit 10 NSS=${TESTSRC}${FS}..${FS}..${FS}pkcs11${FS}nss @@ -113,7 +115,7 @@ cp ${NSS}${FS}db${FS}secmod.db . chmod u+w key3.db chmod u+w cert8.db -echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dnss \ +echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -Dnss \ -Dnss.lib=${LIBNAME} \ KeyToolTest status=$? diff --git a/jdk/test/sun/security/tools/keytool/standard.sh b/jdk/test/sun/security/tools/keytool/standard.sh index 03484aad9ac..f84bd1930ed 100644 --- a/jdk/test/sun/security/tools/keytool/standard.sh +++ b/jdk/test/sun/security/tools/keytool/standard.sh @@ -57,9 +57,11 @@ case "$OS" in ;; esac -${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10 +EXTRAOPTS="-XaddExports:java.base/sun.security.tools.keytool=ALL-UNNAMED,java.base/sun.security.util=ALL-UNNAMED,java.base/sun.security.x509=ALL-UNNAMED" -echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dfile KeyToolTest +${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . -XDignore.symbol.file ${TESTSRC}${FS}KeyToolTest.java || exit 10 + +echo | ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} ${EXTRAOPTS} -Dfile KeyToolTest status=$? exit $status diff --git a/jdk/test/sun/security/util/Oid/OidEquals.java b/jdk/test/sun/security/util/Oid/OidEquals.java index 1682fc3a0d1..554455b345b 100644 --- a/jdk/test/sun/security/util/Oid/OidEquals.java +++ b/jdk/test/sun/security/util/Oid/OidEquals.java @@ -25,6 +25,7 @@ * @test * @bug 8022444 * @summary Test ObjectIdentifier.equals(Object obj) + * @modules java.base/sun.security.util */ import sun.security.util.ObjectIdentifier; diff --git a/jdk/test/sun/security/validator/certreplace.sh b/jdk/test/sun/security/validator/certreplace.sh index 660923181a6..e32d638f0f9 100644 --- a/jdk/test/sun/security/validator/certreplace.sh +++ b/jdk/test/sun/security/validator/certreplace.sh @@ -25,6 +25,7 @@ # @bug 6948803 # @summary CertPath validation regression caused by SHA1 replacement root # and MD2 disable feature +# @modules java.base/sun.security.validator # if [ "${TESTSRC}" = "" ] ; then @@ -82,5 +83,6 @@ $KT -delete -alias user # 5. Build and run test -$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}CertReplace.java -$JAVA ${TESTVMOPTS} CertReplace certreplace.jks certreplace.certs +EXTRAOPTS="-XaddExports:java.base/sun.security.validator=ALL-UNNAMED" +$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . ${TESTSRC}${FS}CertReplace.java +$JAVA ${TESTVMOPTS} ${EXTRAOPTS} CertReplace certreplace.jks certreplace.certs diff --git a/jdk/test/sun/security/validator/samedn.sh b/jdk/test/sun/security/validator/samedn.sh index ebf0660ca4f..acfa49e0914 100644 --- a/jdk/test/sun/security/validator/samedn.sh +++ b/jdk/test/sun/security/validator/samedn.sh @@ -25,6 +25,7 @@ # @bug 6958869 # @summary regression: PKIXValidator fails when multiple trust anchors # have same dn +# @modules java.base/sun.security.validator # if [ "${TESTSRC}" = "" ] ; then @@ -78,6 +79,7 @@ $KT -delete -alias user # 5. Build and run test. Make sure the CA certs are ignored for validity check. # Check both, one of them might be dropped out of map in old codes. -$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . ${TESTSRC}${FS}CertReplace.java -$JAVA ${TESTVMOPTS} CertReplace samedn.jks samedn1.certs || exit 1 -$JAVA ${TESTVMOPTS} CertReplace samedn.jks samedn2.certs || exit 2 +EXTRAOPTS="-XaddExports:java.base/sun.security.validator=ALL-UNNAMED" +$JAVAC ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} ${EXTRAOPTS} -d . ${TESTSRC}${FS}CertReplace.java +$JAVA ${TESTVMOPTS} ${EXTRAOPTS} CertReplace samedn.jks samedn1.certs || exit 1 +$JAVA ${TESTVMOPTS} ${EXTRAOPTS} CertReplace samedn.jks samedn2.certs || exit 2 diff --git a/jdk/test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java b/jdk/test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java index f629aef4ad1..1cccda64f75 100644 --- a/jdk/test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java +++ b/jdk/test/sun/security/x509/URICertStore/ExtensionsWithLDAP.java @@ -51,6 +51,7 @@ import sun.net.spi.nameservice.NameServiceDescriptor; * @test * @bug 8134708 * @summary Check if LDAP resources from CRLDP and AIA extensions can be loaded + * @modules java.base/sun.net.spi.nameservice * @run main/othervm ExtensionsWithLDAP */ public class ExtensionsWithLDAP { diff --git a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java index e10212a0dd2..046a7edb39c 100644 --- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java +++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java @@ -32,6 +32,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.lang.reflect.Module; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -68,7 +69,8 @@ public class ResourceCheckTest { // Ensure that all Message fields have a corresponding key/value // in the resource bundle and that mnemonics can be looked // up where applicable. - ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE); + Module module = sun.tools.jconsole.Messages.class.getModule(); + ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE, module); for (Field field : Messages.class.getFields()) { if (isResourceKeyField(field)) { String resourceKey = field.getName(); diff --git a/jdk/test/sun/tools/jhsdb/SAGetoptTest.java b/jdk/test/sun/tools/jhsdb/SAGetoptTest.java index 736b839e071..5ca48c629a3 100644 --- a/jdk/test/sun/tools/jhsdb/SAGetoptTest.java +++ b/jdk/test/sun/tools/jhsdb/SAGetoptTest.java @@ -25,6 +25,7 @@ /* * @test * @summary unit test for SAGetopt function + * @modules jdk.hotspot.agent/sun.jvm.hotspot * @compile -XDignore.symbol.file SAGetoptTest.java * @run main SAGetoptTest */ diff --git a/jdk/test/sun/util/resources/TimeZone/Bug4640234.java b/jdk/test/sun/util/resources/TimeZone/Bug4640234.java index a8766ea1224..5726bedfdb6 100644 --- a/jdk/test/sun/util/resources/TimeZone/Bug4640234.java +++ b/jdk/test/sun/util/resources/TimeZone/Bug4640234.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 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 @@ -29,6 +29,7 @@ * ISO country codes. * The test program also displays which timezone, country and * language names are not translated + * @modules java.base/sun.util.resources */ @@ -49,6 +50,7 @@ import java.util.Map; import java.util.ResourceBundle; import java.util.TimeZone; +import sun.util.resources.LocaleData; public class Bug4640234 { static SimpleDateFormat sdfEn = new SimpleDateFormat("zzzz", Locale.US); @@ -84,8 +86,8 @@ public class Bug4640234 { String[] countries = locEn.getISOCountries(); String[] languages = locEn.getISOLanguages(); - ResourceBundle resEn = ResourceBundle.getBundle( - "sun.util.resources.LocaleNames", locEn); + ResourceBundle resEn = LocaleData.getBundle("sun.util.resources.LocaleNames", + locEn); Map countryMapEn = getList(resEn, true); Map languageMapEn = getList(resEn, false); @@ -94,8 +96,8 @@ public class Bug4640234 { Map languageMap; for (Locale locale : locales2Test) { - resLoc = ResourceBundle.getBundle( - "sun.util.resources.LocaleNames", locale); + resLoc = LocaleData.getBundle("sun.util.resources.LocaleNames", + locale); sdfLoc = new SimpleDateFormat("zzzz", locale); sdfLocShort = new SimpleDateFormat("z", locale); @@ -257,18 +259,20 @@ public class Bug4640234 { if (nameEn == null) { // We should not get here but test is a MUST have - return new String[] {"", MessageFormat.format(notFoundMessage, - new String[] {"English", ISOCode})}; + return new String[] {"", + MessageFormat.format(notFoundMessage, "English", ISOCode)}; } if (nameLoc == null) { - return new String[] {"", MessageFormat.format(notFoundMessage, - new String[] {locale.getDisplayName(), ISOCode})}; + return new String[] {"", + MessageFormat.format(notFoundMessage, + locale.getDisplayName(), ISOCode)}; } if (nameEn.equals(nameLoc)) { return new String[] {MessageFormat.format(notLocalizedMessage, - new String[] {locale.getDisplayName(), ISOCode}), ""}; + locale.getDisplayName(), ISOCode), + ""}; } return new String[] {"", ""}; diff --git a/jdk/test/tools/jar/compat/CLICompatibility.java b/jdk/test/tools/jar/compat/CLICompatibility.java new file mode 100644 index 00000000000..a69c0829f05 --- /dev/null +++ b/jdk/test/tools/jar/compat/CLICompatibility.java @@ -0,0 +1,633 @@ +/* + * 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. + */ + +import java.io.*; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.stream.Stream; + +import jdk.testlibrary.FileUtils; +import jdk.testlibrary.JDKToolFinder; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import static java.lang.String.format; +import static java.lang.System.out; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.testng.Assert.assertTrue; + +/* + * @test + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder + * @run testng CLICompatibility + * @summary Basic test for compatibility of CLI options + */ + +public class CLICompatibility { + static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", ".")); + static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + final boolean legacyOnly; // for running on older JDK's ( test validation ) + + // Resources we know to exist, that can be used for creating jar files. + static final String RES1 = "CLICompatibility.class"; + static final String RES2 = "CLICompatibility$Result.class"; + + @BeforeTest + public void setupResourcesForJar() throws Exception { + // Copy the files that we are going to use for creating/updating test + // jar files, so that they can be referred to without '-C dir' + Files.copy(TEST_CLASSES.resolve(RES1), USER_DIR.resolve(RES1)); + Files.copy(TEST_CLASSES.resolve(RES2), USER_DIR.resolve(RES2)); + } + + static final IOConsumer ASSERT_CONTAINS_RES1 = in -> { + try (JarInputStream jin = new JarInputStream(in)) { + assertTrue(jarContains(jin, RES1), "Failed to find " + RES1); + } + }; + static final IOConsumer ASSERT_CONTAINS_RES2 = in -> { + try (JarInputStream jin = new JarInputStream(in)) { + assertTrue(jarContains(jin, RES2), "Failed to find " + RES2); + } + }; + static final IOConsumer ASSERT_CONTAINS_MAINFEST = in -> { + try (JarInputStream jin = new JarInputStream(in)) { + assertTrue(jin.getManifest() != null, "No META-INF/MANIFEST.MF"); + } + }; + static final IOConsumer ASSERT_DOES_NOT_CONTAIN_MAINFEST = in -> { + try (JarInputStream jin = new JarInputStream(in)) { + assertTrue(jin.getManifest() == null, "Found unexpected META-INF/MANIFEST.MF"); + } + }; + + static final FailCheckerWithMessage FAIL_TOO_MANY_MAIN_OPS = + new FailCheckerWithMessage("You must specify one of -ctxui options", + /* legacy */ "{ctxui}[vfmn0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files"); + + // Create + + @Test + public void createBadArgs() { + final FailCheckerWithMessage FAIL_CREATE_NO_ARGS = new FailCheckerWithMessage( + "'c' flag requires manifest or input files to be specified!"); + + jar("c") + .assertFailure() + .resultChecker(FAIL_CREATE_NO_ARGS); + + jar("-c") + .assertFailure() + .resultChecker(FAIL_CREATE_NO_ARGS); + + if (!legacyOnly) + jar("--create") + .assertFailure() + .resultChecker(FAIL_CREATE_NO_ARGS); + + jar("ct") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + jar("-ct") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + if (!legacyOnly) + jar("--create --list") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + } + + @Test + public void createWriteToFile() throws IOException { + Path path = Paths.get("createJarFile.jar"); // for creating + String jn = path.toString(); + for (String opts : new String[]{"cf " + jn, "-cf " + jn, "--create --file=" + jn}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + jar(opts, RES1) + .assertSuccess() + .resultChecker(r -> { + ASSERT_CONTAINS_RES1.accept(Files.newInputStream(path)); + ASSERT_CONTAINS_MAINFEST.accept(Files.newInputStream(path)); + }); + } + FileUtils.deleteFileIfExistsWithRetry(path); + } + + @Test + public void createWriteToStdout() throws IOException { + for (String opts : new String[]{"c", "-c", "--create"}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + jar(opts, RES1) + .assertSuccess() + .resultChecker(r -> { + ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream()); + ASSERT_CONTAINS_MAINFEST.accept(r.stdoutAsStream()); + }); + } + } + + @Test + public void createWriteToStdoutNoManifest() throws IOException { + for (String opts : new String[]{"cM", "-cM", "--create --no-manifest"} ){ + if (legacyOnly && opts.startsWith("--")) + continue; + + jar(opts, RES1) + .assertSuccess() + .resultChecker(r -> { + ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream()); + ASSERT_DOES_NOT_CONTAIN_MAINFEST.accept(r.stdoutAsStream()); + }); + } + } + + // Update + + @Test + public void updateBadArgs() { + final FailCheckerWithMessage FAIL_UPDATE_NO_ARGS = new FailCheckerWithMessage( + "'u' flag requires manifest, 'e' flag or input files to be specified!"); + + jar("u") + .assertFailure() + .resultChecker(FAIL_UPDATE_NO_ARGS); + + jar("-u") + .assertFailure() + .resultChecker(FAIL_UPDATE_NO_ARGS); + + if (!legacyOnly) + jar("--update") + .assertFailure() + .resultChecker(FAIL_UPDATE_NO_ARGS); + + jar("ut") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + jar("-ut") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + if (!legacyOnly) + jar("--update --list") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + } + + @Test + public void updateReadFileWriteFile() throws IOException { + Path path = Paths.get("updateReadWriteStdout.jar"); // for updating + String jn = path.toString(); + + for (String opts : new String[]{"uf " + jn, "-uf " + jn, "--update --file=" + jn}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + createJar(path, RES1); + jar(opts, RES2) + .assertSuccess() + .resultChecker(r -> { + ASSERT_CONTAINS_RES1.accept(Files.newInputStream(path)); + ASSERT_CONTAINS_RES2.accept(Files.newInputStream(path)); + ASSERT_CONTAINS_MAINFEST.accept(Files.newInputStream(path)); + }); + } + FileUtils.deleteFileIfExistsWithRetry(path); + } + + @Test + public void updateReadStdinWriteStdout() throws IOException { + Path path = Paths.get("updateReadStdinWriteStdout.jar"); + + for (String opts : new String[]{"u", "-u", "--update"}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + createJar(path, RES1); + jarWithStdin(path.toFile(), opts, RES2) + .assertSuccess() + .resultChecker(r -> { + ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream()); + ASSERT_CONTAINS_RES2.accept(r.stdoutAsStream()); + ASSERT_CONTAINS_MAINFEST.accept(r.stdoutAsStream()); + }); + } + FileUtils.deleteFileIfExistsWithRetry(path); + } + + @Test + public void updateReadStdinWriteStdoutNoManifest() throws IOException { + Path path = Paths.get("updateReadStdinWriteStdoutNoManifest.jar"); + + for (String opts : new String[]{"uM", "-uM", "--update --no-manifest"} ){ + if (legacyOnly && opts.startsWith("--")) + continue; + + createJar(path, RES1); + jarWithStdin(path.toFile(), opts, RES2) + .assertSuccess() + .resultChecker(r -> { + ASSERT_CONTAINS_RES1.accept(r.stdoutAsStream()); + ASSERT_CONTAINS_RES2.accept(r.stdoutAsStream()); + ASSERT_DOES_NOT_CONTAIN_MAINFEST.accept(r.stdoutAsStream()); + }); + } + FileUtils.deleteFileIfExistsWithRetry(path); + } + + // List + + @Test + public void listBadArgs() { + jar("te") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + jar("-te") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + if (!legacyOnly) + jar("--list --extract") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + } + + @Test + public void listReadFromFileWriteToStdout() throws IOException { + Path path = Paths.get("listReadFromFileWriteToStdout.jar"); // for listing + createJar(path, RES1); + String jn = path.toString(); + + for (String opts : new String[]{"tf " + jn, "-tf " + jn, "--list --file " + jn}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + jar(opts) + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.contains("META-INF/MANIFEST.MF") && r.output.contains(RES1), + "Failed, got [" + r.output + "]") + ); + } + FileUtils.deleteFileIfExistsWithRetry(path); + } + + @Test + public void listReadFromStdinWriteToStdout() throws IOException { + Path path = Paths.get("listReadFromStdinWriteToStdout.jar"); + createJar(path, RES1); + + for (String opts : new String[]{"t", "-t", "--list"} ){ + if (legacyOnly && opts.startsWith("--")) + continue; + + jarWithStdin(path.toFile(), opts) + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.contains("META-INF/MANIFEST.MF") && r.output.contains(RES1), + "Failed, got [" + r.output + "]") + ); + } + FileUtils.deleteFileIfExistsWithRetry(path); + } + + // Extract + + @Test + public void extractBadArgs() { + jar("xi") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + jar("-xi") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + + if (!legacyOnly) + jar("--extract --generate-index") + .assertFailure() + .resultChecker(FAIL_TOO_MANY_MAIN_OPS); + } + + @Test + public void extractReadFromStdin() throws IOException { + Path path = Paths.get("extract"); + Path jarPath = path.resolve("extractReadFromStdin.jar"); // for extracting + createJar(jarPath, RES1); + + for (String opts : new String[]{"x" ,"-x", "--extract"}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + jarWithStdinAndWorkingDir(jarPath.toFile(), path.toFile(), opts) + .assertSuccess() + .resultChecker(r -> + assertTrue(Files.exists(path.resolve(RES1)), + "Expected to find:" + path.resolve(RES1)) + ); + FileUtils.deleteFileIfExistsWithRetry(path.resolve(RES1)); + } + FileUtils.deleteFileTreeWithRetry(path); + } + + @Test + public void extractReadFromFile() throws IOException { + Path path = Paths.get("extract"); + String jn = "extractReadFromFile.jar"; + Path jarPath = path.resolve(jn); + createJar(jarPath, RES1); + + for (String opts : new String[]{"xf "+jn ,"-xf "+jn, "--extract --file "+jn}) { + if (legacyOnly && opts.startsWith("--")) + continue; + + jarWithStdinAndWorkingDir(null, path.toFile(), opts) + .assertSuccess() + .resultChecker(r -> + assertTrue(Files.exists(path.resolve(RES1)), + "Expected to find:" + path.resolve(RES1)) + ); + FileUtils.deleteFileIfExistsWithRetry(path.resolve(RES1)); + } + FileUtils.deleteFileTreeWithRetry(path); + } + + // Basic help + + @Test + public void helpBadOptionalArg() { + if (legacyOnly) + return; + + jar("--help:") + .assertFailure(); + + jar("--help:blah") + .assertFailure(); + } + + @Test + public void help() { + if (legacyOnly) + return; + + jar("-h") + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.startsWith("Usage: jar [OPTION...] [-C dir] files"), + "Failed, got [" + r.output + "]") + ); + + jar("--help") + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.startsWith("Usage: jar [OPTION...] [-C dir] files"), + "Failed, got [" + r.output + "]") + ); + + jar("--help:compat") + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.startsWith("Compatibility Interface:"), + "Failed, got [" + r.output + "]") + ); + } + + // -- Infrastructure + + static boolean jarContains(JarInputStream jis, String entryName) + throws IOException + { + JarEntry e; + boolean found = false; + while((e = jis.getNextJarEntry()) != null) { + if (e.getName().equals(entryName)) + return true; + } + return false; + } + + /* Creates a simple jar with entries of size 0, good enough for testing */ + static void createJar(Path path, String... entries) throws IOException { + FileUtils.deleteFileIfExistsWithRetry(path); + Path parent = path.getParent(); + if (parent != null) + Files.createDirectories(parent); + try (OutputStream out = Files.newOutputStream(path); + JarOutputStream jos = new JarOutputStream(out)) { + JarEntry je = new JarEntry("META-INF/MANIFEST.MF"); + jos.putNextEntry(je); + jos.closeEntry(); + + for (String entry : entries) { + je = new JarEntry(entry); + jos.putNextEntry(je); + jos.closeEntry(); + } + } + } + + static class FailCheckerWithMessage implements Consumer { + final String[] messages; + FailCheckerWithMessage(String... m) { + messages = m; + } + @Override + public void accept(Result r) { + //out.printf("%s%n", r.output); + boolean found = false; + for (String m : messages) { + if (r.output.contains(m)) { + found = true; + break; + } + } + assertTrue(found, + "Excepted out to contain one of: " + Arrays.asList(messages) + + " but got: " + r.output); + } + } + + static Result jar(String... args) { + return jarWithStdinAndWorkingDir(null, null, args); + } + + static Result jarWithStdin(File stdinSource, String... args) { + return jarWithStdinAndWorkingDir(stdinSource, null, args); + } + + static Result jarWithStdinAndWorkingDir(File stdinFrom, + File workingDir, + String... args) { + String jar = getJDKTool("jar"); + List commands = new ArrayList<>(); + commands.add(jar); + Stream.of(args).map(s -> s.split(" ")) + .flatMap(Arrays::stream) + .forEach(x -> commands.add(x)); + ProcessBuilder p = new ProcessBuilder(commands); + if (stdinFrom != null) + p.redirectInput(stdinFrom); + if (workingDir != null) + p.directory(workingDir); + return run(p); + } + + static Result run(ProcessBuilder pb) { + Process p; + byte[] stdout, stderr; + out.printf("Running: %s%n", pb.command()); + try { + p = pb.start(); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't start process '%s'", pb.command()), e); + } + + String output; + try { + stdout = readAllBytes(p.getInputStream()); + stderr = readAllBytes(p.getErrorStream()); + + output = toString(stdout, stderr); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't read process output '%s'", pb.command()), e); + } + + try { + p.waitFor(); + } catch (InterruptedException e) { + throw new RuntimeException( + format("Process hasn't finished '%s'", pb.command()), e); + } + return new Result(p.exitValue(), stdout, stderr, output); + } + + static final Path JAVA_HOME = Paths.get(System.getProperty("java.home")); + + static String getJDKTool(String name) { + try { + return JDKToolFinder.getJDKTool(name); + } catch (Exception x) { + Path j = JAVA_HOME.resolve("bin").resolve(name); + if (Files.exists(j)) + return j.toString(); + j = JAVA_HOME.resolve("..").resolve("bin").resolve(name); + if (Files.exists(j)) + return j.toString(); + throw new RuntimeException(x); + } + } + + static String toString(byte[] ba1, byte[] ba2) { + return (new String(ba1, UTF_8)).concat(new String(ba2, UTF_8)); + } + + static class Result { + final int exitValue; + final byte[] stdout; + final byte[] stderr; + final String output; + + private Result(int exitValue, byte[] stdout, byte[] stderr, String output) { + this.exitValue = exitValue; + this.stdout = stdout; + this.stderr = stderr; + this.output = output; + } + + InputStream stdoutAsStream() { return new ByteArrayInputStream(stdout); } + + Result assertSuccess() { assertTrue(exitValue == 0, output); return this; } + Result assertFailure() { assertTrue(exitValue != 0, output); return this; } + + Result resultChecker(IOConsumer r) { + try { r.accept(this); return this; } + catch (IOException x) { throw new UncheckedIOException(x); } + } + + Result resultChecker(FailCheckerWithMessage c) { c.accept(this); return this; } + } + + interface IOConsumer { void accept(T t) throws IOException ; } + + // readAllBytes implementation so the test can be run pre 1.9 ( legacyOnly ) + static byte[] readAllBytes(InputStream is) throws IOException { + byte[] buf = new byte[8192]; + int capacity = buf.length; + int nread = 0; + int n; + for (;;) { + // read to EOF which may read more or less than initial buffer size + while ((n = is.read(buf, nread, capacity - nread)) > 0) + nread += n; + + // if the last call to read returned -1, then we're done + if (n < 0) + break; + + // need to allocate a larger buffer + capacity = capacity << 1; + + buf = Arrays.copyOf(buf, capacity); + } + return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); + } + + // Standalone entry point for running with, possibly older, JDKs. + public static void main(String[] args) throws Throwable { + boolean legacyOnly = false; + if (args.length != 0 && args[0].equals("legacyOnly")) + legacyOnly = true; + + CLICompatibility test = new CLICompatibility(legacyOnly); + for (Method m : CLICompatibility.class.getDeclaredMethods()) { + if (m.getAnnotation(Test.class) != null) { + System.out.println("Invoking " + m.getName()); + m.invoke(test); + } + } + } + CLICompatibility(boolean legacyOnly) { this.legacyOnly = legacyOnly; } + CLICompatibility() { this.legacyOnly = false; } +} diff --git a/jdk/test/tools/jar/modularJar/Basic.java b/jdk/test/tools/jar/modularJar/Basic.java new file mode 100644 index 00000000000..40829ec9280 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/Basic.java @@ -0,0 +1,797 @@ +/* + * 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.io.*; +import java.lang.reflect.Method; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; +import java.util.function.Consumer; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +import jdk.testlibrary.FileUtils; +import jdk.testlibrary.JDKToolFinder; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import static java.lang.String.format; +import static java.lang.System.out; + +/* + * @test + * @library /lib/testlibrary + * @build jdk.testlibrary.FileUtils jdk.testlibrary.JDKToolFinder + * @compile Basic.java + * @run testng Basic + * @summary Basic test for Modular jars + */ + +public class Basic { + static final Path TEST_SRC = Paths.get(System.getProperty("test.src", ".")); + static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", ".")); + static final Path MODULE_CLASSES = TEST_CLASSES.resolve("build"); + + // Details based on the checked in module source + static TestModuleData FOO = new TestModuleData("foo", + "1.123", + "jdk.test.foo.Foo", + "Hello World!!!", null, + "jdk.test.foo.internal"); + static TestModuleData BAR = new TestModuleData("bar", + "4.5.6.7", + "jdk.test.bar.Bar", + "Hello from Bar!", null, + "jdk.test.bar", + "jdk.test.bar.internal"); + + static class TestModuleData { + final String moduleName; + final String mainClass; + final String version; + final String message; + final String hashes; + final Set conceals; + TestModuleData(String mn, String v, String mc, String m, String h, String... pkgs) { + moduleName = mn; mainClass = mc; version = v; message = m; hashes = h; + conceals = new HashSet<>(); + Stream.of(pkgs).forEach(conceals::add); + } + TestModuleData(String mn, String v, String mc, String m, String h, Set pkgs) { + moduleName = mn; mainClass = mc; version = v; message = m; hashes = h; + conceals = pkgs; + } + static TestModuleData from(String s) { + try { + BufferedReader reader = new BufferedReader(new StringReader(s)); + String line; + String message = null; + String name = null, version = null, mainClass = null; + String hashes = null; + Set conceals = null; + while ((line = reader.readLine()) != null) { + if (line.startsWith("message:")) { + message = line.substring("message:".length()); + } else if (line.startsWith("nameAndVersion:")) { + line = line.substring("nameAndVersion:".length()); + int i = line.indexOf('@'); + if (i != -1) { + name = line.substring(0, i); + version = line.substring(i + 1, line.length()); + } else { + name = line; + } + } else if (line.startsWith("mainClass:")) { + mainClass = line.substring("mainClass:".length()); + } else if (line.startsWith("hashes:")) { + hashes = line.substring("hashes:".length()); + } else if (line.startsWith("conceals:")) { + line = line.substring("conceals:".length()); + conceals = new HashSet<>(); + int i = line.indexOf(','); + if (i != -1) { + String[] p = line.split(","); + Stream.of(p).forEach(conceals::add); + } else { + conceals.add(line); + } + } else { + throw new AssertionError("Unknown value " + line); + } + } + + return new TestModuleData(name, version, mainClass, message, hashes, conceals); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + } + + static void assertModuleData(Result r, TestModuleData expected) { + //out.printf("%s%n", r.output); + TestModuleData received = TestModuleData.from(r.output); + if (expected.message != null) + assertTrue(expected.message.equals(received.message), + "Expected message:", expected.message, ", got:", received.message); + assertTrue(expected.moduleName.equals(received.moduleName), + "Expected moduleName: ", expected.moduleName, ", got:", received.moduleName); + assertTrue(expected.version.equals(received.version), + "Expected version: ", expected.version, ", got:", received.version); + assertTrue(expected.mainClass.equals(received.mainClass), + "Expected mainClass: ", expected.mainClass, ", got:", received.mainClass); + expected.conceals.forEach(p -> assertTrue(received.conceals.contains(p), + "Expected ", p, ", in ", received.conceals)); + received.conceals.forEach(p -> assertTrue(expected.conceals.contains(p), + "Expected ", p, ", in ", expected.conceals)); + } + + @BeforeTest + public void compileModules() throws Exception { + compileModule(FOO.moduleName); + compileModule(BAR.moduleName, MODULE_CLASSES); + compileModule("baz"); // for service provider consistency checking + } + + @Test + public void createFoo() throws IOException { + Path mp = Paths.get("createFoo"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + + try (InputStream fis = Files.newInputStream(modularJar); + JarInputStream jis = new JarInputStream(fis)) { + assertTrue(!jarContains(jis, "./"), + "Unexpected ./ found in ", modularJar.toString()); + } + } + + @Test + public void updateFoo() throws IOException { + Path mp = Paths.get("updateFoo"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + jar("--create", + "--file=" + modularJar.toString(), + "--no-manifest", + "-C", modClasses.toString(), "jdk") + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), "module-info.class") + .assertSuccess(); + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + } + + @Test + public void partialUpdateFooMainClass() throws IOException { + Path mp = Paths.get("partialUpdateFooMainClass"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + // A "bad" main class in first create ( and no version ) + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + "IAmNotTheEntryPoint", + "--no-manifest", + "-C", modClasses.toString(), ".") // includes module-info.class + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest") + .assertSuccess(); + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + } + + @Test + public void partialUpdateFooVersion() throws IOException { + Path mp = Paths.get("partialUpdateFooVersion"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + // A "bad" version in first create ( and no main class ) + jar("--create", + "--file=" + modularJar.toString(), + "--module-version=" + "100000000", + "--no-manifest", + "-C", modClasses.toString(), ".") // includes module-info.class + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest") + .assertSuccess(); + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + } + + @Test + public void partialUpdateFooNotAllFiles() throws IOException { + Path mp = Paths.get("partialUpdateFooNotAllFiles"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + // Not all files, and none from non-exported packages, + // i.e. no concealed list in first create + jar("--create", + "--file=" + modularJar.toString(), + "--no-manifest", + "-C", modClasses.toString(), "module-info.class", + "-C", modClasses.toString(), "jdk/test/foo/Foo.class") + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), "jdk/test/foo/internal/Message.class") + .assertSuccess(); + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + } + + @Test + public void partialUpdateFooAllFilesAndAttributes() throws IOException { + Path mp = Paths.get("partialUpdateFooAllFilesAndAttributes"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + // all attributes and files + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + java(mp, FOO.moduleName + "/" + FOO.mainClass) + .assertSuccess() + .resultChecker(r -> assertModuleData(r, FOO)); + } + + @Test + public void partialUpdateFooModuleInfo() throws IOException { + Path mp = Paths.get("partialUpdateFooModuleInfo"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + Path barModInfo = MODULE_CLASSES.resolve(BAR.moduleName); + + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "--no-manifest", + "-C", barModInfo.toString(), "module-info.class") // stuff in bar's info + .assertSuccess(); + jar("-p", + "--file=" + modularJar.toString()) + .assertSuccess() + .resultChecker(r -> { + // Expect similar output: "Name:bar, Requires: foo,... + // Conceals: jdk.test.foo, jdk.test.foo.internal" + Pattern p = Pattern.compile("\\s+Name:\\s+bar\\s+Requires:\\s+foo"); + assertTrue(p.matcher(r.output).find(), + "Expecting to find \"Name: bar, Requires: foo,...\"", + "in output, but did not: [" + r.output + "]"); + p = Pattern.compile( + "Conceals:\\s+jdk.test.foo\\s+jdk.test.foo.internal"); + assertTrue(p.matcher(r.output).find(), + "Expecting to find \"Conceals: jdk.test.foo,...\"", + "in output, but did not: [" + r.output + "]"); + }); + } + + @Test + public void dependencesFooBar() throws IOException { + Path mp = Paths.get("dependencesFooBar"); + createTestDir(mp); + + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + + modClasses = MODULE_CLASSES.resolve(BAR.moduleName); + modularJar = mp.resolve(BAR.moduleName + ".jar"); + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + BAR.mainClass, + "--module-version=" + BAR.version, + "--modulepath=" + mp.toString(), + "--hash-dependencies=" + "foo", // dependency on foo + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + + java(mp, BAR.moduleName + "/" + BAR.mainClass, + "-XaddExports:java.base/jdk.internal.module=bar") + .assertSuccess() + .resultChecker(r -> { + assertModuleData(r, BAR); + TestModuleData received = TestModuleData.from(r.output); + assertTrue(received.hashes != null, "Expected non-null hashes value."); + }); + } + + @Test + public void badDependencyFooBar() throws IOException { + Path mp = Paths.get("badDependencyFooBar"); + createTestDir(mp); + + Path fooClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path fooJar = mp.resolve(FOO.moduleName + ".jar"); + jar("--create", + "--file=" + fooJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", fooClasses.toString(), ".").assertSuccess(); + + Path barClasses = MODULE_CLASSES.resolve(BAR.moduleName); + Path barJar = mp.resolve(BAR.moduleName + ".jar"); + jar("--create", + "--file=" + barJar.toString(), + "--main-class=" + BAR.mainClass, + "--module-version=" + BAR.version, + "--modulepath=" + mp.toString(), + "--hash-dependencies=" + "foo", // dependency on foo + "--no-manifest", + "-C", barClasses.toString(), ".").assertSuccess(); + + // Rebuild foo.jar with a change that will cause its hash to be different + FileUtils.deleteFileWithRetry(fooJar); + jar("--create", + "--file=" + fooJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version + ".1", // a newer version + "--no-manifest", + "-C", fooClasses.toString(), ".").assertSuccess(); + + java(mp, BAR.moduleName + "/" + BAR.mainClass, + "-XaddExports:java.base/jdk.internal.module=bar") + .assertFailure() + .resultChecker(r -> { + // Expect similar output: "java.lang.module.ResolutionException: Hash + // of foo (WdktSIQSkd4+CEacpOZoeDrCosMATNrIuNub9b5yBeo=) differs to + // expected hash (iepvdv8xTeVrFgMtUhcFnmetSub6qQHCHc92lSaSEg0=)" + Pattern p = Pattern.compile(".*Hash of foo.*differs to expected hash.*"); + assertTrue(p.matcher(r.output).find(), + "Expecting error message containing \"Hash of foo ... differs to" + + " expected hash...\" but got: [", r.output + "]"); + }); + } + + @Test + public void badOptionsFoo() throws IOException { + Path mp = Paths.get("badOptionsFoo"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + jar("--create", + "--file=" + modularJar.toString(), + "--module-version=" + 1.1, // no module-info.class + "-C", modClasses.toString(), "jdk") + .assertFailure(); // TODO: expected failure message + + jar("--create", + "--file=" + modularJar.toString(), + "--hash-dependencies=" + ".*", // no module-info.class + "-C", modClasses.toString(), "jdk") + .assertFailure(); // TODO: expected failure message + } + + @Test + public void servicesCreateWithoutFailure() throws IOException { + Path mp = Paths.get("servicesCreateWithoutFailure"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve("baz"); + Path modularJar = mp.resolve("baz" + ".jar"); + + // Positive test, create + jar("--create", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "module-info.class", + "-C", modClasses.toString(), "jdk/test/baz/BazService.class", + "-C", modClasses.toString(), "jdk/test/baz/internal/BazServiceImpl.class") + .assertSuccess(); + } + + @Test + public void servicesCreateWithoutServiceImpl() throws IOException { + Path mp = Paths.get("servicesWithoutServiceImpl"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve("baz"); + Path modularJar = mp.resolve("baz" + ".jar"); + + // Omit service impl + jar("--create", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "module-info.class", + "-C", modClasses.toString(), "jdk/test/baz/BazService.class") + .assertFailure(); + } + + @Test + public void servicesUpdateWithoutFailure() throws IOException { + Path mp = Paths.get("servicesUpdateWithoutFailure"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve("baz"); + Path modularJar = mp.resolve("baz" + ".jar"); + + // Positive test, update + jar("--create", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "jdk/test/baz/BazService.class", + "-C", modClasses.toString(), "jdk/test/baz/internal/BazServiceImpl.class") + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "module-info.class") + .assertSuccess(); + } + + @Test + public void servicesUpdateWithoutServiceImpl() throws IOException { + Path mp = Paths.get("servicesUpdateWithoutServiceImpl"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve("baz"); + Path modularJar = mp.resolve("baz" + ".jar"); + + // Omit service impl + jar("--create", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "jdk/test/baz/BazService.class") + .assertSuccess(); + jar("--update", + "--file=" + modularJar.toString(), + "-C", modClasses.toString(), "module-info.class") + .assertFailure(); + } + + @Test + public void printModuleDescriptorFoo() throws IOException { + Path mp = Paths.get("printModuleDescriptorFoo"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + + for (String option : new String[] {"--print-module-descriptor", "-p" }) { + jar(option, + "--file=" + modularJar.toString()) + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.contains(FOO.moduleName + "@" + FOO.version), + "Expected to find ", FOO.moduleName + "@" + FOO.version, + " in [", r.output, "]") + ); + } + } + + @Test + public void printModuleDescriptorFooFromStdin() throws IOException { + Path mp = Paths.get("printModuleDescriptorFooFromStdin"); + createTestDir(mp); + Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName); + Path modularJar = mp.resolve(FOO.moduleName + ".jar"); + + jar("--create", + "--file=" + modularJar.toString(), + "--main-class=" + FOO.mainClass, + "--module-version=" + FOO.version, + "--no-manifest", + "-C", modClasses.toString(), ".") + .assertSuccess(); + + for (String option : new String[] {"--print-module-descriptor", "-p" }) { + jarWithStdin(modularJar.toFile(), + option) + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.contains(FOO.moduleName + "@" + FOO.version), + "Expected to find ", FOO.moduleName + "@" + FOO.version, + " in [", r.output, "]") + ); + } + } + + // -- Infrastructure + + static Result jarWithStdin(File stdinSource, String... args) { + String jar = getJDKTool("jar"); + List commands = new ArrayList<>(); + commands.add(jar); + Stream.of(args).forEach(x -> commands.add(x)); + ProcessBuilder p = new ProcessBuilder(commands); + if (stdinSource != null) + p.redirectInput(stdinSource); + return run(p); + } + + static Result jar(String... args) { + return jarWithStdin(null, args); + } + + static Path compileModule(String mn) throws IOException { + return compileModule(mn, null); + } + + static Path compileModule(String mn, Path mp) + throws IOException + { + Path fooSourcePath = TEST_SRC.resolve("src").resolve(mn); + Path build = Files.createDirectories(MODULE_CLASSES.resolve(mn)); + javac(build, mp, fileList(fooSourcePath)); + return build; + } + + // Re-enable when there is support in javax.tools for module path +// static void javac(Path dest, Path... sourceFiles) throws IOException { +// out.printf("Compiling %d source files %s%n", sourceFiles.length, +// Arrays.asList(sourceFiles)); +// JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); +// try (StandardJavaFileManager fileManager = +// compiler.getStandardFileManager(null, null, null)) { +// +// List files = Stream.of(sourceFiles) +// .map(p -> p.toFile()) +// .collect(Collectors.toList()); +// List dests = Stream.of(dest) +// .map(p -> p.toFile()) +// .collect(Collectors.toList()); +// Iterable compilationUnits = +// fileManager.getJavaFileObjectsFromFiles(files); +// fileManager.setLocation(StandardLocation.CLASS_OUTPUT, dests); +// JavaCompiler.CompilationTask task = +// compiler.getTask(null, fileManager, null, null, null, compilationUnits); +// boolean passed = task.call(); +// if (!passed) +// throw new RuntimeException("Error compiling " + files); +// } +// } + + static void javac(Path dest, Path... sourceFiles) throws IOException { + javac(dest, null, sourceFiles); + } + + static void javac(Path dest, Path modulePath, Path... sourceFiles) + throws IOException + { + String javac = getJDKTool("javac"); + + List commands = new ArrayList<>(); + commands.add(javac); + commands.add("-d"); + commands.add(dest.toString()); + if (dest.toString().contains("bar")) + commands.add("-XaddExports:java.base/jdk.internal.module=bar"); + if (modulePath != null) { + commands.add("-mp"); + commands.add(modulePath.toString()); + } + Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x)); + + quickFail(run(new ProcessBuilder(commands))); + } + + static Result java(Path modulePath, String entryPoint, String... args) { + String java = getJDKTool("java"); + + List commands = new ArrayList<>(); + commands.add(java); + Stream.of(args).forEach(x -> commands.add(x)); + commands.add("-mp"); + commands.add(modulePath.toString()); + commands.add("-m"); + commands.add(entryPoint); + + return run(new ProcessBuilder(commands)); + } + + static Path[] fileList(Path directory) throws IOException { + final List filePaths = new ArrayList<>(); + Files.walkFileTree(directory, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) { + filePaths.add(file); + return FileVisitResult.CONTINUE; + } + }); + return filePaths.toArray(new Path[filePaths.size()]); + } + + static void createTestDir(Path p) throws IOException{ + if (Files.exists(p)) + FileUtils.deleteFileTreeWithRetry(p); + Files.createDirectory(p); + } + + static boolean jarContains(JarInputStream jis, String entryName) + throws IOException + { + JarEntry e; + while((e = jis.getNextJarEntry()) != null) { + if (e.getName().equals(entryName)) + return true; + } + return false; + } + + static void quickFail(Result r) { + if (r.ec != 0) + throw new RuntimeException(r.output); + } + + static Result run(ProcessBuilder pb) { + Process p; + out.printf("Running: %s%n", pb.command()); + try { + p = pb.start(); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't start process '%s'", pb.command()), e); + } + + String output; + try { + output = toString(p.getInputStream(), p.getErrorStream()); + } catch (IOException e) { + throw new RuntimeException( + format("Couldn't read process output '%s'", pb.command()), e); + } + + try { + p.waitFor(); + } catch (InterruptedException e) { + throw new RuntimeException( + format("Process hasn't finished '%s'", pb.command()), e); + } + return new Result(p.exitValue(), output); + } + + static final String DEFAULT_IMAGE_BIN = System.getProperty("java.home") + + File.separator + "bin" + File.separator; + + static String getJDKTool(String name) { + try { + return JDKToolFinder.getJDKTool(name); + } catch (Exception x) { + return DEFAULT_IMAGE_BIN + name; + } + } + + static String toString(InputStream in1, InputStream in2) throws IOException { + try (ByteArrayOutputStream dst = new ByteArrayOutputStream(); + InputStream concatenated = new SequenceInputStream(in1, in2)) { + concatenated.transferTo(dst); + return new String(dst.toByteArray(), "UTF-8"); + } + } + + static class Result { + final int ec; + final String output; + + private Result(int ec, String output) { + this.ec = ec; + this.output = output; + } + Result assertSuccess() { + assertTrue(ec == 0, "Expected ec 0, got: ", ec, " , output [", output, "]"); + return this; + } + Result assertFailure() { + assertTrue(ec != 0, "Expected ec != 0, got:", ec, " , output [", output, "]"); + return this; + } + Result resultChecker(Consumer r) { r.accept(this); return this; } + } + + static void assertTrue(boolean cond, Object ... failedArgs) { + if (cond) + return; + StringBuilder sb = new StringBuilder(); + for (Object o : failedArgs) + sb.append(o); + org.testng.Assert.assertTrue(false, sb.toString()); + } + + // Standalone entry point. + public static void main(String[] args) throws Throwable { + Basic test = new Basic(); + test.compileModules(); + for (Method m : Basic.class.getDeclaredMethods()) { + if (m.getAnnotation(Test.class) != null) { + System.out.println("Invoking " + m.getName()); + m.invoke(test); + } + } + } +} diff --git a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java new file mode 100644 index 00000000000..7d768fc15d2 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.bar; + +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Method; +import java.util.Optional; +import java.util.StringJoiner; + +import jdk.internal.module.Hasher; +import jdk.test.bar.internal.Message; + +public class Bar { + public static void main(String[] args) throws Exception { + System.out.println("message:" + Message.get()); + + ModuleDescriptor md = Bar.class.getModule().getDescriptor(); + System.out.println("nameAndVersion:" + md.toNameAndVersion()); + System.out.println("mainClass:" + md.mainClass().get()); + + Method m = ModuleDescriptor.class.getDeclaredMethod("hashes"); + m.setAccessible(true); + Optional optHashes = + (Optional) m.invoke(md); + + System.out.println("hashes:" + optHashes.get().hashFor("foo")); + + StringJoiner sj = new StringJoiner(","); + md.conceals().forEach(sj::add); + System.out.println("conceals:" + sj.toString()); + } +} diff --git a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/internal/Message.java b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/internal/Message.java new file mode 100644 index 00000000000..17cbe3a1a03 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/internal/Message.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.bar.internal; + +public class Message { + public static String get() { + return "Hello from Bar!"; + } +} diff --git a/jdk/test/tools/jar/modularJar/src/bar/module-info.java b/jdk/test/tools/jar/modularJar/src/bar/module-info.java new file mode 100644 index 00000000000..72965186eb4 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/bar/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module bar { + requires foo; +} diff --git a/jdk/test/tools/jar/modularJar/src/baz/jdk/test/baz/BazService.java b/jdk/test/tools/jar/modularJar/src/baz/jdk/test/baz/BazService.java new file mode 100644 index 00000000000..85c585fb898 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/baz/jdk/test/baz/BazService.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.baz; + +public interface BazService { + void doSomething(); +} diff --git a/jdk/test/tools/jar/modularJar/src/baz/jdk/test/baz/internal/BazServiceImpl.java b/jdk/test/tools/jar/modularJar/src/baz/jdk/test/baz/internal/BazServiceImpl.java new file mode 100644 index 00000000000..5f41732642d --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/baz/jdk/test/baz/internal/BazServiceImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.baz.internal; + +import jdk.test.baz.BazService; + +public class BazServiceImpl implements jdk.test.baz.BazService { + @Override public void doSomething() { } +} diff --git a/jdk/test/tools/jar/modularJar/src/baz/module-info.java b/jdk/test/tools/jar/modularJar/src/baz/module-info.java new file mode 100644 index 00000000000..8a35edb0bcc --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/baz/module-info.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module baz { + exports jdk.test.baz; + provides jdk.test.baz.BazService with jdk.test.baz.internal.BazServiceImpl; +} diff --git a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java new file mode 100644 index 00000000000..1cb35351b86 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/Foo.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.foo; + +import java.lang.module.ModuleDescriptor; +import java.util.StringJoiner; + +import jdk.test.foo.internal.Message; + +public class Foo { + public static void main(String[] args) { + System.out.println("message:" + Message.get()); + + ModuleDescriptor md = Foo.class.getModule().getDescriptor(); + System.out.println("nameAndVersion:" + md.toNameAndVersion()); + System.out.println("mainClass:" + md.mainClass().get()); + + StringJoiner sj = new StringJoiner(","); + md.conceals().forEach(sj::add); + System.out.println("conceals:" + sj.toString()); + } +} diff --git a/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/internal/Message.java b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/internal/Message.java new file mode 100644 index 00000000000..298a4fce0cb --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/foo/jdk/test/foo/internal/Message.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.foo.internal; + +public class Message { + public static String get() { + return "Hello World!!!"; + } +} diff --git a/jdk/test/tools/jar/modularJar/src/foo/module-info.java b/jdk/test/tools/jar/modularJar/src/foo/module-info.java new file mode 100644 index 00000000000..b46afa0b822 --- /dev/null +++ b/jdk/test/tools/jar/modularJar/src/foo/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module foo { + exports jdk.test.foo; +} diff --git a/jdk/test/tools/jimage/JImageTest.java b/jdk/test/tools/jimage/JImageTest.java new file mode 100644 index 00000000000..be1e784c070 --- /dev/null +++ b/jdk/test/tools/jimage/JImageTest.java @@ -0,0 +1,163 @@ +/* + * 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. + */ +import java.io.File; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import tests.Helper; +import tests.JImageGenerator; +import tests.JImageValidator; + +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +/* + * jimage testing. + * @test + * @summary Test jimage tool + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.jlink/jdk.tools.jlink.internal + * jdk.compiler + * @run build JImageTest + * @run build tests.* + * @run main/othervm -verbose:gc -Xmx1g JImageTest +*/ +public class JImageTest { + + public static void main(String[] args) throws Exception { + List bootClasses = new ArrayList<>(); + + FileSystem fs; + try { + fs = FileSystems.getFileSystem(URI.create("jrt:/")); + } catch (ProviderNotFoundException | FileSystemNotFoundException e) { + System.out.println("Not an image build, test skipped."); + return; + } + + // Build the set of locations expected in the Image + Consumer c = (p) -> { + // take only the .class resources. + if (Files.isRegularFile(p) && p.toString().endsWith(".class") + && !p.toString().endsWith("module-info.class")) { + String loc = p.toString().substring("/modules".length()); + bootClasses.add(loc); + } + }; + + Path javabase = fs.getPath("/modules/java.base"); + Path mgtbase = fs.getPath("/modules/java.management"); + try (Stream stream = Files.walk(javabase)) { + stream.forEach(c); + } + try (Stream stream = Files.walk(mgtbase)) { + stream.forEach(c); + } + + if (bootClasses.isEmpty()) { + throw new RuntimeException("No boot class to check against"); + } + + File jdkHome = new File(System.getProperty("test.jdk")); + // JPRT not yet ready for jmods + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run, NO jmods directory"); + return; + } + + // Generate the sample image + String module = "mod1"; + String[] classes = {module + ".Main"}; + helper.generateDefaultJModule(module, Arrays.asList(classes), "java.management"); + + Path image = helper.generateDefaultImage(module).assertSuccess(); + Path extractedDir = JImageGenerator.getJImageTask() + .dir(helper.createNewExtractedDir("modules")) + .image(image.resolve("lib").resolve("modules")) + .extract().assertSuccess(); + + Path recreatedImage = JImageGenerator.getJImageTask() + .dir(extractedDir) + .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) + .recreate().assertSuccess(); + JImageValidator.validate(recreatedImage, bootClasses, Collections.emptyList()); + + // Check replacing the boot image by recreated one + Path destFile = image.resolve("lib").resolve("modules"); + Files.copy(recreatedImage, destFile, REPLACE_EXISTING); + JImageValidator validator = new JImageValidator(module, Collections.emptyList(), + image.toFile(), Collections.emptyList(), Collections.emptyList()); + validator.validate(); + + Path recreatedImage2 = JImageGenerator.getJImageTask() + .dir(extractedDir) + .option("--compress").option("2") + .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) + .recreate().assertSuccess(); + JImageValidator.validate(recreatedImage2, bootClasses, Collections.emptyList()); + + Path recreatedImage3 = JImageGenerator.getJImageTask() + .dir(extractedDir) + .option("--strip-debug") + .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) + .recreate().assertSuccess(); + JImageValidator.validate(recreatedImage3, bootClasses, Collections.emptyList()); + + Path recreatedImage4 = JImageGenerator.getJImageTask() + .dir(extractedDir) + .option("--exclude-resources") + .option("*.jcov, */META-INF/*") + .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) + .recreate().assertSuccess(); + List unexpectedPaths = new ArrayList<>(); + unexpectedPaths.add(".jcov"); + unexpectedPaths.add("/META-INF/"); + JImageValidator.validate(recreatedImage4, bootClasses, unexpectedPaths); + + Path recreatedImage5 = JImageGenerator.getJImageTask() + .dir(extractedDir) + .option("--compress") + .option("2") + .option("--strip-debug") + .option("--exclude-resources") + .option("*.jcov, */META-INF/*") + .image(helper.createNewRecreatedDir(extractedDir.getFileName().toString())) + .recreate().assertSuccess(); + JImageValidator.validate(recreatedImage5, bootClasses, unexpectedPaths); + } +} diff --git a/jdk/test/jdk/internal/jimage/JImageTest.java b/jdk/test/tools/jimage/JImageToolTest.java similarity index 77% rename from jdk/test/jdk/internal/jimage/JImageTest.java rename to jdk/test/tools/jimage/JImageToolTest.java index 2e7ec735c94..18f22f12fb1 100644 --- a/jdk/test/jdk/internal/jimage/JImageTest.java +++ b/jdk/test/tools/jimage/JImageToolTest.java @@ -25,23 +25,21 @@ * @library /lib/testlibrary * @build jdk.testlibrary.* * @summary Test to see if jimage tool extracts and recreates correctly. - * @run main/timeout=360 JImageTest + * @run main/timeout=360 JImageToolTest */ import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import jdk.testlibrary.ProcessTools; - /** * Basic test for jimage tool. */ -public class JImageTest { +public class JImageToolTest { private static void jimage(String... jimageArgs) throws Exception { ArrayList args = new ArrayList<>(); args.add("-ms8m"); @@ -52,29 +50,27 @@ public class JImageTest { int res = builder.inheritIO().start().waitFor(); if (res != 0) { - throw new RuntimeException("JImageTest tool FAILED"); + throw new RuntimeException("JImageToolTest FAILED"); } } public static void main(String[] args) throws Exception { - final String JAVA_HOME = System.getProperty("java.home"); - Path jimagePath = Paths.get(JAVA_HOME, "bin", "jimage"); - Path bootimagePath = Paths.get(JAVA_HOME, "lib", "modules", "bootmodules.jimage"); + String home = System.getProperty("java.home"); + Path jimagePath = Paths.get(home, "bin", "jimage"); + Path modulesimagePath = Paths.get(home, "lib", "modules"); - if (Files.exists(jimagePath) && Files.exists(bootimagePath)) { + if (Files.exists(jimagePath) && Files.exists(modulesimagePath)) { String jimage = jimagePath.toAbsolutePath().toString(); - String bootimage = bootimagePath.toAbsolutePath().toString(); + String bootimage = modulesimagePath.toAbsolutePath().toString(); String extractDir = Paths.get(".", "extract").toAbsolutePath().toString(); - String recreateImage = Paths.get(".", "recreate.jimage").toAbsolutePath().toString(); - String relativeRecreateImage = Paths.get(".", "recreate2.jimage").toString(); + String recreateImage = Paths.get(".", "recreate").toAbsolutePath().toString(); + String relativeRecreateImage = Paths.get(".", "recreate2").toString(); jimage("extract", "--dir", extractDir, bootimage); jimage("recreate", "--dir", extractDir, recreateImage); jimage("recreate", "--dir", extractDir, relativeRecreateImage); - System.out.println("Test successful"); } else { - System.out.println("Test skipped, no module image"); + System.out.println("Test skipped, not an images build"); } - } } diff --git a/jdk/test/jdk/internal/jimage/VerifyJimage.java b/jdk/test/tools/jimage/VerifyJimage.java similarity index 84% rename from jdk/test/jdk/internal/jimage/VerifyJimage.java rename to jdk/test/tools/jimage/VerifyJimage.java index 406b1fb92b1..c31eb883fba 100644 --- a/jdk/test/jdk/internal/jimage/VerifyJimage.java +++ b/jdk/test/tools/jimage/VerifyJimage.java @@ -49,7 +49,6 @@ import jdk.internal.jimage.ImageLocation; * @test * @summary Verify jimage * @modules java.base/jdk.internal.jimage - * @run main/othervm VerifyJimage */ /** @@ -62,9 +61,18 @@ import jdk.internal.jimage.ImageLocation; * -Djdk.test.threads= to specify the number of threads. */ public class VerifyJimage { + private static final String MODULE_INFO = "module-info.class"; private static final Deque failed = new ConcurrentLinkedDeque<>(); public static void main(String... args) throws Exception { + + String home = System.getProperty("java.home"); + Path bootimagePath = Paths.get(home, "lib", "modules"); + if (Files.notExists(bootimagePath)) { + System.out.println("Test skipped, not an images build"); + return; + } + long start = System.nanoTime(); int numThreads = Integer.getInteger("jdk.test.threads", 1); List readers = newJImageReaders(); @@ -90,6 +98,9 @@ public class VerifyJimage { for (String f : failed) { System.err.println(f); } + if (!failed.isEmpty()) { + throw new AssertionError("Test failed"); + } } private final AtomicInteger count = new AtomicInteger(0); @@ -143,7 +154,9 @@ public class VerifyJimage { ); private void compare(Path mdir, Path p, List readers) { - String entry = mdir.relativize(p).toString().replace(File.separatorChar, '/'); + String entry = p.getFileName().toString().equals(MODULE_INFO) + ? mdir.getFileName().toString() + "/" + MODULE_INFO + : mdir.relativize(p).toString().replace(File.separatorChar, '/'); count.incrementAndGet(); String file = mdir.getFileName().toString() + "/" + entry; @@ -153,14 +166,7 @@ public class VerifyJimage { return; } - String jimage; - if (BOOT_RESOURCES.contains(file)) { - jimage = "bootmodules.jimage"; - } else if (EXT_RESOURCES.contains(file)) { - jimage = "extmodules.jimage"; - } else { - jimage = ""; - } + String jimage = "modules"; JImageReader reader = readers.stream() .filter(r -> r.findLocation(entry) != null) .filter(r -> jimage.isEmpty() || r.imageName().equals(jimage)) @@ -176,9 +182,9 @@ public class VerifyJimage { ClassLoader loader = ClassLoader.getSystemClassLoader(); for (JImageReader reader : readers) { Arrays.stream(reader.getEntryNames()) - .filter(n -> n.endsWith(".class")) + .filter(n -> n.endsWith(".class") && !n.endsWith(MODULE_INFO)) .forEach(n -> { - String cn = n.substring(0, n.length()-6).replace('/', '.'); + String cn = removeModule(n).replaceAll("\\.class$", "").replace('/', '.'); count.incrementAndGet(); try { Class.forName(cn, false, loader); @@ -189,26 +195,25 @@ public class VerifyJimage { } } + private String removeModule(String path) { + int index = path.indexOf('/', 1); + return path.substring(index + 1, path.length()); + } - private static List newJImageReaders() throws IOException { + private static List newJImageReaders() throws IOException { String home = System.getProperty("java.home"); - Path mlib = Paths.get(home, "lib", "modules"); - try (Stream paths = Files.list(mlib)) { - Set jimages = paths.filter(p -> p.toString().endsWith(".jimage")) - .collect(Collectors.toSet()); - List result = new ArrayList<>(); - for (Path jimage: jimages) { - result.add(new JImageReader(jimage)); - System.out.println("opened " + jimage); - } - return result; - } + Path jimage = Paths.get(home, "lib", "modules"); + JImageReader reader = new JImageReader(jimage); + List result = new ArrayList<>(); + System.out.println("opened " + jimage); + result.add(reader); + return result; } static class JImageReader extends BasicImageReader { final Path jimage; JImageReader(Path p) throws IOException { - super(p.toString()); + super(p); this.jimage = p; } @@ -217,12 +222,7 @@ public class VerifyJimage { } int entries() { - try { - return getHeader().getTableLength(); - } catch (IOException ex) { - failed.add(imageName() + ": can't access header"); - return 0; - } + return getHeader().getTableLength(); } void compare(String entry, Path p) { diff --git a/jdk/test/tools/jlink/CheckExecutable.java b/jdk/test/tools/jlink/CheckExecutable.java new file mode 100644 index 00000000000..45335442c4c --- /dev/null +++ b/jdk/test/tools/jlink/CheckExecutable.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015 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 + * 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 8132475 + * @summary Check that jlink creates executables in the bin directory + * that are are executable by all users + * @run main CheckExecutable + * @author Volker Simonis + */ + +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.PosixFilePermission; +import static java.nio.file.attribute.PosixFilePermission.*; +import java.util.EnumSet; +import java.util.Set; + +public class CheckExecutable { + + // The bin directory may contain non-executable files (see 8132704) + private static final String IGNORE = "glob:{*.diz,jmc.ini}"; + + public static void main(String args[]) throws IOException { + String JAVA_HOME = System.getProperty("java.home"); + Path bin = Paths.get(JAVA_HOME, "bin"); + + PathMatcher matcher = FileSystems.getDefault().getPathMatcher(IGNORE); + + try (DirectoryStream stream = Files.newDirectoryStream(bin)) { + EnumSet execPerms + = EnumSet.of(GROUP_EXECUTE, OTHERS_EXECUTE, OWNER_EXECUTE); + + for (Path entry : stream) { + Path file = entry.getFileName(); + if (!Files.isRegularFile(entry) || matcher.matches(file)) { + continue; + } + + if (!Files.isExecutable(entry)) + throw new RuntimeException(entry + " is not executable!"); + + try { + Set perm + = Files.getPosixFilePermissions(entry); + if (!perm.containsAll(execPerms)) { + throw new RuntimeException(entry + + " has not all executable permissions!\n" + + "Should have: " + execPerms + "\nbut has: " + perm); + } + } catch (UnsupportedOperationException uoe) { } + + } + + } + } +} diff --git a/jdk/test/tools/jlink/CustomPluginTest.java b/jdk/test/tools/jlink/CustomPluginTest.java new file mode 100644 index 00000000000..34e4d4b1a5e --- /dev/null +++ b/jdk/test/tools/jlink/CustomPluginTest.java @@ -0,0 +1,138 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import tests.Helper; +import tests.JImageGenerator; +import tests.Result; + +/* + * @test + * @summary Test custom plugin + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm CustomPluginTest + */ + +public class CustomPluginTest { + + public static void main(String[] args) throws Exception { + new CustomPluginTest().test(); + } + + private void test() throws Exception { + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + Path jmod = registerServices(helper); + Path pluginModulePath = jmod.getParent(); + + testHelloProvider(helper, pluginModulePath); + testCustomPlugins(helper, pluginModulePath); + } + + private void testCustomPlugins(Helper helper, Path pluginModulePath) { + Result result = JImageGenerator.getJLinkTask() + .option("--list-plugins") + .pluginModulePath(pluginModulePath) + .output(helper.createNewImageDir("customplugin")) + .call(); + if (result.getExitCode() != 0) { + System.err.println(result.getMessage()); + throw new AssertionError("jlink crashed: " + result.getExitCode()); + } + List customPlugins = Stream.of(result.getMessage().split("\n")) + .filter(s -> s.startsWith("Plugin Name:")) + .filter(s -> s.contains("custom")) + .collect(Collectors.toList()); + if (customPlugins.size() != 1) { + System.err.println(result.getMessage()); + throw new AssertionError("Found plugins: " + customPlugins); + } + } + + private Path registerServices(Helper helper) throws IOException { + String name = "customplugin"; + Path src = Paths.get(System.getProperty("test.src")).resolve(name); + Path classes = helper.getJmodClassesDir().resolve(name); + JImageGenerator.compile(src, classes, "-XaddExports:jdk.jlink/jdk.tools.jlink.internal=customplugin"); + return JImageGenerator.getJModTask() + .addClassPath(classes) + .jmod(helper.getJmodDir().resolve(name + ".jmod")) + .create().assertSuccess(); + } + + private void testHelloProvider(Helper helper, Path pluginModulePath) throws IOException { + Path pluginFile = Paths.get("customplugin.txt"); + if (Files.exists(pluginFile)) { + throw new AssertionError("Custom plugin output file already exists"); + } + String customplugin = "customplugin"; + { + // Add the path but not the option, plugin musn't be called + JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .pluginModulePath(pluginModulePath) + .output(helper.createNewImageDir(customplugin)) + .addMods(customplugin) + .call().assertSuccess(); + } + + if (Files.exists(pluginFile)) { + throw new AssertionError("Custom plugin output file exists, plugin " + + " called although shouldn't have been"); + } + + { // Add the path and the option, plugin should be called. + JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .addMods(customplugin) + .pluginModulePath(pluginModulePath) + .output(helper.createNewImageDir(customplugin)) + .option("--hello") + .call().assertSuccess(); + } + + if (!Files.exists(pluginFile)) { + throw new AssertionError("Custom plugin not called"); + } + } +} diff --git a/jdk/test/tools/jlink/DefaultProviderTest.java b/jdk/test/tools/jlink/DefaultProviderTest.java new file mode 100644 index 00000000000..22c68287d5c --- /dev/null +++ b/jdk/test/tools/jlink/DefaultProviderTest.java @@ -0,0 +1,180 @@ +/* + * 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. + */ + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.PluginException; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.TransformerPlugin; +import tests.Helper; + +/* + * @test + * @summary Test plugins enabled by default + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm DefaultProviderTest + */ +public class DefaultProviderTest { + private static final String NAME = "disable-toto"; + private final static Map expectedOptions = new HashMap<>(); + + static { + expectedOptions.put("disable-toto", "false"); + expectedOptions.put("option1", "value1"); + expectedOptions.put("option2", "value2"); + } + + private static class Custom implements TransformerPlugin { + private boolean enabled = true; + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + + @Override + public Set getState() { + return enabled ? EnumSet.of(STATE.AUTO_ENABLED, STATE.FUNCTIONAL) + : EnumSet.of(STATE.DISABLED); + } + + @Override + public void visit(Pool in, Pool out) { + if (!enabled) { + throw new PluginException(NAME + " was set"); + } + + DefaultProviderTest.isNewPluginsCalled = true; + in.visit((Pool.ModuleData content) -> { + return content; + }, out); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getDescription() { + return NAME; + } + + @Override + public boolean hasArguments() { + return true; + } + + @Override + public void configure(Map config) { + if (config.containsKey(NAME)) { + enabled = !Boolean.parseBoolean(config.get(NAME)); + } + + if (enabled) { + DefaultProviderTest.receivedOptions = config; + } else { + DefaultProviderTest.receivedOptions = null; + } + } + } + + private static boolean isNewPluginsCalled; + private static Map receivedOptions; + + private static void reset() { + isNewPluginsCalled = false; + receivedOptions = null; + } + + public static void main(String[] args) throws Exception { + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + test(helper, new Custom()); + } + + private static void test(Helper helper, Plugin plugin) throws Exception { + PluginRepository.registerPlugin(plugin); + + { + String[] userOptions = {}; + Path imageDir = helper.generateDefaultImage(userOptions, "composite2").assertSuccess(); + helper.checkImage(imageDir, "composite2", null, null); + if (!isNewPluginsCalled) { + throw new Exception("Should have been called"); + } + reset(); + } + + { + String[] userOptions = {"--disable-toto=false:option1=value1:option2=value2"}; + Path imageDir = helper.generateDefaultImage(userOptions, "composite2").assertSuccess(); + helper.checkImage(imageDir, "composite2", null, null); + if (!isNewPluginsCalled) { + throw new Exception("Should have been called"); + } + if (!receivedOptions.equals(expectedOptions)) { + throw new Exception("Optional options " + receivedOptions + " are not expected one " + + expectedOptions); + } + System.err.println("OPTIONS " + receivedOptions); + reset(); + } + + { + String[] userOptions = {"--disable-toto=true:option1=value1"}; + Path imageDir = helper.generateDefaultImage(userOptions, "composite2").assertSuccess(); + helper.checkImage(imageDir, "composite2", null, null); + if (isNewPluginsCalled) { + throw new Exception("Should not have been called"); + } + if (receivedOptions != null) { + throw new Exception("Optional options are not expected"); + } + reset(); + } + } +} diff --git a/jdk/test/tools/jlink/ImageFileCreatorTest.java b/jdk/test/tools/jlink/ImageFileCreatorTest.java new file mode 100644 index 00000000000..a674925b223 --- /dev/null +++ b/jdk/test/tools/jlink/ImageFileCreatorTest.java @@ -0,0 +1,228 @@ +/* + * 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. + */ + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteOrder; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import jdk.tools.jlink.internal.Archive; +import jdk.tools.jlink.internal.ImageFileCreator; +import jdk.tools.jlink.internal.ImagePluginStack; +import jdk.tools.jlink.plugin.ExecutableImage; +import jdk.tools.jlink.builder.ImageBuilder; +import jdk.tools.jlink.plugin.Pool; + + +/* + * @test + * @summary ImageFileCreator class test + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * java.base/jdk.internal.jimage + * @run main/othervm -verbose:gc -Xmx1g ImageFileCreatorTest + */ +public class ImageFileCreatorTest { + + private static class TestArchive implements Archive { + + private final String name; + private final List entries = new ArrayList<>(); + + private TestArchive(String name, List entries) { + this.name = name; + for (String p : entries) { + this.entries.add(new TestEntry(p, p)); + } + } + + @Override + public String moduleName() { + return name; + } + + @Override + public Stream entries() { + return entries.stream(); + } + + @Override + public Path getPath() { + return null; + } + + @Override + public void open() throws IOException { + } + + @Override + public void close() throws IOException { + } + + private class TestEntry extends Entry { + + TestEntry(String path, String name) { + super(TestArchive.this, path, name, Entry.EntryType.CLASS_OR_RESOURCE); + } + + @Override + public long size() { + return 0; + } + + @Override + public InputStream stream() throws IOException { + return new ByteArrayInputStream(new byte[0]); + } + } + } + + public static void main(String[] args) throws Exception { + + { + List entries = new ArrayList<>(); + entries.add("classes/class"); + test(entries); + } + + { + // Add an entry that is a directory, that is wrong + List entries = new ArrayList<>(); + entries.add("classes"); + entries.add("classes/class"); + test(entries); + } + + { + // Add an entry that is wrongly prefixed by / + // /bad//classes/class is the resource added + // /bad/classes/class is the metadata node built. + List entries = new ArrayList<>(); + entries.add("/classes/class"); + test(entries); + } + + { + // Trailing '/' is wrong + List entries = new ArrayList<>(); + entries.add("classes/class/"); + test(entries); + } + + { + // Too much '/' characters + List entries = new ArrayList<>(); + entries.add("classes//class/"); + test(entries); + } + + { + // Too much '/' characters + List entries = new ArrayList<>(); + entries.add("classes/////class/"); + test(entries); + } + + { + // Single '/' character + List entries = new ArrayList<>(); + entries.add("/"); + test(entries); + } + + { + // 2 '/' characters + List entries = new ArrayList<>(); + entries.add("//"); + test(entries); + } + + { + // 3 '/' characters + List entries = new ArrayList<>(); + entries.add("///"); + test(entries); + } + + { + // no character + List entries = new ArrayList<>(); + entries.add(""); + test(entries); + } + + { + // all together + List entries = new ArrayList<>(); + entries.add(""); + entries.add("///"); + entries.add("//"); + entries.add("/"); + entries.add("classes/////class/"); + entries.add("classes//class/"); + entries.add("classes/class/"); + entries.add("/classes/class"); + entries.add("classes"); + entries.add("classes/class"); + test(entries); + } + + } + + private static void test(List entries) throws Exception { + TestArchive arch = new TestArchive("bad", entries); + Set archives = new HashSet<>(); + archives.add(arch); + ImageBuilder noopBuilder = new ImageBuilder() { + + @Override + public DataOutputStream getJImageOutputStream() { + return new DataOutputStream(new ByteArrayOutputStream()); + } + + @Override + public ExecutableImage getExecutableImage() { + return null; + } + + @Override + public void storeFiles(Pool content, String bom) { + + } + + }; + + ImagePluginStack stack = new ImagePluginStack(noopBuilder, Collections.emptyList(), + null, Collections.emptyList(), ""); + + ImageFileCreator.create(archives, ByteOrder.nativeOrder(), stack); + } +} diff --git a/jdk/test/tools/jlink/ImageFilePoolTest.java b/jdk/test/tools/jlink/ImageFilePoolTest.java new file mode 100644 index 00000000000..7d35f9da8d6 --- /dev/null +++ b/jdk/test/tools/jlink/ImageFilePoolTest.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test a pool containing external files. + * @author Andrei Eremeev + * @modules jdk.jlink/jdk.tools.jlink.internal + * @run build ImageFilePoolTest + * @run main ImageFilePoolTest + */ + +import java.io.ByteArrayInputStream; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.Pool.ModuleDataType; +import jdk.tools.jlink.plugin.Pool.Visitor; + +public class ImageFilePoolTest { + public static void main(String[] args) throws Exception { + new ImageFilePoolTest().test(); + } + + public void test() throws Exception { + checkNegative(); + checkVisitor(); + } + + private static final String SUFFIX = "END"; + + private void checkVisitor() throws Exception { + Pool input = new PoolImpl(); + for (int i = 0; i < 1000; ++i) { + String module = "module" + (i / 100); + input.add(new InMemoryImageFile(module, "/" + module + "/java/class" + i, + ModuleDataType.CONFIG, "class" + i)); + } + if (input.getContent().size() != 1000) { + throw new AssertionError(); + } + Pool output = new PoolImpl(); + ResourceVisitor visitor = new ResourceVisitor(); + input.visit(visitor, output); + if (visitor.getAmountBefore() == 0) { + throw new AssertionError("Resources not found"); + } + if (visitor.getAmountBefore() != input.getContent().size()) { + throw new AssertionError("Number of visited resources. Expected: " + + visitor.getAmountBefore() + ", got: " + input.getContent().size()); + } + if (visitor.getAmountAfter() != output.getContent().size()) { + throw new AssertionError("Number of added resources. Expected: " + + visitor.getAmountAfter() + ", got: " + output.getContent().size()); + } + for (ModuleData outFile : output.getContent()) { + String path = outFile.getPath().replaceAll(SUFFIX + "$", ""); + ModuleData inFile = input.get(path); + if (inFile == null) { + throw new AssertionError("Unknown resource: " + path); + } + } + } + + private static class ResourceVisitor implements Visitor { + + private int amountBefore; + private int amountAfter; + + @Override + public ModuleData visit(ModuleData file) { + int index = ++amountBefore % 3; + switch (index) { + case 0: + ++amountAfter; + return new InMemoryImageFile(file.getModule(), file.getPath() + SUFFIX, + file.getType(), file.getPath()); + case 1: + ++amountAfter; + return new InMemoryImageFile(file.getModule(), file.getPath(), + file.getType(), file.getPath()); + } + return null; + } + + public int getAmountAfter() { + return amountAfter; + } + + public int getAmountBefore() { + return amountBefore; + } + } + + private void checkNegative() throws Exception { + PoolImpl input = new PoolImpl(); + try { + input.add(null); + throw new AssertionError("NullPointerException is not thrown"); + } catch (NullPointerException e) { + // expected + } + try { + input.contains(null); + throw new AssertionError("NullPointerException is not thrown"); + } catch (NullPointerException e) { + // expected + } + if (input.get("unknown") != null) { + throw new AssertionError("ImageFilePool does not return null for unknown file"); + } + if (input.contains(new InMemoryImageFile("", "unknown", ModuleDataType.CONFIG, "unknown"))) { + throw new AssertionError("'contain' returns true for unknown file"); + } + input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleDataType.CONFIG, "")); + try { + input.add(new InMemoryImageFile("", "/aaa/bbb", ModuleDataType.CONFIG, "")); + throw new AssertionError("Exception expected"); + } catch (Exception e) { + // expected + } + input.setReadOnly(); + try { + input.add(new InMemoryImageFile("", "/aaa/ccc", ModuleDataType.CONFIG, "")); + throw new AssertionError("Exception expected"); + } catch (Exception e) { + // expected + } + } + + private static class InMemoryImageFile extends ModuleData { + public InMemoryImageFile(String module, String path, ModuleDataType type, String content) { + super(module, path, type, new ByteArrayInputStream(content.getBytes()), content.getBytes().length); + } + } +} diff --git a/jdk/test/tools/jlink/IntegrationTest.java b/jdk/test/tools/jlink/IntegrationTest.java new file mode 100644 index 00000000000..05c61207b7d --- /dev/null +++ b/jdk/test/tools/jlink/IntegrationTest.java @@ -0,0 +1,376 @@ +/* + * 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. + */ + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import jdk.tools.jlink.Jlink; +import jdk.tools.jlink.Jlink.JlinkConfiguration; +import jdk.tools.jlink.Jlink.PluginsConfiguration; +import jdk.tools.jlink.builder.DefaultImageBuilder; +import jdk.tools.jlink.plugin.ExecutableImage; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.PostProcessorPlugin; +import jdk.tools.jlink.plugin.TransformerPlugin; +import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin; +import jdk.tools.jlink.internal.plugins.StripDebugPlugin; +import jdk.tools.jlink.plugin.Plugin; + +import tests.Helper; +import tests.JImageGenerator; + +/* + * @test + * @summary Test integration API + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main IntegrationTest + */ +public class IntegrationTest { + + private static final List ordered = new ArrayList<>(); + + public static class MyPostProcessor implements PostProcessorPlugin { + + public static final String NAME = "mypostprocessor"; + + @Override + public List process(ExecutableImage image) { + try { + Files.createFile(image.getHome().resolve("toto.txt")); + return null; + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + @Override + public String getName() { + return NAME; + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.PROCESSOR); + return Collections.unmodifiableSet(set); + } + + @Override + public void configure(Map config) { + throw new UnsupportedOperationException("Shouldn't be called"); + } + } + + public static class MyPlugin1 implements TransformerPlugin { + + Integer index; + Set after; + Set before; + + private MyPlugin1(Integer index, Set after, Set before) { + this.index = index; + this.after = after; + this.before = before; + } + + @Override + public Set isAfter() { + return after; + } + + @Override + public Set isBefore() { + return before; + } + + @Override + public String getName() { + return NAME + index; + } + + @Override + public void visit(Pool in, Pool out) { + System.err.println(NAME + index); + ordered.add(index); + in.visit((file) -> { + return file; + }, out); + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String getOption() { + return null; + } + static final String NAME = "myprovider"; + static final String INDEX = "INDEX"; + + @Override + public void configure(Map config) { + throw new UnsupportedOperationException("Shouldn't be called"); + } + } + + public static void main(String[] args) throws Exception { + + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + apitest(); + test(); + testOrder(); + testCycleOrder(); + } + + private static void apitest() throws Exception { + boolean failed = false; + Jlink jl = new Jlink(); + + try { + jl.build(null); + failed = true; + } catch (Exception ex) { + // XXX OK + } + if (failed) { + throw new Exception("Should have failed"); + } + System.out.println(jl); + + JlinkConfiguration config + = new JlinkConfiguration(null, null, null, null); + + System.out.println(config); + + Plugin p = Jlink.newPlugin("toto", Collections.emptyMap(), null); + if (p != null) { + throw new Exception("Plugin should be null"); + } + + Plugin p2 = Jlink.newPlugin("compress", Collections.emptyMap(), null); + if (p2 == null) { + throw new Exception("Plugin should not be null"); + } + } + + private static void test() throws Exception { + Jlink jlink = new Jlink(); + Path output = Paths.get("integrationout"); + List modulePaths = new ArrayList<>(); + File jmods + = JImageGenerator.getJModsDir(new File(System.getProperty("test.jdk"))); + modulePaths.add(jmods.toPath()); + Set mods = new HashSet<>(); + mods.add("java.management"); + Set limits = new HashSet<>(); + limits.add("java.management"); + JlinkConfiguration config = new Jlink.JlinkConfiguration(output, + modulePaths, mods, limits, null); + + List lst = new ArrayList<>(); + + //Strip debug + { + Map config1 = new HashMap<>(); + config1.put(StripDebugPlugin.NAME, ""); + Plugin strip = Jlink.newPlugin("strip-debug", config1, null); + lst.add(strip); + } + // compress + { + Map config1 = new HashMap<>(); + config1.put(DefaultCompressPlugin.NAME, "2"); + Plugin compress + = Jlink.newPlugin("compress", config1, null); + lst.add(compress); + } + // Post processor + { + lst.add(new MyPostProcessor()); + } + // Image builder + DefaultImageBuilder builder = new DefaultImageBuilder(true, output); + PluginsConfiguration plugins + = new Jlink.PluginsConfiguration(lst, builder, null); + + jlink.build(config, plugins); + + if (!Files.exists(output)) { + throw new AssertionError("Directory not created"); + } + File jimage = new File(output.toString(), "lib" + File.separator + "modules"); + if (!jimage.exists()) { + throw new AssertionError("jimage not generated"); + } + File bom = new File(output.toString(), "bom"); + if (!bom.exists()) { + throw new AssertionError("bom not generated"); + } + File release = new File(output.toString(), "release"); + if (!release.exists()) { + throw new AssertionError("release not generated"); + } + + if (!Files.exists(output.resolve("toto.txt"))) { + throw new AssertionError("Post processing not called"); + } + + } + + private static void testOrder() throws Exception { + Jlink jlink = new Jlink(); + Path output = Paths.get("integrationout2"); + List modulePaths = new ArrayList<>(); + File jmods + = JImageGenerator.getJModsDir(new File(System.getProperty("test.jdk"))); + modulePaths.add(jmods.toPath()); + Set mods = new HashSet<>(); + mods.add("java.management"); + Set limits = new HashSet<>(); + limits.add("java.management"); + JlinkConfiguration config = new Jlink.JlinkConfiguration(output, + modulePaths, mods, limits, null); + + List lst = new ArrayList<>(); + + // Order is Plug1>Plug2>Plug3 + // Plug1 + + + // TRANSFORMER 3, must be after 2. + { + Set after = new HashSet<>(); + after.add(MyPlugin1.NAME+"2"); + lst.add(new MyPlugin1(3, after, Collections.emptySet())); + } + + // TRANSFORMER 2, must be after 1. + { + Set after = new HashSet<>(); + after.add(MyPlugin1.NAME+"1"); + lst.add(new MyPlugin1(2, after, Collections.emptySet())); + } + + // TRANSFORMER 1 + { + Set before = new HashSet<>(); + before.add(MyPlugin1.NAME+"2"); + lst.add(new MyPlugin1(1, Collections.emptySet(), before)); + } + + // Image builder + DefaultImageBuilder builder = new DefaultImageBuilder(false, output); + PluginsConfiguration plugins + = new Jlink.PluginsConfiguration(lst, builder, null); + + jlink.build(config, plugins); + + if (ordered.isEmpty()) { + throw new AssertionError("Plugins not called"); + } + List clone = new ArrayList<>(); + clone.addAll(ordered); + Collections.sort(clone); + if (!clone.equals(ordered)) { + throw new AssertionError("Ordered is not properly sorted" + ordered); + } + } + + private static void testCycleOrder() throws Exception { + Jlink jlink = new Jlink(); + Path output = Paths.get("integrationout3"); + List modulePaths = new ArrayList<>(); + File jmods + = JImageGenerator.getJModsDir(new File(System.getProperty("test.jdk"))); + modulePaths.add(jmods.toPath()); + Set mods = new HashSet<>(); + mods.add("java.management"); + Set limits = new HashSet<>(); + limits.add("java.management"); + JlinkConfiguration config = new Jlink.JlinkConfiguration(output, + modulePaths, mods, limits, null); + + List lst = new ArrayList<>(); + + // packager 1 + { + Set before = new HashSet<>(); + before.add(MyPlugin1.NAME+"2"); + lst.add(new MyPlugin1(1, Collections.emptySet(), before)); + } + + // packager 2 + { + Set before = new HashSet<>(); + before.add(MyPlugin1.NAME+"1"); + lst.add(new MyPlugin1(2, Collections.emptySet(), before)); + } + + // Image builder + DefaultImageBuilder builder = new DefaultImageBuilder(false, output); + PluginsConfiguration plugins + = new Jlink.PluginsConfiguration(lst, builder, null); + boolean failed = false; + try { + jlink.build(config, plugins); + failed = true; + } catch (Exception ex) { + // XXX OK + } + if (failed) { + throw new AssertionError("Should have failed"); + } + } +} diff --git a/jdk/test/tools/jlink/JLink2Test.java b/jdk/test/tools/jlink/JLink2Test.java new file mode 100644 index 00000000000..4e08a8146be --- /dev/null +++ b/jdk/test/tools/jlink/JLink2Test.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @summary Test image creation + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm -verbose:gc -Xmx1g JLink2Test + */ +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Layer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.plugin.Plugin; + +import tests.Helper; +import tests.JImageGenerator; +import tests.JImageValidator; + +public class JLink2Test { + + public static void main(String[] args) throws Exception { + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + + // This test case must be first one, the JlinkTask is clean + // and reveals possible bug related to plugin options in defaults + // e. g.: --genbom + testBomFile(helper); + testSameNames(helper); + testModulePath(helper); + testOptions(); + } + + private static void testModulePath(Helper helper) throws IOException { + Path doesNotExist = helper.createNewImageDir("doesnotexist"); + Path jar = helper.getJarDir().resolve("bad.jar"); + JImageGenerator.getJLinkTask() + .pluginModulePath(doesNotExist) + .option("--help") + .call().assertSuccess(); + Files.createFile(jar); + JImageGenerator.getJLinkTask() + .pluginModulePath(jar) + .option("--help") + .call().assertFailure("(\n|\r|.)*Error: Invalid modules in the plugins path: (\n|\r|.)*"); + JImageGenerator.getJLinkTask() + .pluginModulePath(jar.getParent()) + .option("--help") + .call().assertFailure("Error: Invalid modules in the plugins path: .*zip file is empty(\n|\r|.)*"); + try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar.toFile()))) { + JarEntry entry = new JarEntry("class"); + out.putNextEntry(entry); + out.write("AAAA".getBytes()); + out.closeEntry(); + } + JImageGenerator.getJLinkTask() + .pluginModulePath(jar.getParent()) + .output(helper.createNewImageDir("crash")) + .addJmods(helper.getStdJmodsDir()) + .addJmods(jar.getParent()) + .addMods("bad") + .call().assertFailure("(\n|\r|.)*Error: jdk.tools.jlink.plugin.PluginException: module-info.class not found for bad module(\n|\r|.)*"); + try (JarOutputStream out = new JarOutputStream(new FileOutputStream(jar.toFile()))) { + JarEntry entry = new JarEntry("classes"); + out.putNextEntry(entry); + out.closeEntry(); + + entry = new JarEntry("classes/class"); + out.putNextEntry(entry); + out.write("AAAA".getBytes()); + out.closeEntry(); + } + JImageGenerator.getJLinkTask() + .pluginModulePath(jar.getParent()) + .output(helper.createNewImageDir("bad")) + .addJmods(jar.getParent()) + .addJars(helper.getStdJmodsDir()) + .addMods("bad") + .call().assertFailure("(\n|\r|.)*Error: jdk.tools.jlink.plugin.PluginException: module-info.class not found for bad module(\n|\r|.)*"); + } + + private static void testSameNames(Helper helper) throws Exception { + // Multiple modules with the same name in modulepath, take the first one in the path. + // First jmods then jars. So jmods are found, jars are hidden. + String[] jarClasses = {"amodule.jar.Main"}; + String[] jmodsClasses = {"amodule.jmods.Main"}; + helper.generateDefaultJarModule("amodule", Arrays.asList(jarClasses)); + helper.generateDefaultJModule("amodule", Arrays.asList(jmodsClasses)); + List okLocations = new ArrayList<>(); + okLocations.addAll(Helper.toLocation("amodule", Arrays.asList(jmodsClasses))); + Path image = helper.generateDefaultImage(new String[0], "amodule").assertSuccess(); + JImageValidator validator = new JImageValidator("amodule", okLocations, + image.toFile(), Collections.emptyList(), Collections.emptyList()); + validator.validate(); + } + + private static void testBomFile(Helper helper) throws Exception { + String[] userOptions = { + "--compress", + "2", + "--addmods", + "bomzip", + "--strip-debug", + "--genbom", + "--exclude-resources", + "*.jcov,*/META-INF/*"}; + String moduleName = "bomzip"; + helper.generateDefaultJModule(moduleName, "composite2"); + Path imgDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imgDir, moduleName, userOptions, null, null); + File bom = new File(imgDir.toFile(), "bom"); + if (!bom.exists()) { + throw new RuntimeException(bom.getAbsolutePath() + " not generated"); + } + String bomcontent = new String(Files.readAllBytes(bom.toPath())); + if (!bomcontent.contains("--strip-debug") + || !bomcontent.contains("--compress") + || !bomcontent.contains("--genbom") + || !bomcontent.contains("--exclude-resources *.jcov," + + "*/META-INF/*") + || !bomcontent.contains("--addmods bomzip")) { + throw new Exception("Not expected content in " + bom); + } + } + + private static void testOptions() throws Exception { + List builtInPlugins = new ArrayList<>(); + builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); + if(builtInPlugins.isEmpty()) { + throw new Exception("No builtin plugins"); + } + List options = new ArrayList<>(); + for (Plugin p : builtInPlugins) { + if (p.getOption() == null) { + throw new Exception("Null option for " + p.getName()); + } + if (options.contains(p.getName())) { + throw new Exception("Option " + p.getOption() + " used more than once"); + } + options.add(p.getName()); + } + } +} diff --git a/jdk/test/tools/jlink/JLinkNegativeTest.java b/jdk/test/tools/jlink/JLinkNegativeTest.java new file mode 100644 index 00000000000..4a1dcf117fe --- /dev/null +++ b/jdk/test/tools/jlink/JLinkNegativeTest.java @@ -0,0 +1,355 @@ +/** + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Negative tests for jlink + * @bug 8130861 + * @author Andrei Eremeev + * @library ../lib + * @modules java.base/jdk.internal.jimage + * java.base/jdk.internal.module + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run testng JLinkNegativeTest + */ + +import java.io.IOException; +import java.io.OutputStream; +import java.lang.module.ModuleDescriptor; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import jdk.internal.module.ModuleInfoWriter; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import tests.Helper; +import tests.JImageGenerator; +import tests.JImageGenerator.InMemoryFile; +import tests.Result; + +@Test +public class JLinkNegativeTest { + + private Helper helper; + + @BeforeClass + public void setUp() throws IOException { + helper = Helper.newHelper(); + if (helper == null) { + throw new SkipException("Not run"); + } + helper.generateDefaultModules(); + } + + private void deleteDirectory(Path dir) throws IOException { + Files.walkFileTree(dir, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + public void testModuleNotExist() { + helper.generateDefaultImage("failure1").assertFailure("Error: Module failure1 not found"); + } + + public void testNotExistInAddMods() { + // cannot find jmod from --addmods + JImageGenerator.getJLinkTask() + .modulePath(".") + .addMods("not_exist") + .output(helper.getImageDir().resolve("failure2")) + .call().assertFailure("Error: Module not_exist not found"); + } + + public void test() throws IOException { + helper.generateDefaultJModule("failure3"); + Path image = helper.generateDefaultImage("failure3").assertSuccess(); + JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(image) + .addMods("leaf1") + .limitMods("leaf1") + .call().assertFailure("Error: directory already exists: .*failure3.image(\n|\r|.)*"); + } + + public void testOutputIsFile() throws IOException { + // output == file + Path image = helper.createNewImageDir("failure4"); + Files.createFile(image); + JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(image) + .addMods("leaf1") + .call().assertFailure("Error: directory already exists: .*failure4.image(\n|\r|.)*"); + } + + public void testModuleNotFound() { + // limit module is not found + Path imageFile = helper.createNewImageDir("test"); + JImageGenerator.getJLinkTask() + .output(imageFile) + .addMods("leaf1") + .limitMods("leaf1") + .limitMods("failure5") + .modulePath(helper.defaultModulePath()) + .call().assertFailure("Error: Module failure5 not found"); + } + + public void testJmodIsDir() throws IOException { + Path imageFile = helper.createNewImageDir("test"); + Path dirJmod = helper.createNewJmodFile("dir"); + Files.createDirectory(dirJmod); + try { + JImageGenerator.getJLinkTask() + .output(imageFile) + .addMods("dir") + .modulePath(helper.defaultModulePath()) + .call().assertFailure("Error: Module dir not found"); + } finally { + deleteDirectory(dirJmod); + } + } + + public void testJarIsDir() throws IOException { + Path imageFile = helper.createNewImageDir("test"); + Path dirJar = helper.createNewJarFile("dir"); + Files.createDirectory(dirJar); + try { + JImageGenerator.getJLinkTask() + .output(imageFile) + .addMods("dir") + .modulePath(helper.defaultModulePath()) + .call().assertFailure("Error: Module dir not found"); + } finally { + deleteDirectory(dirJar); + } + } + + public void testMalformedJar() throws IOException { + Path imageFile = helper.createNewImageDir("test"); + Path jar = helper.createNewJarFile("not_zip"); + Files.createFile(jar); + try { + JImageGenerator.getJLinkTask() + .output(imageFile) + .addMods("not_zip") + .modulePath(helper.defaultModulePath()) + .call().assertFailure("Error: java.util.zip.ZipException: zip file is empty"); + } finally { + deleteDirectory(jar); + } + } + + public void testMalformedJmod() throws IOException { + Path imageFile = helper.createNewImageDir("test"); + Path jmod = helper.createNewJmodFile("not_zip"); + Files.createFile(jmod); + try { + JImageGenerator.getJLinkTask() + .output(imageFile) + .addMods("not_zip") + .modulePath(helper.defaultModulePath()) + .call().assertFailure("Error: java.util.zip.ZipException: zip file is empty"); + } finally { + deleteDirectory(jmod); + } + } + + // Temporarily exclude; the jmod tool can no longer be used to create a jmod + // with a class in the unnamed package. Find another way, or remove. +// public void testAddDefaultPackage() throws IOException { +// String moduleName = "hacked1"; +// Path module = helper.generateModuleCompiledClasses(helper.getJmodSrcDir(), helper.getJmodClassesDir(), +// moduleName, Arrays.asList("hacked1.Main", "A", "B"), "leaf1"); +// JImageGenerator +// .getJModTask() +// .addClassPath(module) +// .jmod(helper.getJmodDir().resolve(moduleName + ".jmod")) +// .create().assertSuccess(); +// Path image = helper.generateDefaultImage(moduleName).assertSuccess(); +// helper.checkImage(image, moduleName, null, null); +// } + + public void testAddSomeTopLevelFiles() throws IOException { + String moduleName = "hacked2"; + Path module = helper.generateModuleCompiledClasses(helper.getJmodSrcDir(), helper.getJmodClassesDir(), + moduleName); + Files.createFile(module.resolve("top-level-file")); + Path jmod = JImageGenerator + .getJModTask() + .addClassPath(module) + .jmod(helper.getJmodDir().resolve(moduleName + ".jmod")) + .create().assertSuccess(); + try { + Path image = helper.generateDefaultImage(moduleName).assertSuccess(); + helper.checkImage(image, moduleName, null, null); + } finally { + deleteDirectory(jmod); + } + } + + public void testAddNonStandardSection() throws IOException { + String moduleName = "hacked3"; + Path module = helper.generateDefaultJModule(moduleName).assertSuccess(); + JImageGenerator.addFiles(module, new InMemoryFile("unknown/A.class", new byte[0])); + try { + Result result = helper.generateDefaultImage(moduleName); + if (result.getExitCode() != 4) { + throw new AssertionError("Crash expected"); + } + if (!result.getMessage().contains("java.lang.InternalError: unexpected entry: unknown")) { + System.err.println(result.getMessage()); + throw new AssertionError("InternalError expected"); + } + } finally { + deleteDirectory(module); + } + } + + @Test(enabled = true) + public void testSectionsAreFiles() throws IOException { + String moduleName = "module"; + Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); + JImageGenerator.addFiles(jmod, + new InMemoryFile("/native", new byte[0]), + new InMemoryFile("/conf", new byte[0]), + new InMemoryFile("/bin", new byte[0])); + try { + Result result = helper.generateDefaultImage(moduleName); + if (result.getExitCode() != 4) { + throw new AssertionError("Crash expected"); + } + if (!result.getMessage().contains("java.lang.InternalError: unexpected entry: ")) { + System.err.println(result.getMessage()); + throw new AssertionError("InternalError expected"); + } + } finally { + deleteDirectory(jmod); + } + } + + public void testDuplicateModule1() throws IOException { + String moduleName1 = "dupRes1Jmod1"; + String moduleName2 = "dupRes1Jmod2"; + List classNames = Arrays.asList("java.A", "javax.B"); + Path module1 = helper.generateModuleCompiledClasses( + helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName1, classNames); + Path module2 = helper.generateModuleCompiledClasses( + helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName2, classNames); + + try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { + ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1) + .requires("java.base").build(), out); + } + + Path jmod1 = JImageGenerator.getJModTask() + .addClassPath(module1) + .jmod(helper.createNewJmodFile(moduleName1)) + .create() + .assertSuccess(); + Path jmod2 = JImageGenerator.getJModTask() + .addClassPath(module2) + .jmod(helper.createNewJmodFile(moduleName2)) + .create() + .assertSuccess(); + try { + helper.generateDefaultImage(moduleName1) + .assertFailure("Error: Two versions of module dupRes1Jmod1 found in"); + } finally { + deleteDirectory(jmod1); + deleteDirectory(jmod2); + } + } + + public void testDuplicateModule2() throws IOException { + String moduleName = "dupRes2Jmod"; + List classNames = Arrays.asList("java.A", "javax.B"); + Path module1 = helper.generateModuleCompiledClasses( + helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName, classNames); + Path module2 = helper.generateModuleCompiledClasses( + helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName, classNames); + + Path jmod = JImageGenerator.getJModTask() + .addClassPath(module1) + .jmod(helper.createNewJmodFile(moduleName)) + .create() + .assertSuccess(); + Path jar = JImageGenerator.createJarFile(helper.getJarDir().resolve(moduleName + ".jar"), module2); + Path newJar = helper.getJmodDir().resolve(jar.getFileName()); + Files.move(jar, newJar); + try { + helper.generateDefaultImage(moduleName) + .assertFailure("Error: Two versions of module dupRes2Jmod found in"); + } finally { + deleteDirectory(jmod); + deleteDirectory(newJar); + } + } + + public void testDuplicateModule3() throws IOException { + String moduleName1 = "dupRes3Jar1"; + String moduleName2 = "dupRes3Jar2"; + List classNames = Arrays.asList("java.A", "javax.B"); + Path module1 = helper.generateModuleCompiledClasses( + helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName1, classNames); + Path module2 = helper.generateModuleCompiledClasses( + helper.getJarSrcDir(), helper.getJarClassesDir(), moduleName2, classNames); + + try (OutputStream out = Files.newOutputStream(module2.resolve("module-info.class"))) { + ModuleInfoWriter.write(new ModuleDescriptor.Builder(moduleName1) + .requires("java.base").build(), out); + } + + Path jar1 = JImageGenerator.createJarFile(helper.getJarDir().resolve(moduleName1 + ".jar"), module1); + Path jar2 = JImageGenerator.createJarFile(helper.getJarDir().resolve(moduleName2 + ".jar"), module2); + try { + helper.generateDefaultImage(moduleName1) + .assertFailure("Error: Two versions of module dupRes3Jar1 found in"); + } finally { + deleteDirectory(jar1); + deleteDirectory(jar2); + } + } +} diff --git a/jdk/test/tools/jlink/JLinkOptimTest.java b/jdk/test/tools/jlink/JLinkOptimTest.java new file mode 100644 index 00000000000..82c5431f034 --- /dev/null +++ b/jdk/test/tools/jlink/JLinkOptimTest.java @@ -0,0 +1,374 @@ + +import java.lang.reflect.Method; +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.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode; +import jdk.internal.org.objectweb.asm.tree.ClassNode; +import jdk.internal.org.objectweb.asm.tree.MethodInsnNode; +import jdk.internal.org.objectweb.asm.tree.MethodNode; +import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.plugins.OptimizationPlugin; +import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; +import jdk.tools.jlink.internal.plugins.asm.AsmPlugin; +import jdk.tools.jlink.internal.plugins.asm.AsmPools; +import jdk.tools.jlink.internal.plugins.optim.ControlFlow; +import jdk.tools.jlink.internal.plugins.optim.ControlFlow.Block; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +import tests.Helper; +import tests.JImageGenerator; + +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @summary Test image creation with class optimization + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.jlink/jdk.tools.jlink.internal.plugins + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * jdk.jlink/jdk.tools.jlink.internal.plugins.optim + * java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * java.base/jdk.internal.org.objectweb.asm.util + * jdk.compiler + * @build tests.* + * @run main JLinkOptimTest + */ +public class JLinkOptimTest { + + private static final String EXPECTED = "expected"; + private static Helper helper; + + public static class ControlFlowPlugin extends AsmPlugin { + + private boolean called; + private int numMethods; + private int numBlocks; + + private static final String NAME = "test-optim"; + + private ControlFlowPlugin() { + } + + @Override + public void visit(AsmPools pools) { + called = true; + for (AsmModulePool p : pools.getModulePools()) { + + p.visitClassReaders((reader) -> { + ClassNode cn = new ClassNode(); + if ((reader.getAccess() & Opcodes.ACC_INTERFACE) == 0) { + reader.accept(cn, ClassReader.EXPAND_FRAMES); + for (MethodNode m : cn.methods) { + if ((m.access & Opcodes.ACC_ABSTRACT) == 0 + && (m.access & Opcodes.ACC_NATIVE) == 0) { + numMethods += 1; + try { + ControlFlow f + = ControlFlow.createControlFlow(cn.name, m); + for (Block b : f.getBlocks()) { + numBlocks += 1; + f.getClosure(b); + } + } catch (Throwable ex) { + //ex.printStackTrace(); + throw new RuntimeException("Exception in " + + cn.name + "." + m.name, ex); + } + } + } + } + return null; + }); + } + } + + @Override + public String getName() { + return NAME; + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + } + + private static void testForName() throws Exception { + String moduleName = "optimplugin"; + Path src = Paths.get(System.getProperty("test.src")).resolve(moduleName); + Path classes = helper.getJmodClassesDir().resolve(moduleName); + JImageGenerator.compile(src, classes); + + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path root = fs.getPath("/modules/java.base"); + // Access module-info.class to be reused as fake module-info.class + List javabaseResources = new ArrayList<>(); + try (Stream stream = Files.walk(root)) { + for (Iterator iterator = stream.iterator(); iterator.hasNext();) { + Path p = iterator.next(); + if (Files.isRegularFile(p)) { + try { + javabaseResources.add(Pool.newResource(p.toString(). + substring("/modules".length()), Files.readAllBytes(p))); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } + } + + //forName folding + PoolImpl pool = new PoolImpl(); + byte[] content = Files.readAllBytes(classes. + resolve("optim").resolve("ForNameTestCase.class")); + byte[] content2 = Files.readAllBytes(classes. + resolve("optim").resolve("AType.class")); + byte[] mcontent = Files.readAllBytes(classes.resolve("module-info.class")); + + pool.add(Pool.newResource("/optimplugin/optim/ForNameTestCase.class", content)); + pool.add(Pool.newResource("/optimplugin/optim/AType.class", content2)); + pool.add(Pool.newResource("/optimplugin/module-info.class", mcontent)); + + for (ModuleData r : javabaseResources) { + pool.add(r); + } + + OptimizationPlugin plugin = new OptimizationPlugin(); + Map optional = new HashMap<>(); + optional.put(OptimizationPlugin.NAME, OptimizationPlugin.FORNAME_REMOVAL); + optional.put(OptimizationPlugin.LOG, "forName.log"); + plugin.configure(optional); + Pool out = new PoolImpl(); + plugin.visit(pool, out); + + ModuleData result = out.getContent().iterator().next(); + + ClassReader optimReader = new ClassReader(result.getBytes()); + ClassNode optimClass = new ClassNode(); + optimReader.accept(optimClass, ClassReader.EXPAND_FRAMES); + + if (!optimClass.name.equals("optim/ForNameTestCase")) { + throw new Exception("Invalid class " + optimClass.name); + } + if (optimClass.methods.size() < 2) { + throw new Exception("Not enough methods in new class"); + } + for (MethodNode mn : optimClass.methods) { + if (!mn.name.contains("forName") && !mn.name.contains("")) { + continue; + } + if (mn.name.startsWith("negative")) { + checkForName(mn); + } else { + checkNoForName(mn); + } + } + Map newClasses = new HashMap<>(); + newClasses.put("optim.ForNameTestCase", result.getBytes()); + newClasses.put("optim.AType", content2); + MemClassLoader loader = new MemClassLoader(newClasses); + Class loaded = loader.loadClass("optim.ForNameTestCase"); + if (loaded.getDeclaredMethods().length < 2) { + throw new Exception("Not enough methods in new class"); + } + for (Method m : loaded.getDeclaredMethods()) { + if (m.getName().contains("Exception")) { + try { + m.invoke(null); + } catch (Exception ex) { + //ex.getCause().printStackTrace(); + if (!ex.getCause().getMessage().equals(EXPECTED)) { + throw new Exception("Unexpected exception " + ex); + } + } + } else if (!m.getName().startsWith("negative")) { + Class clazz = (Class) m.invoke(null); + if (clazz != String.class && clazz != loader.findClass("optim.AType")) { + throw new Exception("Invalid class " + clazz); + } + } + } + } + + private static void checkNoForName(MethodNode m) throws Exception { + Iterator it = m.instructions.iterator(); + while (it.hasNext()) { + AbstractInsnNode n = it.next(); + if (n instanceof MethodInsnNode) { + MethodInsnNode met = (MethodInsnNode) n; + if (met.name.equals("forName") + && met.owner.equals("java/lang/Class") + && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { + throw new Exception("forName not removed in " + m.name); + } + } + } + for (TryCatchBlockNode tcb : m.tryCatchBlocks) { + if (tcb.type.equals(ClassNotFoundException.class.getName().replaceAll("\\.", "/"))) { + throw new Exception("ClassNotFoundException Block not removed for " + m.name); + } + } + } + + private static void checkForName(MethodNode m) throws Exception { + Iterator it = m.instructions.iterator(); + boolean found = false; + while (it.hasNext()) { + AbstractInsnNode n = it.next(); + if (n instanceof MethodInsnNode) { + MethodInsnNode met = (MethodInsnNode) n; + if (met.name.equals("forName") + && met.owner.equals("java/lang/Class") + && met.desc.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { + found = true; + break; + } + } + } + if (!found) { + throw new Exception("forName removed but shouldn't have"); + } + found = false; + for (TryCatchBlockNode tcb : m.tryCatchBlocks) { + if (tcb.type.equals(ClassNotFoundException.class.getName().replaceAll("\\.", "/"))) { + found = true; + break; + } + } + if (!found) { + throw new Exception("tryCatchBlocks removed but shouldn't have"); + } + } + + static class MemClassLoader extends ClassLoader { + + private final Map classes; + private final Map> cache = new HashMap<>(); + + MemClassLoader(Map classes) { + super(null); + this.classes = classes; + } + + @Override + public Class findClass(String name) throws ClassNotFoundException { + Class clazz = cache.get(name); + if (clazz == null) { + byte[] b = classes.get(name); + if (b == null) { + return super.findClass(name); + } else { + clazz = defineClass(name, b, 0, b.length); + cache.put(name, clazz); + } + } + return clazz; + } + } + + public static void main(String[] args) throws Exception { + helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + + testForName(); + + helper.generateDefaultModules(); + helper.generateDefaultJModule("optim1", "java.se"); + { + String[] userOptions = {"--class-optim=all:log=./class-optim-log.txt"}; + + Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess(); + helper.checkImage(imageDir, "optim1", null, null); + } + + /*{ + Path dir = Paths.get("dir.log"); + Files.createDirectory(dir); + String[] userOptions = {"--class-optim=all:log=" + dir.toString()}; + helper.generateDefaultImage(userOptions, "optim1") + .assertFailure("java.io.FileNotFoundException: dir.log (Is a directory)"); + }*/ + /*{ + String[] userOptions = {"--class-optim", "UNKNOWN"}; + helper.generateDefaultImage(userOptions, "optim1").assertFailure("Unknown optimization"); + }*/ + { + String[] userOptions = {"--class-optim=forName-folding:log=./class-optim-log.txt"}; + Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess(); + helper.checkImage(imageDir, "optim1", null, null); + } + + { + ControlFlowPlugin plugin = new ControlFlowPlugin(); + PluginRepository.registerPlugin(plugin); + String[] userOptions = {"--test-optim"}; + Path imageDir = helper.generateDefaultImage(userOptions, "optim1").assertSuccess(); + helper.checkImage(imageDir, "optim1", null, null); + //System.out.println("Num methods analyzed " + provider.numMethods + // + "num blocks " + provider.numBlocks); + if (!plugin.called) { + throw new Exception("Plugin not called"); + } + if (plugin.numMethods < 1000) { + throw new Exception("Not enough method called, should be " + + "around 10000 but is " + plugin.numMethods); + } + if (plugin.numBlocks < 100000) { + throw new Exception("Not enough blocks, should be " + + "around 640000 but is " + plugin.numMethods); + } + } + } + +} diff --git a/jdk/test/tools/jlink/JLinkOptionsTest.java b/jdk/test/tools/jlink/JLinkOptionsTest.java new file mode 100644 index 00000000000..8c8d241f5b7 --- /dev/null +++ b/jdk/test/tools/jlink/JLinkOptionsTest.java @@ -0,0 +1,99 @@ +/* + * 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. + */ +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.plugin.TransformerPlugin; + +import tests.Helper; + +/* + * @test + * @summary Test jlink options + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main JLinkOptionsTest + */ +public class JLinkOptionsTest { + + private static class TestPlugin implements TransformerPlugin { + private final String name; + private final String option; + + private TestPlugin(String name, String option) { + this.name = name; + this.option = option; + } + + + @Override + public String getOption() { + return option; + } + + @Override + public void visit(Pool in, Pool out) { + + } + + @Override + public String getName() { + return name; + } + + @Override + public String getDescription() { + return name; + } + } + + public static void main(String[] args) throws Exception { + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + { + // multiple plugins with same option + + PluginRepository. + registerPlugin(new TestPlugin("test1", "test1")); + PluginRepository. + registerPlugin(new TestPlugin("test2", "test1")); + helper.generateDefaultImage("composite2").assertFailure("Error: More than one plugin enabled by test1 option"); + PluginRepository.unregisterPlugin("test1"); + PluginRepository.unregisterPlugin("test2"); + } + } +} diff --git a/jdk/test/tools/jlink/JLinkPluginsTest.java b/jdk/test/tools/jlink/JLinkPluginsTest.java new file mode 100644 index 00000000000..560fc53f9a3 --- /dev/null +++ b/jdk/test/tools/jlink/JLinkPluginsTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; + +import tests.Helper; + +/* + * @test + * @summary Test image creation + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm -verbose:gc -Xmx1g JLinkPluginsTest + */ +public class JLinkPluginsTest { + + private static String createProperties(String fileName, String content) throws IOException { + Path p = Paths.get(fileName); + Files.write(p, Collections.singletonList(content)); + return p.toAbsolutePath().toString(); + } + + public static void main(String[] args) throws Exception { + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + { + // Skip debug + String[] userOptions = {"--strip-debug"}; + String moduleName = "skipdebugcomposite"; + helper.generateDefaultJModule(moduleName, "composite2"); + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, null, null); + } + { + // Filter out files + String[] userOptions = {"--exclude-resources", "*.jcov, */META-INF/*"}; + String moduleName = "excludecomposite"; + helper.generateDefaultJModule(moduleName, "composite2"); + String[] res = {".jcov", "/META-INF/"}; + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, res, null); + } + } +} diff --git a/jdk/test/tools/jlink/JLinkPostProcessingTest.java b/jdk/test/tools/jlink/JLinkPostProcessingTest.java new file mode 100644 index 00000000000..b32bf207ff2 --- /dev/null +++ b/jdk/test/tools/jlink/JLinkPostProcessingTest.java @@ -0,0 +1,147 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.plugin.ExecutableImage; +import jdk.tools.jlink.plugin.PostProcessorPlugin; +import tests.Helper; + +/* + * @test + * @summary Test post processing + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm JLinkPostProcessingTest + */ +public class JLinkPostProcessingTest { + + private static class PPPlugin implements PostProcessorPlugin { + + private static ExecutableImage called; + private static final String NAME = "pp"; + + @Override + public List process(ExecutableImage image) { + called = image; + Path gen = image.getHome().resolve("lib").resolve("toto.txt"); + try { + Files.createFile(gen); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + return null; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.PROCESSOR); + return Collections.unmodifiableSet(set); + } + + @Override + public String getDescription() { + return NAME; + } + } + + public static void main(String[] args) throws Exception { + + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + + PluginRepository.registerPlugin(new PPPlugin()); + + // Generate an image and post-process in same jlink execution. + { + String[] userOptions = {"--pp"}; + String moduleName = "postprocessing1"; + helper.generateDefaultJModule(moduleName, "composite2"); + String[] res = {}; + String[] files = {}; + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, res, files); + + test(imageDir); + } + + // Generate an image, post-process in 2 jlink executions. + { + String[] userOptions = {}; + String moduleName = "postprocessing2"; + helper.generateDefaultJModule(moduleName, "composite2"); + String[] res = {}; + String[] files = {}; + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, res, files); + + String[] ppOptions = {"--pp"}; + helper.postProcessImage(imageDir, ppOptions); + test(imageDir); + } + } + + private static void test(Path imageDir) + throws Exception { + if (PPPlugin.called == null) { + throw new Exception("Post processor not called."); + } + if (!PPPlugin.called.getHome().equals(imageDir)) { + throw new Exception("Not right imageDir " + PPPlugin.called.getHome()); + } + if (PPPlugin.called.getExecutionArgs().isEmpty()) { + throw new Exception("No arguments to run java..."); + } + Path gen = imageDir.resolve("lib").resolve("toto.txt"); + if (!Files.exists(gen)) { + throw new Exception("Generated file doesn;t exist"); + } + PPPlugin.called = null; + } +} diff --git a/jdk/test/tools/jlink/JLinkTest.java b/jdk/test/tools/jlink/JLinkTest.java new file mode 100644 index 00000000000..180dc4c4644 --- /dev/null +++ b/jdk/test/tools/jlink/JLinkTest.java @@ -0,0 +1,229 @@ +/* + * 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. + */ + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Layer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.internal.PluginRepository; +import tests.Helper; +import tests.JImageGenerator; +import tests.JImageGenerator.InMemoryFile; + +/* + * @test + * @summary Test image creation + * @author Jean-Francois Denise + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm -verbose:gc -Xmx1g JLinkTest + */ +public class JLinkTest { + + public static void main(String[] args) throws Exception { + + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + helper.generateDefaultModules(); + int numPlugins = 12; + { + // number of built-in plugins + List builtInPlugins = new ArrayList<>(); + builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); + for (Plugin p : builtInPlugins) { + p.getState(); + p.getType(); + } + if (builtInPlugins.size() != numPlugins) { + throw new AssertionError("Found plugins doesn't match expected number : " + + numPlugins + "\n" + builtInPlugins); + } + } + + { + String moduleName = "bug8134651"; + JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(helper.createNewImageDir(moduleName)) + .addMods("leaf1") + .option("") + .call().assertSuccess(); + JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .addMods("leaf1") + .option("--output") + .option("") + .call().assertFailure("Error: no value given for --output"); + JImageGenerator.getJLinkTask() + .modulePath("") + .output(helper.createNewImageDir(moduleName)) + .addMods("leaf1") + .option("") + .call().assertFailure("Error: no value given for --modulepath"); + } + + { + String moduleName = "filter"; + Path jmod = helper.generateDefaultJModule(moduleName).assertSuccess(); + String className = "_A.class"; + JImageGenerator.addFiles(jmod, new InMemoryFile(className, new byte[0])); + Path image = helper.generateDefaultImage(moduleName).assertSuccess(); + helper.checkImage(image, moduleName, new String[] {"/" + moduleName + "/" + className}, null); + } + + { + // Help + StringWriter writer = new StringWriter(); + jdk.tools.jlink.internal.Main.run(new String[]{"--help"}, new PrintWriter(writer)); + String output = writer.toString(); + if (output.split("\n").length < 10) { + System.err.println(output); + throw new AssertionError("Help"); + } + } + + { + // License files + String copied = "LICENSE"; + String[] arr = copied.split(","); + String[] copyFiles = new String[2]; + copyFiles[0] = "--copy-files"; + copyFiles[1] = copied; + Path imageDir = helper.generateDefaultImage(copyFiles, "composite2").assertSuccess(); + helper.checkImage(imageDir, "composite2", null, null, arr); + } + + { + // List plugins + StringWriter writer = new StringWriter(); + jdk.tools.jlink.internal.Main.run(new String[]{"--list-plugins"}, new PrintWriter(writer)); + String output = writer.toString(); + long number = Stream.of(output.split("\\R")) + .filter((s) -> s.matches("Plugin Name:.*")) + .count(); + if (number != numPlugins) { + System.err.println(output); + throw new AssertionError("Found: " + number + " expected " + numPlugins); + } + } + + // filter out files and resources + Skip debug + compress + { + String[] userOptions = {"--compress", "2", "--strip-debug", + "--exclude-resources", "*.jcov, */META-INF/*", "--exclude-files", + "*" + Helper.getDebugSymbolsExtension()}; + String moduleName = "excludezipskipdebugcomposite2"; + helper.generateDefaultJModule(moduleName, "composite2"); + String[] res = {".jcov", "/META-INF/"}; + String[] files = {Helper.getDebugSymbolsExtension()}; + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, res, files); + } + + // filter out + Skip debug + compress with filter + sort resources + { + String[] userOptions2 = {"--compress=2:compress-filter=^/java.base/*", + "--strip-debug", "--exclude-resources", + "*.jcov, */META-INF/*", "--sort-resources", + "*/module-info.class,/sortcomposite2/*,*/javax/management/*"}; + String moduleName = "excludezipfilterskipdebugcomposite2"; + helper.generateDefaultJModule(moduleName, "composite2"); + String[] res = {".jcov", "/META-INF/"}; + Path imageDir = helper.generateDefaultImage(userOptions2, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, res, null); + } + + // default compress + { + testCompress(helper, "compresscmdcomposite2", "--compress", "2"); + } + + { + testCompress(helper, "compressfiltercmdcomposite2", + "--compress=2:filter=^/java.base/java/lang/*"); + } + + // compress 0 + { + testCompress(helper, "compress0filtercmdcomposite2", + "--compress=0:filter=^/java.base/java/lang/*"); + } + + // compress 1 + { + testCompress(helper, "compress1filtercmdcomposite2", + "--compress=1:filter=^/java.base/java/lang/*"); + } + + // compress 2 + { + testCompress(helper, "compress2filtercmdcomposite2", + "--compress=2:filter=^/java.base/java/lang/*"); + } + + // invalid compress level + { + String[] userOptions = {"--compress", "invalid"}; + String moduleName = "invalidCompressLevel"; + helper.generateDefaultJModule(moduleName, "composite2"); + helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid level invalid"); + } + + // @file + { + Path path = Paths.get("embedded.properties"); + Files.write(path, Collections.singletonList("--strip-debug --addmods " + + "toto.unknown --compress UNKNOWN\n")); + String[] userOptions = {"@", path.toAbsolutePath().toString()}; + String moduleName = "configembeddednocompresscomposite2"; + helper.generateDefaultJModule(moduleName, "composite2"); + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, null, null); + } + + } + + private static void testCompress(Helper helper, String moduleName, String... userOptions) throws IOException { + helper.generateDefaultJModule(moduleName, "composite2"); + Path imageDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess(); + helper.checkImage(imageDir, moduleName, null, null); + } +} diff --git a/jdk/test/tools/jlink/NativeTest.java b/jdk/test/tools/jlink/NativeTest.java new file mode 100644 index 00000000000..b147617be8b --- /dev/null +++ b/jdk/test/tools/jlink/NativeTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test config, cmd and lib directories of jmod. + * @author Andrei Eremeev + * @library ../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main NativeTest + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +import tests.Helper; +import tests.JImageGenerator; + +public class NativeTest { + + private final Helper helper; + + public NativeTest(Helper helper) { + this.helper = helper; + } + + public static void main(String[] args) throws IOException { + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Not run"); + return; + } + new NativeTest(helper).test(); + } + + public void test() throws IOException { + String moduleName = "native_library"; + Path classesDir = helper.generateModuleCompiledClasses( + helper.getJmodSrcDir(), helper.getJmodClassesDir(), moduleName); + Path libsDir = helper.getJmodDir().resolve("lib").resolve(moduleName); + Path configDir = helper.getJmodDir().resolve("config").resolve(moduleName); + Path cmdDir = helper.getJmodDir().resolve("cmd").resolve(moduleName); + + Path config = writeFile(configDir.resolve("config.txt"), "AAAA\nBBBB"); + Path cmd = writeFile(cmdDir.resolve("ls.sh"), "ls"); + Path lib = writeFile(libsDir.resolve("native.so"), "native library"); + + JImageGenerator.getJModTask() + .addClassPath(classesDir) + .addNativeLibraries(libsDir) + .addCmds(cmdDir) + .addConfig(configDir) + .jmod(helper.createNewJmodFile(moduleName)) + .create() + .assertSuccess(); + + String[] expectedFiles = new String[] { + "bin" + File.separator + cmd.getFileName(), + "conf" + File.separator + config.getFileName(), + "lib" + File.separator + lib.getFileName() + }; + Path image = JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .addMods(moduleName) + .output(helper.createNewImageDir(moduleName)) + .call().assertSuccess(); + helper.checkImage(image, moduleName, null, null, expectedFiles); + } + + private Path writeFile(Path path, String content) throws IOException { + if (path.getParent() != null) { + Files.createDirectories(path.getParent()); + } + Files.write(path, Arrays.asList(content.split("\n"))); + return path; + } +} diff --git a/jdk/test/tools/jlink/ResourcePoolTest.java b/jdk/test/tools/jlink/ResourcePoolTest.java new file mode 100644 index 00000000000..77a82e5c1b2 --- /dev/null +++ b/jdk/test/tools/jlink/ResourcePoolTest.java @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test a pool containing jimage resources and classes. + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * @run build ResourcePoolTest + * @run main ResourcePoolTest + */ + +import java.io.ByteArrayInputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.Module; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.Pool.ModuleDataType; +import jdk.tools.jlink.plugin.Pool.Visitor; + +public class ResourcePoolTest { + + public static void main(String[] args) throws Exception { + new ResourcePoolTest().test(); + } + + public void test() throws Exception { + checkResourceAdding(); + checkResourceVisitor(); + checkResourcesAfterCompression(); + } + + private static final String SUFFIX = "END"; + + private void checkResourceVisitor() throws Exception { + Pool input = new PoolImpl(); + for (int i = 0; i < 1000; ++i) { + String module = "/module" + (i / 10); + String resourcePath = module + "/java/package" + i; + byte[] bytes = resourcePath.getBytes(); + input.add(new ModuleData(module, resourcePath, + ModuleDataType.CLASS_OR_RESOURCE, + new ByteArrayInputStream(bytes), bytes.length)); + } + Pool output = new PoolImpl(); + ResourceVisitor visitor = new ResourceVisitor(); + input.visit(visitor, output); + if (visitor.getAmountBefore() == 0) { + throw new AssertionError("Resources not found"); + } + if (visitor.getAmountBefore() != input.getContent().size()) { + throw new AssertionError("Number of visited resources. Expected: " + + visitor.getAmountBefore() + ", got: " + input.getContent().size()); + } + if (visitor.getAmountAfter() != output.getContent().size()) { + throw new AssertionError("Number of added resources. Expected: " + + visitor.getAmountAfter() + ", got: " + output.getContent().size()); + } + for (ModuleData outResource : output.getContent()) { + String path = outResource.getPath().replaceAll(SUFFIX + "$", ""); + ModuleData inResource = input.get(path); + if (inResource == null) { + throw new AssertionError("Unknown resource: " + path); + } + } + } + + private static class ResourceVisitor implements Visitor { + + private int amountBefore; + private int amountAfter; + + @Override + public ModuleData visit(ModuleData resource) { + int index = ++amountBefore % 3; + switch (index) { + case 0: + ++amountAfter; + return new ModuleData(resource.getModule(), resource.getPath() + SUFFIX, + resource.getType(), resource.stream(), resource.getLength()); + case 1: + ++amountAfter; + return new ModuleData(resource.getModule(), resource.getPath(), + resource.getType(), resource.stream(), resource.getLength()); + } + return null; + } + + public int getAmountAfter() { + return amountAfter; + } + + public int getAmountBefore() { + return amountBefore; + } + } + + private void checkResourceAdding() { + List samples = new ArrayList<>(); + samples.add("java.base"); + samples.add("java/lang/Object"); + samples.add("java.base"); + samples.add("java/lang/String"); + samples.add("java.management"); + samples.add("javax/management/ObjectName"); + test(samples, (resources, module, path) -> { + try { + resources.add(new ModuleData(module, path, + ModuleDataType.CLASS_OR_RESOURCE, + new ByteArrayInputStream(new byte[0]), 0)); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + }); + test(samples, (resources, module, path) -> { + try { + resources.add(PoolImpl. + newCompressedResource(new ModuleData(module, path, + ModuleDataType.CLASS_OR_RESOURCE, + new ByteArrayInputStream(new byte[0]), 0), + ByteBuffer.allocate(99), "bitcruncher", null, + ((PoolImpl)resources).getStringTable(), ByteOrder.nativeOrder())); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + }); + } + + private void test(List samples, ResourceAdder adder) { + if (samples.isEmpty()) { + throw new AssertionError("No sample to test"); + } + Pool resources = new PoolImpl(); + Set modules = new HashSet<>(); + for (int i = 0; i < samples.size(); i++) { + String module = samples.get(i); + modules.add(module); + i++; + String clazz = samples.get(i); + String path = "/" + module + "/" + clazz + ".class"; + adder.add(resources, module, path); + } + for (int i = 0; i < samples.size(); i++) { + String module = samples.get(i); + i++; + String clazz = samples.get(i); + String path = "/" + module + "/" + clazz + ".class"; + ModuleData res = resources.get(path); + checkModule(resources, res); + if (res == null) { + throw new AssertionError("Resource not found " + path); + } + ModuleData res2 = resources.get(clazz); + if (res2 != null) { + throw new AssertionError("Resource found " + clazz); + } + } + if (resources.getContent().size() != samples.size() / 2) { + throw new AssertionError("Invalid number of resources"); + } + } + + private void checkModule(Pool resources, ModuleData res) { + Module m = resources.getModule(res.getModule()); + if (m == null) { + throw new AssertionError("No module " + res.getModule()); + } + if (!m.getName().equals(res.getModule())) { + throw new AssertionError("Not right module name " + res.getModule()); + } + if (m.get(res.getPath()) == null) { + throw new AssertionError("resource " + res.getPath() + + " not in module " + m.getName()); + } + } + + private void checkResourcesAfterCompression() throws Exception { + PoolImpl resources1 = new PoolImpl(); + ModuleData res1 = new ModuleData("module1", "/module1/toto1", + ModuleDataType.CLASS_OR_RESOURCE, + new ByteArrayInputStream(new byte[0]), 0); + ModuleData res2 = new ModuleData("module2", "/module2/toto1", + ModuleDataType.CLASS_OR_RESOURCE, + new ByteArrayInputStream(new byte[0]), 0); + resources1.add(res1); + resources1.add(res2); + + checkResources(resources1, res1, res2); + Pool resources2 = new PoolImpl(); + ModuleData res3 = new ModuleData("module2", "/module2/toto1", + ModuleDataType.CLASS_OR_RESOURCE, + new ByteArrayInputStream(new byte[7]), 7); + resources2.add(res3); + resources2.add(PoolImpl.newCompressedResource(res1, + ByteBuffer.allocate(7), "zip", null, resources1.getStringTable(), + ByteOrder.nativeOrder())); + checkResources(resources2, res1, res2); + } + + private void checkResources(Pool resources, ModuleData... expected) { + Collection ms = resources.getModules(); + List modules = new ArrayList(); + for(Module m : ms) { + modules.add(m.getName()); + } + for (ModuleData res : expected) { + if (!resources.contains(res)) { + throw new AssertionError("Resource not found: " + res); + } + + if (resources.get(res.getPath()) == null) { + throw new AssertionError("Resource not found: " + res); + } + + if (!modules.contains(res.getModule())) { + throw new AssertionError("Module not found: " + res.getModule()); + } + + if (!resources.getContent().contains(res)) { + throw new AssertionError("Resources not found: " + res); + } + + try { + resources.add(res); + throw new AssertionError(res + " already present, but an exception is not thrown"); + } catch (Exception ex) { + // Expected + } + } + + if (resources.isReadOnly()) { + throw new AssertionError("ReadOnly resources"); + } + + ((PoolImpl) resources).setReadOnly(); + try { + resources.add(new ModuleData("module2", "/module2/toto1", + ModuleDataType.CLASS_OR_RESOURCE, new ByteArrayInputStream(new byte[0]), 0)); + throw new AssertionError("Pool is read-only, but an exception is not thrown"); + } catch (Exception ex) { + // Expected + } + } + + interface ResourceAdder { + void add(Pool resources, String module, String path); + } +} diff --git a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp b/jdk/test/tools/jlink/SecurityTest.java similarity index 63% rename from hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp rename to jdk/test/tools/jlink/SecurityTest.java index 35f47f9967d..b21c1bc7d09 100644 --- a/hotspot/src/share/vm/jvmci/commandLineFlagConstraintsJVMCI.hpp +++ b/jdk/test/tools/jlink/SecurityTest.java @@ -19,22 +19,33 @@ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. - * */ -#ifndef SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP -#define SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP - -#include "runtime/globals.hpp" -#include "utilities/globalDefinitions.hpp" - /* - * Here we have JVMCI arguments constraints functions, which are called automatically - * whenever flag's value changes. If the constraint fails the function should return - * an appropriate error value. + * @test + * @summary Test JlinkPermission + * @author Jean-Francois Denise + * @run main SecurityTest */ -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(bool value, bool verbose); -Flag::Error EnableJVMCIMustBeEnabledConstraintFunc(intx value, bool verbose); +import java.security.AccessControlException; +import jdk.tools.jlink.Jlink; -#endif /* SHARE_VM_JVMCI_COMMANDLINEFLAGCONSTRAINTSJVMCI_HPP */ +public class SecurityTest { + + public static void main(String[] args) throws Exception { + new Jlink(); + System.setSecurityManager(new SecurityManager()); + boolean failed = false; + try { + new Jlink(); + failed = true; + } catch (AccessControlException ex) { + //XXX OK. + } + if (failed) { + throw new Exception("Call should have failed"); + } + + } +} diff --git a/jdk/test/tools/jlink/asmplugin/AddForgetResourcesTest.java b/jdk/test/tools/jlink/asmplugin/AddForgetResourcesTest.java new file mode 100644 index 00000000000..6a414b57d63 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/AddForgetResourcesTest.java @@ -0,0 +1,509 @@ +/* + * 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. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test resource transformation. + * @author Andrei Eremeev + * @modules java.base/jdk.internal.org.objectweb.asm + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * jdk.jdeps/com.sun.tools.classfile + * @build AsmPluginTestBase + * @run main AddForgetResourcesTest +*/ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Method; +import java.io.UncheckedIOException; +import java.util.Set; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool; +import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableClassPool; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool; +import jdk.tools.jlink.internal.plugins.asm.AsmPools; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class AddForgetResourcesTest extends AsmPluginTestBase { + + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new AddForgetResourcesTest().test(); + } + + @Override + public void test() throws Exception { + TestPlugin[] plugins = new TestPlugin[] { + new AddClassesPlugin(), + new AddResourcesPlugin(), + new ReplaceClassesPlugin(), + new ReplaceResourcesPlugin(), + new ForgetClassesPlugin(), + new ForgetResourcesPlugin(), + new AddForgetClassesPlugin(), + new AddForgetResourcesPlugin(), + new ComboPlugin() + }; + for (TestPlugin p : plugins) { + Pool out = p.visit(getPool()); + p.test(getPool(), out); + } + } + + private static final String SUFFIX = "HELLOWORLD"; + + private static class RenameClassVisitor extends ClassVisitor { + + public RenameClassVisitor(ClassWriter cv) { + super(Opcodes.ASM5, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + super.visit(version, access, name + SUFFIX, signature, superName, interfaces); + } + } + + private static class AddMethodClassVisitor extends ClassVisitor { + + public AddMethodClassVisitor(ClassWriter cv) { + super(Opcodes.ASM5, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + this.visitMethod(0, SUFFIX, "()V", null, null); + super.visit(version, access, name, signature, superName, interfaces); + } + } + + private class AddClassesPlugin extends TestPlugin { + + private int expected = 0; + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + WritableClassPool transformedClasses = globalPool.getTransformedClasses(); + expected = globalPool.getClasses().size(); + for (ModuleData res : globalPool.getClasses()) { + ClassReader reader = globalPool.getClassReader(res); + String className = reader.getClassName(); + if (!className.endsWith("module-info")) { + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + reader.accept(new RenameClassVisitor(writer), ClassReader.EXPAND_FRAMES); + transformedClasses.addClass(writer); + ++expected; + } + } + } + + @Override + public void test(Pool inResources, Pool outResources) { + Collection inClasses = extractClasses(inResources); + Collection outClasses = extractClasses(outResources); + if (expected != outClasses.size()) { + throw new AssertionError("Classes were not added. Expected: " + expected + + ", got: " + outClasses.size()); + } + for (ModuleData in : inClasses) { + String path = in.getPath(); + if (!outClasses.contains(in)) { + throw new AssertionError("Class not found: " + path); + } + if (path.endsWith("module-info.class")) { + continue; + } + String modifiedPath = path.replace(".class", SUFFIX + ".class"); + if (!outClasses.contains(Pool.newResource(modifiedPath, new byte[0]))) { + throw new AssertionError("Class not found: " + modifiedPath); + } + } + } + } + + private class AddResourcesPlugin extends TestPlugin { + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + for (ModuleData res : globalPool.getResourceFiles()) { + String path = res.getPath(); + String moduleName = getModule(path); + AsmModulePool modulePool = pools.getModulePool(moduleName); + WritableResourcePool resourcePool = modulePool.getTransformedResourceFiles(); + resourcePool.addResourceFile(new ResourceFile(removeModule(res.getPath()) + SUFFIX, + res.getBytes())); + } + } + + @Override + public void test(Pool in, Pool out) throws Exception { + Collection inResources = extractResources(in); + Collection outResources = extractResources(out); + if (2 * inResources.size() != outResources.size()) { + throw new AssertionError("Classes were not added. Expected: " + (2 * inResources.size()) + + ", got: " + outResources.size()); + } + for (ModuleData r : inResources) { + String path = r.getPath(); + if (!outResources.contains(r)) { + throw new AssertionError("Class not found: " + path); + } + String modifiedPath = path + SUFFIX; + if (!outResources.contains(Pool.newResource(modifiedPath, new byte[0]))) { + throw new AssertionError("Class not found: " + modifiedPath); + } + } + } + } + + private class ReplaceClassesPlugin extends TestPlugin { + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + WritableClassPool transformedClasses = globalPool.getTransformedClasses(); + for (ModuleData res : globalPool.getClasses()) { + ClassReader reader = globalPool.getClassReader(res); + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + reader.accept(new AddMethodClassVisitor(writer), ClassReader.EXPAND_FRAMES); + transformedClasses.addClass(writer); + } + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + Collection inClasses = extractClasses(inResources); + Collection outClasses = extractClasses(outResources); + if (inClasses.size() != outClasses.size()) { + throw new AssertionError("Number of classes. Expected: " + (inClasses.size()) + + ", got: " + outClasses.size()); + } + for (ModuleData out : outClasses) { + String path = out.getPath(); + if (!inClasses.contains(out)) { + throw new AssertionError("Class not found: " + path); + } + ClassFile cf = ClassFile.read(new ByteArrayInputStream(out.getBytes())); + if (path.endsWith("module-info.class")) { + continue; + } + boolean failed = true; + for (Method m : cf.methods) { + if (m.getName(cf.constant_pool).equals(SUFFIX)) { + failed = false; + } + } + if (failed) { + throw new AssertionError("Not found method with name " + SUFFIX + " in class " + path); + } + } + } + } + + private class ReplaceResourcesPlugin extends TestPlugin { + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + for (ModuleData res : globalPool.getResourceFiles()) { + String path = res.getPath(); + AsmModulePool modulePool = pools.getModulePool(getModule(path)); + modulePool.getTransformedResourceFiles().addResourceFile(new ResourceFile(removeModule(path), + "HUI".getBytes())); + } + } + + @Override + public void test(Pool in, Pool out) throws Exception { + Collection inResources = extractResources(in); + Collection outResources = extractResources(out); + if (inResources.size() != outResources.size()) { + throw new AssertionError("Number of resources. Expected: " + inResources.size() + + ", got: " + outResources.size()); + } + for (ModuleData r : outResources) { + String path = r.getPath(); + if (!inResources.contains(r)) { + throw new AssertionError("Resource not found: " + path); + } + String content = new String(r.getBytes()); + if (!"HUI".equals(content)) { + throw new AssertionError("Content expected: 'HUI', got: " + content); + } + } + } + } + + private class ForgetClassesPlugin extends TestPlugin { + + private int expected = 0; + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + WritableClassPool transformedClasses = globalPool.getTransformedClasses(); + int i = 0; + for (ModuleData res : globalPool.getClasses()) { + String path = removeModule(res.getPath()); + String className = path.replace(".class", ""); + if ((i & 1) == 0 && !className.endsWith("module-info")) { + transformedClasses.forgetClass(className); + } else { + ++expected; + } + i ^= 1; + } + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + Collection outClasses = extractClasses(outResources); + if (expected != outClasses.size()) { + throw new AssertionError("Number of classes. Expected: " + expected + + ", got: " + outClasses.size()); + } + } + } + + private class ForgetResourcesPlugin extends TestPlugin { + + private int expectedAmount = 0; + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + int i = 0; + for (ModuleData res : globalPool.getResourceFiles()) { + String path = res.getPath(); + if (!path.contains("META-INF/services")) { + if ((i & 1) == 0) { + AsmModulePool modulePool = pools.getModulePool(getModule(path)); + modulePool.getTransformedResourceFiles().forgetResourceFile(removeModule(res.getPath())); + } else { + ++expectedAmount; + } + i ^= 1; + } else { + ++expectedAmount; + } + } + } + + @Override + public void test(Pool in, Pool out) throws Exception { + Collection outResources = extractResources(out); + if (expectedAmount != outResources.size()) { + throw new AssertionError("Number of classes. Expected: " + expectedAmount + + ", got: " + outResources.size()); + } + } + } + + private class AddForgetClassesPlugin extends TestPlugin { + + private int expected = 0; + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + WritableClassPool transformedClasses = globalPool.getTransformedClasses(); + int i = 0; + for (ModuleData res : globalPool.getClasses()) { + ClassReader reader = globalPool.getClassReader(res); + String className = reader.getClassName(); + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + if (!className.endsWith("module-info")) { + reader.accept(new RenameClassVisitor(writer), ClassReader.EXPAND_FRAMES); + transformedClasses.addClass(writer); + ++expected; + } + + if ((i & 1) == 0 && !className.endsWith("module-info")) { + transformedClasses.forgetClass(className); + } else { + ++expected; + } + i ^= 1; + } + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + Collection outClasses = extractClasses(outResources); + if (expected != outClasses.size()) { + throw new AssertionError("Number of classes. Expected: " + expected + + ", got: " + outClasses.size()); + } + } + } + + private class AddForgetResourcesPlugin extends TestPlugin { + + private int expectedAmount = 0; + + @Override + public void visit() { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + int i = 0; + for (ModuleData res : globalPool.getResourceFiles()) { + String path = res.getPath(); + String moduleName = getModule(path); + if (!path.contains("META-INF")) { + AsmModulePool modulePool = pools.getModulePool(moduleName); + WritableResourcePool transformedResourceFiles = modulePool.getTransformedResourceFiles(); + String newPath = removeModule(path) + SUFFIX; + transformedResourceFiles.addResourceFile(new ResourceFile(newPath, res.getBytes())); + if ((i & 1) == 0) { + transformedResourceFiles.forgetResourceFile(newPath); + } else { + ++expectedAmount; + } + i ^= 1; + } + ++expectedAmount; + } + } + + @Override + public void test(Pool inResources, Pool out) throws Exception { + Collection outResources = extractResources(out); + if (expectedAmount != outResources.size()) { + throw new AssertionError("Number of classes. Expected: " + expectedAmount + + ", got: " + outResources.size()); + } + } + } + + private class ComboPlugin extends TestPlugin { + + private class RenameClassVisitor extends ClassVisitor { + + public RenameClassVisitor(ClassWriter cv) { + super(Opcodes.ASM5, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + super.visit(version, access, name + SUFFIX, signature, superName, interfaces); + } + } + + @Override + public void visit() { + try { + renameClasses(); + renameResources(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + if (!isVisitCalled()) { + throw new AssertionError("Resources not visited"); + } + AsmGlobalPool globalPool = getPools().getGlobalPool(); + if (globalPool.getTransformedClasses().getClasses().size() != getClasses().size()) { + throw new AssertionError("Number of transformed classes not equal to expected"); + } + // Check that only renamed classes and resource files are in the result. + for (ModuleData r : outResources.getContent()) { + String resourceName = r.getPath(); + if (resourceName.endsWith(".class") && !resourceName.endsWith("module-info.class")) { + if (!resourceName.endsWith(SUFFIX + ".class")) { + throw new AssertionError("Class not renamed " + resourceName); + } + } else if (resourceName.contains("META-INF/services/") && MODULES.containsKey(r.getModule())) { + String newClassName = new String(r.getBytes()); + if(!newClassName.endsWith(SUFFIX)) { + throw new AssertionError("Resource file not renamed " + resourceName); + } + } + } + } + + private void renameResources() throws IOException { + AsmPools pools = getPools(); + // Rename the resource Files + for (Map.Entry> mod : MODULES.entrySet()) { + String moduleName = mod.getKey(); + AsmModulePool modulePool = pools.getModulePool(moduleName); + for (ModuleData res : modulePool.getResourceFiles()) { + ResourceFile resFile = modulePool.getResourceFile(res); + if (resFile.getPath().startsWith("META-INF/services/")) { + String newContent = new String(resFile.getContent()) + SUFFIX; + ResourceFile newResourceFile = new ResourceFile(resFile.getPath(), + newContent.getBytes()); + modulePool.getTransformedResourceFiles().addResourceFile(newResourceFile); + } + } + } + } + + private void renameClasses() throws IOException { + AsmPools pools = getPools(); + AsmGlobalPool globalPool = pools.getGlobalPool(); + WritableClassPool transformedClasses = globalPool.getTransformedClasses(); + for (ModuleData res : globalPool.getClasses()) { + if (res.getPath().endsWith("module-info.class")) { + continue; + } + ClassReader reader = globalPool.getClassReader(res); + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + RenameClassVisitor visitor = new RenameClassVisitor(writer); + reader.accept(visitor, ClassReader.EXPAND_FRAMES); + + transformedClasses.forgetClass(reader.getClassName()); + transformedClasses.addClass(writer); + } + } + } +} diff --git a/jdk/test/tools/jlink/asmplugin/AsmPluginTestBase.java b/jdk/test/tools/jlink/asmplugin/AsmPluginTestBase.java new file mode 100644 index 00000000000..d5c035562fa --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/AsmPluginTestBase.java @@ -0,0 +1,249 @@ +/* + * 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. + */ +import java.io.IOException; +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.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.StringTable; + +import jdk.tools.jlink.internal.plugins.asm.AsmPlugin; +import jdk.tools.jlink.internal.plugins.asm.AsmPools; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public abstract class AsmPluginTestBase { + + protected static final String TEST_MODULE = "jlink.test"; + protected static final Map> MODULES; + + private static final Predicate isClass = r -> r.getPath().endsWith(".class"); + private final List classes; + private final List resources; + private final Pool pool; + + static { + Map> map = new HashMap<>(); + map.put("jdk.localedata", new ArrayList<>()); + map.put("java.base", new ArrayList<>()); + map.put(TEST_MODULE, new ArrayList<>()); + MODULES = Collections.unmodifiableMap(map); + } + + public static boolean isImageBuild() { + Path javaHome = Paths.get(System.getProperty("test.jdk")); + Path jmods = javaHome.resolve("jmods"); + return Files.exists(jmods); + } + + public AsmPluginTestBase() { + try { + List classes = new ArrayList<>(); + List resources = new ArrayList<>(); + + pool = new PoolImpl(); + + FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); + Path root = fs.getPath("/modules"); + + List moduleInfos = new ArrayList<>(); + try (Stream stream = Files.walk(root)) { + for (Iterator iterator = stream.iterator(); iterator.hasNext(); ) { + Path p = iterator.next(); + if (Files.isRegularFile(p)) { + String module = p.toString().substring("/modules/".length()); + module = module.substring(0, module.indexOf("/")); + if (MODULES.keySet().contains(module)) { + try { + boolean isModuleInfo = p.endsWith("module-info.class"); + if (isModuleInfo) { + moduleInfos.add(Files.readAllBytes(p)); + } + byte[] content = Files.readAllBytes(p); + if (p.toString().endsWith(".class") && !isModuleInfo) { + classes.add(toClassName(p)); + } else if (!isModuleInfo) { + MODULES.get(module).add(toResourceFile(p)); + } + resources.add(toPath(p.toString())); + ModuleData res = Pool.newResource(toPath(p.toString()), content); + pool.add(res); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } + } + } + // There is more than 10 classes in java.base... + if (classes.size() < 10 || pool.getContent().size() < 10) { + throw new AssertionError("Not expected resource or class number"); + } + + //Add a fake resource file + String content = "java.lang.Object"; + String path = "META-INF/services/com.foo.BarProvider"; + ModuleData resFile = Pool.newResource("/" + TEST_MODULE + "/" + + path, content.getBytes()); + pool.add(resFile); + ModuleData fakeInfoFile = Pool.newResource("/" + TEST_MODULE + + "/module-info.class", moduleInfos.get(0)); + pool.add(fakeInfoFile); + MODULES.get(TEST_MODULE).add(path); + for(Map.Entry> entry : MODULES.entrySet()) { + if (entry.getValue().isEmpty()) { + throw new AssertionError("No resource file for " + entry.getKey()); + } + } + this.classes = Collections.unmodifiableList(classes); + this.resources = Collections.unmodifiableList(resources); + } catch (Exception e) { + throw new ExceptionInInitializerError(e); + } + } + + public List getClasses() { + return classes; + } + + public List getResources() { + return resources; + } + + public Pool getPool() { + return pool; + } + + public abstract void test() throws Exception; + + public Collection extractClasses(Pool pool) { + return pool.getContent().stream() + .filter(isClass) + .collect(Collectors.toSet()); + } + + public Collection extractResources(Pool pool) { + return pool.getContent().stream() + .filter(isClass.negate()) + .collect(Collectors.toSet()); + } + + public String getModule(String path) { + int index = path.indexOf("/", 1); + return path.substring(1, index); + } + + public String removeModule(String path) { + int index = path.indexOf("/", 1); + return path.substring(index + 1); + } + + private String toPath(String p) { + return p.substring("/modules".length()); + } + + private String toClassName(Path p) { + String path = p.toString(); + path = path.substring("/modules/".length()); + // remove module + if (!path.endsWith("module-info.class")) { + path = path.substring(path.indexOf("/") + 1); + } + path = path.substring(0, path.length() - ".class".length()); + + return path; + } + + private String toResourceFile(Path p) { + String path = p.toString(); + path = path.substring("/modules/".length()); + // remove module + path = path.substring(path.indexOf("/") + 1); + + return path; + } + + public abstract class TestPlugin extends AsmPlugin { + + private AsmPools pools; + + public AsmPools getPools() { + return pools; + } + + public boolean isVisitCalled() { + return pools != null; + } + + public Pool visit(Pool inResources) throws IOException { + try { + Pool outResources = new PoolImpl(inResources.getByteOrder(), new StringTable() { + @Override + public int addString(String str) { + return -1; + } + + @Override + public String getString(int id) { + return null; + } + }); + visit(inResources, outResources); + return outResources; + } catch (Exception e) { + throw new IOException(e); + } + } + + @Override + public void visit(AsmPools pools) { + if (isVisitCalled()) { + throw new AssertionError("Visit was called twice"); + } + this.pools = pools; + visit(); + } + + public abstract void visit(); + public abstract void test(Pool inResources, Pool outResources) throws Exception; + + @Override + public String getName() { + return "test-plugin"; + } + } +} diff --git a/jdk/test/tools/jlink/asmplugin/BasicTest.java b/jdk/test/tools/jlink/asmplugin/BasicTest.java new file mode 100644 index 00000000000..0c42d4cfb99 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/BasicTest.java @@ -0,0 +1,177 @@ +/* + * 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. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test basic functionality. + * @author Jean-Francois Denise + * @modules java.base/jdk.internal.org.objectweb.asm + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * @build AsmPluginTestBase + * @run main BasicTest + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; +import jdk.tools.jlink.internal.plugins.asm.AsmPool; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class BasicTest extends AsmPluginTestBase { + + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new BasicTest().test(); + } + + @Override + public void test() throws Exception { + BasicPlugin basicPlugin = new BasicPlugin(getClasses()); + Pool res = basicPlugin.visit(getPool()); + basicPlugin.test(getPool(), res); + } + + private class BasicPlugin extends TestPlugin { + + private final List classes; + + public BasicPlugin(List classes) { + this.classes = classes; + } + + @Override + public void visit() { + for (String m : MODULES.keySet()) { + AsmModulePool pool = getPools().getModulePool(m); + if (pool == null) { + throw new AssertionError(m + " pool not found"); + } + if(!pool.getModuleName().equals(m)) { + throw new AssertionError("Invalid module name " + + pool.getModuleName() + " should be "+ m); + } + if (pool.getClasses().size() == 0 && !m.equals(TEST_MODULE)) { + throw new AssertionError("Empty pool " + m); + } + pool.addPackage("toto"); + if (!pool.getTransformedClasses().getClasses().isEmpty()) { + throw new AssertionError("Should be empty"); + } + for(String res : MODULES.get(m)) { + AsmPool.ResourceFile resFile = pool.getResourceFile(res); + if(resFile == null) { + throw new AssertionError("No resource file for " + res); + } + } + } + try { + testPools(); + testVisitor(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + if (!isVisitCalled()) { + throw new AssertionError("Resources not visited"); + } + if (inResources.getContent().size() != outResources.getContent().size()) { + throw new AssertionError("Input size " + inResources.getContent().size() + + " != to " + outResources.getContent().size()); + } + } + + private void testVisitor() throws IOException { + List seen = new ArrayList<>(); + getPools().getGlobalPool().visitClassReaders((reader) -> { + String className = reader.getClassName(); + // Wrong naming of module-info.class in ASM + if (className.endsWith("module-info")) { + return null; + } + if (!classes.contains(className)) { + throw new AssertionError("Class is not expected " + className); + } + if (getPools().getGlobalPool().getClassReader(className) == null) { + throw new AssertionError("Class not found in pool " + className); + } + seen.add(className); + return null; + }); + + if (!seen.equals(classes)) { + throw new AssertionError("Expected and seen are not equal"); + } + } + + private void testPools() throws IOException { + Set remain = new HashSet<>(classes); + for (ModuleData res : getPools().getGlobalPool().getClasses()) { + ClassReader reader = getPools().getGlobalPool().getClassReader(res); + String className = reader.getClassName(); + // Wrong naming of module-info.class in ASM + if (className.endsWith("module-info")) { + continue; + } + if (!classes.contains(className)) { + throw new AssertionError("Class is not expected " + className); + } + if (getPools().getGlobalPool().getClassReader(className) == null) { + throw new AssertionError("Class " + className + " not found in pool "); + } + // Check the module pool + boolean found = false; + for(AsmModulePool mp : getPools().getModulePools()) { + if(mp.getClassReader(className) != null) { + found = true; + break; + } + } + if(!found) { + throw new AssertionError("No modular pool for " + + className); + } + remain.remove(className); + } + if (!remain.isEmpty()) { + throw new AssertionError("Remaining classes " + remain); + } + } + } +} diff --git a/jdk/test/tools/jlink/asmplugin/IdentityPluginTest.java b/jdk/test/tools/jlink/asmplugin/IdentityPluginTest.java new file mode 100644 index 00000000000..ceb2e50f9b9 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/IdentityPluginTest.java @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test basic functionality. + * @author Jean-Francois Denise + * @modules java.base/jdk.internal.org.objectweb.asm + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * @build AsmPluginTestBase + * @run main IdentityPluginTest + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableClassPool; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class IdentityPluginTest extends AsmPluginTestBase { + + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new IdentityPluginTest().test(); + } + + public void test() throws Exception { + IdentityPlugin asm = new IdentityPlugin(); + Pool resourcePool = asm.visit(getPool()); + asm.test(getPool(), resourcePool); + } + + private class IdentityPlugin extends TestPlugin { + + @Override + public void visit() { + for (ModuleData res : getPools().getGlobalPool().getClasses()) { + if (res.getPath().endsWith("module-info.class")) { + continue; + } + ClassReader reader = getPools().getGlobalPool().getClassReader(res); + ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + IdentityClassVisitor visitor = new IdentityClassVisitor(writer); + reader.accept(visitor, ClassReader.EXPAND_FRAMES); + getPools().getGlobalPool().getTransformedClasses().addClass(writer); + } + } + + @Override + public void test(Pool inResources, Pool outResources) throws IOException { + if (outResources.isEmpty()) { + throw new AssertionError("Empty result"); + } + if (!isVisitCalled()) { + throw new AssertionError("Resources not visited"); + } + WritableClassPool transformedClasses = getPools().getGlobalPool().getTransformedClasses(); + if (transformedClasses.getClasses().size() != getClasses().size()) { + throw new AssertionError("Number of transformed classes not equal to expected"); + } + for (String className : getClasses()) { + if (transformedClasses.getClassReader(className) == null) { + throw new AssertionError("Class not transformed " + className); + } + } + for (ModuleData r : outResources.getContent()) { + if (r.getPath().endsWith(".class") && !r.getPath().endsWith("module-info.class")) { + ClassReader reader = new ClassReader(new ByteArrayInputStream(r.getBytes())); + ClassWriter w = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + reader.accept(w, ClassReader.EXPAND_FRAMES); + } + } + } + + @Override + public String getName() { + return "identity-plugin"; + } + } + + private static class IdentityClassVisitor extends ClassVisitor { + public IdentityClassVisitor(ClassWriter cv) { + super(Opcodes.ASM5, cv); + } + } +} diff --git a/jdk/test/tools/jlink/asmplugin/NegativeTest.java b/jdk/test/tools/jlink/asmplugin/NegativeTest.java new file mode 100644 index 00000000000..f95b7c62399 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/NegativeTest.java @@ -0,0 +1,172 @@ +/* + * 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. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test basic functionality. + * @author Andrei Eremeev + * @modules java.base/jdk.internal.org.objectweb.asm + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * @build AsmPluginTestBase + * @run main NegativeTest + */ + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.ByteOrder; +import java.util.Map; +import java.util.Set; +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.StringTable; +import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool; +import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; +import jdk.tools.jlink.internal.plugins.asm.AsmPlugin; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile; +import jdk.tools.jlink.internal.plugins.asm.AsmPools; +import jdk.tools.jlink.plugin.PluginException; +import jdk.tools.jlink.plugin.Pool; + +public class NegativeTest extends AsmPluginTestBase { + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new NegativeTest().test(); + } + + @Override + public void test() throws Exception { + testNull(); + testUnknownPackage(); + } + + private void testUnknownPackage() throws Exception { + AsmPlugin t = new AsmPlugin() { + @Override + public void visit(AsmPools pools) { + try { + AsmGlobalPool globalPool = pools.getGlobalPool(); + AsmModulePool javabase = pools.getModulePool("java.base"); + ClassReader cr = new ClassReader(NegativeTest.class.getResourceAsStream("NegativeTest.class")); + ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_FRAMES); + cr.accept(new RenameClassVisitor(cw), ClassReader.EXPAND_FRAMES); + action(() -> globalPool.getTransformedClasses().addClass(cw), + "Unknown package", PluginException.class); + action(() -> javabase.getTransformedClasses().addClass(cw), + "Unknown package", PluginException.class); + + ResourceFile newResFile = new ResourceFile("java/aaa/file", new byte[0]); + action(() -> globalPool.getTransformedResourceFiles().addResourceFile(newResFile), + "Unknown package", PluginException.class); + action(() -> javabase.getTransformedResourceFiles().addResourceFile(newResFile), + "Unknown package", PluginException.class); + + action(() -> globalPool.getTransformedClasses().forgetClass("java/aaa/file"), + "Unknown package", PluginException.class); + action(() -> javabase.getTransformedClasses().forgetClass("java/aaa/file"), + "Unknown package", PluginException.class); + action(() -> globalPool.getTransformedResourceFiles().forgetResourceFile("java/aaa/file"), + "Unknown package", PluginException.class); + action(() -> javabase.getTransformedResourceFiles().forgetResourceFile("java/aaa/file"), + "Unknown package", PluginException.class); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + }; + Pool resources = new PoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() { + @Override + public int addString(String str) { + return -1; + } + + @Override + public String getString(int id) { + throw new UnsupportedOperationException("Not supported yet."); + } + }); + t.visit(getPool(), resources); + } + + private static class RenameClassVisitor extends ClassVisitor { + + public RenameClassVisitor(ClassWriter cv) { + super(Opcodes.ASM5, cv); + } + + @Override + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + super.visit(version, access, "RENAMED", signature, superName, interfaces); + } + } + + private void testNull() throws Exception { + AsmPlugin t = new AsmPlugin() { + @Override + public void visit(AsmPools pools) { + action(() -> pools.getModulePool(null), "Module name is null", NullPointerException.class); + action(() -> pools.fillOutputResources(null), "Output resource is null", NullPointerException.class); + } + }; + Pool resources = new PoolImpl(ByteOrder.BIG_ENDIAN, new StringTable() { + @Override + public int addString(String str) { + return -1; + } + + @Override + public String getString(int id) { + throw new UnsupportedOperationException("Not supported yet."); + } + }); + action(() -> t.visit(null, resources), "Input resource is null", NullPointerException.class); + action(() -> t.visit(resources, null), "Output resource is null", NullPointerException.class); + t.visit(resources, resources); + } + + private void action(Action action, String message, Class expected) { + try { + System.err.println("Testing: " + message); + action.call(); + throw new AssertionError(message + ": should have failed"); + } catch (Exception e) { + if (!expected.isInstance(e)) { + throw new RuntimeException(e); + } else { + System.err.println("Got exception as expected: " + e); + } + } + } + + private interface Action { + void call() throws Exception; + } +} diff --git a/jdk/test/tools/jlink/asmplugin/PackageMappingTest.java b/jdk/test/tools/jlink/asmplugin/PackageMappingTest.java new file mode 100644 index 00000000000..9453ac5f917 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/PackageMappingTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test plugins + * @author Andrei Eremeev + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * @run main PackageMappingTest + */ +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +import jdk.tools.jlink.internal.plugins.asm.AsmGlobalPool; +import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.WritableResourcePool; +import jdk.tools.jlink.plugin.PluginException; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class PackageMappingTest extends AsmPluginTestBase { + + private final List newFiles = Arrays.asList( + "/java.base/a1/bbb/c", + "/" + TEST_MODULE + "/a2/bbb/d" + ); + + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new PackageMappingTest().test(); + } + + public void test() throws Exception { + TestPlugin[] plugins = new TestPlugin[]{ + new PackageMappingPlugin(newFiles, false), + new PackageMappingPlugin(newFiles, true) + }; + for (TestPlugin p : plugins) { + Pool pool = p.visit(getPool()); + p.test(getPool(), pool); + } + } + + public class PackageMappingPlugin extends TestPlugin { + + private final Map> newFiles; + private final boolean testGlobal; + + private String getModuleName(String res) { + return res.substring(1, res.indexOf("/", 1)); + } + + private PackageMappingPlugin(List files, boolean testGlobal) { + this.newFiles = new HashMap<>(); + this.testGlobal = testGlobal; + for (String file : files) { + String moduleName = getModuleName(file); + String path = file.substring(1 + moduleName.length() + 1); + newFiles.computeIfAbsent(moduleName, $ -> new ArrayList<>()).add( + new ResourceFile(path, new byte[0])); + } + } + + @Override + public void visit() { + testMapToUnknownModule(); + testMapPackageTwice(); + testPackageMapping(); + } + + @Override + public void test(Pool inResources, Pool outResources) { + Set in = getPools().getGlobalPool().getResourceFiles().stream() + .map(ModuleData::getPath) + .collect(Collectors.toSet()); + Set out = extractResources(outResources).stream() + .map(ModuleData::getPath) + .collect(Collectors.toSet()); + in.addAll(PackageMappingTest.this.newFiles); + if (!Objects.equals(in, out)) { + throw new AssertionError("Expected: " + in + ", got: " + outResources); + } + } + + private void testPackageMapping() { + AsmGlobalPool globalPool = getPools().getGlobalPool(); + try { + Map> mappedPackages = new HashMap<>(); + Function> produceSet = $ -> new HashSet<>(); + for (Map.Entry> entry : newFiles.entrySet()) { + String moduleName = entry.getKey(); + Set module = mappedPackages.computeIfAbsent(moduleName, produceSet); + AsmModulePool modulePool = getPools().getModulePool(moduleName); + for (ResourceFile r : entry.getValue()) { + String name = r.getPath(); + String packageName = name.substring(0, name.lastIndexOf('/')); + if (module.add(packageName)) { + globalPool.addPackageModuleMapping(packageName, moduleName); + } + WritableResourcePool transformedResourceFiles = testGlobal + ? globalPool.getTransformedResourceFiles() + : modulePool.getTransformedResourceFiles(); + transformedResourceFiles.addResourceFile(r); + } + try { + modulePool.getTransformedResourceFiles().addResourceFile( + new ResourceFile("a3/bbb", new byte[0])); + throw new AssertionError("Exception expected"); + } catch (Exception ex) { + // expected + } + } + try { + globalPool.getTransformedResourceFiles().addResourceFile( + new ResourceFile("a3/bbb", new byte[0])); + throw new AssertionError("Exception expected"); + } catch (Exception ex) { + // expected + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private void testMapPackageTwice() { + try { + AsmGlobalPool globalPool = getPools().getGlobalPool(); + globalPool.addPackageModuleMapping("a/p1", TEST_MODULE); + globalPool.addPackageModuleMapping("a/p1", TEST_MODULE); + throw new AssertionError("Exception expected after mapping a package twice to the same module"); + } catch (Exception e) { + if (e instanceof PluginException) { + // expected + String message = e.getMessage(); + if (!(TEST_MODULE + " module already contains package a.p1").equals(message)) { + throw new AssertionError(e); + } + } else { + throw new AssertionError(e); + } + } + } + + private void testMapToUnknownModule() { + AsmModulePool unknownModule = getPools().getModulePool("UNKNOWN"); + if (unknownModule != null) { + throw new AssertionError("getModulePool returned not null value: " + unknownModule.getModuleName()); + } + try { + AsmGlobalPool globalPool = getPools().getGlobalPool(); + globalPool.addPackageModuleMapping("a/b", "UNKNOWN"); + throw new AssertionError("Exception expected after mapping a package to unknown module"); + } catch (Exception e) { + String message = e.getMessage(); + if (message == null || !message.startsWith("Unknown module UNKNOWN")) { + throw new AssertionError(e); + } + } + } + } +} diff --git a/jdk/test/tools/jlink/asmplugin/SortingTest.java b/jdk/test/tools/jlink/asmplugin/SortingTest.java new file mode 100644 index 00000000000..0fc4c7a6854 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/SortingTest.java @@ -0,0 +1,181 @@ +/* + * 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. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test resource sorting. + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * @build AsmPluginTestBase + * @run main SortingTest + */ + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import jdk.tools.jlink.internal.plugins.asm.AsmModulePool; +import jdk.tools.jlink.plugin.PluginException; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class SortingTest extends AsmPluginTestBase { + + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new SortingTest().test(); + } + + @Override + public void test() { + try { + classSorting(); + moduleSorting(); + } catch (Exception ex) { + throw new PluginException(ex); + } + } + + private void classSorting() throws Exception { + List sorted = new ArrayList<>(getResources()); + sorted.sort(null); + ClassSorterPlugin sorterPlugin = new ClassSorterPlugin(sorted); + Pool resourcePool = sorterPlugin.visit(getPool()); + sorterPlugin.test(getPool(), resourcePool); + } + + private String getModuleName(String p) { + return p.substring(1, p.indexOf('/', 1)); + } + + private void moduleSorting() throws Exception { + List sorted = new ArrayList<>(getResources()); + sorted.sort((s1, s2) -> -getModuleName(s1).compareTo(getModuleName(s2))); + ModuleSorterPlugin sorterPlugin = new ModuleSorterPlugin(); + Pool resourcePool = sorterPlugin.visit(getPool()); + sorterPlugin.test(getPool(), resourcePool); + } + + private class ModuleSorterPlugin extends TestPlugin { + + @Override + public void visit() { + for (AsmModulePool modulePool : getPools().getModulePools()) { + modulePool.setSorter(resources -> { + List sort = resources.getContent().stream() + .map(ModuleData::getPath) + .collect(Collectors.toList()); + sort.sort(null); + return sort; + }); + } + getPools().setModuleSorter(modules -> { + modules.sort((s1, s2) -> -s1.compareTo(s2)); + return modules; + }); + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + if (!isVisitCalled()) { + throw new AssertionError("Resources not visited"); + } + List sortedResourcePaths = outResources.getContent().stream() + .map(ModuleData::getPath) + .collect(Collectors.toList()); + + List defaultResourceOrder = new ArrayList<>(); + for (ModuleData r : inResources.getContent()) { + if (!inResources.getContent().contains(r)) { + throw new AssertionError("Resource " + r.getPath() + " not in result pool"); + } + defaultResourceOrder.add(r.getPath()); + } + // Check that default sorting is not equal to sorted one + if (defaultResourceOrder.equals(sortedResourcePaths)) { + throw new AssertionError("Sorting not applied, default ordering"); + } + // Check module order. + for (int i = 0; i < sortedResourcePaths.size() - 1; ++i) { + String first = sortedResourcePaths.get(i); + String p1 = getModuleName(first); + String second = sortedResourcePaths.get(i + 1); + String p2 = getModuleName(second); + if (p1.compareTo(p2) < 0 || p1.compareTo(p2) == 0 && + removeModule(first).compareTo(removeModule(second)) >= 0) { + throw new AssertionError("Modules are not sorted properly: resources: " + first + " " + second); + } + } + } + } + + private class ClassSorterPlugin extends TestPlugin { + + private final List expectedClassesOrder; + + private ClassSorterPlugin(List expectedClassesOrder) { + this.expectedClassesOrder = expectedClassesOrder; + } + + @Override + public void visit() { + getPools().getGlobalPool().setSorter( + (resources) -> expectedClassesOrder.stream() + .map(resources::get) + .map(ModuleData::getPath) + .collect(Collectors.toList())); + } + + @Override + public void test(Pool inResources, Pool outResources) throws Exception { + if (!isVisitCalled()) { + throw new AssertionError("Resources not visited"); + } + List sortedResourcePaths = outResources.getContent().stream() + .map(ModuleData::getPath) + .collect(Collectors.toList()); + + List defaultResourceOrder = new ArrayList<>(); + for (ModuleData r : getPool().getContent()) { + if (!getPool().getContent().contains(r)) { + throw new AssertionError("Resource " + r.getPath() + " not in result pool"); + } + defaultResourceOrder.add(r.getPath()); + } + // Check that default sorting is not equal to sorted one + if (defaultResourceOrder.equals(sortedResourcePaths)) { + throw new AssertionError("Sorting not applied, default ordering"); + } + // Check that sorted is equal to result. + if (!expectedClassesOrder.equals(sortedResourcePaths)) { + throw new AssertionError("Sorting not properly applied"); + } + } + } +} diff --git a/jdk/test/tools/jlink/asmplugin/VisitorTest.java b/jdk/test/tools/jlink/asmplugin/VisitorTest.java new file mode 100644 index 00000000000..1b278a8bd48 --- /dev/null +++ b/jdk/test/tools/jlink/asmplugin/VisitorTest.java @@ -0,0 +1,219 @@ +/* + * 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. + */ + +/* + * Asm plugin testing. + * @test + * @summary Test visitors. + * @author Andrei Eremeev + * @modules java.base/jdk.internal.org.objectweb.asm + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins.asm + * @build AsmPluginTestBase + * @run main VisitorTest + */ + +import java.io.IOException; +import java.util.Collection; +import java.util.function.Function; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.tools.jlink.internal.plugins.asm.AsmPool; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.ClassReaderVisitor; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFile; +import jdk.tools.jlink.internal.plugins.asm.AsmPool.ResourceFileVisitor; +import jdk.tools.jlink.internal.plugins.asm.AsmPools; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class VisitorTest extends AsmPluginTestBase { + + public static void main(String[] args) throws Exception { + if (!isImageBuild()) { + System.err.println("Test not run. Not image build."); + return; + } + new VisitorTest().test(); + } + + @Override + public void test() throws Exception { + TestPlugin[] plugins = new TestPlugin[] { + new ClassVisitorPlugin("Class-global-pool", AsmPools::getGlobalPool), + new ClassVisitorPlugin("Class-module-pool", pools -> pools.getModulePool("java.base")), + new ResourceVisitorPlugin("Resource-global-pool", AsmPools::getGlobalPool), + new ResourceVisitorPlugin("Resource-module-pool", pools -> pools.getModulePool("java.base")) + }; + for (TestPlugin p : plugins) { + System.err.println("Testing: " + p.getName()); + Pool out = p.visit(getPool()); + p.test(getPool(), out); + } + } + + private static class CustomClassReaderVisitor implements ClassReaderVisitor { + private int amount = 0; + private int changed = 0; + + @Override + public ClassWriter visit(ClassReader reader) { + if ((amount++ % 2) == 0) { + String className = reader.getClassName(); + if (className.endsWith("module-info")) { + return null; + } + ClassWriter cw = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES); + reader.accept(new ClassVisitor(Opcodes.ASM5, cw) { + @Override + public void visit(int i, int i1, String s, String s1, String s2, String[] strings) { + super.visit(i, i1, s + "Changed", s1, s2, strings); + } + }, ClassReader.EXPAND_FRAMES); + ++changed; + return cw; + } else { + return null; + } + } + + public int getAmount() { + return amount; + } + + public int getNumberOfChanged() { + return changed; + } + } + + private static class CustomResourceFileVisitor implements ResourceFileVisitor { + private int amount = 0; + private int changed = 0; + + @Override + public ResourceFile visit(ResourceFile resourceFile) { + if ((amount++ % 2) == 0) { + ++changed; + return new ResourceFile(resourceFile.getPath() + "Changed", resourceFile.getContent()); + } else { + return null; + } + } + + public int getAmount() { + return amount; + } + + public int getNumberOfChanged() { + return changed; + } + } + + public class ClassVisitorPlugin extends TestPlugin { + + private final String name; + private final Function getPool; + private final CustomClassReaderVisitor classReaderVisitor = new CustomClassReaderVisitor(); + + public ClassVisitorPlugin(String name, Function getPool) { + this.name = name; + this.getPool = getPool; + } + + @Override + public void visit() { + AsmPool pool = getPool.apply(getPools()); + pool.visitClassReaders(classReaderVisitor); + } + + @Override + public void test(Pool in, Pool out) throws Exception { + Collection inClasses = getPool.apply(getPools()).getClasses(); + if (inClasses.size() != classReaderVisitor.getAmount()) { + throw new AssertionError("Testing " + name + ". Number of visited classes. Expected: " + + inClasses.size() + ", got: " + classReaderVisitor.getAmount()); + } + Collection outClasses = extractClasses(out); + int changedClasses = 0; + for (ModuleData r : outClasses) { + if (r.getPath().endsWith("Changed.class")) { + ++changedClasses; + } + } + if (changedClasses != classReaderVisitor.getNumberOfChanged()) { + throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses + + ", got: " + classReaderVisitor.getNumberOfChanged()); + } + } + + @Override + public String getName() { + return name; + } + } + + public class ResourceVisitorPlugin extends TestPlugin { + + private final String name; + private final Function getPool; + private final CustomResourceFileVisitor resourceFileVisitor = new CustomResourceFileVisitor(); + + public ResourceVisitorPlugin(String name, Function getPool) { + this.name = name; + this.getPool = getPool; + } + + @Override + public void visit() { + AsmPool pool = getPool.apply(getPools()); + pool.visitResourceFiles(resourceFileVisitor); + } + + @Override + public void test(Pool in, Pool out) throws Exception { + Collection inResources = getPool.apply(getPools()).getResourceFiles(); + if (inResources.size() != resourceFileVisitor.getAmount()) { + throw new AssertionError("Testing " + name + ". Number of visited resources. Expected: " + + inResources.size() + ", got: " + resourceFileVisitor.getAmount()); + } + Collection outResources = extractResources(out); + int changedClasses = 0; + for (ModuleData r : outResources) { + if (r.getPath().endsWith("Changed")) { + ++changedClasses; + } + } + if (changedClasses != resourceFileVisitor.getNumberOfChanged()) { + throw new AssertionError("Testing " + name + ". Changed classes. Expected: " + changedClasses + + ", got: " + resourceFileVisitor.getNumberOfChanged()); + } + } + + @Override + public String getName() { + return name; + } + } +} diff --git a/jdk/test/tools/jlink/basic/BasicTest.java b/jdk/test/tools/jlink/basic/BasicTest.java new file mode 100644 index 00000000000..4135f4a2141 --- /dev/null +++ b/jdk/test/tools/jlink/basic/BasicTest.java @@ -0,0 +1,131 @@ +/** + * 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. + */ + +/* + * @test + * @summary Basic test of jlink to create jmods and images + * @author Andrei Eremeev + * @library /lib/testlibrary + * @modules java.base/jdk.internal.module + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @build jdk.testlibrary.ProcessTools + * jdk.testlibrary.OutputAnalyzer + * JarUtils CompilerUtils + * @run main BasicTest + */ + +import java.io.File; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +public class BasicTest { + + private final Path jdkHome = Paths.get(System.getProperty("test.jdk")); + private final Path jdkMods = jdkHome.resolve("jmods"); + private final Path testSrc = Paths.get(System.getProperty("test.src")); + private final Path src = testSrc.resolve("src"); + private final Path classes = Paths.get("classes"); + private final Path jmods = Paths.get("jmods"); + private final Path jars = Paths.get("jars"); + + public static void main(String[] args) throws Throwable { + new BasicTest().run(); + } + + public void run() throws Throwable { + if (Files.notExists(jdkMods)) { + return; + } + + if (!CompilerUtils.compile(src, classes)) { + throw new AssertionError("Compilation failure. See log."); + } + + String modName = "test"; + Files.createDirectories(jmods); + Files.createDirectories(jars); + Path jarfile = jars.resolve("test.jar"); + JarUtils.createJarFile(jarfile, classes); + + Path image = Paths.get("mysmallimage"); + runJmod(jarfile.toString(), modName); + runJlink(image, modName, "--compress", "2"); + execute(image, modName); + + Files.delete(jmods.resolve(modName + ".jmod")); + + image = Paths.get("myimage"); + runJmod(classes.toString(), modName); + runJlink(image, modName); + execute(image, modName); + } + + private void execute(Path image, String moduleName) throws Throwable { + String cmd = image.resolve("bin").resolve(moduleName).toString(); + OutputAnalyzer analyzer; + if (System.getProperty("os.name").startsWith("Windows")) { + analyzer = ProcessTools.executeProcess("sh.exe", cmd, "1", "2", "3"); + } else { + analyzer = ProcessTools.executeProcess(cmd, "1", "2", "3"); + } + if (analyzer.getExitValue() != 0) { + throw new AssertionError("Image invocation failed: rc=" + analyzer.getExitValue()); + } + } + + private void runJlink(Path image, String modName, String... options) { + List args = new ArrayList<>(); + Collections.addAll(args, + "--modulepath", jdkMods + File.pathSeparator + jmods, + "--addmods", modName, + "--output", image.toString()); + Collections.addAll(args, options); + int rc = jdk.tools.jlink.internal.Main.run(args.toArray(new String[args.size()]), new PrintWriter(System.out)); + if (rc != 0) { + throw new AssertionError("Jlink failed: rc = " + rc); + } + } + + private void runJmod(String cp, String modName) { + int rc = jdk.tools.jmod.Main.run(new String[] { + "create", + "--class-path", cp, + "--module-version", "1.0", + "--main-class", "jdk.test.Test", + jmods.resolve(modName + ".jmod").toString(), + }, System.out); + if (rc != 0) { + throw new AssertionError("Jmod failed: rc = " + rc); + } + } +} diff --git a/jdk/test/tools/jlink/basic/src/test/jdk/test/Test.java b/jdk/test/tools/jlink/basic/src/test/jdk/test/Test.java new file mode 100644 index 00000000000..e038745c80b --- /dev/null +++ b/jdk/test/tools/jlink/basic/src/test/jdk/test/Test.java @@ -0,0 +1,47 @@ +/** + * 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. + */ + +package jdk.test; + +import java.lang.reflect.Module; +import java.lang.reflect.Layer; + +public class Test { + public static void main(String[] args) { + System.out.println(Test.class + " ..."); + for (String arg: args) { + System.out.println(arg); + } + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ClassLoader cl1 = Test.class.getClassLoader(); + Module testModule = Test.class.getModule(); + ClassLoader cl2 = Layer.boot().findLoader(testModule.getName()); + + if (cl1 != scl) + throw new RuntimeException("Not loaded by system class loader"); + if (cl2 != scl) + throw new RuntimeException("Not associated with system class loader"); + + } +} diff --git a/jdk/test/tools/jlink/basic/src/test/module-info.java b/jdk/test/tools/jlink/basic/src/test/module-info.java new file mode 100644 index 00000000000..1972e2c7379 --- /dev/null +++ b/jdk/test/tools/jlink/basic/src/test/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module test { +} diff --git a/jdk/test/tools/jlink/customplugin/module-info.java b/jdk/test/tools/jlink/customplugin/module-info.java new file mode 100644 index 00000000000..63e227544ba --- /dev/null +++ b/jdk/test/tools/jlink/customplugin/module-info.java @@ -0,0 +1,28 @@ +/* + * 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. + */ + +module customplugin { + requires jdk.jlink; + provides jdk.tools.jlink.plugin.TransformerPlugin with plugin.HelloPlugin; + provides jdk.tools.jlink.plugin.TransformerPlugin with plugin.CustomPlugin; +} diff --git a/jdk/test/tools/jlink/customplugin/plugin/CustomPlugin.java b/jdk/test/tools/jlink/customplugin/plugin/CustomPlugin.java new file mode 100644 index 00000000000..38054ec2015 --- /dev/null +++ b/jdk/test/tools/jlink/customplugin/plugin/CustomPlugin.java @@ -0,0 +1,69 @@ +/* + * 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 plugin; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class CustomPlugin implements TransformerPlugin { + + private final static String NAME = "custom-plugin"; + + public CustomPlugin() { + } + + @Override + public void visit(Pool in, Pool out) { + in.visit(new Pool.Visitor() { + @Override + public Pool.ModuleData visit(Pool.ModuleData content) { + return content; + } + }, out); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public String getDescription() { + return NAME + "-description"; + } + + @Override + public void configure(Map config) { + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.PROCESSOR); + return Collections.unmodifiableSet(set); + } +} diff --git a/jdk/test/tools/jlink/customplugin/plugin/HelloPlugin.java b/jdk/test/tools/jlink/customplugin/plugin/HelloPlugin.java new file mode 100644 index 00000000000..d06f99050b1 --- /dev/null +++ b/jdk/test/tools/jlink/customplugin/plugin/HelloPlugin.java @@ -0,0 +1,76 @@ +/* + * 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 plugin; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; + +/** + * Custom plugin + */ +public final class HelloPlugin implements TransformerPlugin { + + private static final String OUTPUT_FILE = "customplugin.txt"; + public static final String NAME = "hello"; + + public static boolean called; + + @Override + public String getName() { + return NAME; + } + + @Override + public void visit(Pool inResources, Pool outResources) { + try { + System.out.println("Hello!!!!!!!!!!"); + File f = new File(OUTPUT_FILE); + f.createNewFile(); + for (ModuleData res : inResources.getContent()) { + outResources.add(res); + } + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + + @Override + public String getDescription() { + return NAME + "-description"; + } +} diff --git a/jdk/test/tools/jlink/hashes/HashesTest.java b/jdk/test/tools/jlink/hashes/HashesTest.java new file mode 100644 index 00000000000..8060bd9d466 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/HashesTest.java @@ -0,0 +1,160 @@ +/** + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test the recording and checking of dependency hashes + * @author Andrei Eremeev + * @library /lib/testlibrary + * @modules java.base/jdk.internal.module + * jdk.jlink/jdk.tools.jlink + * jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @ignore + * @build jdk.testlibrary.ProcessTools jdk.testlibrary.OutputAnalyzer CompilerUtils + * @run main HashesTest + */ + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +import jdk.testlibrary.OutputAnalyzer; +import jdk.testlibrary.ProcessTools; + +public class HashesTest { + + private final Path jdkHome = Paths.get(System.getProperty("test.jdk")); + private final Path stdJmods = jdkHome.resolve("jmods"); + private final Path testSrc = Paths.get(System.getProperty("test.src")); + private final Path modSrc = testSrc.resolve("src"); + private final Path newModSrc = testSrc.resolve("newsrc"); + private final Path classes = Paths.get("classes"); + private final Path jmods = Paths.get("jmods"); + + public static void main(String[] args) throws Exception { + new HashesTest().run(); + } + + private void run() throws Exception { + if (!Files.exists(stdJmods)) { + return; + } + Files.createDirectories(jmods); + Path m1Classes = classes.resolve("m1"); + Path m2Classes = classes.resolve("m2"); + Path m3Classes = classes.resolve("not_matched"); + // build the second module + compileClasses(modSrc, m2Classes); + runJmod(m2Classes.toString(), m2Classes.getFileName().toString()); + + // build the third module + compileClasses(modSrc, m3Classes); + runJmod(m3Classes.toString(), m3Classes.getFileName().toString()); + + compileClasses(modSrc, m1Classes, "-mp", jmods.toString()); + runJmod(m1Classes.toString(), m1Classes.getFileName().toString(), + "--modulepath", jmods.toString(), "--hash-dependencies", "m2"); + runJava(0, "-mp", jmods.toString(), "-m", "m1/org.m1.Main"); + + deleteDirectory(m3Classes); + Files.delete(jmods.resolve("not_matched.jmod")); + + // build the new third module + compileClasses(newModSrc, m3Classes); + runJmod(m3Classes.toString(), m3Classes.getFileName().toString()); + runJava(0, "-mp", jmods.toString(), "-m", "m1/org.m1.Main"); + + deleteDirectory(m2Classes); + Files.delete(jmods.resolve("m2.jmod")); + + compileClasses(newModSrc, m2Classes); + runJmod(m2Classes.toString(), m2Classes.getFileName().toString()); + + runJava(1, "-mp", jmods.toString(), "-m", "m1/org.m1.Main"); + + if (jdk.tools.jlink.internal.Main.run(new String[]{ + "--modulepath", stdJmods.toString() + File.pathSeparator + jmods.toString(), + "--addmods", "m1", "--output", "myimage"}, new PrintWriter(System.out)) == 0) { + throw new AssertionError("Expected failure. rc = 0"); + } + } + + private void deleteDirectory(Path dir) throws IOException { + Files.walkFileTree(dir, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + }); + } + + private void runJava(int expectedExitCode, String... args) throws Exception { + OutputAnalyzer analyzer = ProcessTools.executeTestJava(args); + if (analyzer.getExitValue() != expectedExitCode) { + throw new AssertionError("Expected exit code: " + expectedExitCode + + ", got: " + analyzer.getExitValue()); + } + } + + private void compileClasses(Path src, Path output, String... options) throws IOException { + List args = new ArrayList<>(); + Collections.addAll(args, options); + Collections.addAll(args, "-d", output.toString()); + args.add(src.toString()); + System.out.println("javac options: " + args.stream().collect(Collectors.joining(" "))); + if (!CompilerUtils.compile(src.resolve(output.getFileName()), output, options)) { + throw new AssertionError("Compilation failure. See log."); + } + } + + private void runJmod(String cp, String modName, String... options) { + List args = new ArrayList<>(); + args.add("create"); + Collections.addAll(args, options); + Collections.addAll(args, "--class-path", cp, + jmods + File.separator + modName + ".jmod"); + int rc = jdk.tools.jmod.Main.run(args.toArray(new String[args.size()]), System.out); + System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" "))); + if (rc != 0) { + throw new AssertionError("Jmod failed: rc = " + rc); + } + } +} diff --git a/jdk/test/tools/jlink/hashes/newsrc/m2/module-info.java b/jdk/test/tools/jlink/hashes/newsrc/m2/module-info.java new file mode 100644 index 00000000000..4489049b402 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/newsrc/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + exports org.m2; +} diff --git a/jdk/test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java b/jdk/test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java new file mode 100644 index 00000000000..b7e0b62fc77 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java @@ -0,0 +1,32 @@ +/* + * 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 org.m2; + +public class Util { + private Util() { } + + public static String timeOfDay() { + return "Time for a beer"; + } +} diff --git a/jdk/test/tools/jlink/hashes/newsrc/not_matched/module-info.java b/jdk/test/tools/jlink/hashes/newsrc/not_matched/module-info.java new file mode 100644 index 00000000000..a72988ae6ae --- /dev/null +++ b/jdk/test/tools/jlink/hashes/newsrc/not_matched/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module not_matched { + exports org.not_matched; +} diff --git a/jdk/test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java b/jdk/test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java new file mode 100644 index 00000000000..eb71f80b451 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java @@ -0,0 +1,32 @@ +/* + * 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 org.not_matched; + +public class Name { + private Name() { } + + public static String name() { + return "new_module"; + } +} diff --git a/jdk/test/tools/jlink/hashes/src/m1/module-info.java b/jdk/test/tools/jlink/hashes/src/m1/module-info.java new file mode 100644 index 00000000000..8268cd84662 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/src/m1/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m1 { + requires m2; + requires not_matched; +} diff --git a/jdk/test/tools/jlink/hashes/src/m1/org/m1/Main.java b/jdk/test/tools/jlink/hashes/src/m1/org/m1/Main.java new file mode 100644 index 00000000000..5b1d2f0c8e3 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/src/m1/org/m1/Main.java @@ -0,0 +1,34 @@ +/* + * 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 org.m1; + +import org.m2.Util; +import org.not_matched.Name; + +public class Main { + public static void main(String[] args) { + System.out.println(Util.timeOfDay()); + System.out.println(Name.name()); + } +} diff --git a/jdk/test/tools/jlink/hashes/src/m2/module-info.java b/jdk/test/tools/jlink/hashes/src/m2/module-info.java new file mode 100644 index 00000000000..4489049b402 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/src/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + exports org.m2; +} diff --git a/jdk/test/tools/jlink/hashes/src/m2/org/m2/Util.java b/jdk/test/tools/jlink/hashes/src/m2/org/m2/Util.java new file mode 100644 index 00000000000..b6ae4950971 --- /dev/null +++ b/jdk/test/tools/jlink/hashes/src/m2/org/m2/Util.java @@ -0,0 +1,32 @@ +/* + * 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 org.m2; + +public class Util { + private Util() { } + + public static String timeOfDay() { + return "Time for lunch"; + } +} diff --git a/jdk/test/tools/jlink/hashes/src/not_matched/module-info.java b/jdk/test/tools/jlink/hashes/src/not_matched/module-info.java new file mode 100644 index 00000000000..a72988ae6ae --- /dev/null +++ b/jdk/test/tools/jlink/hashes/src/not_matched/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module not_matched { + exports org.not_matched; +} diff --git a/jdk/test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java b/jdk/test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java new file mode 100644 index 00000000000..d17333408cb --- /dev/null +++ b/jdk/test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java @@ -0,0 +1,32 @@ +/* + * 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 org.not_matched; + +public class Name { + private Name() { } + + public static String name() { + return "old_module"; + } +} diff --git a/jdk/test/tools/jlink/optimplugin/module-info.java b/jdk/test/tools/jlink/optimplugin/module-info.java new file mode 100644 index 00000000000..87eac36079f --- /dev/null +++ b/jdk/test/tools/jlink/optimplugin/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module optimplugin { + exports optim; +} diff --git a/jdk/test/tools/jlink/optimplugin/optim/AType.java b/jdk/test/tools/jlink/optimplugin/optim/AType.java new file mode 100644 index 00000000000..6f5e038a7c2 --- /dev/null +++ b/jdk/test/tools/jlink/optimplugin/optim/AType.java @@ -0,0 +1,28 @@ +/* + * 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 optim; + +//package class +class AType { +} diff --git a/jdk/test/tools/jlink/optimplugin/optim/ForNameTestCase.java b/jdk/test/tools/jlink/optimplugin/optim/ForNameTestCase.java new file mode 100644 index 00000000000..b3452c384a0 --- /dev/null +++ b/jdk/test/tools/jlink/optimplugin/optim/ForNameTestCase.java @@ -0,0 +1,172 @@ +/* + * 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 optim; + +public class ForNameTestCase { + private static final String EXPECTED = "expected"; + public static Class forName() { + try { + Class cl = Class.forName("java.lang.String"); + return cl; + } catch (ClassNotFoundException | + IllegalArgumentException | + ClassCastException x) { + throw new InternalError(x); + } + } + + public static Class forName0() throws ClassNotFoundException { + return Class.forName("java.lang.String"); + } + + public static Class forName1() throws Exception { + Class clazz = null; + try { + clazz = Class.forName("java.lang.String"); + } catch (ClassNotFoundException e) { + return null; + } + return clazz; + } + + public static void forNameException() throws Exception { + try { + Class.forName("java.lang.String"); + throw new Exception(EXPECTED); + } catch (ClassNotFoundException e) { + return; + } catch (RuntimeException e) { + return; + } + } + + public static Class forName2() throws Exception { + Class clazz = null; + try { + clazz = Class.forName("java.lang.String"); + try { + throw new Exception("das"); + } catch (Exception ex) { + } + } catch (ClassNotFoundException e) { + return null; + } + return clazz; + } + + public static Class forName3() throws Exception { + Class clazz = null; + try { + return clazz = Class.forName("java.lang.String"); + } catch (ClassNotFoundException e) { + return null; + } + } + + public static Class forName4() throws Exception { + Class clazz = null; + try { + clazz = Class.forName("java.lang.String"); + } catch (ClassNotFoundException e) { + return null; + } catch (RuntimeException e) { + return null; + } + return clazz; + } + + public static Class forName5() { + Class clazz = null; + try { + clazz = Class.forName("java.lang.String"); + } catch (ClassNotFoundException e) { + } + int i; + try { + i = 0; + } catch (Exception e) { + } + return clazz; + } + + public static Class forName6() { + Class clazz = null; + try { + return Class.forName("java.lang.String"); + } catch (ClassNotFoundException e) { + } + + try { + // This one is removed because no more reachable when + // Class.forName is removed + int k = 0; + } catch (RuntimeException e) { + } + + int i; + try { + // This one is removed because no more reachable when + // Class.forName is removed + return Class.forName("TOTO"); + } catch (ClassNotFoundException e) { + } + try { + // This one is removed because no more reachable when + // Class.forName is removed + return Class.forName("TOTO"); + } catch (ClassNotFoundException e) { + } + try { + // This one is removed because no more reachable when + // Class.forName is removed + return Class.forName("TOTO"); + } catch (ClassNotFoundException e) { + } + try { + // This one is removed because no more reachable when + // Class.forName is removed + return Class.forName("TOTO"); + } catch (ClassNotFoundException e) { + } + return clazz; + } + + public static Class forName7() { + Class clazz = null; + try { + clazz = Class.forName("optim.AType"); + } catch (ClassNotFoundException e) { + } + return clazz; + } + + public static Class negativeforName() { + Class clazz = null; + try { + clazz = Class.forName("jdk.internal.jimage.BasicImageReader"); + } catch (ClassNotFoundException e) { + } + return clazz; + } +} diff --git a/jdk/test/tools/jlink/plugins/CompressIndexesTest.java b/jdk/test/tools/jlink/plugins/CompressIndexesTest.java new file mode 100644 index 00000000000..d13807e3eaa --- /dev/null +++ b/jdk/test/tools/jlink/plugins/CompressIndexesTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test CompressIndexes + * @author Jean-Francois Denise + * @modules java.base/jdk.internal.jimage.decompressor + * @run main CompressIndexesTest + */ + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import jdk.internal.jimage.decompressor.CompressIndexes; + +public class CompressIndexesTest { + + public static void main(String[] args) throws IOException { + new CompressIndexesTest().test(); + } + + public void test() throws IOException { + int[] data = { + // compressed length 1 + 0x00000000, + 0x00000001, + 0x0000000F, + 0x0000001F, + // compressed length 2 + 0x0000002F, + 0x00000100, + 0x00001FFF, + // compressed length 3 + 0x00002FFF, + 0x00010000, + 0x001FFFFF, + // compressed length 4 + 0x00200000, + 0x01000000, + Integer.MAX_VALUE + }; + int[] intervals = {4, 7, 10, data.length}; + List arrays = new ArrayList<>(); + int length = 0; + int begin = 0; + for (int interval : intervals) { + ++length; + for (int j = begin; j < interval; ++j) { + arrays.add(check(data[j], length)); + } + begin = interval; + } + + int totalLength = arrays.stream().mapToInt(b -> b.length).sum(); + ByteBuffer all = ByteBuffer.allocate(totalLength); + arrays.forEach(all::put); + byte[] flow = all.array(); + check(flow, arrays); + System.err.println(arrays.size() * 4 + " compressed in " + flow.length + + " gain of " + (100 - ((flow.length * 100) / (arrays.size() * 4))) + "%"); + try (DataInputStream is = new DataInputStream(new ByteArrayInputStream(flow))) { + int index = 0; + while (is.available() > 0) { + int d = CompressIndexes.readInt(is); + if (data[index] != d) { + throw new AssertionError("Expected: " + data[index] + ", got: " + d); + } + ++index; + } + } + } + + private void check(byte[] flow, List arrays) { + List d = CompressIndexes.decompressFlow(flow); + List dd = new ArrayList<>(); + for (byte[] b : arrays) { + int i = CompressIndexes.decompress(b, 0); + dd.add(i); + } + if (!d.equals(dd)) { + System.err.println(dd); + System.err.println(d); + throw new AssertionError("Invalid flow " + d); + } else { + System.err.println("OK for flow"); + } + } + + private byte[] check(int val, int size) { + byte[] c = CompressIndexes.compress(val); + if (c.length != size) { + throw new AssertionError("Invalid compression size " + c.length); + } + int d = CompressIndexes.decompress(c, 0); + if (val != d) { + throw new AssertionError("Invalid " + d); + } else { + System.err.println("Ok for " + val); + } + return c; + } +} diff --git a/jdk/test/tools/jlink/plugins/CompressorPluginTest.java b/jdk/test/tools/jlink/plugins/CompressorPluginTest.java new file mode 100644 index 00000000000..cd01b93836b --- /dev/null +++ b/jdk/test/tools/jlink/plugins/CompressorPluginTest.java @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test zip compressor + * @author Jean-Francois Denise + * @modules java.base/jdk.internal.jimage.decompressor + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main CompressorPluginTest + */ +import java.net.URI; +import java.nio.ByteOrder; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.internal.jimage.decompressor.CompressedResourceHeader; +import jdk.internal.jimage.decompressor.ResourceDecompressor; +import jdk.internal.jimage.decompressor.ResourceDecompressorFactory; +import jdk.internal.jimage.decompressor.StringSharingDecompressorFactory; +import jdk.internal.jimage.decompressor.ZipDecompressorFactory; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.StringTable; +import jdk.tools.jlink.internal.plugins.DefaultCompressPlugin; +import jdk.tools.jlink.internal.plugins.StringSharingPlugin; +import jdk.tools.jlink.internal.plugins.ZipPlugin; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class CompressorPluginTest { + + private static int strID = 1; + + public static void main(String[] args) throws Exception { + new CompressorPluginTest().test(); + } + + public void test() throws Exception { + FileSystem fs; + try { + fs = FileSystems.getFileSystem(URI.create("jrt:/")); + } catch (ProviderNotFoundException | FileSystemNotFoundException e) { + System.err.println("Not an image build, test skipped."); + return; + } + Path javabase = fs.getPath("/modules/java.base"); + + checkCompress(gatherResources(javabase), new ZipPlugin(), null, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory() + }); + + Pool classes = gatherClasses(javabase); + // compress = String sharing + checkCompress(classes, new StringSharingPlugin(), null, + new ResourceDecompressorFactory[]{ + new StringSharingDecompressorFactory()}); + + // compress == ZIP + String sharing + Properties options = new Properties(); + options.setProperty(ZipPlugin.NAME, ""); + checkCompress(classes, new DefaultCompressPlugin(), options, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + new StringSharingDecompressorFactory() + }); + + // compress == ZIP + String sharing + filter + options.setProperty(DefaultCompressPlugin.FILTER, + "*Exception.class,^*IOException.class"); + checkCompress(classes, new DefaultCompressPlugin(), options, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + new StringSharingDecompressorFactory() + }, Collections.singletonList(".*Exception.class"), + Collections.singletonList(".*IOException.class")); + + // compress level 1 == ZIP + Properties options1 = new Properties(); + options1.setProperty(DefaultCompressPlugin.NAME, + "1"); + checkCompress(classes, new DefaultCompressPlugin(), + options1, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory() + }); + + // compress level 1 == ZIP + options1.setProperty(DefaultCompressPlugin.FILTER, + "*Exception.class,^*IOException.class"); + checkCompress(classes, new DefaultCompressPlugin(), + options1, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory() + }, Collections.singletonList(".*Exception.class"), + Collections.singletonList(".*IOException.class")); + + // compress level 2 == ZIP + String sharing + Properties options2 = new Properties(); + options2.setProperty(DefaultCompressPlugin.NAME, + "2"); + checkCompress(classes, new DefaultCompressPlugin(), + options2, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + new StringSharingDecompressorFactory() + }); + + // compress level 2 == ZIP + String sharing + filter + options2.setProperty(DefaultCompressPlugin.FILTER, + "*Exception.class,^*IOException.class"); + checkCompress(classes, new DefaultCompressPlugin(), + options2, + new ResourceDecompressorFactory[]{ + new ZipDecompressorFactory(), + new StringSharingDecompressorFactory() + }, Collections.singletonList(".*Exception.class"), + Collections.singletonList(".*IOException.class")); + + // compress level 0 == String sharing + Properties options0 = new Properties(); + options0.setProperty(DefaultCompressPlugin.NAME, "0"); + checkCompress(classes, new DefaultCompressPlugin(), + options0, + new ResourceDecompressorFactory[]{ + new StringSharingDecompressorFactory() + }); + + // compress level 0 == String sharing + filter + options0.setProperty(DefaultCompressPlugin.FILTER, + "*Exception.class,^*IOException.class"); + checkCompress(classes, new DefaultCompressPlugin(), + options0, + new ResourceDecompressorFactory[]{ + new StringSharingDecompressorFactory() + }, Collections.singletonList(".*Exception.class"), + Collections.singletonList(".*IOException.class")); + } + + private Pool gatherResources(Path module) throws Exception { + Pool pool = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() { + + @Override + public int addString(String str) { + return -1; + } + + @Override + public String getString(int id) { + return null; + } + }); + try (Stream stream = Files.walk(module)) { + for (Iterator iterator = stream.iterator(); iterator.hasNext();) { + Path p = iterator.next(); + if (Files.isRegularFile(p)) { + byte[] content = Files.readAllBytes(p); + pool.add(Pool.newResource(p.toString(), content)); + } + } + } + return pool; + } + + private Pool gatherClasses(Path module) throws Exception { + Pool pool = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() { + + @Override + public int addString(String str) { + return -1; + } + + @Override + public String getString(int id) { + return null; + } + }); + try (Stream stream = Files.walk(module)) { + for (Iterator iterator = stream.iterator(); iterator.hasNext();) { + Path p = iterator.next(); + if (Files.isRegularFile(p) && p.toString().endsWith(".class")) { + byte[] content = Files.readAllBytes(p); + pool.add(Pool.newResource(p.toString(), content)); + } + } + } + return pool; + } + + private void checkCompress(Pool resources, Plugin prov, + Properties config, + ResourceDecompressorFactory[] factories) throws Exception { + checkCompress(resources, prov, config, factories, Collections.emptyList(), Collections.emptyList()); + } + + private void checkCompress(Pool resources, Plugin prov, + Properties config, + ResourceDecompressorFactory[] factories, + List includes, + List excludes) throws Exception { + long original = 0; + long compressed = 0; + for (ModuleData resource : resources.getContent()) { + List includesPatterns = includes.stream() + .map(Pattern::compile) + .collect(Collectors.toList()); + List excludesPatterns = excludes.stream() + .map(Pattern::compile) + .collect(Collectors.toList()); + + Map props = new HashMap<>(); + if (config != null) { + for (String p : config.stringPropertyNames()) { + props.put(p, config.getProperty(p)); + } + } + prov.configure(props); + final Map strings = new HashMap<>(); + PoolImpl inputResources = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() { + @Override + public int addString(String str) { + int id = strID; + strID += 1; + strings.put(id, str); + return id; + } + + @Override + public String getString(int id) { + return strings.get(id); + } + }); + inputResources.add(resource); + Pool compressedResources = applyCompressor(prov, inputResources, resource, includesPatterns, excludesPatterns); + original += resource.getLength(); + compressed += compressedResources.get(resource.getPath()).getLength(); + applyDecompressors(factories, inputResources, compressedResources, strings, includesPatterns, excludesPatterns); + } + String compressors = Stream.of(factories) + .map(Object::getClass) + .map(Class::getSimpleName) + .collect(Collectors.joining(", ")); + String size = "Compressed size: " + compressed + ", original size: " + original; + System.out.println("Used " + compressors + ". " + size); + if (original <= compressed) { + throw new AssertionError("java.base not compressed."); + } + } + + private Pool applyCompressor(Plugin plugin, + PoolImpl inputResources, + ModuleData res, + List includesPatterns, + List excludesPatterns) throws Exception { + TransformerPlugin compressor = (TransformerPlugin) plugin; + Pool compressedPool = new PoolImpl(ByteOrder.nativeOrder(), inputResources.getStringTable()); + compressor.visit(inputResources, compressedPool); + String path = res.getPath(); + ModuleData compressed = compressedPool.get(path); + CompressedResourceHeader header + = CompressedResourceHeader.readFromResource(ByteOrder.nativeOrder(), compressed.getBytes()); + if (isIncluded(includesPatterns, excludesPatterns, path)) { + if (header == null) { + throw new AssertionError("Path should be compressed: " + path); + } + if (header.getDecompressorNameOffset() == 0) { + throw new AssertionError("Invalid plugin offset " + + header.getDecompressorNameOffset()); + } + if (header.getResourceSize() <= 0) { + throw new AssertionError("Invalid compressed size " + + header.getResourceSize()); + } + } else if (header != null) { + throw new AssertionError("Path should not be compressed: " + path); + } + return compressedPool; + } + + private void applyDecompressors(ResourceDecompressorFactory[] decompressors, + Pool inputResources, + Pool compressedResources, + Map strings, + List includesPatterns, + List excludesPatterns) throws Exception { + for (ModuleData compressed : compressedResources.getContent()) { + CompressedResourceHeader header = CompressedResourceHeader.readFromResource( + ByteOrder.nativeOrder(), compressed.getBytes()); + String path = compressed.getPath(); + ModuleData orig = inputResources.get(path); + if (!isIncluded(includesPatterns, excludesPatterns, path)) { + continue; + } + byte[] decompressed = compressed.getBytes(); + for (ResourceDecompressorFactory factory : decompressors) { + ResourceDecompressor decompressor = factory.newDecompressor(new Properties()); + decompressed = decompressor.decompress( + strings::get, decompressed, + CompressedResourceHeader.getSize(), header.getUncompressedSize()); + } + + if (decompressed.length != orig.getLength()) { + throw new AssertionError("Invalid uncompressed size " + + header.getUncompressedSize()); + } + byte[] origContent = orig.getBytes(); + for (int i = 0; i < decompressed.length; i++) { + if (decompressed[i] != origContent[i]) { + throw new AssertionError("Decompressed and original differ at index " + i); + } + } + } + } + + private boolean isIncluded(List includesPatterns, List excludesPatterns, String path) { + return !excludesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches()) + && (includesPatterns.isEmpty() + || includesPatterns.stream().anyMatch((pattern) -> pattern.matcher(path).matches())); + } +} diff --git a/jdk/test/tools/jlink/plugins/ExcludeFilesPluginTest.java b/jdk/test/tools/jlink/plugins/ExcludeFilesPluginTest.java new file mode 100644 index 00000000000..cde83aa2761 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/ExcludeFilesPluginTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test exclude files plugin + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main ExcludeFilesPluginTest + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import jdk.tools.jlink.internal.PoolImpl; + +import jdk.tools.jlink.internal.plugins.ExcludeFilesPlugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.Pool.ModuleDataType; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class ExcludeFilesPluginTest { + public static void main(String[] args) throws Exception { + new ExcludeFilesPluginTest().test(); + } + + public void test() throws Exception { + checkFiles("*.jcov", "num/toto.jcov", "", true); + checkFiles("*.jcov", "/toto.jcov", "", true); + checkFiles("*.jcov", "toto.jcov/tutu/tata", "", false); + checkFiles("/java.base/*.jcov", "toto.jcov", "java.base", true); + checkFiles("/java.base/toto.jcov", "iti.jcov", "t/java.base", false); + checkFiles("/java.base/*/toto.jcov", "toto.jcov", "java.base", false); + checkFiles("/java.base/*/toto.jcov", "tutu/toto.jcov", "java.base", true); + checkFiles("*/java.base/*/toto.jcov", "java.base/tutu/toto.jcov", "/tutu", true); + + checkFiles("/*$*.properties", "tutu/Toto$Titi.properties", "java.base", true); + checkFiles("*$*.properties", "tutu/Toto$Titi.properties", "java.base", true); + + // Excluded files list in a file + File order = new File("files.exc"); + order.createNewFile(); + Files.write(order.toPath(), "*.jcov".getBytes()); + checkFiles(order.getAbsolutePath(), "/num/toto.jcov", "", true); + } + + public void checkFiles(String s, String sample, String module, boolean exclude) throws Exception { + Map prop = new HashMap<>(); + prop.put(ExcludeFilesPlugin.NAME, s); + ExcludeFilesPlugin fplug = new ExcludeFilesPlugin(); + fplug.configure(prop); + PoolImpl files = new PoolImpl(); + PoolImpl fresult = new PoolImpl(); + ModuleData f = Pool.newImageFile(module, "/" + module + "/" + sample, + ModuleDataType.CONFIG, new ByteArrayInputStream(new byte[0]), 0); + files.add(f); + + fplug.visit(files, fresult); + + if (exclude) { + if (fresult.getContent().contains(f)) { + throw new Exception(sample + " should be excluded by " + s); + } + } else { + if (!fresult.getContent().contains(f)) { + throw new Exception(sample + " shouldn't be excluded by " + s); + } + } + } +} diff --git a/jdk/test/tools/jlink/plugins/ExcludePluginTest.java b/jdk/test/tools/jlink/plugins/ExcludePluginTest.java new file mode 100644 index 00000000000..0f508073288 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/ExcludePluginTest.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test exclude plugin + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main ExcludePluginTest + */ + +import java.io.File; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import jdk.tools.jlink.internal.PoolImpl; + +import jdk.tools.jlink.internal.plugins.ExcludePlugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; + +public class ExcludePluginTest { + + public static void main(String[] args) throws Exception { + new ExcludePluginTest().test(); + } + + public void test() throws Exception { + check("*.jcov", "/num/toto.jcov", true); + check("*.jcov", "//toto.jcov", true); + check("*.jcov", "/toto.jcov/tutu/tata", false); + check("/java.base/*.jcov", "/java.base/toto.jcov", true); + check("/java.base/toto.jcov", "t/java.base/iti.jcov", false); + check("/java.base/*/toto.jcov", "/java.base/toto.jcov", false); + check("/java.base/*/toto.jcov", "/java.base/tutu/toto.jcov", true); + check("*/java.base/*/toto.jcov", "/tutu/java.base/tutu/toto.jcov", true); + check("*/META-INF/*", "/META-INF/services/ MyProvider ", false); + check("*/META-INF/*", "/META-INF/services/MyProvider", false); + check("*/META-INF", " /META-INF/services/MyProvider", false); + check("*/META-INF/*", "/java.base//META-INF/services/MyProvider", true); + check("/java.base/*/Toto$Titi.class", "/java.base/tutu/Toto$Titi.class", true); + check("/*$*.class", "/java.base/tutu/Toto$Titi.class", true); + check("*$*.class", "/java.base/tutu/Toto$Titi.class", true); + + // Excluded resource list in a file + File order = new File("resources.exc"); + order.createNewFile(); + Files.write(order.toPath(), "*.jcov".getBytes()); + check(order.getAbsolutePath(), "/num/toto.jcov", true); + } + + public void check(String s, String sample, boolean exclude) throws Exception { + Map prop = new HashMap<>(); + prop.put(ExcludePlugin.NAME, s); + ExcludePlugin excludePlugin = new ExcludePlugin(); + excludePlugin.configure(prop); + Pool resources = new PoolImpl(); + ModuleData resource = Pool.newResource(sample, new byte[0]); + resources.add(resource); + Pool result = new PoolImpl(); + excludePlugin.visit(resources, result); + if (exclude) { + if (result.getContent().contains(resource)) { + throw new AssertionError(sample + " should be excluded by " + s); + } + } else { + if (!result.getContent().contains(resource)) { + throw new AssertionError(sample + " shouldn't be excluded by " + s); + } + } + } +} diff --git a/jdk/test/tools/jlink/plugins/ExcludeVMPluginTest.java b/jdk/test/tools/jlink/plugins/ExcludeVMPluginTest.java new file mode 100644 index 00000000000..701368c3dd0 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/ExcludeVMPluginTest.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @summary Test exclude VM plugin + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main ExcludeVMPluginTest + */ +import java.io.ByteArrayInputStream; +import java.util.HashMap; +import java.util.Map; +import jdk.tools.jlink.internal.PoolImpl; + +import jdk.tools.jlink.internal.plugins.ExcludeVMPlugin; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.Pool.ModuleDataType; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class ExcludeVMPluginTest { + + private static final String TAG = "# orig in test\n"; + + private static final String[] ARCHITECTURES = {"/", "/amd64/", "/i386/", "/arm/", + "/aarch64/", "/toto/"}; + + private static final String[] CLIENT = {"client/" + jvmlib(),}; + private static final String[] SERVER = {"server/" + jvmlib()}; + private static final String[] MINIMAL = {"minimal/" + jvmlib()}; + private static final String[] ALL = {CLIENT[0], SERVER[0], MINIMAL[0]}; + private static final String JVM_CFG_ALL = TAG + "-server KNOWN\n-client KNOWN\n-minimal KNOWN\n"; + private static final String JVM_CFG_CLIENT = TAG + "-client KNOWN\n"; + private static final String JVM_CFG_SERVER = TAG + "-server KNOWN\n"; + private static final String JVM_CFG_SERVER_ALIAS_OTHERS = TAG + "-server KNOWN\n-client ALIASED_TO -server\n-minimal ALIASED_TO -server\n"; + private static final String JVM_CFG_CLIENT_ALIAS_OTHERS = TAG + "-client KNOWN\n-server ALIASED_TO -client\n-minimal ALIASED_TO -client\n"; + private static final String JVM_CFG_MINIMAL_ALIAS_OTHERS = TAG + "-minimal KNOWN\n-server ALIASED_TO -minimal\n-client ALIASED_TO -minimal\n"; + private static final String JVM_CFG_MINIMAL = TAG + "-minimal KNOWN\n"; + + public static void main(String[] args) throws Exception { + new ExcludeVMPluginTest().test(); + } + + public void test() throws Exception { + boolean failed = false; + + try { + checkVM("toto", ALL, JVM_CFG_ALL, ALL, JVM_CFG_ALL); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + + checkVM("all", ALL, JVM_CFG_ALL, ALL, JVM_CFG_ALL); + checkVM("all", CLIENT, JVM_CFG_CLIENT, CLIENT, JVM_CFG_CLIENT); + checkVM("all", SERVER, JVM_CFG_SERVER, SERVER, JVM_CFG_SERVER); + checkVM("all", MINIMAL, JVM_CFG_MINIMAL, MINIMAL, JVM_CFG_MINIMAL); + + checkVM("server", ALL, JVM_CFG_ALL, SERVER, JVM_CFG_SERVER_ALIAS_OTHERS); + checkVM("server", SERVER, JVM_CFG_SERVER, SERVER, JVM_CFG_SERVER); + try { + checkVM("server", CLIENT, JVM_CFG_CLIENT, SERVER, JVM_CFG_SERVER); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + try { + checkVM("server", MINIMAL, JVM_CFG_MINIMAL, SERVER, JVM_CFG_SERVER); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + + checkVM("client", ALL, JVM_CFG_ALL, CLIENT, JVM_CFG_CLIENT_ALIAS_OTHERS); + checkVM("client", CLIENT, JVM_CFG_CLIENT, CLIENT, JVM_CFG_CLIENT); + try { + checkVM("client", SERVER, JVM_CFG_SERVER, CLIENT, JVM_CFG_CLIENT); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + try { + checkVM("client", MINIMAL, JVM_CFG_MINIMAL, CLIENT, JVM_CFG_CLIENT); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + + checkVM("minimal", ALL, JVM_CFG_ALL, MINIMAL, JVM_CFG_MINIMAL_ALIAS_OTHERS); + checkVM("minimal", MINIMAL, JVM_CFG_MINIMAL, MINIMAL, JVM_CFG_MINIMAL); + try { + checkVM("minimal", SERVER, JVM_CFG_SERVER, MINIMAL, JVM_CFG_MINIMAL); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + try { + checkVM("minimal", CLIENT, JVM_CFG_CLIENT, MINIMAL, JVM_CFG_MINIMAL); + failed = true; + throw new Exception("Should have failed"); + } catch (Exception ex) { + if (failed) { + throw ex; + } + } + + } + + public void checkVM(String vm, String[] input, String jvmcfg, String[] expectedOutput, String expectdJvmCfg) throws Exception { + + for (String arch : ARCHITECTURES) { + String[] winput = new String[input.length]; + String[] woutput = new String[expectedOutput.length]; + for (int i = 0; i < input.length; i++) { + winput[i] = "/java.base/native" + arch + input[i]; + } + for (int i = 0; i < expectedOutput.length; i++) { + woutput[i] = "/java.base/native" + arch + expectedOutput[i]; + } + doCheckVM(vm, winput, jvmcfg, woutput, expectdJvmCfg); + } + } + + private void doCheckVM(String vm, String[] input, String jvmcfg, String[] expectedOutput, String expectdJvmCfg) throws Exception { + // Create a pool with jvm.cfg and the input paths. + byte[] jvmcfgContent = jvmcfg.getBytes(); + Pool pool = new PoolImpl(); + pool.add(Pool.newImageFile("java.base", "/java.base/native/jvm.cfg", + ModuleDataType.NATIVE_LIB, new ByteArrayInputStream(jvmcfgContent), jvmcfgContent.length)); + for (String in : input) { + pool.add(Pool.newImageFile("java.base", in, + ModuleDataType.NATIVE_LIB, new ByteArrayInputStream(new byte[0]), 0)); + } + Pool out = new PoolImpl(); + + TransformerPlugin p = new ExcludeVMPlugin(); + Map config = new HashMap<>(); + if (vm != null) { + config.put(ExcludeVMPlugin.NAME, vm); + } + p.configure(config); + p.visit(pool, out); + + String newContent = new String(out.get("/java.base/native/jvm.cfg").stream().readAllBytes()); + + if (!expectdJvmCfg.equals(newContent)) { + throw new Exception("Got content " + newContent + " expected " + expectdJvmCfg); + } + + if (out.getContent().size() != (expectedOutput.length + 1)) { + for (ModuleData m : out.getContent()) { + System.err.println(m.getPath()); + } + throw new Exception("Invalid output size " + out.getContent().size() + " expected " + (expectedOutput.length + 1)); + } + + for (ModuleData md : out.getContent()) { + if (md.getPath().equals("/java.base/native/jvm.cfg")) { + continue; + } + boolean contained = false; + for (String o : expectedOutput) { + if (md.getPath().equals(o)) { + contained = true; + break; + } + } + if (!contained) { + throw new Exception(md.getPath() + " not expected"); + } + } + + } + + private static boolean isWindows() { + return System.getProperty("os.name").startsWith("Windows"); + } + + private static boolean isMac() { + return System.getProperty("os.name").startsWith("Mac OS"); + } + + private static String jvmlib() { + String lib = "libjvm.so"; + if (isWindows()) { + lib = "jvm.dll"; + } else if (isMac()) { + lib = "libjvm.dylib"; + } + return lib; + } +} diff --git a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java new file mode 100644 index 00000000000..69388e7f6e9 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test files copy plugin + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main FileCopierPluginTest + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.builder.DefaultImageBuilder; + +import jdk.tools.jlink.internal.plugins.FileCopierPlugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.Pool.ModuleDataType; + +public class FileCopierPluginTest { + + public static void main(String[] args) throws Exception { + new FileCopierPluginTest().test(); + } + + /** + * 3 cases - Absolute, no target ==> copy in image root dir - Absolute and + * target ==> copy in image root dir/target - Relative ==> copy from JDK + * home dir. + * + * @throws Exception + */ + public void test() throws Exception { + FileCopierPlugin plug = new FileCopierPlugin(); + String content = "You \n should \n be \bthere.\n"; + String name = "sample.txt"; + File src = new File("src"); + src.mkdir(); + // Need a fake bin + File bin = new File("bin"); + bin.mkdir(); + + File txt = new File(src, name); + txt.createNewFile(); + + String target = "target" + File.separator + name; + Files.write(txt.toPath(), content.getBytes()); + File lic = new File(System.getProperty("java.home"), "LICENSE"); + StringBuilder builder = new StringBuilder(); + int expected = lic.exists() ? 4 : 3; + if (lic.exists()) { + builder.append("LICENSE,"); + } + builder.append(txt.getAbsolutePath()+","); + builder.append(txt.getAbsolutePath() + "=" + target+","); + builder.append(src.getAbsolutePath() + "=src2"); + + Map conf = new HashMap<>(); + conf.put(FileCopierPlugin.NAME, builder.toString()); + plug.configure(conf); + Pool pool = new PoolImpl(); + plug.visit(new PoolImpl(), pool); + if (pool.getContent().size() != expected) { + throw new AssertionError("Wrong number of added files"); + } + for (ModuleData f : pool.getContent()) { + if (!f.getType().equals(ModuleDataType.OTHER)) { + throw new AssertionError("Invalid type " + f.getType() + + " for file " + f.getPath()); + } + if (f.stream() == null) { + throw new AssertionError("Null stream for file " + f.getPath()); + } + + } + Path root = new File(".").toPath(); + DefaultImageBuilder imgbuilder = new DefaultImageBuilder(false, + root); + imgbuilder.storeFiles(pool, ""); + + if (lic.exists()) { + File license = new File(root.toFile(), "LICENSE"); + if (!license.exists() || license.length() == 0) { + throw new AssertionError("Invalide license file " + + license.getAbsoluteFile()); + } + } + + File sample1 = new File(root.toFile(), txt.getName()); + if (!sample1.exists() || sample1.length() == 0) { + throw new AssertionError("Invalide sample1 file " + + sample1.getAbsoluteFile()); + } + if (!new String(Files.readAllBytes(sample1.toPath())).equals(content)) { + throw new AssertionError("Invalid Content in sample1"); + } + + File sample2 = new File(root.toFile(), target); + if (!sample2.exists() || sample2.length() == 0) { + throw new AssertionError("Invalide sample2 file " + + sample2.getAbsoluteFile()); + } + if (!new String(Files.readAllBytes(sample2.toPath())).equals(content)) { + throw new AssertionError("Invalid Content in sample2"); + } + + File src2 = new File(root.toFile(), "src2"); + if (!src2.exists() || src2.list().length != 1) { + throw new AssertionError("Invalide src2 dir " + + src2.getAbsoluteFile()); + } + File f = src2.listFiles()[0]; + if (!f.getName().equals(txt.getName())) { + throw new AssertionError("Invalide file name in src2 dir " + + f.getAbsoluteFile()); + } + if (!new String(Files.readAllBytes(f.toPath())).equals(content)) { + throw new AssertionError("Invalid Content in src2 dir"); + } + } +} diff --git a/jdk/test/tools/jlink/plugins/GetAvailableLocales.java b/jdk/test/tools/jlink/plugins/GetAvailableLocales.java new file mode 100644 index 00000000000..5752f01b3b8 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/GetAvailableLocales.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.Arrays; +import java.util.Locale; +import java.util.stream.Collectors; + +class GetAvailableLocales { + + public static void main(String[] args) { + String availableLocales = Arrays.stream(Locale.getAvailableLocales()) + .map(l -> l.toString()) + .sorted() + .collect(Collectors.joining(" ")); + + if (!availableLocales.equals(args[0])) { + throw new RuntimeException("Available locales are not equal to the expected ones.\n" + + "Expected: " + args[0] + "\n" + + "Actual: " + availableLocales); + } + } +} diff --git a/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java new file mode 100644 index 00000000000..b29c30fb7ba --- /dev/null +++ b/jdk/test/tools/jlink/plugins/IncludeLocalesPluginTest.java @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Layer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; + +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.internal.PluginRepository; +import tests.Helper; +import tests.JImageGenerator; +import tests.JImageValidator; + +/* + * @test + * @summary IncludeLocalesPlugin tests + * @author Naoto Sato + * @library ../../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @build tools.jlink.plugins.GetAvailableLocales + * @run main/othervm -verbose:gc -Xmx1g IncludeLocalesPluginTest + */ +public class IncludeLocalesPluginTest { + + private final static String moduleName = "IncludeLocalesTest"; + private static Helper helper; + private final static int INCLUDE_LOCALES_OPTION = 0; + private final static int EXPECTED_LOCATIONS = 1; + private final static int UNEXPECTED_PATHS = 2; + private final static int AVAILABLE_LOCALES = 3; + + private final static Object[][] testData = { + // without --include-locales option: should include all locales + { + "", + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), + List.of(), + " af af_NA af_ZA agq agq_CM ak ak_GH am am_ET ar ar_001 ar_AE ar_BH " + + "ar_DJ ar_DZ ar_EG ar_EH ar_ER ar_IL ar_IQ ar_JO ar_KM ar_KW ar_LB " + + "ar_LY ar_MA ar_MR ar_OM ar_PS ar_QA ar_SA ar_SD ar_SO ar_SS ar_SY " + + "ar_TD ar_TN ar_YE as as_IN asa asa_TZ ast ast_ES az az_AZ_#Cyrl " + + "az_AZ_#Latn az__#Cyrl az__#Latn bas bas_CM be be_BY bem bem_ZM bez " + + "bez_TZ bg bg_BG bm bm_ML_#Latn bm__#Latn bn bn_BD bn_IN bo bo_CN " + + "bo_IN br br_FR brx brx_IN bs bs_BA_#Cyrl bs_BA_#Latn bs__#Cyrl " + + "bs__#Latn ca ca_AD ca_ES ca_ES_VALENCIA ca_FR ca_IT cgg cgg_UG chr " + + "chr_US cs cs_CZ cy cy_GB da da_DK da_GL dav dav_KE de de_AT de_BE " + + "de_CH de_DE de_GR de_LI de_LU dje dje_NE dsb dsb_DE dua dua_CM dyo " + + "dyo_SN dz dz_BT ebu ebu_KE ee ee_GH ee_TG el el_CY el_GR en en_001 " + + "en_150 en_AG en_AI en_AS en_AU en_BB en_BE en_BM en_BS en_BW en_BZ " + + "en_CA en_CC en_CK en_CM en_CX en_DG en_DM en_ER en_FJ en_FK en_FM " + + "en_GB en_GD en_GG en_GH en_GI en_GM en_GU en_GY en_HK en_IE en_IM " + + "en_IN en_IO en_JE en_JM en_KE en_KI en_KN en_KY en_LC en_LR en_LS " + + "en_MG en_MH en_MO en_MP en_MS en_MT en_MU en_MW en_MY en_NA en_NF " + + "en_NG en_NR en_NU en_NZ en_PG en_PH en_PK en_PN en_PR en_PW en_RW " + + "en_SB en_SC en_SD en_SG en_SH en_SL en_SS en_SX en_SZ en_TC en_TK " + + "en_TO en_TT en_TV en_TZ en_UG en_UM en_US en_US_POSIX en_VC en_VG " + + "en_VI en_VU en_WS en_ZA en_ZM en_ZW eo eo_001 es es_419 es_AR es_BO " + + "es_CL es_CO es_CR es_CU es_DO es_EA es_EC es_ES es_GQ es_GT es_HN " + + "es_IC es_MX es_NI es_PA es_PE es_PH es_PR es_PY es_SV es_US es_UY " + + "es_VE et et_EE eu eu_ES ewo ewo_CM fa fa_AF fa_IR ff ff_CM ff_GN " + + "ff_MR ff_SN fi fi_FI fil fil_PH fo fo_FO fr fr_BE fr_BF fr_BI fr_BJ " + + "fr_BL fr_CA fr_CD fr_CF fr_CG fr_CH fr_CI fr_CM fr_DJ fr_DZ fr_FR " + + "fr_GA fr_GF fr_GN fr_GP fr_GQ fr_HT fr_KM fr_LU fr_MA fr_MC fr_MF " + + "fr_MG fr_ML fr_MQ fr_MR fr_MU fr_NC fr_NE fr_PF fr_PM fr_RE fr_RW " + + "fr_SC fr_SN fr_SY fr_TD fr_TG fr_TN fr_VU fr_WF fr_YT fur fur_IT fy " + + "fy_NL ga ga_IE gd gd_GB gl gl_ES gsw gsw_CH gsw_FR gsw_LI gu gu_IN " + + "guz guz_KE gv gv_IM ha ha_GH_#Latn ha_NE_#Latn ha_NG_#Latn ha__#Latn " + + "haw haw_US hi hi_IN hr hr_BA hr_HR hsb hsb_DE hu hu_HU hy hy_AM ig " + + "ig_NG ii ii_CN in in_ID is is_IS it it_CH it_IT it_SM iw iw_IL ja " + + "ja_JP ja_JP_JP_#u-ca-japanese jgo jgo_CM ji ji_001 jmc jmc_TZ ka " + + "ka_GE kab kab_DZ kam kam_KE kde kde_TZ kea kea_CV khq khq_ML ki " + + "ki_KE kk kk_KZ_#Cyrl kk__#Cyrl kkj kkj_CM kl kl_GL kln kln_KE km " + + "km_KH kn kn_IN ko ko_KP ko_KR kok kok_IN ks ks_IN_#Arab ks__#Arab " + + "ksb ksb_TZ ksf ksf_CM ksh ksh_DE kw kw_GB ky ky_KG_#Cyrl ky__#Cyrl " + + "lag lag_TZ lb lb_LU lg lg_UG lkt lkt_US ln ln_AO ln_CD ln_CF ln_CG " + + "lo lo_LA lt lt_LT lu lu_CD luo luo_KE luy luy_KE lv lv_LV mas " + + "mas_KE mas_TZ mer mer_KE mfe mfe_MU mg mg_MG mgh mgh_MZ mgo mgo_CM " + + "mk mk_MK ml ml_IN mn mn_MN_#Cyrl mn__#Cyrl mr mr_IN ms ms_BN_#Latn " + + "ms_MY ms_MY_#Latn ms_SG_#Latn ms__#Latn mt mt_MT mua mua_CM my " + + "my_MM naq naq_NA nb nb_NO nb_SJ nd nd_ZW ne ne_IN ne_NP nl nl_AW " + + "nl_BE nl_BQ nl_CW nl_NL nl_SR nl_SX nmg nmg_CM nn nn_NO nnh nnh_CM " + + "no no_NO no_NO_NY nus nus_SD nyn nyn_UG om om_ET om_KE or or_IN os " + + "os_GE os_RU pa pa_IN_#Guru pa_PK_#Arab pa__#Arab pa__#Guru pl pl_PL " + + "ps ps_AF pt pt_AO pt_BR pt_CV pt_GW pt_MO pt_MZ pt_PT pt_ST pt_TL qu " + + "qu_BO qu_EC qu_PE rm rm_CH rn rn_BI ro ro_MD ro_RO rof rof_TZ ru " + + "ru_BY ru_KG ru_KZ ru_MD ru_RU ru_UA rw rw_RW rwk rwk_TZ sah sah_RU " + + "saq saq_KE sbp sbp_TZ se se_FI se_NO se_SE seh seh_MZ ses ses_ML sg " + + "sg_CF shi shi_MA_#Latn shi_MA_#Tfng shi__#Latn shi__#Tfng si si_LK " + + "sk sk_SK sl sl_SI smn smn_FI sn sn_ZW so so_DJ so_ET so_KE so_SO sq " + + "sq_AL sq_MK sq_XK sr sr_BA sr_BA_#Cyrl sr_BA_#Latn sr_CS sr_ME " + + "sr_ME_#Cyrl sr_ME_#Latn sr_RS sr_RS_#Cyrl sr_RS_#Latn sr_XK_#Cyrl " + + "sr_XK_#Latn sr__#Cyrl sr__#Latn sv sv_AX sv_FI sv_SE sw sw_CD sw_KE " + + "sw_TZ sw_UG ta ta_IN ta_LK ta_MY ta_SG te te_IN teo teo_KE teo_UG " + + "th th_TH th_TH_TH_#u-nu-thai ti ti_ER ti_ET to to_TO tr tr_CY tr_TR " + + "twq twq_NE tzm tzm_MA_#Latn tzm__#Latn ug ug_CN_#Arab ug__#Arab uk " + + "uk_UA ur ur_IN ur_PK uz uz_AF_#Arab uz_UZ_#Cyrl uz_UZ_#Latn " + + "uz__#Arab uz__#Cyrl uz__#Latn vai vai_LR_#Latn vai_LR_#Vaii " + + "vai__#Latn vai__#Vaii vi vi_VN vun vun_TZ wae wae_CH xog xog_UG yav " + + "yav_CM yo yo_BJ yo_NG zgh zgh_MA zh zh_CN zh_CN_#Hans zh_HK " + + "zh_HK_#Hans zh_HK_#Hant zh_MO_#Hans zh_MO_#Hant zh_SG zh_SG_#Hans " + + "zh_TW zh_TW_#Hant zh__#Hans zh__#Hant zu zu_ZA", + }, + + // All English/Japanese locales + { + "--include-locales=en,ja", + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class"), + List.of( + "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/thai_dict", + "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), + " en en_001 en_150 en_AG en_AI en_AS en_AU en_BB en_BE en_BM en_BS " + + "en_BW en_BZ en_CA en_CC en_CK en_CM en_CX en_DG en_DM en_ER en_FJ " + + "en_FK en_FM en_GB en_GD en_GG en_GH en_GI en_GM en_GU en_GY en_HK " + + "en_IE en_IM en_IN en_IO en_JE en_JM en_KE en_KI en_KN en_KY en_LC " + + "en_LR en_LS en_MG en_MH en_MO en_MP en_MS en_MT en_MU en_MW en_MY " + + "en_NA en_NF en_NG en_NR en_NU en_NZ en_PG en_PH en_PK en_PN en_PR " + + "en_PW en_RW en_SB en_SC en_SD en_SG en_SH en_SL en_SS en_SX en_SZ " + + "en_TC en_TK en_TO en_TT en_TV en_TZ en_UG en_UM en_US en_US_POSIX " + + "en_VC en_VG en_VI en_VU en_WS en_ZA en_ZM en_ZW ja ja_JP ja_JP_JP_#u-ca-japanese", + }, + + // All locales in India + { + "--include-locales=*-IN", + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_en_IN.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_hi_IN.class", + "/jdk.localedata/sun/util/resources/cldr/ext/CalendarData_as_IN.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_IN.class", + "/jdk.localedata/sun/util/resources/cldr/ext/CalendarData_kok_IN.class", + "/jdk.localedata/sun/util/resources/cldr/ext/CalendarData_ks_Arab_IN.class"), + List.of( + "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/thai_dict", + "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), + " as_IN bn_IN bo_IN brx_IN en en_IN en_US en_US_POSIX gu_IN hi_IN kn_IN " + + "kok_IN ks_IN_#Arab ml_IN mr_IN ne_IN or_IN pa_IN_#Guru ta_IN te_IN ur_IN", + }, + + // Thai + {"--include-locales=th", + List.of( + "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/thai_dict", + "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class"), + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), + " en en_US en_US_POSIX th th_TH th_TH_TH_#u-nu-thai", + }, + + // Hong Kong + {"--include-locales=zh-HK", + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_zh.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_zh_HK.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_zh_TW.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_zh.class"), + List.of( + "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/thai_dict", + "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"), + " en en_US en_US_POSIX zh_HK zh_HK_#Hans zh_HK_#Hant", + }, + + // Norwegian + {"--include-locales=nb,nn,no", + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_no.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_no_NO.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_no_NO_NY.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_nb.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_nn.class"), + List.of( + "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/thai_dict", + "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"), + " en en_US en_US_POSIX nb nb_NO nb_SJ nn nn_NO no no_NO no_NO_NY", + }, + + // Hebrew/Indonesian/Yiddish + {"--include-locales=he,id,yi", + List.of( + "/jdk.localedata/sun/text/resources/ext/FormatData_in.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_in_ID.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_iw.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_iw_IL.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_in.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_iw.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ji.class"), + List.of( + "/jdk.localedata/sun/text/resources/LineBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/thai_dict", + "/jdk.localedata/sun/text/resources/WordBreakIteratorData_th", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorInfo_th.class", + "/jdk.localedata/sun/text/resources/ext/BreakIteratorRules_th.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_en_GB.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/ext/FormatData_th.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_en_001.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_ja.class", + "/jdk.localedata/sun/text/resources/cldr/ext/FormatData_th.class"), + " en en_US en_US_POSIX in in_ID iw iw_IL ji ji_001", + }, + }; + + public static void main(String[] args) throws Exception { + helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run"); + return; + } + + helper.generateDefaultModules(); + + for (Object[] data : testData) { + // create image for each test data + Path image = JImageGenerator.getJLinkTask() + .modulePath(helper.defaultModulePath()) + .output(helper.createNewImageDir(moduleName)) + .addMods("jdk.localedata") + .option((String)data[INCLUDE_LOCALES_OPTION]) + .call().assertSuccess(); + + // test locale data entries + testLocaleDataEntries(image, + (List)data[EXPECTED_LOCATIONS], + (List)data[UNEXPECTED_PATHS]); + + // test available locales + testAvailableLocales(image, (String)data[AVAILABLE_LOCALES]); + } + } + + private static void testLocaleDataEntries(Path image, List expectedLocations, + List unexpectedPaths) throws Exception { + JImageValidator.validate( + image.resolve("lib").resolve("modules"), + expectedLocations, unexpectedPaths); + } + + private static void testAvailableLocales(Path image, String availableLocales) throws Exception { + Path launcher = image.resolve("bin/java" + + (System.getProperty("os.name").startsWith("Windows") ? ".exe" : "")); + System.out.print(launcher); + ProcessBuilder pb = new ProcessBuilder(launcher.toString(), + "GetAvailableLocales", availableLocales); + int ret = pb.start().waitFor(); + System.out.println(" Return code: " + ret); + } +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/InstalledModulesTest.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/InstalledModulesTest.java new file mode 100644 index 00000000000..af1fe3ed490 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/InstalledModulesTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleDescriptor.Requires.Modifier; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import java.util.Collections; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; + +import jdk.internal.misc.JavaLangModuleAccess; +import jdk.internal.misc.SharedSecrets; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * @test + * @modules java.base/jdk.internal.misc + * @run testng InstalledModulesTest + * @summary Verify the properties of ModuleDescriptor created + * by InstalledModules + */ + +public class InstalledModulesTest { + private static final JavaLangModuleAccess jlma = SharedSecrets.getJavaLangModuleAccess(); + + /** + * Verify ModuleDescriptor contains unmodifiable sets + */ + @Test + public void testUnmodifableDescriptors() throws Exception { + ModuleFinder.ofSystem().findAll() + .stream() + .map(ModuleReference::descriptor) + .forEach(this::testModuleDescriptor); + } + + private void testModuleDescriptor(ModuleDescriptor md) { + assertUnmodifiable(md.conceals(), "conceal"); + assertUnmodifiable(md.packages(), "package"); + assertUnmodifiable(md.requires(), + jlma.newRequires(EnumSet.allOf(Modifier.class), "require")); + assertUnmodifiable(md.exports(), jlma.newExports("export")); + assertUnmodifiable(md.uses(), "use"); + assertUnmodifiable(md.provides(), "provide", + jlma.newProvides("provide", Collections.singleton("provide"))); + + } + + private void assertUnmodifiable(Set set, T dummy) { + try { + set.add(dummy); + fail("Should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // pass + } catch (Exception e) { + fail("Should throw UnsupportedOperationException"); + } + } + + private void assertUnmodifiable(Map set, T dummyKey, V dummyValue) { + try { + set.put(dummyKey, dummyValue); + fail("Should throw UnsupportedOperationException"); + } catch (UnsupportedOperationException e) { + // pass + } catch (Exception e) { + fail("Should throw UnsupportedOperationException"); + } + } + +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/UserModuleTest.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/UserModuleTest.java new file mode 100644 index 00000000000..f5bbe62bcb3 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/UserModuleTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.stream.Collectors; + +import jdk.testlibrary.FileUtils; +import static jdk.testlibrary.ProcessTools.*; + + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build UserModuleTest CompilerUtils jdk.testlibrary.FileUtils jdk.testlibrary.ProcessTools + * @run testng UserModuleTest + */ + +public class UserModuleTest { + private static final String JAVA_HOME = System.getProperty("java.home"); + 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"); + private static final Path IMAGE = Paths.get("image"); + private static final Path JMODS = Paths.get(JAVA_HOME, "jmods"); + + // the names of the modules in this test + private static String[] modules = new String[] {"m1", "m2", "m3"}; + + private static boolean hasJmods() { + if (!Files.exists(JMODS)) { + System.err.println("Test skipped. NO jmods directory"); + return false; + } + return true; + } + + /* + * Compiles all modules used by the test + */ + @BeforeTest + public void compileAll() throws Throwable { + if (!hasJmods()) return; + + for (String mn : modules) { + Path msrc = SRC_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(msrc, MODS_DIR, "-modulesourcepath", SRC_DIR.toString())); + } + + if (Files.exists(IMAGE)) { + FileUtils.deleteFileTreeUnchecked(IMAGE); + } + + createImage(IMAGE, "java.base", "m1"); + } + + private void createImage(Path outputDir, String... modules) throws Throwable { + Path jlink = Paths.get(JAVA_HOME, "bin", "jlink"); + String mp = JMODS.toString() + File.pathSeparator + MODS_DIR.toString(); + assertTrue(executeProcess(jlink.toString(), "--output", outputDir.toString(), + "--addmods", Arrays.stream(modules).collect(Collectors.joining(",")), + "--modulepath", mp) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + /* + * Test the image created when linking with a module with + * no ConcealedPackages attribute + */ + @Test + public void test() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + /* + * Disable the fast loading of installed modules. + * Parsing module-info.class + */ + @Test + public void disableInstalledModules() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-Djdk.installed.modules.disable", + "-m", "m1/p1.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + /* + * Test the optimization that deduplicates Set on targets of exports, + * uses, provides. + */ + @Test + public void testDedupSet() throws Throwable { + if (!hasJmods()) return; + + Path dir = Paths.get("newImage"); + createImage(dir, "java.base", "m1", "m2", "m3"); + Path java = dir.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), "-m", "m1/p1.Main") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/module-info.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/module-info.java new file mode 100644 index 00000000000..f6ecf6b2bf5 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m1 { +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java new file mode 100644 index 00000000000..4e516970d4d --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p1/Main.java @@ -0,0 +1,60 @@ +/* + * 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 p1; + +import java.lang.module.ModuleDescriptor; +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.util.Set; + +public class Main { + public static void main(String... args) throws Exception { + // load another package + p2.T.test(); + + // check the module descriptor of an installed module + validate(Main.class.getModule().getDescriptor()); + + // read m1/module-info.class + FileSystem fs = FileSystems.newFileSystem(URI.create("jrt:/"), null); + Path path = fs.getPath("/", "modules", "m1", "module-info.class"); + validate(ModuleDescriptor.read(Files.newInputStream(path))); + } + + static void validate(ModuleDescriptor md) { + checkPackages(md.conceals(), "p1", "p2"); + checkPackages(md.packages(), "p1", "p2"); + } + + static void checkPackages(Set pkgs, String... expected) { + for (String pn : expected) { + if (!pkgs.contains(pn)) { + throw new RuntimeException(pn + " missing in " + pkgs); + } + } + } +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p2/T.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p2/T.java new file mode 100644 index 00000000000..7a83ae92cb2 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m1/p2/T.java @@ -0,0 +1,28 @@ +/* + * 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 p2; + +public class T { + public static void test() { } +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/module-info.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/module-info.java new file mode 100644 index 00000000000..dae7a3ac6d3 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module m2 { + uses q.S1; + uses q.S2; +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S1.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S1.java new file mode 100644 index 00000000000..3aa3b3841d1 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S1.java @@ -0,0 +1,28 @@ +/* + * 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 q; + +public interface S1 { + public String name(); +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S2.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S2.java new file mode 100644 index 00000000000..57cb64670f3 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m2/q/S2.java @@ -0,0 +1,28 @@ +/* + * 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 q; + +public interface S2 { + public String name(); +} diff --git a/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m3/module-info.java b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m3/module-info.java new file mode 100644 index 00000000000..b164b24e95c --- /dev/null +++ b/jdk/test/tools/jlink/plugins/InstalledModuleDescriptors/src/m3/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m3 { +} diff --git a/jdk/test/tools/jlink/plugins/LastSorterTest.java b/jdk/test/tools/jlink/plugins/LastSorterTest.java new file mode 100644 index 00000000000..100ca1e4674 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/LastSorterTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test last sorter property + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * @run main/othervm LastSorterTest + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jdk.tools.jlink.internal.ImagePluginConfiguration; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.internal.ImagePluginStack; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.Jlink; +import jdk.tools.jlink.Jlink.PluginsConfiguration; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class LastSorterTest { + + public LastSorterTest() { + for (int i = 1; i <= 6; i++) { + PluginRepository.registerPlugin(new SorterPlugin("sorterplugin" + i)); + } + } + + public static void main(String[] args) throws Exception { + new LastSorterTest().test(); + } + + public void test() throws Exception { + checkUnknownPlugin(); + + checkOrderAfterLastSorter(); + + checkPositiveCase(); + + checkTwoLastSorters(); + } + + private void checkTwoLastSorters() throws Exception { + List plugins = new ArrayList<>(); + plugins.add(createPlugin("sorterplugin5", "/a")); + plugins.add(createPlugin("sorterplugin6", "/a")); + PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins, + null, "sorterplugin5"); + + ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config); + + // check order + PoolImpl res = fillOutResourcePool(); + + try { + stack.visitResources(res); + throw new AssertionError("Exception expected: Order of resources is already frozen." + + "Plugin sorterplugin6 is badly located"); + } catch (Exception e) { + // expected + } + } + + private PoolImpl fillOutResourcePool() throws Exception { + PoolImpl res = new PoolImpl(); + res.add(Pool.newResource("/eee/bbb/res1.class", new byte[90])); + res.add(Pool.newResource("/aaaa/bbb/res2.class", new byte[90])); + res.add(Pool.newResource("/bbb/aa/res1.class", new byte[90])); + res.add(Pool.newResource("/aaaa/bbb/res3.class", new byte[90])); + res.add(Pool.newResource("/bbb/aa/res2.class", new byte[90])); + res.add(Pool.newResource("/fff/bbb/res1.class", new byte[90])); + res.add(Pool.newResource("/aaaa/bbb/res1.class", new byte[90])); + res.add(Pool.newResource("/bbb/aa/res3.class", new byte[90])); + res.add(Pool.newResource("/ccc/bbb/res1.class", new byte[90])); + res.add(Pool.newResource("/ddd/bbb/res1.class", new byte[90])); + return res; + } + + private static Plugin createPlugin(String name, String arg) { + Map conf = new HashMap<>(); + conf.put(name, arg); + return Jlink.newPlugin(name, conf, null); + } + + private void checkPositiveCase() throws Exception { + List plugins = new ArrayList<>(); + plugins.add(createPlugin("sorterplugin1", "/c")); + plugins.add(createPlugin("sorterplugin2", "/b")); + plugins.add(createPlugin("sorterplugin3", "/a")); + + PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins, + null, "sorterplugin3"); + + ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config); + + // check order + PoolImpl res = fillOutResourcePool(); + + stack.visitResources(res); + } + + private void checkUnknownPlugin() { + List plugins = new ArrayList<>(); + plugins.add(createPlugin("sorterplugin1", "/1")); + plugins.add(createPlugin("sorterplugin2", "/1")); + plugins.add(createPlugin("sorterplugin3", "/1")); + plugins.add(createPlugin("sorterplugin4", "/1")); + + PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins, + null, "sorterplugin5"); + try { + ImagePluginConfiguration.parseConfiguration(config); + throw new AssertionError("Unknown plugin should have failed."); + } catch (Exception ex) { + // XXX OK expected + } + } + + private void checkOrderAfterLastSorter() throws Exception { + List plugins = new ArrayList<>(); + plugins.add(createPlugin("sorterplugin1", "/c")); + plugins.add(createPlugin("sorterplugin2", "/b")); + plugins.add(createPlugin("sorterplugin3", "/a")); + plugins.add(createPlugin("sorterplugin4", "/d")); + + PluginsConfiguration config = new Jlink.PluginsConfiguration(plugins, + null, "sorterplugin3"); + + ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(config); + + // check order + PoolImpl res = fillOutResourcePool(); + try { + stack.visitResources(res); + throw new AssertionError("Order was changed after the last sorter, but no exception occurred"); + } catch (Exception ex) { + // XXX OK expected + } + } + + public static class SorterPlugin implements TransformerPlugin { + + private final String name; + private String starts; + + private SorterPlugin(String name) { + this.name = name; + } + + @Override + public void visit(Pool resources, Pool output) { + List paths = new ArrayList<>(); + for (ModuleData res : resources.getContent()) { + if (res.getPath().startsWith(starts)) { + paths.add(0, res); + } else { + paths.add(res); + } + } + + for (ModuleData r : paths) { + output.add(r); + } + } + + @Override + public String getName() { + return name; + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + + @Override + public void configure(Map config) { + String arguments = config.get(name); + this.starts = arguments; + } + } +} diff --git a/jdk/test/tools/jlink/plugins/PluginOrderTest.java b/jdk/test/tools/jlink/plugins/PluginOrderTest.java new file mode 100644 index 00000000000..42655d408fe --- /dev/null +++ b/jdk/test/tools/jlink/plugins/PluginOrderTest.java @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @summary Test order of plugins + * @author Jean-Francois Denise + * @library ../../lib + * @modules java.base/jdk.internal.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.compiler + * @build tests.* + * @run main/othervm PluginOrderTest + */ +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jdk.tools.jlink.internal.PluginOrderingGraph; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.Plugin.CATEGORY; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class PluginOrderTest { + + public static void main(String[] args) throws Exception { + + validGraph0(); + validGraph1(); + + boolean failed = false; + + try { + withCycles0(); + failed = true; + } catch (Exception ex) { + //ok + System.err.println(ex.getMessage()); + } + if (failed) { + throw new Exception("Should have failed"); + } + + try { + withCycles1(); + failed = true; + } catch (Exception ex) { + //ok + System.err.println(ex.getMessage()); + } + if (failed) { + throw new Exception("Should have failed"); + } + + try { + withCycles2(); + failed = true; + } catch (Exception ex) { + //ok + System.err.println(ex.getMessage()); + } + if (failed) { + throw new Exception("Should have failed"); + } + } + + private static void validGraph0() throws Exception { + Set set = new HashSet<>(); + set.add("plug2"); + List plugins = new ArrayList<>(); + plugins.add(new Plug("plug2", Collections.emptySet(), Collections.emptySet(), + CATEGORY.TRANSFORMER)); + plugins.add(new Plug("plug1", set, Collections.emptySet(), CATEGORY.TRANSFORMER)); + List ordered = PluginOrderingGraph.sort(plugins); + if (ordered.get(0) != plugins.get(1) || ordered.get(1) != plugins.get(0)) { + throw new Exception("Invalid sorting"); + } + } + + private static void validGraph1() { + Set lst1 = new HashSet<>(); + lst1.add("plug2"); + lst1.add("plug3"); + Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst3 = new HashSet<>(); + lst3.add("plug4"); + lst3.add("plug6"); + Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst5 = new HashSet<>(); + lst5.add("plug3"); + lst5.add("plug1"); + lst5.add("plug2"); + lst5.add("plug6"); + Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst6 = new HashSet<>(); + lst6.add("plug4"); + lst6.add("plug2"); + Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + List plugins = new ArrayList<>(); + plugins.add(p1); + plugins.add(p2); + plugins.add(p3); + plugins.add(p4); + plugins.add(p5); + plugins.add(p6); + plugins.add(p7); + plugins.add(p8); + + PluginOrderingGraph.sort(plugins); + } + + private static void withCycles0() throws Exception { + Set set2 = new HashSet<>(); + set2.add("plug1"); + List plugins = new ArrayList<>(); + plugins.add(new Plug("plug2", set2, Collections.emptySet(), + CATEGORY.TRANSFORMER)); + + Set set1 = new HashSet<>(); + set1.add("plug2"); + plugins.add(new Plug("plug1", set1, Collections.emptySet(), CATEGORY.TRANSFORMER)); + PluginOrderingGraph.sort(plugins); + + } + + private static void withCycles2() { + Set lst1 = new HashSet<>(); + lst1.add("plug2"); + lst1.add("plug3"); + Plugin p1 = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst3 = new HashSet<>(); + lst3.add("plug4"); + lst3.add("plug6"); + Plugin p3 = new Plug("plug3", lst3, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p4 = new Plug("plug4", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst5 = new HashSet<>(); + lst5.add("plug3"); + lst5.add("plug1"); + lst5.add("plug2"); + Plugin p5 = new Plug("plug5", lst5, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst6 = new HashSet<>(); + lst6.add("plug4"); + lst6.add("plug1"); + Plugin p6 = new Plug("plug6", lst6, Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p7 = new Plug("plug7", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Plugin p8 = new Plug("plug8", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + List plugins = new ArrayList<>(); + plugins.add(p1); + plugins.add(p2); + plugins.add(p3); + plugins.add(p4); + plugins.add(p5); + plugins.add(p6); + plugins.add(p7); + plugins.add(p8); + PluginOrderingGraph.sort(plugins); + } + + private static void withCycles1() { + Set lst1 = new HashSet<>(); + lst1.add("plug2"); + lst1.add("plug3"); + Plugin p = new Plug("plug1", lst1, Collections.emptySet(), CATEGORY.TRANSFORMER); + Plugin p2 = new Plug("plug2", Collections.emptySet(), Collections.emptySet(), CATEGORY.TRANSFORMER); + + Set lst3 = new HashSet<>(); + lst3.add("plug2"); + + Set lst4 = new HashSet<>(); + lst4.add("plug1"); + + Plugin p3 = new Plug("plug3", lst4, lst3, CATEGORY.TRANSFORMER); + List plugins = new ArrayList<>(); + plugins.add(p); + plugins.add(p2); + plugins.add(p3); + PluginOrderingGraph.sort(plugins); + } + + private static class Plug implements TransformerPlugin { + + private final Set isBefore; + private final Set isAfter; + private final CATEGORY category; + private final String name; + + private Plug(String name, Set isBefore, Set isAfter, CATEGORY category) { + this.name = name; + this.isBefore = isBefore; + this.isAfter = isAfter; + this.category = category; + } + + @Override + public Set isAfter() { + return isAfter; + } + + @Override + public Set isBefore() { + return isBefore; + } + + @Override + public String toString() { + return name; + } + + @Override + public void visit(Pool in, Pool out) { + + } + + @Override + public Set getType() { + return Collections.singleton(category); + } + + @Override + public String getName() { + return name; + } + } +} diff --git a/jdk/test/tools/jlink/plugins/PluginsNegativeTest.java b/jdk/test/tools/jlink/plugins/PluginsNegativeTest.java new file mode 100644 index 00000000000..525fb0b5ce2 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/PluginsNegativeTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @summary Negative test for ImagePluginStack. + * @author Andrei Eremeev + * @modules jdk.jlink/jdk.tools.jlink.internal + * @run main/othervm PluginsNegativeTest + */ +import java.lang.reflect.Layer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import jdk.tools.jlink.internal.ImagePluginConfiguration; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.internal.ImagePluginStack; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.Jlink; +import jdk.tools.jlink.Jlink.PluginsConfiguration; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class PluginsNegativeTest { + + public static void main(String[] args) throws Exception { + new PluginsNegativeTest().test(); + } + + public void test() throws Exception { + testDuplicateBuiltInProviders(); + testUnknownProvider(); + PluginRepository.registerPlugin(new CustomPlugin("plugin")); + testEmptyInputResource(); + testEmptyOutputResource(); + } + + private void testDuplicateBuiltInProviders() { + List javaPlugins = new ArrayList<>(); + javaPlugins.addAll(PluginRepository.getPlugins(Layer.boot())); + for (Plugin javaPlugin : javaPlugins) { + System.out.println("Registered plugin: " + javaPlugin.getName()); + } + for (Plugin javaPlugin : javaPlugins) { + String pluginName = javaPlugin.getName(); + try { + PluginRepository.registerPlugin(new CustomPlugin(pluginName)); + try { + PluginRepository.getPlugin(pluginName, Layer.boot()); + throw new AssertionError("Exception is not thrown for duplicate plugin: " + pluginName); + } catch (Exception ignored) { + } + } finally { + PluginRepository.unregisterPlugin(pluginName); + } + } + } + + private void testUnknownProvider() { + if (PluginRepository.getPlugin("unknown", Layer.boot()) != null) { + throw new AssertionError("Exception expected for unknown plugin name"); + } + } + + private static Plugin createPlugin(String name) { + return Jlink.newPlugin(name, Collections.emptyMap(), null); + } + + private void testEmptyOutputResource() throws Exception { + List plugins = new ArrayList<>(); + plugins.add(createPlugin("plugin")); + ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new PluginsConfiguration(plugins, + null, null)); + PoolImpl inResources = new PoolImpl(); + inResources.add(Pool.newResource("/aaa/bbb/A", new byte[10])); + try { + stack.visitResources(inResources); + throw new AssertionError("Exception expected when output resource is empty"); + } catch (Exception ignored) { + } + } + + private void testEmptyInputResource() throws Exception { + List plugins = new ArrayList<>(); + plugins.add(createPlugin("plugin")); + ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new PluginsConfiguration(plugins, + null, null)); + PoolImpl inResources = new PoolImpl(); + PoolImpl outResources = (PoolImpl) stack.visitResources(inResources); + if (!outResources.isEmpty()) { + throw new AssertionError("Output resource is not empty"); + } + } + + public static class CustomPlugin implements TransformerPlugin { + + private final String name; + + CustomPlugin(String name) { + this.name = name; + } + + @Override + public void visit(Pool inResources, Pool outResources) { + // do nothing + } + + @Override + public String getName() { + return name; + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + + @Override + public String getDescription() { + return null; + } + + @Override + public void configure(Map config) { + + } + } +} diff --git a/jdk/test/tools/jlink/plugins/PrevisitorTest.java b/jdk/test/tools/jlink/plugins/PrevisitorTest.java new file mode 100644 index 00000000000..16d79f0c068 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/PrevisitorTest.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + /* + * @test + * @summary Test previsitor + * @author Andrei Eremeev + * @modules jdk.jlink/jdk.tools.jlink.internal + * @run main/othervm PrevisitorTest + */ +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import jdk.tools.jlink.internal.ImagePluginConfiguration; +import jdk.tools.jlink.internal.PluginRepository; +import jdk.tools.jlink.internal.ImagePluginStack; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.ResourcePrevisitor; +import jdk.tools.jlink.internal.StringTable; +import jdk.tools.jlink.Jlink; +import jdk.tools.jlink.plugin.Plugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class PrevisitorTest { + + public static void main(String[] args) throws Exception { + new PrevisitorTest().test(); + } + + private static Plugin createPlugin(String name) { + return Jlink.newPlugin(name, Collections.emptyMap(), null); + } + + public void test() throws Exception { + CustomPlugin plugin = new CustomPlugin(); + PluginRepository.registerPlugin(plugin); + List plugins = new ArrayList<>(); + plugins.add(createPlugin(CustomPlugin.NAME)); + ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(new Jlink.PluginsConfiguration(plugins, + null, null)); + PoolImpl inResources = new PoolImpl(ByteOrder.nativeOrder(), new CustomStringTable()); + inResources.add(Pool.newResource("/aaa/bbb/res1.class", new byte[90])); + inResources.add(Pool.newResource("/aaa/bbb/res2.class", new byte[90])); + inResources.add(Pool.newResource("/aaa/bbb/res3.class", new byte[90])); + inResources.add(Pool.newResource("/aaa/ddd/res1.class", new byte[90])); + inResources.add(Pool.newResource("/aaa/res1.class", new byte[90])); + Pool outResources = stack.visitResources(inResources); + Collection input = inResources.getContent().stream() + .map(Object::toString) + .collect(Collectors.toList()); + Collection output = outResources.getContent().stream() + .map(Object::toString) + .collect(Collectors.toList()); + if (!input.equals(output)) { + throw new AssertionError("Input and output resources differ: input: " + + input + ", output: " + output); + } + } + + private static class CustomStringTable implements StringTable { + + private final List strings = new ArrayList<>(); + + @Override + public int addString(String str) { + strings.add(str); + return strings.size() - 1; + } + + @Override + public String getString(int id) { + return strings.get(id); + } + + public int size() { + return strings.size(); + } + } + + private static class CustomPlugin implements TransformerPlugin, ResourcePrevisitor { + + private static String NAME = "plugin"; + + private boolean isPrevisitCalled = false; + + @Override + public void visit(Pool inResources, Pool outResources) { + if (!isPrevisitCalled) { + throw new AssertionError("Previsit was not called"); + } + CustomStringTable table = (CustomStringTable) + ((PoolImpl) inResources).getStringTable(); + if (table.size() == 0) { + throw new AssertionError("Table is empty"); + } + Map count = new HashMap<>(); + for (int i = 0; i < table.size(); ++i) { + String s = table.getString(i); + if (inResources.get(s) != null) { + throw new AssertionError(); + } + count.compute(s, (k, c) -> 1 + (c == null ? 0 : c)); + } + count.forEach((k, v) -> { + if (v != 1) { + throw new AssertionError("Expected one entry in the table, got: " + v + " for " + k); + } + }); + for (ModuleData r : inResources.getContent()) { + outResources.add(r); + } + } + + @Override + public String getName() { + return NAME; + } + + @Override + public void previsit(Pool resources, StringTable strings) { + isPrevisitCalled = true; + for (ModuleData r : resources.getContent()) { + String s = r.getPath(); + int lastIndexOf = s.lastIndexOf('/'); + if (lastIndexOf >= 0) { + strings.addString(s.substring(0, lastIndexOf)); + } + } + } + + @Override + public Set getType() { + Set set = new HashSet<>(); + set.add(CATEGORY.TRANSFORMER); + return Collections.unmodifiableSet(set); + } + } +} diff --git a/jdk/test/tools/jlink/plugins/ResourceFilterTest.java b/jdk/test/tools/jlink/plugins/ResourceFilterTest.java new file mode 100644 index 00000000000..b7b0f2b3a82 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/ResourceFilterTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test ResourceFilter class + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main ResourceFilterTest + */ + +import java.io.File; +import java.nio.file.Files; +import jdk.tools.jlink.internal.plugins.ResourceFilter; + +public class ResourceFilterTest { + + public static void main(String[] args) throws Exception { + new ResourceFilterTest().test(); + } + + public void test() throws Exception { + String[] samples = {"toto.jcov", "/module/META-INF/services/MyProvider"}; + String[] patterns = {"*.jcov", "*/META-INF/*"}; + ResourceFilter rf = new ResourceFilter(patterns); + for (String s : samples) { + if (!rf.test(s)) { + throw new Exception("Sample " + s + "not accepted"); + } + } + ResourceFilter rf2 = new ResourceFilter(patterns, true); + for (String s : samples) { + if (rf2.test(s)) { + throw new Exception("Sample " + s + " accepted"); + } + } + + // Excluded resource list in a file + File resources = new File("resources.exc"); + resources.createNewFile(); + StringBuilder builder = new StringBuilder(); + for (String p : patterns) { + builder.append(p).append("\n"); + } + Files.write(resources.toPath(), builder.toString().getBytes()); + + String[] input = {resources.getAbsolutePath()}; + ResourceFilter rf3 = new ResourceFilter(input); + for (String s : samples) { + if (!rf3.test(s)) { + throw new Exception("Sample " + s + "not accepted"); + } + } + ResourceFilter rf4 = new ResourceFilter(input, true); + for (String s : samples) { + if (rf4.test(s)) { + throw new Exception("Sample " + s + " accepted"); + } + } + } +} diff --git a/jdk/test/tools/jlink/plugins/SignatureParserTest.java b/jdk/test/tools/jlink/plugins/SignatureParserTest.java new file mode 100644 index 00000000000..836c401788a --- /dev/null +++ b/jdk/test/tools/jlink/plugins/SignatureParserTest.java @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test SignatureParser + * @author Jean-Francois Denise + * @modules java.base/jdk.internal.jimage.decompressor + * @run main SignatureParserTest + */ + +import java.util.Arrays; +import java.util.Objects; + +import jdk.internal.jimage.decompressor.SignatureParser; + +public class SignatureParserTest { + + private int passed = 0; + private int failed = 0; + + public static void main(String[] args) { + new SignatureParserTest().test(); + } + + private void test() { + test("[Ljava/lang/String;", "[L;", "java/lang/String"); + test("[[[[[[[[[[Ljava/lang/String;", "[[[[[[[[[[L;", "java/lang/String"); + test(";>" + + "(Ljava/lang/String;Ljava/lang/Class;TT;Ljava/lang/Comparable<-TT;>;" + + "Ljava/lang/Comparable<-TT;>;ZZ)V", + ";>(L;L;TT;L<-TT;>;L<-TT;>;ZZ)V", + "java/lang/Object", "java/lang/Comparable", "java/lang/String", + "java/lang/Class", "java/lang/Comparable", "java/lang/Comparable"); + test("(Ljava/lang/String;ZLjava/util/EventListener;TTK;)V", + "(L;ZL;TTK;)V", + "java/lang/String", "java/util/EventListener"); + test("", "", "java/lang/String"); + test("", + "", "java/lang/String", + "java/util/EventListener"); + test(";>", + ";>", + "java/lang/String", "java/util/EventListener", "java/lang/Comparable", "java/lang/String"); + test(";>", + ";>", + "java/lang/String", "java/lang/Comparable", "java/lang/String", "java/lang/Float"); + test(";>;>", + ";>;>", + "java/lang/String", "java/lang/Comparable", "java/lang/String", "java/lang/Float", "java/lang/Object"); + test("Ljava/util/Set;", "L;", "java/util/Set"); + test("Ljavaapplication20/Titi<[Ljava/lang/String;Ljava/lang/Integer;>;", "L<[L;L;>;", + "javaapplication20/Titi", + "java/lang/String", "java/lang/Integer"); + test("Ljava/lang/Comparable;", "L;", "java/lang/Comparable"); + test("Ljava/io/Serializable;Ljava/lang/Comparable;", "L;L;", + "java/io/Serializable", "java/lang/Comparable"); + test(";>" + + "Ljavaapplication20/Titi<[Ljava/lang/String;Ljava/lang/Integer;TZ;>;" + + "Ljava/io/Serializable;Ljava/lang/Comparable;", + ";>L<[L;L;TZ;>;L;L;", + "java/lang/String", "java/util/EventListener", "java/util/EventListener", "java/lang/Comparable", + "java/lang/String", "javaapplication20/Titi", "java/lang/String", "java/lang/Integer", + "java/io/Serializable", "java/lang/Comparable"); + test("(Ljava/lang/Integer;TPO;)Ljava/lang/Integer;", + "(L;TPO;)L;", + "java/lang/Object", "java/lang/Integer", "java/lang/Integer"); + test("(Ljava/lang/Integer;TPO;)TPO;", "(L;TPO;)TPO;", + "java/lang/Object", "java/lang/Integer"); + test("(Ljava/lang/Class;)[TT;", + "(L;)[TT;", + "java/util/EventListener", "java/lang/Class"); + test("(Ljava/lang/Integer;ITPO;)Z", "(L;ITPO;)Z", + "Titi", "java/lang/Integer"); + test("Ljava/lang/Object;", + "L;", + "java/lang/Object", "java/lang/Object", "java/lang/Object"); + test("Ljava/util/LinkedHashMap.LinkedHashIterator;Ljava/util/Iterator;", + "L.L;L;", + "java/util/LinkedHashMap", + "inkedHashIterator", + "java/util/Iterator"); + test("LToto;", "L;", "Toto", + "java/lang/String"); + test("Ljavaapplication20/Titi<[Ljava/lang/String;Ljava/lang/Integer;TZ;>;", + "L<[L;L;TZ;>;", + "javaapplication20/Titi", "java/lang/String", "java/lang/Integer", "Toto"); + test("LX<[LQ;LW;TZ;>;", "L<[L;L;TZ;>;", + "X", "Q", "W", "Toto"); + test("Ljava/lang/String<*>;", "L<*>;", "java/lang/String"); + test("Ljava/util/List<[B>;", "L<[B>;", "java/util/List"); + test(";>Ljava/lang/Object;Ljava/util/stream/Node;", + ";>L;L;", + "java/lang/Object", "java/util/stream/Node", "java/lang/Object", "java/util/stream/Node"); + test("Ljavaapplication20/Titi<[Ljava/lang/String;>;", "L<[L;>;", + "javaapplication20/Titi", "java/lang/String"); + test(";>" + + "Ljava/lang/Object;Ljava/lang/reflect/InvocationHandler;" + + "Lcom/sun/codemodel/internal/JAnnotationWriter;", + ";>L;L;L;", + "java/lang/annotation/Annotation", "com/sun/codemodel/internal/JAnnotationWriter", + "java/lang/Object", "java/lang/reflect/InvocationHandler", "com/sun/codemodel/internal/JAnnotationWriter"); + test(";>(Ljava/lang/Class;" + + "Lcom/sun/codemodel/internal/JAnnotatable;)TW;", + ";>(L;L;)TW;", + "com/sun/codemodel/internal/JAnnotationWriter", "java/lang/Class", "com/sun/codemodel/internal/JAnnotatable"); + test("Ljava/util/Set.Edge;>;", + "L.Edge;>;", + "java/util/Set", + "com/sun/tools/jdeps/JdepsTask$DotGraph"); + test(";>Ljava/lang/Object;", + ";>L;", + "com/sun/xml/internal/rngom/ast/om/ParsedElementAnnotation", + "", + "com/sun/xml/internal/rngom/ast/om/Location", + "", + "com/sun/xml/internal/rngom/ast/builder/CommentList", + "", + "java/lang/Object"); + test("(Ljava/util/List;TL;TA;)" + + "Lcom/sun/xml/internal/rngom/nc/NameClass;", + "(L;TL;TA;)L;", + "java/util/List", + "com/sun/xml/internal/rngom/nc/NameClass", + "", + "com/sun/xml/internal/rngom/nc/NameClass"); + test("[Ljava/util/List;", "[L;", "java/util/List"); + test("[Ljava/util/List<+Lcom/sun/jdi/request/EventRequest;>;", + "[L<+L;>;", + "java/util/List", "com/sun/jdi/request/EventRequest"); + test("Lcom/sun/xml/internal/bind/v2/util/QNameMap.HashIterator" + + ";>;", + "L.HashIterator;>;", + "com/sun/xml/internal/bind/v2/util/QNameMap", "com/sun/xml/internal/bind/v2/util/QNameMap$Entry"); + test("[Ljava/lang/String;", "[L;", "java/lang/String"); + test("[Ljava/lang/String;>;", + "[L;>;", + "java/lang/String", "java/lang/Toto", "java/lang/Titi"); + test("(ZCLjava/lang/Class;IJS)[TT;", + "(ZCL;IJS)[TT;", + "java/util/EventListener", "java/util/BOO", "java/lang/Class"); + test("(TT;ILjava/lang/Long;)TT;", + "(TT;IL;)TT;", "java/lang/Object", "java/lang/Long"); + test("(TT;ILjava/lang/Long;)TT;^TT;", + "(TT;IL;)TT;^TT;", "java/lang/Object", "java/lang/Long"); + test("(TT;ILjava/lang/Long;)TT;^TT;^Ljava/lang/Exception;", + "(TT;IL;)TT;^TT;^L;", + "java/lang/Object", "java/lang/Long", "java/lang/Exception"); + if (passed + failed == 0) { + throw new AssertionError("No tests were run"); + } + String message = String.format("Passed: %d, failed: %d, total: %d", passed, failed, passed + failed); + if (failed > 0) { + throw new AssertionError("Test failed: " + message); + } else { + System.err.println(message); + } + } + + private void test(String type, String formatted, String...classNames) { + try { + SignatureParser.ParseResult result = SignatureParser.parseSignatureDescriptor(type); + String[] parsedNames = parse(classNames); + assertEquals(result.formatted, formatted, "Input: '" + type + "', checking 'formatted'"); + assertEquals(result.types.size(), 2 * classNames.length, + "Input: '" + type + "', checking the length of 'types':" + + "\nexpected: " + Arrays.toString(parsedNames) + + "\n got: " + result.types); + for (int i = 0; i < result.types.size(); ++i) { + assertEquals(result.types.get(i), parsedNames[i], + "Input: '" + type + "', checking 'packageName' at index " + i / 2); + ++i; + assertEquals(result.types.get(i), parsedNames[i], + "Input: '" + type + "', checking 'simpleName' at index " + i / 2); + } + String reconstructed = SignatureParser.reconstruct(result.formatted, result.types); + assertEquals(reconstructed, type, "Input: '" + type + "', checking reconstruction from: " + + result.formatted + " " + result.types); + ++passed; + } catch (Exception | AssertionError e) { + e.printStackTrace(); + ++failed; + } + } + + private void assertEquals(Object actual, Object expected, String message) { + if (!Objects.equals(actual, expected)) { + throw new AssertionError(message + ": expected: " + expected + ", actual: " + actual); + } + } + + private String[] parse(String[] classNames) { + String[] result = new String[2 * classNames.length]; + for (int i = 0; i < classNames.length; ++i) { + int index = classNames[i].lastIndexOf("/"); + result[2 * i] = index == -1 ? "" : classNames[i].substring(0, index); + result[2 *i + 1] = classNames[i].substring(index + 1); + } + return result; + } +} diff --git a/jdk/test/tools/jlink/plugins/SorterPluginTest.java b/jdk/test/tools/jlink/plugins/SorterPluginTest.java new file mode 100644 index 00000000000..1e01fa9a001 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/SorterPluginTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test sorter plugin + * @author Jean-Francois Denise + * @modules jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * @run main SorterPluginTest + */ + +import java.io.File; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import jdk.tools.jlink.internal.PoolImpl; + +import jdk.tools.jlink.internal.plugins.SortResourcesPlugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; + +public class SorterPluginTest { + + public static void main(String[] args) throws Exception { + new SorterPluginTest().test(); + } + + public void test() throws Exception { + ModuleData[] array = { + Pool.newResource("/module1/toto1", new byte[0]), + Pool.newResource("/module2/toto1", new byte[0]), + Pool.newResource("/module3/toto1", new byte[0]), + Pool.newResource("/module3/toto1/module-info.class", new byte[0]), + Pool.newResource("/zazou/toto1", new byte[0]), + Pool.newResource("/module4/zazou", new byte[0]), + Pool.newResource("/module5/toto1", new byte[0]), + Pool.newResource("/module6/toto1/module-info.class", new byte[0]) + }; + + ModuleData[] sorted = { + Pool.newResource("/zazou/toto1", new byte[0]), + Pool.newResource("/module3/toto1/module-info.class", new byte[0]), + Pool.newResource("/module6/toto1/module-info.class", new byte[0]), + Pool.newResource("/module1/toto1", new byte[0]), + Pool.newResource("/module2/toto1", new byte[0]), + Pool.newResource("/module3/toto1", new byte[0]), + Pool.newResource("/module4/zazou", new byte[0]), + Pool.newResource("/module5/toto1", new byte[0]), +}; + + ModuleData[] sorted2 = { + Pool.newResource("/module5/toto1", new byte[0]), + Pool.newResource("/module6/toto1/module-info.class", new byte[0]), + Pool.newResource("/module4/zazou", new byte[0]), + Pool.newResource("/module3/toto1", new byte[0]), + Pool.newResource("/module3/toto1/module-info.class", new byte[0]), + Pool.newResource("/module1/toto1", new byte[0]), + Pool.newResource("/module2/toto1", new byte[0]), + Pool.newResource("/zazou/toto1", new byte[0]),}; + + Pool resources = new PoolImpl(); + for (ModuleData r : array) { + resources.add(r); + } + + { + Pool out = new PoolImpl(); + Map config = new HashMap<>(); + config.put(SortResourcesPlugin.NAME, "/zazou/*,*/module-info.class"); + TransformerPlugin p = new SortResourcesPlugin(); + p.configure(config); + p.visit(resources, out); + check(out.getContent(), sorted); + } + + { + // Order of resources in the file, then un-ordered resources. + File order = new File("resources.order"); + order.createNewFile(); + StringBuilder builder = new StringBuilder(); + // 5 first resources come from file + for (int i = 0; i < 5; i++) { + builder.append(sorted2[i].getPath()).append("\n"); + } + Files.write(order.toPath(), builder.toString().getBytes()); + + Pool out = new PoolImpl(); + Map config = new HashMap<>(); + config.put(SortResourcesPlugin.NAME, order.getAbsolutePath()); + TransformerPlugin p = new SortResourcesPlugin(); + p.configure(config); + p.visit(resources, out); + check(out.getContent(), sorted2); + + } + } + + private void check(Collection outResources, + ModuleData[] sorted) { + if (outResources.size() != sorted.length) { + throw new AssertionError("Wrong number of resources:\n" + + "expected: " + Arrays.toString(sorted) + ",\n" + + " got: " + outResources); + } + int i = 0; + for (ModuleData r : outResources) { + System.err.println("Resource: " + r); + if (!sorted[i].getPath().equals(r.getPath())) { + throw new AssertionError("Resource not properly sorted, difference at: " + i + "\n" + + "expected: " + Arrays.toString(sorted) + ",\n" + + " got: " + outResources); + } + i++; + } + } +} diff --git a/jdk/test/tools/jlink/plugins/StringSharingPluginTest.java b/jdk/test/tools/jlink/plugins/StringSharingPluginTest.java new file mode 100644 index 00000000000..786da460990 --- /dev/null +++ b/jdk/test/tools/jlink/plugins/StringSharingPluginTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test StringSharingPluginTest + * @author Jean-Francois Denise + * @library ../../lib + * @modules java.base/jdk.internal.jimage + * java.base/jdk.internal.jimage.decompressor + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * jdk.jlink/jdk.tools.jmod + * jdk.jlink/jdk.tools.jimage + * jdk.jdeps/com.sun.tools.classfile + * jdk.compiler + * @run build tests.* + * @run main StringSharingPluginTest + */ + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import jdk.internal.jimage.decompressor.CompressedResourceHeader; +import jdk.internal.jimage.decompressor.StringSharingDecompressor; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.StringTable; +import jdk.tools.jlink.internal.plugins.StringSharingPlugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; +import tests.Helper; +import tests.JImageValidator; + +public class StringSharingPluginTest { + + private static int strID = 1; + + public static void main(String[] args) throws Exception { + // JPRT not yet ready for jmods + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run, NO jmods directory"); + return; + } + + List classes = Arrays.asList("toto.Main", "toto.com.foo.bar.X"); + Path compiledClasses = helper.generateModuleCompiledClasses( + helper.getJmodSrcDir(), helper.getJmodClassesDir(), "composite2", classes); + + Map map = new HashMap<>(); + Map reversedMap = new HashMap<>(); + + PoolImpl resources = new PoolImpl(ByteOrder.nativeOrder(), new StringTable() { + @Override + public int addString(String str) { + Integer id = map.get(str); + if (id == null) { + id = strID; + map.put(str, id); + reversedMap.put(id, str); + strID += 1; + } + return id; + } + + @Override + public String getString(int id) { + throw new UnsupportedOperationException("Not supported yet."); + } + }); + Consumer c = (p) -> { + // take only the .class resources. + if (Files.isRegularFile(p) && p.toString().endsWith(".class") + && !p.toString().endsWith("module-info.class")) { + try { + byte[] content = Files.readAllBytes(p); + String path = p.toString().replace('\\', '/'); + path = path.substring("/modules".length()); + ModuleData res = Pool.newResource(path, content); + resources.add(res); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + }; + try (java.util.stream.Stream stream = Files.walk(compiledClasses)) { + stream.forEach(c); + } + TransformerPlugin plugin = new StringSharingPlugin(); + PoolImpl result = new PoolImpl(resources.getByteOrder(), resources.getStringTable()); + plugin.visit(resources, result); + + if (result.isEmpty()) { + throw new AssertionError("No result"); + } + + for (ModuleData res : result.getContent()) { + if (res.getPath().endsWith(".class")) { + byte[] uncompacted = StringSharingDecompressor.normalize(reversedMap::get, res.getBytes(), + CompressedResourceHeader.getSize()); + JImageValidator.readClass(uncompacted); + } + } + } +} diff --git a/jdk/test/tools/jlink/plugins/StripDebugPluginTest.java b/jdk/test/tools/jlink/plugins/StripDebugPluginTest.java new file mode 100644 index 00000000000..fd8acae896c --- /dev/null +++ b/jdk/test/tools/jlink/plugins/StripDebugPluginTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test StripDebugPlugin + * @author Jean-Francois Denise + * @library ../../lib + * @build tests.* + * @modules java.base/jdk.internal.jimage + * jdk.jlink/jdk.tools.jlink.internal + * jdk.jlink/jdk.tools.jlink.internal.plugins + * jdk.jlink/jdk.tools.jimage + * jdk.jlink/jdk.tools.jmod + * jdk.jdeps/com.sun.tools.classfile + * jdk.compiler + * @run main StripDebugPluginTest + */ + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; + +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.ConstantPoolException; +import com.sun.tools.classfile.Method; +import java.util.HashMap; +import java.util.Map; +import jdk.tools.jlink.internal.PoolImpl; +import jdk.tools.jlink.internal.plugins.StripDebugPlugin; +import jdk.tools.jlink.plugin.Pool; +import jdk.tools.jlink.plugin.Pool.ModuleData; +import jdk.tools.jlink.plugin.TransformerPlugin; +import tests.Helper; + +public class StripDebugPluginTest { + public static void main(String[] args) throws Exception { + new StripDebugPluginTest().test(); + } + + public void test() throws Exception { + // JPRT not yet ready for jmods + Helper helper = Helper.newHelper(); + if (helper == null) { + System.err.println("Test not run, NO jmods directory"); + return; + } + + List classes = Arrays.asList("toto.Main", "toto.com.foo.bar.X"); + Path moduleFile = helper.generateModuleCompiledClasses( + helper.getJmodSrcDir(), helper.getJmodClassesDir(), "leaf1", classes); + Path moduleInfo = moduleFile.resolve("module-info.class"); + + // Classes have been compiled in debug. + List covered = new ArrayList<>(); + byte[] infoContent = Files.readAllBytes(moduleInfo); + try (Stream stream = Files.walk(moduleFile)) { + for (Iterator iterator = stream.iterator(); iterator.hasNext(); ) { + Path p = iterator.next(); + if (Files.isRegularFile(p) && p.toString().endsWith(".class")) { + byte[] content = Files.readAllBytes(p); + String path = "/" + helper.getJmodClassesDir().relativize(p).toString(); + String moduleInfoPath = path + "/module-info.class"; + check(path, content, moduleInfoPath, infoContent); + covered.add(p); + } + } + } + if (covered.isEmpty()) { + throw new AssertionError("No class to compress"); + } else { + System.err.println("removed debug attributes from " + + covered.size() + " classes"); + } + } + + private void check(String path, byte[] content, String infoPath, byte[] moduleInfo) throws Exception { + path = path.replace('\\', '/'); + StripDebugPlugin debug = new StripDebugPlugin(); + debug.configure(new HashMap<>()); + ModuleData result1 = stripDebug(debug, Pool.newResource(path,content), path, infoPath, moduleInfo); + + if (!path.endsWith("module-info.class")) { + if (result1.getLength() >= content.length) { + throw new AssertionError("Class size not reduced, debug info not " + + "removed for " + path); + } + checkDebugAttributes(result1.getBytes()); + } + + ModuleData result2 = stripDebug(debug, result1, path, infoPath, moduleInfo); + if (result1.getLength() != result2.getLength()) { + throw new AssertionError("removing debug info twice reduces class size of " + + path); + } + checkDebugAttributes(result1.getBytes()); + } + + private ModuleData stripDebug(TransformerPlugin debug, ModuleData classResource, + String path, String infoPath, byte[] moduleInfo) throws Exception { + Pool resources = new PoolImpl(); + resources.add(classResource); + if (!path.endsWith("module-info.class")) { + ModuleData res2 = Pool.newResource(infoPath, moduleInfo); + resources.add(res2); + } + Pool results = new PoolImpl(); + debug.visit(resources, results); + System.out.println(classResource.getPath()); + return results.get(classResource.getPath()); + } + + private void checkDebugAttributes(byte[] strippedClassFile) throws IOException, ConstantPoolException { + ClassFile classFile = ClassFile.read(new ByteArrayInputStream(strippedClassFile)); + String[] debugAttributes = new String[]{ + Attribute.LineNumberTable, + Attribute.LocalVariableTable, + Attribute.LocalVariableTypeTable + }; + for (Method method : classFile.methods) { + String methodName = method.getName(classFile.constant_pool); + Code_attribute code = (Code_attribute) method.attributes.get(Attribute.Code); + for (String attr : debugAttributes) { + if (code.attributes.get(attr) != null) { + throw new AssertionError("Debug attribute was not removed: " + attr + + " from method " + classFile.getName() + "#" + methodName); + } + } + } + } +} diff --git a/jdk/test/tools/jmod/JmodNegativeTest.java b/jdk/test/tools/jmod/JmodNegativeTest.java new file mode 100644 index 00000000000..5469726a318 --- /dev/null +++ b/jdk/test/tools/jmod/JmodNegativeTest.java @@ -0,0 +1,552 @@ +/** + * 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. + */ + +/* + * @test + * @library /lib/testlibrary + * @modules jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @build jdk.testlibrary.FileUtils CompilerUtils + * @run testng JmodNegativeTest + * @summary Negative tests for jmod + */ + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.zip.ZipOutputStream; +import jdk.testlibrary.FileUtils; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static java.io.File.pathSeparator; +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.testng.Assert.assertTrue; + +public class JmodNegativeTest { + + static final String TEST_SRC = System.getProperty("test.src", "."); + static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + static final Path EXPLODED_DIR = Paths.get("build"); + static final Path MODS_DIR = Paths.get("jmods"); + + @BeforeTest + public void buildExplodedModules() throws IOException { + if (Files.exists(EXPLODED_DIR)) + FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR); + + for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { + Path dir = EXPLODED_DIR.resolve(name); + assertTrue(compileModule(name, dir.resolve("classes"))); + } + + if (Files.exists(MODS_DIR)) + FileUtils.deleteFileTreeWithRetry(MODS_DIR); + Files.createDirectories(MODS_DIR); + } + + @Test + public void testNoArgs() { + jmod() + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: one of create, list, or describe must be specified") + ); + } + + @Test + public void testBadAction() { + jmod("badAction") + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: mode must be one of create, list, or describe") + ); + + jmod("--badOption") + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: 'badOption' is not a recognized option") + ); + } + + @Test + public void testTooManyArgs() throws IOException { + Path jmod = MODS_DIR.resolve("doesNotExist.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + + jmod("create", + jmod.toString(), + "AAA") + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: unknown option(s): [AAA]") + ); + } + + @Test + public void testCreateNoArgs() { + jmod("create") + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: jmod-file must be specified") + ); + } + + @Test + public void testListNoArgs() { + jmod("list") + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: jmod-file must be specified") + ); + } + + @Test + public void testListFileDoesNotExist() throws IOException { + Path jmod = MODS_DIR.resolve("doesNotExist.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + + jmod("list", + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: no jmod file found: " + + jmod.toString()) + ); + } + + @Test + public void testListJmodIsDir() throws IOException { + Path jmod = MODS_DIR.resolve("testListJmodIsDir.jmod"); + if (Files.notExists(jmod)) + Files.createDirectory(jmod); + + jmod("list", + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: error opening jmod file") + ); + } + + @Test + public void testlistJmodMalformed() throws IOException { + Path jmod = MODS_DIR.resolve("testlistJmodMalformed.jmod"); + if (Files.notExists(jmod)) + Files.createFile(jmod); + + jmod("list", + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: error opening jmod file") + ); + } + + @Test + public void testHashDependenciesModulePathNotSpecified() { + jmod("create", + "--hash-dependencies", "anyPattern.*", + "output.jmod") + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: --module-path must be " + +"specified when hashing dependencies") + ); + } + + @Test + public void testCreateJmodAlreadyExists() throws IOException { + Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists.jmod"); + if (Files.notExists(jmod)) + Files.createFile(jmod); + + jmod("create", + "--class-path", Paths.get(".").toString(), // anything that exists + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: file already exists: " + jmod.toString()) + ); + } + + @Test + public void testCreateJmodIsDir() throws IOException { + Path jmod = MODS_DIR.resolve("testCreateJmodAlreadyExists"); + if (Files.notExists(jmod)) + Files.createDirectory(jmod); + + jmod("create", + "--class-path", Paths.get(".").toString(), // anything that exists + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: file already exists: " + jmod.toString()) + ); + } + + @Test + public void testInvalidModuleVersion() throws IOException { + Path jmod = MODS_DIR.resolve("testEmptyModuleVersion.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + for (String version : new String[] { "", "NOT_A_VALID_VERSION" }) { + jmod("create", + "--class-path", cp, + "--module-version", version, + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: invalid module version") + ); + } + } + + @Test(enabled = false) // TODO: jmod should check for duplicates before creating. + public void testDuplicates() throws IOException { + Path jmod = MODS_DIR.resolve("testDuplicates.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + jmod("create", + "--class-path", cp + pathSeparator + cp, + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: duplicate resource found, etc..") + ); + } + + @Test + public void testEmptyFileInClasspath() throws IOException { + Path jmod = MODS_DIR.resolve("testEmptyFileInClasspath.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path jar = MODS_DIR.resolve("NotARealJar_Empty.jar"); + FileUtils.deleteFileIfExistsWithRetry(jar); + Files.createFile(jar); + + jmod("create", + "--class-path", jar.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: module-info.class not found") + ); + } + + @Test + public void testEmptyJarInClasspath() throws IOException { + Path jmod = MODS_DIR.resolve("testEmptyJarInClasspath.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path jar = MODS_DIR.resolve("empty.jar"); + FileUtils.deleteFileIfExistsWithRetry(jar); + try (FileOutputStream fos = new FileOutputStream(jar.toFile()); + ZipOutputStream zos = new ZipOutputStream(fos)) { + // empty + } + + jmod("create", + "--class-path", jar.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: module-info.class not found") + ); + } + + @Test + public void testModuleInfoNotFound() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path jar = MODS_DIR.resolve("empty"); + FileUtils.deleteFileIfExistsWithRetry(jar); + Files.createDirectory(jar); + + jmod("create", + "--class-path", jar.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: module-info.class not found") + ); + } + + @Test + public void testModuleInfoIsDir() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = MODS_DIR.resolve("module-info.class"); + FileUtils.deleteFileIfExistsWithRetry(cp); + Files.createDirectory(cp); + Files.createFile(cp.resolve("nada.txt")); + + jmod("create", + "--class-path", cp.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: module-info.class not found") + ); + } + + @Test + public void testDependencyNotFound() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path emptyDir = Paths.get("empty"); + if (Files.exists(emptyDir)) + FileUtils.deleteFileTreeWithRetry(emptyDir); + Files.createDirectory(emptyDir); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + jmod("create", + "--class-path", cp, + "--hash-dependencies", ".*", + "--modulepath", emptyDir.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Hashing module foo dependencies, " + + "unable to find module java.base on module path") + ); + } + + @Test + public void testEmptyFileInModulePath() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path empty = MODS_DIR.resolve("emptyFile.jmod"); + FileUtils.deleteFileIfExistsWithRetry(empty); + Files.createFile(empty); + try { + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + jmod("create", + "--class-path", cp, + "--hash-dependencies", ".*", + "--modulepath", MODS_DIR.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: error reading module path") + ); + } finally { + FileUtils.deleteFileWithRetry(empty); + } + } + + @Test + public void testFileInModulePath() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path file = MODS_DIR.resolve("testFileInModulePath.txt"); + FileUtils.deleteFileIfExistsWithRetry(file); + Files.createFile(file); + + jmod("create", + "--hash-dependencies", ".*", + "--modulepath", file.toString(), + jmod.toString()) + .assertFailure() + .resultChecker(r -> + assertContains(r.output, "Error: path must be a directory") + ); + } + + @DataProvider(name = "pathDoesNotExist") + public Object[][] pathDoesNotExist() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist")); + + List> tasks = Arrays.asList( + () -> jmod("create", + "--hash-dependencies", "anyPattern", + "--modulepath", "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--class-path", "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--class-path", "doesNotExist.jar", + "output.jmod"), + () -> jmod("create", + "--cmds", "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--config", "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--libs", "doesNotExist", + "output.jmod") ); + + String errMsg = "Error: path not found: doesNotExist"; + return tasks.stream().map(t -> new Object[] {t, errMsg} ) + .toArray(Object[][]::new); + } + + @Test(dataProvider = "pathDoesNotExist") + public void testPathDoesNotExist(Supplier supplier, + String errMsg) + { + supplier.get() + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, errMsg); + }); + } + + @DataProvider(name = "partOfPathDoesNotExist") + public Object[][] partOfPathDoesNotExist() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + FileUtils.deleteFileIfExistsWithRetry(Paths.get("doesNotExist")); + + Path emptyDir = Paths.get("empty"); + if (Files.exists(emptyDir)) + FileUtils.deleteFileTreeWithRetry(emptyDir); + Files.createDirectory(emptyDir); + + List> tasks = Arrays.asList( + () -> jmod("create", + "--hash-dependencies", "anyPattern", + "--modulepath","empty" + pathSeparator + "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--class-path", "empty" + pathSeparator + "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--class-path", "empty" + pathSeparator + "doesNotExist.jar", + "output.jmod"), + () -> jmod("create", + "--cmds", "empty" + pathSeparator + "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--config", "empty" + pathSeparator + "doesNotExist", + "output.jmod"), + () -> jmod("create", + "--libs", "empty" + pathSeparator + "doesNotExist", + "output.jmod") ); + + String errMsg = "Error: path not found: doesNotExist"; + return tasks.stream().map(t -> new Object[] {t, errMsg} ) + .toArray(Object[][]::new); + } + + @Test(dataProvider = "partOfPathDoesNotExist") + public void testPartOfPathNotExist(Supplier supplier, + String errMsg) + { + supplier.get() + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, errMsg); + }); + } + + @DataProvider(name = "pathIsFile") + public Object[][] pathIsFile() throws IOException { + Path jmod = MODS_DIR.resolve("output.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path aFile = Paths.get("aFile.txt"); + if (Files.exists(aFile) && !Files.isRegularFile(aFile)) + throw new InternalError("Unexpected file:" + aFile); + else + Files.createFile(aFile); + + List> tasks = Arrays.asList( + () -> jmod("create", + "--class-path", "aFile.txt", + "output.jmod"), + () -> jmod("create", + "--modulepath", "aFile.txt", + "output.jmod"), + () -> jmod("create", + "--cmds", "aFile.txt", + "output.jmod"), + () -> jmod("create", + "--config", "aFile.txt", + "output.jmod"), + () -> jmod("create", + "--libs", "aFile.txt", + "output.jmod") ); + + String errMsg = "Error: path must be a directory: aFile.txt"; + Object[][] a = tasks.stream().map(t -> new Object[] {t, errMsg} ) + .toArray(Object[][]::new); + a[0][1] = "invalid class path entry: aFile.txt"; // class path err msg + return a; + } + + @Test(dataProvider = "pathIsFile") + public void testPathIsFile(Supplier supplier, + String errMsg) + { + supplier.get() + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, errMsg); + }); + } + + // --- + + static boolean compileModule(String name, Path dest) throws IOException { + return CompilerUtils.compile(SRC_DIR.resolve(name), dest); + } + + static void assertContains(String output, String subString) { + if (output.contains(subString)) + assertTrue(true); + else + assertTrue(false,"Expected to find [" + subString + "], in output [" + + output + "]"); + } + + static JmodResult jmod(String... args) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + System.out.println("jmod " + Arrays.asList(args)); + int ec = jdk.tools.jmod.Main.run(args, ps); + return new JmodResult(ec, new String(baos.toByteArray(), UTF_8)); + } + + static class JmodResult { + final int exitCode; + final String output; + + JmodResult(int exitValue, String output) { + this.exitCode = exitValue; + this.output = output; + } + JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; } + JmodResult resultChecker(Consumer r) { r.accept(this); return this; } + } +} diff --git a/jdk/test/tools/jmod/JmodTest.java b/jdk/test/tools/jmod/JmodTest.java new file mode 100644 index 00000000000..01f2b238b5f --- /dev/null +++ b/jdk/test/tools/jmod/JmodTest.java @@ -0,0 +1,485 @@ +/** + * 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. + */ + +/* + * @test + * @library /lib/testlibrary + * @modules jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @build jdk.testlibrary.FileUtils CompilerUtils + * @run testng JmodTest + * @summary Basic test for jmod + */ + +import java.io.*; +import java.lang.module.ModuleDescriptor; +import java.lang.reflect.Method; +import java.nio.file.*; +import java.util.*; +import java.util.function.Consumer; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import jdk.testlibrary.FileUtils; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static java.lang.module.ModuleDescriptor.Version; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.stream.Collectors.toSet; +import static org.testng.Assert.*; + +public class JmodTest { + + static final String TEST_SRC = System.getProperty("test.src", "."); + static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + static final Path EXPLODED_DIR = Paths.get("build"); + static final Path MODS_DIR = Paths.get("jmods"); + + static final String CLASSES_PREFIX = "classes/"; + static final String CMDS_PREFIX = "bin/"; + static final String LIBS_PREFIX = "native/"; + static final String CONFIGS_PREFIX = "conf/"; + + @BeforeTest + public void buildExplodedModules() throws IOException { + if (Files.exists(EXPLODED_DIR)) + FileUtils.deleteFileTreeWithRetry(EXPLODED_DIR); + + for (String name : new String[] { "foo"/*, "bar", "baz"*/ } ) { + Path dir = EXPLODED_DIR.resolve(name); + assertTrue(compileModule(name, dir.resolve("classes"))); + createCmds(dir.resolve("bin")); + createLibs(dir.resolve("lib")); + createConfigs(dir.resolve("conf")); + } + + if (Files.exists(MODS_DIR)) + FileUtils.deleteFileTreeWithRetry(MODS_DIR); + Files.createDirectories(MODS_DIR); + } + + @Test + public void testList() throws IOException { + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + jmod("create", + "--class-path", cp, + MODS_DIR.resolve("foo.jmod").toString()) + .assertSuccess(); + + jmod("list", + MODS_DIR.resolve("foo.jmod").toString()) + .assertSuccess() + .resultChecker(r -> { + // asserts dependent on the exact contents of foo + assertContains(r.output, CLASSES_PREFIX + "module-info.class"); + assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/Foo.class"); + assertContains(r.output, CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); + }); + } + + @Test + public void testMainClass() throws IOException { + Path jmod = MODS_DIR.resolve("fooMainClass.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + jmod("create", + "--class-path", cp, + "--main-class", "jdk.test.foo.Foo", + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + Optional omc = getModuleDescriptor(jmod).mainClass(); + assertTrue(omc.isPresent()); + assertEquals(omc.get(), "jdk.test.foo.Foo"); + }); + } + + @Test + public void testModuleVersion() throws IOException { + Path jmod = MODS_DIR.resolve("fooVersion.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + jmod("create", + "--class-path", cp, + "--module-version", "5.4.3", + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + Optional ov = getModuleDescriptor(jmod).version(); + assertTrue(ov.isPresent()); + assertEquals(ov.get().toString(), "5.4.3"); + }); + } + + @Test + public void testConfig() throws IOException { + Path jmod = MODS_DIR.resolve("fooConfig.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); + Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); + + jmod("create", + "--class-path", cp.toString(), + "--config", cf.toString(), + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + try (Stream s1 = findFiles(cf).map(p -> CONFIGS_PREFIX + p); + Stream s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { + Set expectedFilenames = Stream.concat(s1, s2) + .collect(toSet()); + assertJmodContent(jmod, expectedFilenames); + } + }); + } + + @Test + public void testCmds() throws IOException { + Path jmod = MODS_DIR.resolve("fooCmds.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); + Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); + + jmod("create", + "--cmds", bp.toString(), + "--class-path", cp.toString(), + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + try (Stream s1 = findFiles(bp).map(p -> CMDS_PREFIX + p); + Stream s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { + Set expectedFilenames = Stream.concat(s1,s2) + .collect(toSet()); + assertJmodContent(jmod, expectedFilenames); + } + }); + } + + @Test + public void testLibs() throws IOException { + Path jmod = MODS_DIR.resolve("fooLibs.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); + Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); + + jmod("create", + "--libs=", lp.toString(), + "--class-path", cp.toString(), + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + try (Stream s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); + Stream s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p)) { + Set expectedFilenames = Stream.concat(s1,s2) + .collect(toSet()); + assertJmodContent(jmod, expectedFilenames); + } + }); + } + + @Test + public void testAll() throws IOException { + Path jmod = MODS_DIR.resolve("fooAll.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); + Path bp = EXPLODED_DIR.resolve("foo").resolve("bin"); + Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); + Path cf = EXPLODED_DIR.resolve("foo").resolve("conf"); + + jmod("create", + "--conf", cf.toString(), + "--cmds=", bp.toString(), + "--libs=", lp.toString(), + "--class-path", cp.toString(), + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + try (Stream s1 = findFiles(lp).map(p -> LIBS_PREFIX + p); + Stream s2 = findFiles(cp).map(p -> CLASSES_PREFIX + p); + Stream s3 = findFiles(bp).map(p -> CMDS_PREFIX + p); + Stream s4 = findFiles(cf).map(p -> CONFIGS_PREFIX + p)) { + Set expectedFilenames = Stream.concat(Stream.concat(s1,s2), + Stream.concat(s3, s4)) + .collect(toSet()); + assertJmodContent(jmod, expectedFilenames); + } + }); + } + + @Test + public void testExcludes() throws IOException { + Path jmod = MODS_DIR.resolve("fooLibs.jmod"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + Path cp = EXPLODED_DIR.resolve("foo").resolve("classes"); + Path lp = EXPLODED_DIR.resolve("foo").resolve("lib"); + + jmod("create", + "--libs=", lp.toString(), + "--class-path", cp.toString(), + "--exclude", "**internal**", + "--exclude", "first.so", + jmod.toString()) + .assertSuccess() + .resultChecker(r -> { + Set expectedFilenames = new HashSet<>(); + expectedFilenames.add(CLASSES_PREFIX + "module-info.class"); + expectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/Foo.class"); + expectedFilenames.add(LIBS_PREFIX + "second.so"); + expectedFilenames.add(LIBS_PREFIX + "third/third.so"); + assertJmodContent(jmod, expectedFilenames); + + Set unexpectedFilenames = new HashSet<>(); + unexpectedFilenames.add(CLASSES_PREFIX + "jdk/test/foo/internal/Message.class"); + unexpectedFilenames.add(LIBS_PREFIX + "first.so"); + assertJmodDoesNotContain(jmod, unexpectedFilenames); + }); + } + + @Test + public void describe() throws IOException { + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + jmod("create", + "--class-path", cp, + MODS_DIR.resolve("describeFoo.jmod").toString()) + .assertSuccess(); + + jmod("describe", + MODS_DIR.resolve("describeFoo.jmod").toString()) + .assertSuccess() + .resultChecker(r -> { + // Expect similar output: "foo, requires mandated java.base + // exports jdk.test.foo, conceals jdk.test.foo.internal" + Pattern p = Pattern.compile("\\s+foo\\s+requires\\s+mandated\\s+java.base"); + assertTrue(p.matcher(r.output).find(), + "Expecting to find \"foo, requires java.base\"" + + "in output, but did not: [" + r.output + "]"); + p = Pattern.compile( + "exports\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal"); + assertTrue(p.matcher(r.output).find(), + "Expecting to find \"exports ..., conceals ...\"" + + "in output, but did not: [" + r.output + "]"); + }); + } + + @Test + public void testVersion() { + jmod("--version") + .assertSuccess() + .resultChecker(r -> { + assertContains(r.output, System.getProperty("java.version")); + }); + } + + @Test + public void testHelp() { + jmod("--help") + .assertSuccess() + .resultChecker(r -> + assertTrue(r.output.startsWith("Usage: jmod"), "Help not printed") + ); + } + + @Test + public void testTmpFileAlreadyExists() throws IOException { + // Implementation detail: jmod tool creates .tmp + // Ensure that there are no problems if existing + + Path jmod = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod"); + Path tmp = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod.tmp"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + FileUtils.deleteFileIfExistsWithRetry(tmp); + Files.createFile(tmp); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString(); + + jmod("create", + "--class-path", cp, + jmod.toString()) + .assertSuccess() + .resultChecker(r -> + assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp) + ); + } + + @Test + public void testTmpFileRemoved() throws IOException { + // Implementation detail: jmod tool creates .tmp + // Ensure that it is removed in the event of a failure. + // The failure in this case is a class in the unnamed package. + + Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod"); + Path tmp = MODS_DIR.resolve("testTmpFileRemoved.jmod.tmp"); + FileUtils.deleteFileIfExistsWithRetry(jmod); + FileUtils.deleteFileIfExistsWithRetry(tmp); + String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator + + EXPLODED_DIR.resolve("foo").resolve("classes") + .resolve("jdk").resolve("test").resolve("foo").toString(); + + jmod("create", + "--class-path", cp, + jmod.toString()) + .assertFailure() + .resultChecker(r -> { + assertContains(r.output, "unnamed package"); + assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp); + }); + } + + // --- + + static boolean compileModule(String name, Path dest) throws IOException { + return CompilerUtils.compile(SRC_DIR.resolve(name), dest); + } + + static void assertContains(String output, String subString) { + if (output.contains(subString)) + assertTrue(true); + else + assertTrue(false,"Expected to find [" + subString + "], in output [" + + output + "]" + "\n"); + } + + static ModuleDescriptor getModuleDescriptor(Path jmod) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + try (FileSystem fs = FileSystems.newFileSystem(jmod, cl)) { + String p = "/classes/module-info.class"; + try (InputStream is = Files.newInputStream(fs.getPath(p))) { + return ModuleDescriptor.read(is); + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + + static Stream findFiles(Path dir) { + try { + return Files.find(dir, Integer.MAX_VALUE, (p, a) -> a.isRegularFile()) + .map(dir::relativize) + .map(Path::toString) + .map(p -> p.replace(File.separator, "/")); + } catch (IOException x) { + throw new UncheckedIOException(x); + } + } + + static Set getJmodContent(Path jmod) { + JmodResult r = jmod("list", jmod.toString()).assertSuccess(); + return Stream.of(r.output.split("\r?\n")).collect(toSet()); + } + + static void assertJmodContent(Path jmod, Set expected) { + Set actual = getJmodContent(jmod); + if (!Objects.equals(actual, expected)) { + Set unexpected = new HashSet<>(actual); + unexpected.removeAll(expected); + Set notFound = new HashSet<>(expected); + notFound.removeAll(actual); + StringBuilder sb = new StringBuilder(); + sb.append("Unexpected but found:\n"); + unexpected.forEach(s -> sb.append("\t" + s + "\n")); + sb.append("Expected but not found:\n"); + notFound.forEach(s -> sb.append("\t" + s + "\n")); + assertTrue(false, "Jmod content check failed.\n" + sb.toString()); + } + } + + static void assertJmodDoesNotContain(Path jmod, Set unexpectedNames) { + Set actual = getJmodContent(jmod); + Set unexpected = new HashSet<>(); + for (String name : unexpectedNames) { + if (actual.contains(name)) + unexpected.add(name); + } + if (!unexpected.isEmpty()) { + StringBuilder sb = new StringBuilder(); + for (String s : unexpected) + sb.append("Unexpected but found: " + s + "\n"); + sb.append("In :"); + for (String s : actual) + sb.append("\t" + s + "\n"); + assertTrue(false, "Jmod content check failed.\n" + sb.toString()); + } + } + + static JmodResult jmod(String... args) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + System.out.println("jmod " + Arrays.asList(args)); + int ec = jdk.tools.jmod.Main.run(args, ps); + return new JmodResult(ec, new String(baos.toByteArray(), UTF_8)); + } + + static class JmodResult { + final int exitCode; + final String output; + + JmodResult(int exitValue, String output) { + this.exitCode = exitValue; + this.output = output; + } + JmodResult assertSuccess() { assertTrue(exitCode == 0, output); return this; } + JmodResult assertFailure() { assertTrue(exitCode != 0, output); return this; } + JmodResult resultChecker(Consumer r) { r.accept(this); return this; } + } + + static void createCmds(Path dir) throws IOException { + List files = Arrays.asList( + "first", "second", "third" + File.separator + "third"); + createFiles(dir, files); + } + + static void createLibs(Path dir) throws IOException { + List files = Arrays.asList( + "first.so", "second.so", "third" + File.separator + "third.so"); + createFiles(dir, files); + } + + static void createConfigs(Path dir) throws IOException { + List files = Arrays.asList( + "first.cfg", "second.cfg", "third" + File.separator + "third.cfg"); + createFiles(dir, files); + } + + static void createFiles(Path dir, List filenames) throws IOException { + for (String name : filenames) { + Path file = dir.resolve(name); + Files.createDirectories(file.getParent()); + Files.createFile(file); + try (OutputStream os = Files.newOutputStream(file)) { + os.write("blahblahblah".getBytes(UTF_8)); + } + } + } + + // Standalone entry point. + public static void main(String[] args) throws Throwable { + JmodTest test = new JmodTest(); + test.buildExplodedModules(); + for (Method m : JmodTest.class.getDeclaredMethods()) { + if (m.getAnnotation(Test.class) != null) { + System.out.println("Invoking " + m.getName()); + m.invoke(test); + } + } + } +} diff --git a/jdk/test/tools/jmod/src/foo/jdk/test/foo/Foo.java b/jdk/test/tools/jmod/src/foo/jdk/test/foo/Foo.java new file mode 100644 index 00000000000..2c56159bab7 --- /dev/null +++ b/jdk/test/tools/jmod/src/foo/jdk/test/foo/Foo.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.foo; + +public class Foo { } diff --git a/jdk/test/tools/jmod/src/foo/jdk/test/foo/internal/Message.java b/jdk/test/tools/jmod/src/foo/jdk/test/foo/internal/Message.java new file mode 100644 index 00000000000..298a4fce0cb --- /dev/null +++ b/jdk/test/tools/jmod/src/foo/jdk/test/foo/internal/Message.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test.foo.internal; + +public class Message { + public static String get() { + return "Hello World!!!"; + } +} diff --git a/jdk/test/tools/jmod/src/foo/module-info.java b/jdk/test/tools/jmod/src/foo/module-info.java new file mode 100644 index 00000000000..b46afa0b822 --- /dev/null +++ b/jdk/test/tools/jmod/src/foo/module-info.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module foo { + exports jdk.test.foo; +} diff --git a/jdk/test/tools/launcher/MiscTests.java b/jdk/test/tools/launcher/MiscTests.java index 1a03cc9b49e..c4e1f0b4cf7 100644 --- a/jdk/test/tools/launcher/MiscTests.java +++ b/jdk/test/tools/launcher/MiscTests.java @@ -31,29 +31,71 @@ import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; public class MiscTests extends TestHelper { - // 6856415: Checks to ensure that proper exceptions are thrown by java - static void test6856415() { - StringBuilder sb = new StringBuilder(); - sb.append("public static void main(String... args) {\n"); - sb.append("java.security.Provider p = new sun.security.pkcs11.SunPKCS11();\n"); - sb.append("java.security.Security.insertProviderAt(p, 1);\n"); - sb.append("}"); + /** + * Test with class path set on the command line via -Djava.class.path + */ + static void testWithClassPathSetViaProperty() throws IOException { + final String mainClass = "Foo"; + + File source = new File(mainClass + ".java"); + + List scratch = new ArrayList<>(); + scratch.add("public class Foo {"); + scratch.add("public static void main(String... args) {"); + scratch.add("}"); + scratch.add("}"); + createFile(source, scratch); + + compile(mainClass + ".java"); + + String dir = new File(mainClass + ".class").getAbsoluteFile().getParent(); + TestResult tr = doExec(javaCmd, "-Djava.class.path=" + dir, mainClass); + for (String s : tr.testOutput) { + System.out.println(s); + } + } + + /** + * 6856415: Checks to ensure that proper exceptions are thrown by java + */ + static void test6856415() throws IOException { + + final String mainClass = "Foo6856415"; + final String exportOpts + = "-XaddExports:jdk.crypto.pkcs11/sun.security.pkcs11=ALL-UNNAMED"; + + List scratch = new ArrayList<>(); + scratch.add("public class Foo6856415 {"); + scratch.add("public static void main(String... args) {"); + scratch.add("java.security.Provider p = new sun.security.pkcs11.SunPKCS11();"); + scratch.add("java.security.Security.insertProviderAt(p, 1);"); + scratch.add("}"); + scratch.add("}"); + createFile(new File(mainClass + ".java"), scratch); + + compile(mainClass + ".java", exportOpts); + File testJar = new File("Foo.jar"); testJar.delete(); - try { - createJar(testJar, sb.toString()); - } catch (FileNotFoundException fnfe) { - throw new RuntimeException(fnfe); - } + String jarArgs[] = { + (debug) ? "cvfe" : "cfe", + testJar.getAbsolutePath(), + mainClass, + mainClass + ".class" + }; + createJar(jarArgs); + TestResult tr = doExec(javaCmd, "-Djava.security.manager", "-jar", testJar.getName(), "foo.bak"); for (String s : tr.testOutput) { System.out.println(s); - } + } if (!tr.contains("java.security.AccessControlException:" + " access denied (\"java.lang.RuntimePermission\"" + " \"accessClassInPackage.sun.security.pkcs11\")")) { @@ -61,7 +103,8 @@ public class MiscTests extends TestHelper { } } - public static void main(String... args) { + public static void main(String... args) throws IOException { + testWithClassPathSetViaProperty(); test6856415(); if (testExitValue != 0) { throw new Error(testExitValue + " tests failed"); diff --git a/jdk/test/tools/launcher/ToolsOpts.java b/jdk/test/tools/launcher/ToolsOpts.java index f01931d5482..bff769a54ff 100644 --- a/jdk/test/tools/launcher/ToolsOpts.java +++ b/jdk/test/tools/launcher/ToolsOpts.java @@ -38,8 +38,6 @@ import java.util.ArrayList; import java.util.List; public class ToolsOpts extends TestHelper { - static final String JBCP_PREPEND = "-J-Xbootclasspath/p:"; - private static File testJar = null; static String[][] optionPatterns = { {"-J-Xmx128m"}, {"-J-version"}, @@ -75,14 +73,10 @@ public class ToolsOpts extends TestHelper { {"option1", "-J-version", "-J-XshowSettings:vm", "option2"},}; static void init() throws IOException { - if (testJar != null) { - return; - } // A tool which simulates com.sun.tools.javac.Main argument processing, // intercepts options passed via the javac launcher. final String mainJava = "Main" + JAVA_FILE_EXT; - testJar = new File("test" + JAR_FILE_EXT); List contents = new ArrayList<>(); contents.add("package com.sun.tools.javac;"); contents.add("public class Main {"); @@ -95,10 +89,10 @@ public class ToolsOpts extends TestHelper { contents.add("}\n"); createFile(new File(mainJava), contents); - // compile and jar Main.java into test.jar - compile("-d", ".", mainJava); - createJar("cvf", testJar.getAbsolutePath(), "com"); - } + // compile Main.java into directory to override classes in jdk.compiler + new File("jdk.compiler").mkdir(); + compile("-Xmodule:jdk.compiler", "-d", "jdk.compiler", mainJava); + } static void pass(String msg) { System.out.println("pass: " + msg); @@ -156,30 +150,29 @@ public class ToolsOpts extends TestHelper { static void runTestOptions() throws IOException { init(); TestResult tr = null; - String sTestJar = testJar.getAbsolutePath(); int jpos = -1; for (String arg[] : optionPatterns) { jpos = indexOfJoption(arg); //Build a cmd string for output in results reporting. - String cmdString = javacCmd + " " + JBCP_PREPEND + sTestJar; + String cmdString = javacCmd + " -J-Xpatch:."; for (String opt : arg) { cmdString = cmdString.concat(" " + opt); } switch (arg.length) { case 1: - tr = doExec(javacCmd, JBCP_PREPEND + sTestJar, + tr = doExec(javacCmd, "-J-Xpatch:.", arg[0]); break; case 2: - tr = doExec(javacCmd, JBCP_PREPEND + sTestJar, + tr = doExec(javacCmd, "-J-Xpatch:.", arg[0], arg[1]); break; case 3: - tr = doExec(javacCmd, JBCP_PREPEND + sTestJar, + tr = doExec(javacCmd, "-J-Xpatch:.", arg[0], arg[1], arg[2]); break; case 4: - tr = doExec(javacCmd, JBCP_PREPEND + sTestJar, + tr = doExec(javacCmd, "-J-Xpatch:.", arg[0], arg[1], arg[2], arg[3]); break; default: diff --git a/jdk/test/tools/launcher/VersionCheck.java b/jdk/test/tools/launcher/VersionCheck.java index 4fd933c67c3..08a18bd2a28 100644 --- a/jdk/test/tools/launcher/VersionCheck.java +++ b/jdk/test/tools/launcher/VersionCheck.java @@ -85,7 +85,9 @@ public class VersionCheck extends TestHelper { "jdeps", "jimage", "jinfo", + "jlink", "jmap", + "jmod", "jmc", "jmc.ini", "jps", diff --git a/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java new file mode 100644 index 00000000000..8f92cf2b2ad --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/AddExportsTest.java @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build AddExportsTest CompilerUtils jdk.testlibrary.* + * @run testng AddExportsTest + * @summary Basic tests for java -XaddExports + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class AddExportsTest { + + 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"); + private static final Path UPGRADE_MODS_DIRS = Paths.get("upgrademods"); + + // test module m1 that uses Unsafe + private static final String TEST1_MODULE = "m1"; + private static final String TEST1_MAIN_CLASS = "jdk.test1.Main"; + + // test module m2 uses java.transaction internals + private static final String TEST2_MODULE = "m2"; + private static final String TEST2_MAIN_CLASS = "jdk.test2.Main"; + + // test module m3 uses m4 internals + private static final String TEST3_MODULE = "m3"; + private static final String TEST3_MAIN_CLASS = "jdk.test3.Main"; + private static final String TEST4_MODULE = "m4"; + + + @BeforeTest + public void compileTestModules() throws Exception { + + // javac -d mods/m1 src/m1/** + boolean compiled = CompilerUtils.compile( + SRC_DIR.resolve(TEST1_MODULE), + MODS_DIR.resolve(TEST1_MODULE), + "-XaddExports:java.base/sun.misc=m1"); + assertTrue(compiled, "module " + TEST1_MODULE + " did not compile"); + + // javac -d upgrademods/java.transaction src/java.transaction/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve("java.transaction"), + UPGRADE_MODS_DIRS.resolve("java.transaction")); + assertTrue(compiled, "module java.transaction did not compile"); + + // javac -upgrademodulepath upgrademods -d mods/m2 src/m2/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve(TEST2_MODULE), + MODS_DIR.resolve(TEST2_MODULE), + "-upgrademodulepath", UPGRADE_MODS_DIRS.toString(), + "-XaddExports:java.transaction/javax.transaction.internal=m2"); + assertTrue(compiled, "module " + TEST2_MODULE + " did not compile"); + + // javac -d mods/m3 src/m3/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve(TEST3_MODULE), + MODS_DIR.resolve(TEST3_MODULE)); + assertTrue(compiled, "module " + TEST3_MODULE + " did not compile"); + + // javac -d mods/m4 src/m4/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve(TEST4_MODULE), + MODS_DIR.resolve(TEST4_MODULE)); + assertTrue(compiled, "module " + TEST4_MODULE + " did not compile"); + } + + /** + * Sanity check with -version + */ + public void testSanity() throws Exception { + + int exitValue + = executeTestJava("-XaddExports:java.base/sun.reflect=ALL-UNNAMED", + "-version") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Run class path application that uses sun.misc.Unsafe + */ + public void testUnnamedModule() throws Exception { + + // java -XaddExports:java.base/sun.misc=ALL-UNNAMED \ + // -cp mods/$TESTMODULE jdk.test.UsesUnsafe + + String classpath = MODS_DIR.resolve(TEST1_MODULE).toString(); + int exitValue + = executeTestJava("-XaddExports:java.base/sun.misc=ALL-UNNAMED", + "-cp", classpath, + TEST1_MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Run named module that uses sun.misc.Unsafe + */ + public void testNamedModule() throws Exception { + + // java -XaddExports:java.base/sun.misc=test \ + // -mp mods -m $TESTMODULE/$MAIN_CLASS + + String mid = TEST1_MODULE + "/" + TEST1_MAIN_CLASS; + int exitValue = + executeTestJava("-XaddExports:java.base/sun.misc=" + TEST1_MODULE, + "-mp", MODS_DIR.toString(), + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Test -XaddExports with upgraded module + */ + public void testWithUpgradedModule() throws Exception { + + // java -XaddExports:java.transaction/javax.transaction.internal=m2 + // -upgrademodulepath upgrademods -mp mods -m ... + String mid = TEST2_MODULE + "/" + TEST2_MAIN_CLASS; + int exitValue = executeTestJava( + "-XaddExports:java.transaction/javax.transaction.internal=m2", + "-upgrademodulepath", UPGRADE_MODS_DIRS.toString(), + "-mp", MODS_DIR.toString(), + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Test -XaddExports with module that is added to the set of root modules + * with -addmods. + */ + public void testWithAddMods() throws Exception { + + // java -XaddExports:m4/jdk.test4=m3 -mp mods -m ... + String mid = TEST3_MODULE + "/" + TEST3_MAIN_CLASS; + int exitValue = executeTestJava( + "-XaddExports:m4/jdk.test4=m3", + "-mp", MODS_DIR.toString(), + "-addmods", TEST4_MODULE, + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * -XaddExports can only be specified once + */ + public void testWithDuplicateOption() throws Exception { + + int exitValue + = executeTestJava("-XaddExports:java.base/sun.reflect=ALL-UNNAMED", + "-XaddExports:java.base/sun.reflect=ALL-UNNAMED", + "-version") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("specified more than once") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Exercise -XaddExports with bad values + */ + @Test(dataProvider = "badvalues") + public void testWithBadValue(String value, String ignore) throws Exception { + + // -XaddExports:$VALUE -version + int exitValue = + executeTestJava("-XaddExports:" + value, + "-version") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + @DataProvider(name = "badvalues") + public Object[][] badValues() { + return new Object[][]{ + + { "java.base/sun.misc", null }, // missing target + { "java.base/sun.misc=sun.monkey", null }, // unknown target + { "java.monkey/sun.monkey=ALL-UNNAMED", null }, // unknown module + { "java.base/sun.monkey=ALL-UNNAMED", null }, // unknown package + { "java.monkey/sun.monkey=ALL-UNNAMED", null }, // unknown module/package + { "java.base=ALL-UNNAMED", null }, // missing package + { "java.base/=ALL-UNNAMED", null } // missing package + + }; + } +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/Transaction.java b/jdk/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/Transaction.java new file mode 100644 index 00000000000..44bb0194c41 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/Transaction.java @@ -0,0 +1,27 @@ +/* + * 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 javax.transaction; + +public class Transaction { +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/internal/Helper.java b/jdk/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/internal/Helper.java new file mode 100644 index 00000000000..f7a38cc6b09 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/java.transaction/javax/transaction/internal/Helper.java @@ -0,0 +1,27 @@ +/* + * 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 javax.transaction.internal; + +public class Helper { +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/java.transaction/module-info.java b/jdk/test/tools/launcher/modules/addexports/src/java.transaction/module-info.java new file mode 100644 index 00000000000..95ddcb75f4f --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/java.transaction/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module java.transaction { + exports javax.transaction; +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java new file mode 100644 index 00000000000..a047c91d80d --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m1/jdk/test1/Main.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test1; + +import java.lang.reflect.Field; +import sun.misc.Unsafe; + +public class Main { + public static void main(String[] args) throws Exception { + Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + Unsafe unsafe = (Unsafe) theUnsafe.get(null); + } +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/m1/module-info.java b/jdk/test/tools/launcher/modules/addexports/src/m1/module-info.java new file mode 100644 index 00000000000..16490ed5c93 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m1/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module m1 { +} + diff --git a/jdk/test/tools/launcher/modules/addexports/src/m2/jdk/test2/Main.java b/jdk/test/tools/launcher/modules/addexports/src/m2/jdk/test2/Main.java new file mode 100644 index 00000000000..969936320ea --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m2/jdk/test2/Main.java @@ -0,0 +1,32 @@ +/** + * 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 jdk.test2; + +import javax.transaction.internal.Helper; + +public class Main { + public static void main(String[] args) { + Helper h = new Helper(); + } +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/m2/module-info.java b/jdk/test/tools/launcher/modules/addexports/src/m2/module-info.java new file mode 100644 index 00000000000..527a4dbbfc2 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m2/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module m2 { + requires java.transaction; +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/m3/jdk/test3/Main.java b/jdk/test/tools/launcher/modules/addexports/src/m3/jdk/test3/Main.java new file mode 100644 index 00000000000..068d5878be6 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m3/jdk/test3/Main.java @@ -0,0 +1,32 @@ +/** + * 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 jdk.test3; + +public class Main { + public static void main(String[] args) throws Exception { + Class c = Class.forName("jdk.test4.Type"); + Main.class.getModule().addReads(c.getModule()); + Object o = c.newInstance(); + } +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/m3/module-info.java b/jdk/test/tools/launcher/modules/addexports/src/m3/module-info.java new file mode 100644 index 00000000000..a92b756bbef --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m3/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m3 { +} diff --git a/jdk/test/tools/launcher/modules/addexports/src/m4/jdk/test4/Type.java b/jdk/test/tools/launcher/modules/addexports/src/m4/jdk/test4/Type.java new file mode 100644 index 00000000000..6d5f414ad23 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m4/jdk/test4/Type.java @@ -0,0 +1,29 @@ +/* + * 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 jdk.test4; + +public class Type { + public Type() { } +} + diff --git a/jdk/test/tools/launcher/modules/addexports/src/m4/module-info.java b/jdk/test/tools/launcher/modules/addexports/src/m4/module-info.java new file mode 100644 index 00000000000..2544650bd0e --- /dev/null +++ b/jdk/test/tools/launcher/modules/addexports/src/m4/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m4 { +} diff --git a/jdk/test/tools/launcher/modules/addmods/AddModsTest.java b/jdk/test/tools/launcher/modules/addmods/AddModsTest.java new file mode 100644 index 00000000000..a65c3d4eb81 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addmods/AddModsTest.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @build AddModsTest CompilerUtils jdk.testlibrary.* + * @run testng AddModsTest + * @summary Basic test for java -addmods + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class AddModsTest { + + 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 module name of the library module + private static final String LIB_MODULE = "lib"; + + // application source directory + private static final String APP_SRC = "app"; + + // application is compiled to classes + private static final Path CLASSES_DIR = Paths.get("classes"); + + // application main class + private static final String MAIN_CLASS = "app.Main"; + + + @BeforeTest + public void compile() throws Exception { + + // javac -d mods/$LIB_MODULE src/$LIB_MODULE/** + boolean compiled = CompilerUtils.compile( + SRC_DIR.resolve(LIB_MODULE), + MODS_DIR.resolve(LIB_MODULE) + ); + assertTrue(compiled, "library module did not compile"); + + // javac -d classes -mp mods src/$APP_DIR/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve(APP_SRC), + CLASSES_DIR, + "-mp", MODS_DIR.toString(), + "-addmods", LIB_MODULE + ); + assertTrue(compiled, "app did not compile"); + } + + + /** + * Basic test of -addmods ALL-SYSTEM, using the output of -listmods to + * check that the a sample of the system modules are resolved. + */ + public void testAddSystemModules() throws Exception { + + executeTestJava("-addmods", "ALL-SYSTEM", + "-listmods", + "-m", "java.base") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("java.sql") + .shouldContain("java.corba"); + + // no exit value to check as -m java.base will likely fail + } + + + /** + * Run application on class path that makes use of module on the + * application module path. Uses {@code -addmods lib} + */ + public void testRunWithAddMods() throws Exception { + + // java -mp mods -addmods lib -cp classes app.Main + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", LIB_MODULE, + "-cp", CLASSES_DIR.toString(), + MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + + /** + * Run application on class path that makes use of module on the + * application module path. Uses {@code -addmods ALL-MODULE-PATH}. + */ + public void testAddAllModulePath() throws Exception { + + // java -mp mods -addmods lib -cp classes app.Main + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", "ALL-MODULE-PATH", + "-cp", CLASSES_DIR.toString(), + MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + + + /** + * Run application on class path that makes use of module on the + * application module path. Does not use -addmods and so will + * fail at run-time. + */ + public void testRunMissingAddMods() throws Exception { + + // java -mp mods -cp classes app.Main + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-cp", CLASSES_DIR.toString(), + MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + // CNFE or other error/exception + assertTrue(exitValue != 0); + + } + + + /** + * Attempt to run with a bad module name specified to -addmods + */ + public void testRunWithBadAddMods() throws Exception { + + // java -mp mods -addmods,DoesNotExist lib -cp classes app.Main + int exitValue + = executeTestJava("-mp", MODS_DIR.toString(), + "-addmods", LIB_MODULE + ",DoesNotExist", + "-cp", CLASSES_DIR.toString(), + MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + + } + +} diff --git a/jdk/test/tools/launcher/modules/addmods/src/app/Main.java b/jdk/test/tools/launcher/modules/addmods/src/app/Main.java new file mode 100644 index 00000000000..be903e510ac --- /dev/null +++ b/jdk/test/tools/launcher/modules/addmods/src/app/Main.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package app; + +import jdk.lib.Util; + +public class Main { + public static void main(String[] args) { + Object obj = Util.makeObject(); + } +} diff --git a/jdk/test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java b/jdk/test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java new file mode 100644 index 00000000000..682a22921f3 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +package jdk.lib; + +public class Util { + private Util() { } + + public static Object makeObject() { + return new Object(); + } +} diff --git a/jdk/test/tools/launcher/modules/addmods/src/lib/module-info.java b/jdk/test/tools/launcher/modules/addmods/src/lib/module-info.java new file mode 100644 index 00000000000..16dae96e170 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addmods/src/lib/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module lib { + exports jdk.lib; +} diff --git a/jdk/test/tools/launcher/modules/addreads/AddReadsTest.java b/jdk/test/tools/launcher/modules/addreads/AddReadsTest.java new file mode 100644 index 00000000000..3bcf4bfa50c --- /dev/null +++ b/jdk/test/tools/launcher/modules/addreads/AddReadsTest.java @@ -0,0 +1,212 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build AddReadsTest CompilerUtils jdk.testlibrary.* + * @run testng AddReadsTest + * @summary Basic tests for java -XaddReads + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.testlibrary.OutputAnalyzer; +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * The tests consists of two modules: m1 and junit. + * Code in module m1 calls into code in module junit but the module-info.java + * does not have a 'requires'. Instead a read edge is added via the command + * line option -XaddReads. + */ + +@Test +public class AddReadsTest { + + 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 CLASSES_DIR = Paths.get("classes"); + private static final Path MODS_DIR = Paths.get("mods"); + + private static final String MAIN = "m1/p.Main"; + + + @BeforeTest + public void setup() throws Exception { + + // javac -d classes src/junit/** + assertTrue(CompilerUtils + .compile(SRC_DIR.resolve("junit"), CLASSES_DIR)); + + // javac -d mods/m1 -cp classes/ src/m1/** + assertTrue(CompilerUtils + .compile(SRC_DIR.resolve("m1"), + MODS_DIR.resolve("m1"), + "-cp", CLASSES_DIR.toString(), + "-XaddReads:m1=ALL-UNNAMED")); + + // jar cf mods/junit.jar -C classes . + JarUtils.createJarFile(MODS_DIR.resolve("junit.jar"), CLASSES_DIR); + + } + + private OutputAnalyzer run(String... options) throws Exception { + return executeTestJava(options) + .outputTo(System.out) + .errorTo(System.out); + } + + + /** + * Run with junit as a module on the module path. + */ + public void testJUnitOnModulePath() throws Exception { + + // java -mp mods -addmods junit -XaddReads:m1=junit -m .. + int exitValue + = run("-mp", MODS_DIR.toString(), + "-addmods", "junit", + "-XaddReads:m1=junit", + "-m", MAIN) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Exercise -XaddReads:m1=ALL-UNNAMED by running with junit on the + * class path. + */ + public void testJUnitOnClassPath() throws Exception { + + // java -mp mods -cp mods/junit.jar -XaddReads:m1=ALL-UNNAMED -m .. + String cp = MODS_DIR.resolve("junit.jar").toString(); + int exitValue + = run("-mp", MODS_DIR.toString(), + "-cp", cp, + "-XaddReads:m1=ALL-UNNAMED", + "-m", MAIN) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Run with junit as a module on the module path but without -XaddReads. + */ + public void testJUnitOnModulePathMissingAddReads() throws Exception { + // java -mp mods -addmods junit -m .. + int exitValue + = run("-mp", MODS_DIR.toString(), + "-addmods", "junit", + "-m", MAIN) + .shouldContain("IllegalAccessError") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Run with junit on the class path but without -XaddReads. + */ + public void testJUnitOnClassPathMissingAddReads() throws Exception { + // java -mp mods -cp mods/junit.jar -m .. + String cp = MODS_DIR.resolve("junit.jar").toString(); + int exitValue + = run("-mp", MODS_DIR.toString(), + "-cp", cp, + "-m", MAIN) + .shouldContain("IllegalAccessError") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Exercise -XaddReads with a more than one source module. + */ + public void testJUnitWithMultiValueOption() throws Exception { + + int exitValue + = run("-mp", MODS_DIR.toString(), + "-addmods", "java.xml,junit", + "-XaddReads:m1=java.xml,junit", + "-m", MAIN) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Exercise -XaddReads where the target module is specified more than once + */ + public void testWithTargetSpecifiedManyTimes() throws Exception { + + int exitValue + = run("-mp", MODS_DIR.toString(), + "-addmods", "java.xml,junit", + "-XaddReads:m1=java.xml", + "-XaddReads:m1=junit", + "-m", MAIN) + .shouldContain("specified more than once") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Exercise -XaddReads with bad values + */ + @Test(dataProvider = "badvalues") + public void testWithBadValue(String value, String ignore) throws Exception { + + // -XaddExports:$VALUE -version + assertTrue(run("-XaddReads:" + value, "-version").getExitValue() != 0); + } + + @DataProvider(name = "badvalues") + public Object[][] badValues() { + return new Object[][]{ + + { "java.base", null }, // missing source + { "java.monkey=java.base", null }, // unknown module + { "java.base=sun.monkey", null }, // unknown source + + }; + } +} diff --git a/jdk/test/tools/launcher/modules/addreads/src/junit/org/junit/Assert.java b/jdk/test/tools/launcher/modules/addreads/src/junit/org/junit/Assert.java new file mode 100644 index 00000000000..a36ce18e567 --- /dev/null +++ b/jdk/test/tools/launcher/modules/addreads/src/junit/org/junit/Assert.java @@ -0,0 +1,30 @@ +/* + * 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 org.junit; + +public class Assert { + public static void assertEquals(Object o1, Object o2) { + if (!o1.equals(o2)) throw new RuntimeException(); + } +} diff --git a/jdk/test/tools/launcher/modules/addreads/src/m1/module-info.java b/jdk/test/tools/launcher/modules/addreads/src/m1/module-info.java new file mode 100644 index 00000000000..1c15fc5724f --- /dev/null +++ b/jdk/test/tools/launcher/modules/addreads/src/m1/module-info.java @@ -0,0 +1,24 @@ +/* + * 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. + */ + +module m1 { } diff --git a/jdk/test/tools/launcher/modules/addreads/src/m1/p/Main.java b/jdk/test/tools/launcher/modules/addreads/src/m1/p/Main.java new file mode 100644 index 00000000000..a1bc1fd59ba --- /dev/null +++ b/jdk/test/tools/launcher/modules/addreads/src/m1/p/Main.java @@ -0,0 +1,33 @@ +/* + * 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 p; + +import static org.junit.Assert.assertEquals; + +public class Main { + public static void main(String[] args) { + Object o = new Object(); + assertEquals(o, o); + } +} diff --git a/jdk/test/tools/launcher/modules/basic/BasicTest.java b/jdk/test/tools/launcher/modules/basic/BasicTest.java new file mode 100644 index 00000000000..1c2cf2352c9 --- /dev/null +++ b/jdk/test/tools/launcher/modules/basic/BasicTest.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.jartool/sun.tools.jar + * jdk.jlink/jdk.tools.jmod + * jdk.compiler + * @build BasicTest CompilerUtils jdk.testlibrary.* + * @run testng BasicTest + * @summary Basic test of starting an application as a module + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class BasicTest { + + private static final Path USER_DIR = Paths.get(System.getProperty("user.dir")); + + 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 module name of the test module + private static final String TEST_MODULE = "test"; + + // the module main class + private static final String MAIN_CLASS = "jdk.test.Main"; + + + @BeforeTest + public void compileTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + boolean compiled + = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE)); + + assertTrue(compiled, "test module did not compile"); + } + + + /** + * The initial module is loaded from an exploded module + */ + public void testRunWithExplodedModule() throws Exception { + String dir = MODS_DIR.toString(); + String subdir = MODS_DIR.resolve(TEST_MODULE).toString(); + String mid = TEST_MODULE + "/" + MAIN_CLASS; + + // java -mp mods -m $TESTMODULE/$MAINCLASS + int exitValue + = executeTestJava("-mp", dir, "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + assertTrue(exitValue == 0); + + // java -mp mods/$TESTMODULE -m $TESTMODULE/$MAINCLASS + exitValue + = executeTestJava("-mp", subdir, "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + assertTrue(exitValue == 0); + } + + + /** + * The initial module is loaded from a modular JAR file + */ + public void testRunWithModularJar() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mlib"); + Path jar = dir.resolve("m.jar"); + + // jar --create ... + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + String[] args = { + "--create", + "--file=" + jar, + "--main-class=" + MAIN_CLASS, + "-C", classes, "." + }; + boolean success + = new sun.tools.jar.Main(System.out, System.out, "jar") + .run(args); + assertTrue(success); + + // java -mp mlib -m $TESTMODULE + int exitValue + = executeTestJava("-mp", dir.toString(), + "-m", TEST_MODULE) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + assertTrue(exitValue == 0); + + // java -mp mlib/m.jar -m $TESTMODULE + exitValue + = executeTestJava("-mp", jar.toString(), + "-m", TEST_MODULE) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + assertTrue(exitValue == 0); + } + + + /** + * Attempt to run with the initial module packaged as a JMOD file. + */ + public void testTryRunWithJMod() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mlib"); + + // jmod create ... + String cp = MODS_DIR.resolve(TEST_MODULE).toString(); + String jmod = dir.resolve("m.jmod").toString(); + String[] args = { + "create", + "--class-path", cp, + "--main-class", MAIN_CLASS, + jmod + }; + jdk.tools.jmod.JmodTask task = new jdk.tools.jmod.JmodTask(); + assertEquals(task.run(args), 0); + + // java -mp mods -m $TESTMODULE + int exitValue + = executeTestJava("-mp", dir.toString(), + "-m", TEST_MODULE) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Run the test with a non-existent file on the application module path. + * It should be silently ignored. + */ + public void testRunWithNonExistentEntry() throws Exception { + String mp = "DoesNotExist" + File.pathSeparator + MODS_DIR.toString(); + String mid = TEST_MODULE + "/" + MAIN_CLASS; + + // java -mp mods -m $TESTMODULE/$MAINCLASS + int exitValue + = executeTestJava("-mp", mp, + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Attempt to run an unknown initial module + */ + public void testTryRunWithBadModule() throws Exception { + String modulepath = MODS_DIR.toString(); + + // java -mp mods -m $TESTMODULE + int exitValue + = executeTestJava("-mp", modulepath, + "-m", "rhubarb") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("not found") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Attempt to run with -m specifying a main class that does not + * exist. + */ + public void testTryRunWithBadMainClass() throws Exception { + String modulepath = MODS_DIR.toString(); + String mid = TEST_MODULE + "/p.rhubarb"; + + // java -mp mods -m $TESTMODULE/$MAINCLASS + int exitValue + = executeTestJava("-mp", modulepath, + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Attempt to run with -m specifying a modular JAR that does not have + * a MainClass attribute + */ + public void testTryRunWithMissingMainClass() throws Exception { + Path dir = Files.createTempDirectory(USER_DIR, "mlib"); + + // jar --create ... + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + String jar = dir.resolve("m.jar").toString(); + String[] args = { + "--create", + "--file=" + jar, + "-C", classes, "." + }; + boolean success + = new sun.tools.jar.Main(System.out, System.out, "jar") + .run(args); + assertTrue(success); + + // java -mp mods -m $TESTMODULE + int exitValue + = executeTestJava("-mp", dir.toString(), + "-m", TEST_MODULE) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("does not have a MainClass attribute") + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Attempt to run with -m specifying a main class that is a different + * module to that specified to -m + */ + public void testTryRunWithMainClassInWrongModule() throws Exception { + String modulepath = MODS_DIR.toString(); + String mid = "java.base/" + MAIN_CLASS; + + // java -mp mods -m $TESTMODULE/$MAINCLASS + int exitValue + = executeTestJava("-mp", modulepath, + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + } + +} diff --git a/langtools/test/tools/jdeps/javax/activity/NotCompactProfile.java b/jdk/test/tools/launcher/modules/basic/src/test/jdk/test/Main.java similarity index 83% rename from langtools/test/tools/jdeps/javax/activity/NotCompactProfile.java rename to jdk/test/tools/launcher/modules/basic/src/test/jdk/test/Main.java index 37e466186dd..46f4bb737a8 100644 --- a/langtools/test/tools/jdeps/javax/activity/NotCompactProfile.java +++ b/jdk/test/tools/launcher/modules/basic/src/test/jdk/test/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -21,10 +21,10 @@ * questions. */ -package javax.activity; +package jdk.test; -public class NotCompactProfile { - public static String name() { - return "not Java SE API"; +public class Main { + public static void main(String[] args) { + System.out.println("Hello world"); } } diff --git a/jdk/test/tools/launcher/modules/basic/src/test/module-info.java b/jdk/test/tools/launcher/modules/basic/src/test/module-info.java new file mode 100644 index 00000000000..779c3c8a656 --- /dev/null +++ b/jdk/test/tools/launcher/modules/basic/src/test/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module test { +} + diff --git a/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java b/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java new file mode 100644 index 00000000000..0cafaf42e66 --- /dev/null +++ b/jdk/test/tools/launcher/modules/limitmods/LimitModsTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules java.desktop java.compact1 jdk.compiler + * @build LimitModsTest CompilerUtils jdk.testlibrary.* + * @run testng LimitModsTest + * @summary Basic tests for java -limitmods + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +@Test +public class LimitModsTest { + + 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 module name / main class of the test module + private static final String TEST_MODULE = "test"; + private static final String MAIN_CLASS = "jdk.test.UseAWT"; + + + @BeforeTest + public void compileTestModule() throws Exception { + + // javac -d mods/$TESTMODULE src/$TESTMODULE/** + boolean compiled + = CompilerUtils.compile(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE)); + + assertTrue(compiled, "test module did not compile"); + } + + + /** + * Basic test of -limitmods to limit which platform modules are observable. + */ + public void testLimitingPlatformModules() throws Exception { + int exitValue; + + // java -limitmods java.base -listmods + exitValue = executeTestJava("-limitmods", "java.base", "-listmods") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("java.base") + .shouldNotContain("java.logging") + .shouldNotContain("java.xml") + .getExitValue(); + + assertTrue(exitValue == 0); + + + // java -limitmods java.compact1 -listmods + exitValue = executeTestJava("-limitmods", "java.compact1", "-listmods") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("java.base") + .shouldContain("java.logging") + .shouldContain("java.compact1") + .shouldNotContain("java.xml") + .getExitValue(); + + assertTrue(exitValue == 0); + } + + + /** + * Test -limitmods with -addmods + */ + public void testWithAddMods() throws Exception { + int exitValue; + + // java -limitmods java.base -addmods java.logging -listmods + exitValue = executeTestJava("-limitmods", "java.base", + "-addmods", "java.logging", + "-listmods") + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("java.base") + .shouldContain("java.logging") + .shouldNotContain("java.xml") + .getExitValue(); + + assertTrue(exitValue == 0); + + + // java -limitmods java.base -addmods java.sql -listmods + // This should fail because java.sql has dependences beyond java.base + exitValue = executeTestJava("-limitmods", "java.base", + "-addmods", "java.sql", + "-listmods") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + } + + + /** + * Run class path application with -limitmods + */ + public void testUnnamedModule() throws Exception { + String classpath = MODS_DIR.resolve(TEST_MODULE).toString(); + + // java -limitmods java.base -cp mods/$TESTMODULE ... + int exitValue1 + = executeTestJava("-limitmods", "java.base", + "-cp", classpath, + MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .shouldContain("NoClassDefFoundError") + .getExitValue(); + + assertTrue(exitValue1 != 0); + + + // java -limitmods java.base -cp mods/$TESTMODULE ... + int exitValue2 + = executeTestJava("-limitmods", "java.desktop", + "-cp", classpath, + MAIN_CLASS) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue2 == 0); + } + + + /** + * Run named module with -limitmods + */ + public void testNamedModule() throws Exception { + + String modulepath = MODS_DIR.toString(); + String mid = TEST_MODULE + "/" + MAIN_CLASS; + + // java -limitmods java.base -mp mods -m $TESTMODULE/$MAINCLASS + int exitValue = executeTestJava("-limitmods", "java.base", + "-mp", modulepath, + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue != 0); + + // java -limitmods java.desktop -mp mods -m $TESTMODULE/$MAINCLASS + exitValue = executeTestJava("-limitmods", "java.desktop", + "-mp", modulepath, + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + } + +} diff --git a/jdk/test/tools/launcher/modules/limitmods/src/test/jdk/test/UseAWT.java b/jdk/test/tools/launcher/modules/limitmods/src/test/jdk/test/UseAWT.java new file mode 100644 index 00000000000..08fa5da1fc2 --- /dev/null +++ b/jdk/test/tools/launcher/modules/limitmods/src/test/jdk/test/UseAWT.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test; + +import java.awt.Component; + +public class UseAWT { + public static void main(String[] args) { + System.out.println(java.awt.Component.class); + } +} diff --git a/jdk/test/tools/launcher/modules/limitmods/src/test/module-info.java b/jdk/test/tools/launcher/modules/limitmods/src/test/module-info.java new file mode 100644 index 00000000000..5fe0739f3b9 --- /dev/null +++ b/jdk/test/tools/launcher/modules/limitmods/src/test/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module test { + requires java.desktop; +} diff --git a/jdk/test/tools/launcher/modules/listmods/ListModsTest.java b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java new file mode 100644 index 00000000000..bd57d38d98f --- /dev/null +++ b/jdk/test/tools/launcher/modules/listmods/ListModsTest.java @@ -0,0 +1,203 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules java.se + * @build ListModsTest CompilerUtils jdk.testlibrary.* + * @run testng ListModsTest + * @summary Basic test for java -listmods + */ + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.*; +import jdk.testlibrary.OutputAnalyzer; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * Basic tests for java -listmods + */ + +public class ListModsTest { + + 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"); + private static final Path UPGRADEMODS_DIR = Paths.get("upgrademods"); + + @BeforeTest + public void setup() throws Exception { + boolean compiled; + + // javac -d mods/m1 -mp mods src/m1/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve("m1"), + MODS_DIR.resolve("m1")); + assertTrue(compiled); + + // javac -d upgrademods/java.transaction -mp mods src/java.transaction/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve("java.transaction"), + UPGRADEMODS_DIR.resolve("java.transaction")); + assertTrue(compiled); + + } + + + @Test + public void testListAll() throws Exception { + OutputAnalyzer output + = executeTestJava("-listmods") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.base"); + output.shouldContain("java.xml"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListOneModule() throws Exception { + OutputAnalyzer output + = executeTestJava("-listmods:java.base") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.base"); + output.shouldContain("exports java.lang"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListTwoModules() throws Exception { + OutputAnalyzer output + = executeTestJava("-listmods:java.base,java.xml") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.base"); + output.shouldContain("exports java.lang"); + output.shouldContain("java.xml"); + output.shouldContain("exports javax.xml"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListUnknownModule() throws Exception { + OutputAnalyzer output + = executeTestJava("-listmods:java.rhubarb") + .outputTo(System.out) + .errorTo(System.out); + output.shouldNotContain("java.base"); + output.shouldNotContain("java.rhubarb"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListWithModulePath() throws Exception { + OutputAnalyzer output + = executeTestJava("-mp", MODS_DIR.toString(), "-listmods") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.base"); + output.shouldContain("m1"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListWithUpgradeModulePath() throws Exception { + OutputAnalyzer output + = executeTestJava("-upgrademodulepath", UPGRADEMODS_DIR.toString(), + "-listmods:java.transaction") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("exports javax.transaction.atomic"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListWithLimitMods1() throws Exception { + OutputAnalyzer output + = executeTestJava("-limitmods", "java.compact1", "-listmods") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.compact1"); + output.shouldContain("java.base"); + output.shouldNotContain("java.xml"); + assertTrue(output.getExitValue() == 0); + } + + + @Test + public void testListWithLimitMods2() throws Exception { + OutputAnalyzer output + = executeTestJava("-mp", MODS_DIR.toString(), + "-limitmods", "java.compact1", + "-listmods") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.base"); + output.shouldNotContain("m1"); + assertTrue(output.getExitValue() == 0); + } + + + /** + * java -version -listmods => should print version and exit + */ + @Test + public void testListWithPrintVersion1() throws Exception { + OutputAnalyzer output + = executeTestJava("-version", "-listmods") + .outputTo(System.out) + .errorTo(System.out); + output.shouldNotContain("java.base"); + output.shouldContain("Runtime Environment"); + assertTrue(output.getExitValue() == 0); + } + + + /** + * java -listmods -version => should list modules and exit + */ + @Test + public void testListWithPrintVersion2() throws Exception { + OutputAnalyzer output + = executeTestJava("-listmods", "-version") + .outputTo(System.out) + .errorTo(System.out); + output.shouldContain("java.base"); + output.shouldNotContain("Runtime Environment"); + assertTrue(output.getExitValue() == 0); + } + +} diff --git a/jdk/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/Transaction.java b/jdk/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/Transaction.java new file mode 100644 index 00000000000..3988d8d6721 --- /dev/null +++ b/jdk/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/Transaction.java @@ -0,0 +1,30 @@ +/* + * 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 javax.transaction; + +public class Transaction { + + public Transaction() { } + +} diff --git a/jdk/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/atomic/Atomic.java b/jdk/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/atomic/Atomic.java new file mode 100644 index 00000000000..f4974e39065 --- /dev/null +++ b/jdk/test/tools/launcher/modules/listmods/src/java.transaction/javax/transaction/atomic/Atomic.java @@ -0,0 +1,28 @@ +/* + * 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 javax.transaction.atomic; + +public interface Atomic { + +} diff --git a/jdk/test/tools/launcher/modules/listmods/src/java.transaction/module-info.java b/jdk/test/tools/launcher/modules/listmods/src/java.transaction/module-info.java new file mode 100644 index 00000000000..d1a268c6ded --- /dev/null +++ b/jdk/test/tools/launcher/modules/listmods/src/java.transaction/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module java.transaction { + exports javax.transaction; + exports javax.transaction.atomic; +} diff --git a/jdk/test/tools/launcher/modules/listmods/src/m1/module-info.java b/jdk/test/tools/launcher/modules/listmods/src/m1/module-info.java new file mode 100644 index 00000000000..967d5535675 --- /dev/null +++ b/jdk/test/tools/launcher/modules/listmods/src/m1/module-info.java @@ -0,0 +1,25 @@ +/* + * 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. + */ + +module m1 { +} diff --git a/jdk/test/tools/launcher/modules/patch/PatchTest.java b/jdk/test/tools/launcher/modules/patch/PatchTest.java new file mode 100644 index 00000000000..215882f1e4b --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/PatchTest.java @@ -0,0 +1,154 @@ +/* + * 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. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build PatchTest CompilerUtils jdk.testlibrary.* + * @run testng PatchTest + * @summary Basic test for -Xpatch + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static jdk.testlibrary.ProcessTools.*; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + + +/** + * Compiles and launches a test that uses -Xpatch with two directories of + * classes to override existing and add new classes to modules in the + * boot layer. + * + * The classes overridden or added via -Xpatch all define a public no-arg + * constructor and override toString to return "hi". This allows the launched + * test to check that the overridden classes are loaded. + */ + +@Test +public class PatchTest { + + // top-level source directory + private static final String TEST_SRC = System.getProperty("test.src"); + + // source/destination tree for the test module + private static final Path SRC_DIR = Paths.get(TEST_SRC, "src"); + private static final Path MODS_DIR = Paths.get("mods"); + + // source/destination tree for patch tree 1 + private static final Path SRC1_DIR = Paths.get(TEST_SRC, "src1"); + private static final Path PATCHES1_DIR = Paths.get("patches1"); + + // source/destination tree for patch tree 2 + private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2"); + private static final Path PATCHES2_DIR = Paths.get("patches2"); + + + // the classes overridden or added with -Xpatch + private static final String[] CLASSES = { + + // java.base = boot loader + "java.base/java.text.Annotation", // override class + "java.base/java.text.AnnotationBuddy", // add class to package + "java.base/java.lang2.Object", // new package + + // jdk.naming.dns = platform class loader + "jdk.naming.dns/com.sun.jndi.dns.DnsClient", + "jdk.naming.dns/com.sun.jndi.dns.DnsClientBuddy", + "jdk.naming.dns/com.sun.jndi.dns2.Zone", + + // jdk.compiler = application class loaded + "jdk.compiler/com.sun.tools.javac.Main", + "jdk.compiler/com.sun.tools.javac.MainBuddy", + "jdk.compiler/com.sun.tools.javac2.Main", + + }; + + + @BeforeTest + public void compile() throws Exception { + + // javac -d mods/test src/test/** + boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"), + MODS_DIR.resolve("test")); + assertTrue(compiled, "classes did not compile"); + + // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/** + for (Path src : Files.newDirectoryStream(SRC1_DIR)) { + Path output = PATCHES1_DIR.resolve(src.getFileName()); + String mn = src.getFileName().toString(); + compiled = CompilerUtils.compile(src, output, "-Xmodule:" + mn); + assertTrue(compiled, "classes did not compile"); + } + + // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/** + for (Path src : Files.newDirectoryStream(SRC2_DIR)) { + Path output = PATCHES2_DIR.resolve(src.getFileName()); + String mn = src.getFileName().toString(); + compiled = CompilerUtils.compile(src, output, "-Xmodule:" + mn); + assertTrue(compiled, "classes did not compile"); + } + + } + + /** + * Run the test with -Xpatch + */ + public void testRunWithXPatch() throws Exception { + + // value for -Xpatch + String patchPath = PATCHES1_DIR + File.pathSeparator + PATCHES2_DIR; + + // value for -XaddExports + String addExportsValue = "java.base/java.lang2=test" + + ",jdk.naming.dns/com.sun.jndi.dns=test" + + ",jdk.naming.dns/com.sun.jndi.dns2=test" + + ",jdk.compiler/com.sun.tools.javac2=test"; + + // the argument to the test is the list of classes overridden or added + String arg = Stream.of(CLASSES).collect(Collectors.joining(",")); + + int exitValue + = executeTestJava("-Xpatch:" + patchPath, + "-XaddExports:" + addExportsValue, + "-addmods", "jdk.naming.dns,jdk.compiler", + "-mp", MODS_DIR.toString(), + "-m", "test/jdk.test.Main", arg) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + +} diff --git a/jdk/test/tools/launcher/modules/patch/src/test/jdk/test/Main.java b/jdk/test/tools/launcher/modules/patch/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..88e09856710 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src/test/jdk/test/Main.java @@ -0,0 +1,74 @@ +/** + * 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. + */ + +/** + * Used with -Xpatch to exercise the replacement or addition of classes + * in modules that are linked into the runtime image. + */ + +package jdk.test; + +import java.lang.reflect.Module; + +public class Main { + + public static void main(String[] args) throws Exception { + + for (String moduleAndClass : args[0].split(",")) { + String mn = moduleAndClass.split("/")[0]; + String cn = moduleAndClass.split("/")[1]; + + // load class + Class c = Class.forName(cn); + + // check in expected module + Module m = c.getModule(); + assertEquals(m.getName(), mn); + + // instantiate object + Main.class.getModule().addReads(m); + Object obj = c.newInstance(); + + // check that the expected version of the class is loaded + System.out.print(moduleAndClass); + String s = obj.toString(); + System.out.println(" says " + s); + assertEquals(s, "hi"); + + // check Module getResourceAsStream + String rn = cn.replace('.', '/') + ".class"; + assertNotNull(m.getResourceAsStream(rn)); + } + } + + + static void assertEquals(Object o1, Object o2) { + if (!o1.equals(o2)) + throw new RuntimeException("assertion failed"); + } + + static void assertNotNull(Object o) { + if (o == null) + throw new RuntimeException("unexpected null"); + } +} diff --git a/jdk/test/tools/launcher/modules/patch/src/test/module-info.java b/jdk/test/tools/launcher/modules/patch/src/test/module-info.java new file mode 100644 index 00000000000..2ac3cbe907f --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src/test/module-info.java @@ -0,0 +1,25 @@ +/** + * 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. + */ + +module test { +} diff --git a/jdk/test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java b/jdk/test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java new file mode 100644 index 00000000000..1e1ab62ad62 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src1/java.base/java/text/Annotation.java @@ -0,0 +1,28 @@ +/* + * 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 java.text; + +public class Annotation { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java b/jdk/test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java new file mode 100644 index 00000000000..5ef445d5960 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src1/java.base/java/text/AnnotationBuddy.java @@ -0,0 +1,28 @@ +/* + * 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 java.text; + +public class AnnotationBuddy { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java b/jdk/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java new file mode 100644 index 00000000000..a1f7aa65be1 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/Main.java @@ -0,0 +1,28 @@ +/* + * 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 com.sun.tools.javac; + +public class Main { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java b/jdk/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java new file mode 100644 index 00000000000..8fcd6b687b6 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src1/jdk.compiler/com/sun/tools/javac/MainBuddy.java @@ -0,0 +1,28 @@ +/* + * 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 com.sun.tools.javac; + +public class MainBuddy { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java b/jdk/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java new file mode 100644 index 00000000000..c87cc45ed19 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClient.java @@ -0,0 +1,28 @@ +/* + * 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 com.sun.jndi.dns; + +public class DnsClient { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java b/jdk/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java new file mode 100644 index 00000000000..b173a22bb45 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src1/jdk.naming.dns/com/sun/jndi/dns/DnsClientBuddy.java @@ -0,0 +1,28 @@ +/* + * 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 com.sun.jndi.dns; + +public class DnsClientBuddy { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java b/jdk/test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java new file mode 100644 index 00000000000..980889432d4 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src2/java.base/java/lang2/Object.java @@ -0,0 +1,28 @@ +/** + * 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 java.lang2; + +public class Object { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java b/jdk/test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java new file mode 100644 index 00000000000..c5ee7db7e41 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src2/jdk.compiler/com/sun/tools/javac2/Main.java @@ -0,0 +1,28 @@ +/** + * 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 com.sun.tools.javac2; + +public class Main { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java b/jdk/test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java new file mode 100644 index 00000000000..0ef3ac31ef3 --- /dev/null +++ b/jdk/test/tools/launcher/modules/patch/src2/jdk.naming.dns/com/sun/jndi/dns2/Zone.java @@ -0,0 +1,28 @@ +/** + * 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 com.sun.jndi.dns2; + +public class Zone { + public String toString() { return "hi"; } +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/UpgradeModulePathTest.java b/jdk/test/tools/launcher/modules/upgrademodulepath/UpgradeModulePathTest.java new file mode 100644 index 00000000000..31351b53f8d --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/UpgradeModulePathTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /lib/testlibrary + * @modules jdk.compiler + * @build UpgradeModulePathTest CompilerUtils jdk.testlibrary.* + * @run testng UpgradeModulePathTest + * @summary Basic test for java -upgrademodulepath + */ + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static jdk.testlibrary.ProcessTools.executeTestJava; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + +/** + * This test upgrades module java.transaction. The upgraded module has a + * dependency on module java.enterprise that is deployed on the application + * modue path. + */ + + +@Test +public class UpgradeModulePathTest { + + 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"); + private static final Path UPGRADEDMODS_DIR = Paths.get("upgradedmods"); + + + @BeforeTest + public void setup() throws Exception { + + // javac -d mods/java.enterprise src/java.enterprise/** + boolean compiled = CompilerUtils.compile( + SRC_DIR.resolve("java.enterprise"), + MODS_DIR.resolve("java.enterprise")); + assertTrue(compiled); + + // javac -d upgrademods/java.transaction -mp mods src/java.transaction/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve("java.transaction"), + UPGRADEDMODS_DIR.resolve("java.transaction"), + "-mp", MODS_DIR.toString()); + assertTrue(compiled); + + // javac -d mods -upgrademodulepath upgrademods -mp mods src/test/** + compiled = CompilerUtils.compile( + SRC_DIR.resolve("test"), + MODS_DIR.resolve("test"), + "-upgrademodulepath", UPGRADEDMODS_DIR.toString(), + "-mp", MODS_DIR.toString()); + assertTrue(compiled); + + } + + + /** + * Run the test with an upgraded java.transaction module. + */ + public void testWithUpgradedModule() throws Exception { + + String mid = "test/jdk.test.Main"; + + int exitValue + = executeTestJava( + "-upgrademodulepath", UPGRADEDMODS_DIR.toString(), + "-mp", MODS_DIR.toString(), + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + + + /** + * Run the test with a non-existent file on the upgrade module path. + * It should be silently ignored. + */ + public void testRunWithNonExistentEntry() throws Exception { + + String upgrademodulepath + = "DoesNotExit" + File.pathSeparator + UPGRADEDMODS_DIR.toString(); + String mid = "test/jdk.test.Main"; + + int exitValue + = executeTestJava( + "-upgrademodulepath", upgrademodulepath, + "-mp", MODS_DIR.toString(), + "-m", mid) + .outputTo(System.out) + .errorTo(System.out) + .getExitValue(); + + assertTrue(exitValue == 0); + + } + +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/javax/enterprise/context/Scope.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/javax/enterprise/context/Scope.java new file mode 100644 index 00000000000..906266502db --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/javax/enterprise/context/Scope.java @@ -0,0 +1,28 @@ +/* + * 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 javax.enterprise.context; + +public class Scope { + public Scope() { } +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/module-info.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/module-info.java new file mode 100644 index 00000000000..aa96112a480 --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.enterprise/module-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +module java.enterprise { + exports javax.enterprise.context; +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/javax/transaction/Transaction.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/javax/transaction/Transaction.java new file mode 100644 index 00000000000..27350fdae63 --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/javax/transaction/Transaction.java @@ -0,0 +1,36 @@ +/* + * 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 javax.transaction; + +import javax.enterprise.context.Scope; + +public class Transaction { + + public Transaction() { } + + public Scope getScope() { + return new Scope(); + } + +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java new file mode 100644 index 00000000000..746ce3f974b --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/java.transaction/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module java.transaction { + requires public java.enterprise; + exports javax.transaction; +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java new file mode 100644 index 00000000000..9f87f53a0b7 --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/test/jdk/test/Main.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.test; + +import javax.transaction.Transaction; +import javax.enterprise.context.Scope; + +/** + * Uses an upgraded version of module java.transaction. + */ + +public class Main { + + public static void main(String[] args) { + + ClassLoader scl = ClassLoader.getSystemClassLoader(); + ClassLoader pcl = ClassLoader.getPlatformClassLoader(); + assertTrue(pcl.getParent() == null); + + Transaction transaction = new Transaction(); + Scope scope = transaction.getScope(); + + // javax.transaction.Transaction should be in module java.transaction + // and defined by the platform class loader + assertTrue(Transaction.class.getModule().getName().equals("java.transaction")); + assertTrue(Transaction.class.getClassLoader() == pcl); + + // javax.enterprise.context.Scope should be in module java.enterprise + // and defined by the application class loader + assertTrue(Scope.class.getModule().getName().equals("java.enterprise")); + assertTrue(Scope.class.getClassLoader() == scl); + } + + static void assertTrue(boolean e) { + if (!e) throw new RuntimeException(); + } + +} diff --git a/jdk/test/tools/launcher/modules/upgrademodulepath/src/test/module-info.java b/jdk/test/tools/launcher/modules/upgrademodulepath/src/test/module-info.java new file mode 100644 index 00000000000..e4087eac484 --- /dev/null +++ b/jdk/test/tools/launcher/modules/upgrademodulepath/src/test/module-info.java @@ -0,0 +1,27 @@ +/* + * 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. + */ + +module test { + requires java.transaction; +} + diff --git a/jdk/test/tools/lib/tests/Helper.java b/jdk/test/tools/lib/tests/Helper.java new file mode 100644 index 00000000000..c134cef25ac --- /dev/null +++ b/jdk/test/tools/lib/tests/Helper.java @@ -0,0 +1,405 @@ +/* + * 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 tests; + +import java.io.File; +import java.io.IOException; +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.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import tests.JImageGenerator.JLinkTask; +import tests.JImageGenerator.JModTask; + +/** + * JLink tests helper. + */ +public class Helper { + + private final Path explodedmodssrc; + private final Path jmodssrc; + private final Path jarssrc; + private final Path explodedmodsclasses; + private final Path jmodsclasses; + private final Path jarsclasses; + private final Path jmods; + private final Path jars; + private final Path images; + private final Path explodedmods; + private final Path stdjmods; + private final Path extracted; + private final Path recreated; + + private final Map> moduleClassDependencies = new HashMap<>(); + private final Map> moduleDependencies = new HashMap<>(); + private final List bootClasses; + private final FileSystem fs; + + public static Helper newHelper() throws IOException { + Path jdkHome = Paths.get(System.getProperty("test.jdk")); + // JPRT not yet ready for jmods + if (!Files.exists(jdkHome.resolve("jmods"))) { + System.err.println("Test not run, NO jmods directory"); + return null; + } + return new Helper(jdkHome); + } + + private Helper(Path jdkHome) throws IOException { + this.stdjmods = jdkHome.resolve("jmods").normalize(); + if (!Files.exists(stdjmods)) { + throw new IOException("Standard jMods do not exist."); + } + this.fs = FileSystems.getFileSystem(URI.create("jrt:/")); + + Path javabase = fs.getPath("/modules/java.base"); + this.bootClasses = Files.find(javabase, Integer.MAX_VALUE, + (file, attrs) -> file.toString().endsWith(".class")) + .map(Object::toString) + .map(s -> s.substring("/modules".length())) + .collect(Collectors.toList()); + + if (bootClasses.isEmpty()) { + throw new AssertionError("No boot class to check against"); + } + + this.jmods = Paths.get("jmods").toAbsolutePath(); + Files.createDirectories(jmods); + this.jars = Paths.get("jars").toAbsolutePath(); + Files.createDirectories(jars); + this.explodedmods = Paths.get("explodedmods").toAbsolutePath(); + Files.createDirectories(explodedmods); + this.explodedmodssrc = explodedmods.resolve("src"); + Files.createDirectories(explodedmodssrc); + this.jarssrc = jars.resolve("src"); + Files.createDirectories(jarssrc); + this.jmodssrc = jmods.resolve("src"); + Files.createDirectories(jmodssrc); + this.explodedmodsclasses = explodedmods.resolve("classes"); + Files.createDirectories(explodedmodsclasses); + this.jmodsclasses = jmods.resolve("classes"); + Files.createDirectories(jmodsclasses); + this.jarsclasses = jars.resolve("classes"); + Files.createDirectories(jarsclasses); + this.images = Paths.get("images").toAbsolutePath(); + Files.createDirectories(images); + this.extracted = Paths.get("extracted").toAbsolutePath(); + Files.createDirectories(extracted); + this.recreated = Paths.get("recreated").toAbsolutePath(); + Files.createDirectories(recreated); + } + + public void generateDefaultModules() throws IOException { + generateDefaultJModule("leaf1"); + generateDefaultJModule("leaf2"); + generateDefaultJModule("leaf3"); + + generateDefaultJarModule("leaf4"); + generateDefaultJarModule("leaf5"); + + generateDefaultExplodedModule("leaf6"); + generateDefaultExplodedModule("leaf7"); + + generateDefaultJarModule("composite1", "leaf1", "leaf2", "leaf4", "leaf6"); + generateDefaultJModule("composite2", "composite1", "leaf3", "leaf5", "leaf7", + "java.management"); + } + + public String defaultModulePath() { + return stdjmods.toAbsolutePath().toString() + File.pathSeparator + + jmods.toAbsolutePath().toString() + File.pathSeparator + + jars.toAbsolutePath().toString() + File.pathSeparator + + explodedmodsclasses.toAbsolutePath().toString(); + } + + public Path generateModuleCompiledClasses( + Path src, Path classes, String moduleName, String... dependencies) throws IOException { + return generateModuleCompiledClasses(src, classes, moduleName, getDefaultClasses(moduleName), dependencies); + } + + public Path generateModuleCompiledClasses( + Path src, Path classes, String moduleName, + List classNames, String... dependencies) throws IOException { + if (classNames == null) { + classNames = getDefaultClasses(moduleName); + } + putAppClasses(moduleName, classNames); + moduleDependencies.put(moduleName, Arrays.asList(dependencies)); + String modulePath = defaultModulePath(); + JImageGenerator.generateSourcesFromTemplate(src, moduleName, classNames.toArray(new String[classNames.size()])); + List packages = classNames.stream() + .map(JImageGenerator::getPackageName) + .distinct() + .collect(Collectors.toList()); + Path srcMod = src.resolve(moduleName); + JImageGenerator.generateModuleInfo(srcMod, packages, dependencies); + Path destination = classes.resolve(moduleName); + if (!JImageGenerator.compile(srcMod, destination, "-modulepath", modulePath, "-g")) { + throw new AssertionError("Compilation failure"); + } + return destination; + } + + public Result generateDefaultJModule(String moduleName, String... dependencies) throws IOException { + return generateDefaultJModule(moduleName, getDefaultClasses(moduleName), dependencies); + } + + public Result generateDefaultJModule(String moduleName, List classNames, + String... dependencies) throws IOException { + generateModuleCompiledClasses(jmodssrc, jmodsclasses, moduleName, classNames, dependencies); + generateGarbage(jmodsclasses.resolve(moduleName)); + + Path jmodFile = jmods.resolve(moduleName + ".jmod"); + JModTask task = JImageGenerator.getJModTask() + .jmod(jmodFile) + .addJmods(stdjmods) + .addJmods(jmods.toAbsolutePath()) + .addJars(jars.toAbsolutePath()) + .addClassPath(jmodsclasses.resolve(moduleName)); + if (!classNames.isEmpty()) { + task.mainClass(classNames.get(0)); + } + return task.create(); + } + + public Result generateDefaultJarModule(String moduleName, String... dependencies) throws IOException { + return generateDefaultJarModule(moduleName, getDefaultClasses(moduleName), dependencies); + } + + public Result generateDefaultJarModule(String moduleName, List classNames, + String... dependencies) throws IOException { + generateModuleCompiledClasses(jarssrc, jarsclasses, moduleName, classNames, dependencies); + generateGarbage(jarsclasses.resolve(moduleName)); + + Path jarFile = jars.resolve(moduleName + ".jar"); + JImageGenerator.createJarFile(jarFile, jarsclasses.resolve(moduleName)); + return new Result(0, "", jarFile); + } + + public Result generateDefaultExplodedModule(String moduleName, String... dependencies) throws IOException { + return generateDefaultExplodedModule(moduleName, getDefaultClasses(moduleName), dependencies); + } + + public Result generateDefaultExplodedModule(String moduleName, List classNames, + String... dependencies) throws IOException { + generateModuleCompiledClasses(explodedmodssrc, explodedmodsclasses, + moduleName, classNames, dependencies); + + Path dir = explodedmods.resolve(moduleName); + return new Result(0, "", dir); + } + + private void generateGarbage(Path compiled) throws IOException { + Path metaInf = compiled.resolve("META-INF").resolve("services"); + Files.createDirectories(metaInf); + Path provider = metaInf.resolve("MyProvider"); + Files.createFile(provider); + Files.createFile(compiled.resolve("toto.jcov")); + } + + public static Path createNewFile(Path root, String pathName, String extension) { + Path out = root.resolve(pathName + extension); + int i = 1; + while (Files.exists(out)) { + out = root.resolve(pathName + "-" + (++i) + extension); + } + return out; + } + + public Result generateDefaultImage(String module) { + return generateDefaultImage(new String[0], module); + } + + public Result generateDefaultImage(String[] options, String module) { + Path output = createNewFile(images, module, ".image"); + JLinkTask jLinkTask = JImageGenerator.getJLinkTask() + .modulePath(defaultModulePath()) + .output(output) + .addMods(module) + .limitMods(module); + for (String option : options) { + jLinkTask.option(option); + } + return jLinkTask.call(); + } + + public Result postProcessImage(Path root, String[] options) { + JLinkTask jLinkTask = JImageGenerator.getJLinkTask() + .existing(root); + for (String option : options) { + jLinkTask.option(option); + } + return jLinkTask.callPostProcess(); + } + + private List getDefaultClasses(String module) { + return Arrays.asList(module + ".Main", module + ".com.foo.bar.X"); + } + + private void putAppClasses(String module, List classes) { + List appClasses = toLocation(module, classes).stream().collect(Collectors.toList()); + appClasses.add(toLocation(module, "module-info")); + moduleClassDependencies.put(module, appClasses); + } + + private static String toLocation(String module, String className) { + return "/" + module + "/" + className.replaceAll("\\.", "/") + ".class"; + } + + public static List toLocation(String module, List classNames) { + return classNames.stream() + .map(clazz -> toLocation(module, clazz)) + .collect(Collectors.toList()); + } + + public void checkImage(Path imageDir, String module, String[] paths, String[] files) throws IOException { + checkImage(imageDir, module, paths, files, null); + } + + public void checkImage(Path imageDir, String module, String[] paths, String[] files, String[] expectedFiles) throws IOException { + List unexpectedPaths = new ArrayList<>(); + if (paths != null) { + Collections.addAll(unexpectedPaths, paths); + } + List unexpectedFiles = new ArrayList<>(); + if (files != null) { + Collections.addAll(unexpectedFiles, files); + } + + JImageValidator validator = new JImageValidator(module, gatherExpectedLocations(module), + imageDir.toFile(), + unexpectedPaths, + unexpectedFiles, + expectedFiles); + System.out.println("*** Validate Image " + module); + validator.validate(); + long moduleExecutionTime = validator.getModuleLauncherExecutionTime(); + if (moduleExecutionTime != 0) { + System.out.println("Module launcher execution time " + moduleExecutionTime); + } + System.out.println("Java launcher execution time " + + validator.getJavaLauncherExecutionTime()); + System.out.println("***"); + } + + private List gatherExpectedLocations(String module) throws IOException { + List expectedLocations = new ArrayList<>(); + expectedLocations.addAll(bootClasses); + List modules = moduleDependencies.get(module); + for (String dep : modules) { + Path path = fs.getPath("/modules/" + dep); + if (Files.exists(path)) { + List locations = Files.find(path, Integer.MAX_VALUE, + (p, attrs) -> Files.isRegularFile(p) && p.toString().endsWith(".class") + && !p.toString().endsWith("module-info.class")) + .map(p -> p.toString().substring("/modules".length())) + .collect(Collectors.toList()); + expectedLocations.addAll(locations); + } + } + + List appClasses = moduleClassDependencies.get(module); + if (appClasses != null) { + expectedLocations.addAll(appClasses); + } + return expectedLocations; + } + + public static String getDebugSymbolsExtension() { + return ".diz"; + } + + public Path createNewImageDir(String moduleName) { + return createNewFile(getImageDir(), moduleName, ".image"); + } + + public Path createNewExtractedDir(String name) { + return createNewFile(getExtractedDir(), name, ".extracted"); + } + + public Path createNewRecreatedDir(String name) { + return createNewFile(getRecreatedDir(), name, ".jimage"); + } + + public Path createNewJmodFile(String moduleName) { + return createNewFile(getJmodDir(), moduleName, ".jmod"); + } + + public Path createNewJarFile(String moduleName) { + return createNewFile(getJarDir(), moduleName, ".jar"); + } + + public Path getJmodSrcDir() { + return jmodssrc; + } + + public Path getJarSrcDir() { + return jarssrc; + } + + public Path getJmodClassesDir() { + return jmodsclasses; + } + + public Path getJarClassesDir() { + return jarsclasses; + } + + public Path getJmodDir() { + return jmods; + } + + public Path getExplodedModsDir() { + return explodedmods; + } + + public Path getJarDir() { + return jars; + } + + public Path getImageDir() { + return images; + } + + public Path getStdJmodsDir() { + return stdjmods; + } + + public Path getExtractedDir() { + return extracted; + } + + public Path getRecreatedDir() { + return recreated; + } +} diff --git a/jdk/test/tools/lib/tests/JImageGenerator.java b/jdk/test/tools/lib/tests/JImageGenerator.java new file mode 100644 index 00000000000..77366aafb13 --- /dev/null +++ b/jdk/test/tools/lib/tests/JImageGenerator.java @@ -0,0 +1,735 @@ +/* + * 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 tests; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; + +import javax.tools.JavaCompiler; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +/** + * + * A generator for jmods, jars and images. + */ +public class JImageGenerator { + + public static final String LOAD_ALL_CLASSES_TEMPLATE = "package PACKAGE;\n" + + "\n" + + "import java.net.URI;\n" + + "import java.nio.file.FileSystems;\n" + + "import java.nio.file.Files;\n" + + "import java.nio.file.Path;\n" + + "import java.util.function.Function;\n" + + "\n" + + "public class CLASS {\n" + + " private static long total_time;\n" + + " private static long num_classes;\n" + + " public static void main(String[] args) throws Exception {\n" + + " Function formatter = (path) -> {\n" + + " String clazz = path.toString().substring(\"modules/\".length()+1, path.toString().lastIndexOf(\".\"));\n" + + " clazz = clazz.substring(clazz.indexOf(\"/\") + 1);\n" + + " return clazz.replaceAll(\"/\", \"\\\\.\");\n" + + " };\n" + + " Files.walk(FileSystems.getFileSystem(URI.create(\"jrt:/\")).getPath(\"/modules/\")).\n" + + " filter((p) -> {\n" + + " return Files.isRegularFile(p) && p.toString().endsWith(\".class\")\n" + + " && !p.toString().endsWith(\"module-info.class\");\n" + + " }).\n" + + " map(formatter).forEach((clazz) -> {\n" + + " try {\n" + + " long t = System.currentTimeMillis();\n" + + " Class.forName(clazz, false, Thread.currentThread().getContextClassLoader());\n" + + " total_time+= System.currentTimeMillis()-t;\n" + + " num_classes+=1;\n" + + " } catch (IllegalAccessError ex) {\n" + + " // Security exceptions can occur, this is not what we are testing\n" + + " System.err.println(\"Access error, OK \" + clazz);\n" + + " } catch (Exception ex) {\n" + + " System.err.println(\"ERROR \" + clazz);\n" + + " throw new RuntimeException(ex);\n" + + " }\n" + + " });\n" + + " double res = (double) total_time / num_classes;\n" + + " // System.out.println(\"Total time \" + total_time + \" num classes \" + num_classes + \" average \" + res);\n" + + " }\n" + + "}\n"; + + private static final String OUTPUT_OPTION = "--output"; + private static final String POST_PROCESS_OPTION = "--post-process-path"; + private static final String MAIN_CLASS_OPTION = "--main-class"; + private static final String CLASS_PATH_OPTION = "--class-path"; + private static final String MODULE_PATH_OPTION = "--modulepath"; + private static final String ADD_MODS_OPTION = "--addmods"; + private static final String LIMIT_MODS_OPTION = "--limitmods"; + private static final String PLUGINS_MODULE_PATH = "--plugin-module-path"; + + private static final String CMDS_OPTION = "--cmds"; + private static final String CONFIG_OPTION = "--config"; + private static final String HASH_DEPENDENCIES_OPTION = "--hash-dependencies"; + private static final String LIBS_OPTION = "--libs"; + private static final String MODULE_VERSION_OPTION = "--module-version"; + + private JImageGenerator() {} + + private static String optionsPrettyPrint(String... args) { + return Stream.of(args).collect(Collectors.joining(" ")); + } + + public static File getJModsDir(File jdkHome) { + File jdkjmods = new File(jdkHome, "jmods"); + if (!jdkjmods.exists()) { + return null; + } + return jdkjmods; + } + + public static Path addFiles(Path module, InMemoryFile... resources) throws IOException { + Path tempFile = Files.createTempFile("jlink-test", ""); + try (JarInputStream in = new JarInputStream(Files.newInputStream(module)); + JarOutputStream out = new JarOutputStream(new FileOutputStream(tempFile.toFile()))) { + ZipEntry entry; + while ((entry = in.getNextEntry()) != null) { + String name = entry.getName(); + out.putNextEntry(new ZipEntry(name)); + copy(in, out); + out.closeEntry(); + } + for (InMemoryFile r : resources) { + addFile(r, out); + } + } + Files.move(tempFile, module, StandardCopyOption.REPLACE_EXISTING); + return module; + } + + private static void copy(InputStream in, OutputStream out) throws IOException { + int len; + byte[] buf = new byte[4096]; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } + + public static JModTask getJModTask() { + return new JModTask(); + } + + public static JLinkTask getJLinkTask() { + return new JLinkTask(); + } + + public static JImageTask getJImageTask() { + return new JImageTask(); + } + + private static void addFile(InMemoryFile resource, JarOutputStream target) throws IOException { + String fileName = resource.getPath(); + fileName = fileName.replace("\\", "/"); + String[] ss = fileName.split("/"); + Path p = Paths.get(""); + for (int i = 0; i < ss.length; ++i) { + if (i < ss.length - 1) { + if (!ss[i].isEmpty()) { + p = p.resolve(ss[i]); + JarEntry entry = new JarEntry(p.toString() + "/"); + target.putNextEntry(entry); + target.closeEntry(); + } + } else { + p = p.resolve(ss[i]); + JarEntry entry = new JarEntry(p.toString()); + target.putNextEntry(entry); + copy(resource.getBytes(), target); + target.closeEntry(); + } + } + } + + public static Path createNewFile(Path root, String pathName, String extension) { + Path out = root.resolve(pathName + extension); + int i = 1; + while (Files.exists(out)) { + out = root.resolve(pathName + "-" + (++i) + extension); + } + return out; + } + + public static Path generateSources(Path output, String moduleName, List sources) throws IOException { + Path moduleDir = output.resolve(moduleName); + Files.createDirectory(moduleDir); + for (InMemorySourceFile source : sources) { + Path fileDir = moduleDir; + if (!source.packageName.isEmpty()) { + String dir = source.packageName.replace('.', File.separatorChar); + fileDir = moduleDir.resolve(dir); + Files.createDirectories(fileDir); + } + Files.write(fileDir.resolve(source.className + ".java"), source.source.getBytes()); + } + return moduleDir; + } + + public static Path generateSourcesFromTemplate(Path output, String moduleName, String... classNames) throws IOException { + List sources = new ArrayList<>(); + for (String className : classNames) { + String packageName = getPackageName(className); + String simpleName = getSimpleName(className); + String content = LOAD_ALL_CLASSES_TEMPLATE + .replace("CLASS", simpleName); + if (packageName.isEmpty()) { + content = content.replace("package PACKAGE;", packageName); + } else { + content = content.replace("PACKAGE", packageName); + } + sources.add(new InMemorySourceFile(packageName, simpleName, content)); + } + return generateSources(output, moduleName, sources); + } + + public static void generateModuleInfo(Path moduleDir, List packages, String... dependencies) throws IOException { + StringBuilder moduleInfoBuilder = new StringBuilder(); + Path file = moduleDir.resolve("module-info.java"); + String moduleName = moduleDir.getFileName().toString(); + moduleInfoBuilder.append("module ").append(moduleName).append("{\n"); + for (String dep : dependencies) { + moduleInfoBuilder.append("requires ").append(dep).append(";\n"); + } + for (String pkg : packages) { + if (!pkg.trim().isEmpty()) { + moduleInfoBuilder.append("exports ").append(pkg).append(";\n"); + } + } + moduleInfoBuilder.append("}"); + Files.write(file, moduleInfoBuilder.toString().getBytes()); + } + + public static void compileSuccess(Path source, Path destination, String... options) throws IOException { + if (!compile(source, destination, options)) { + throw new AssertionError("Compilation failed."); + } + } + + public static boolean compile(Path source, Path destination, String... options) throws IOException { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + try (StandardJavaFileManager jfm = compiler.getStandardFileManager(null, null, null)) { + List sources + = Files.find(source, Integer.MAX_VALUE, + (file, attrs) -> file.toString().endsWith(".java")) + .collect(Collectors.toList()); + + Files.createDirectories(destination); + jfm.setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Collections.singleton(destination)); + + List opts = Arrays.asList(options); + JavaCompiler.CompilationTask task + = compiler.getTask(null, jfm, null, opts, null, + jfm.getJavaFileObjectsFromPaths(sources)); + List list = new ArrayList<>(opts); + list.addAll(sources.stream() + .map(Path::toString) + .collect(Collectors.toList())); + System.err.println("javac options: " + optionsPrettyPrint(list.toArray(new String[list.size()]))); + return task.call(); + } + } + + public static Path createJarFile(Path jarfile, Path dir) throws IOException { + return createJarFile(jarfile, dir, Paths.get(".")); + } + + public static Path createJarFile(Path jarfile, Path dir, Path file) throws IOException { + // create the target directory + Path parent = jarfile.getParent(); + if (parent != null) + Files.createDirectories(parent); + + List entries = Files.find(dir.resolve(file), Integer.MAX_VALUE, + (p, attrs) -> attrs.isRegularFile()) + .map(dir::relativize) + .collect(Collectors.toList()); + + try (OutputStream out = Files.newOutputStream(jarfile); + JarOutputStream jos = new JarOutputStream(out)) { + for (Path entry : entries) { + // map the file path to a name in the JAR file + Path normalized = entry.normalize(); + String name = normalized + .subpath(0, normalized.getNameCount()) // drop root + .toString() + .replace(File.separatorChar, '/'); + + jos.putNextEntry(new JarEntry(name)); + Files.copy(dir.resolve(entry), jos); + } + } + return jarfile; + } + + public static Set getModuleContent(Path module) { + Result result = JImageGenerator.getJModTask() + .jmod(module) + .list(); + result.assertSuccess(); + return Stream.of(result.getMessage().split("\r?\n")) + .collect(Collectors.toSet()); + } + + public static void checkModule(Path module, Set expected) throws IOException { + Set actual = getModuleContent(module); + if (!Objects.equals(actual, expected)) { + Set unexpected = new HashSet<>(actual); + unexpected.removeAll(expected); + Set notFound = new HashSet<>(expected); + notFound.removeAll(actual); + System.err.println("Unexpected files:"); + unexpected.forEach(s -> System.err.println("\t" + s)); + System.err.println("Not found files:"); + notFound.forEach(s -> System.err.println("\t" + s)); + throw new AssertionError("Module check failed."); + } + } + + public static class JModTask { + + private final List classpath = new ArrayList<>(); + private final List libs = new ArrayList<>(); + private final List cmds = new ArrayList<>(); + private final List config = new ArrayList<>(); + private final List jars = new ArrayList<>(); + private final List jmods = new ArrayList<>(); + private final List options = new ArrayList<>(); + private Path output; + private String hashDependencies; + private String mainClass; + private String moduleVersion; + + public JModTask addNativeLibraries(Path cp) { + this.libs.add(cp); + return this; + } + + public JModTask hashDependencies(String hash) { + this.hashDependencies = hash; + return this; + } + + public JModTask addCmds(Path cp) { + this.cmds.add(cp); + return this; + } + + public JModTask addClassPath(Path cp) { + this.classpath.add(cp); + return this; + } + + public JModTask addConfig(Path cp) { + this.config.add(cp); + return this; + } + + public JModTask addJars(Path jars) { + this.jars.add(jars); + return this; + } + + public JModTask addJmods(Path jmods) { + this.jmods.add(jmods); + return this; + } + + public JModTask jmod(Path output) { + this.output = output; + return this; + } + + public JModTask moduleVersion(String moduleVersion) { + this.moduleVersion = moduleVersion; + return this; + } + + public JModTask mainClass(String mainClass) { + this.mainClass = mainClass; + return this; + } + + public JModTask option(String o) { + this.options.add(o); + return this; + } + + private String modulePath() { + // This is expect FIRST jmods THEN jars, if you change this, some tests could fail + String jmods = toPath(this.jmods); + String jars = toPath(this.jars); + return jmods + File.pathSeparator + jars; + } + + private String toPath(List paths) { + return paths.stream() + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + } + + private String[] optionsJMod(String cmd) { + List options = new ArrayList<>(); + options.add(cmd); + if (!cmds.isEmpty()) { + options.add(CMDS_OPTION); + options.add(toPath(cmds)); + } + if (!config.isEmpty()) { + options.add(CONFIG_OPTION); + options.add(toPath(config)); + } + if (hashDependencies != null) { + options.add(HASH_DEPENDENCIES_OPTION); + options.add(hashDependencies); + } + if (mainClass != null) { + options.add(MAIN_CLASS_OPTION); + options.add(mainClass); + } + if (!libs.isEmpty()) { + options.add(LIBS_OPTION); + options.add(toPath(libs)); + } + if (!classpath.isEmpty()) { + options.add(CLASS_PATH_OPTION); + options.add(toPath(classpath)); + } + if (!jars.isEmpty() || !jmods.isEmpty()) { + options.add(MODULE_PATH_OPTION); + options.add(modulePath()); + } + if (moduleVersion != null) { + options.add(MODULE_VERSION_OPTION); + options.add(moduleVersion); + } + options.addAll(this.options); + if (output != null) { + options.add(output.toString()); + } + return options.toArray(new String[options.size()]); + } + + public Result create() { + return cmd("create"); + } + + public Result list() { + return cmd("list"); + } + + public Result call() { + return cmd(""); + } + + private Result cmd(String cmd) { + String[] args = optionsJMod(cmd); + System.err.println("jmod options: " + optionsPrettyPrint(args)); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int exitCode = jdk.tools.jmod.Main.run(args, new PrintStream(baos)); + String msg = new String(baos.toByteArray()); + return new Result(exitCode, msg, output); + } + } + + public static String getPackageName(String canonicalName) { + int index = canonicalName.lastIndexOf('.'); + return index > 0 ? canonicalName.substring(0, index) : ""; + } + + public static String getSimpleName(String canonicalName) { + int index = canonicalName.lastIndexOf('.'); + return canonicalName.substring(index + 1); + } + + public static class JImageTask { + + private final List pluginModulePath = new ArrayList<>(); + private final List options = new ArrayList<>(); + private Path dir; + private Path image; + + public JImageTask pluginModulePath(Path p) { + this.pluginModulePath.add(p); + return this; + } + + public JImageTask image(Path image) { + this.image = image; + return this; + } + + public JImageTask dir(Path dir) { + this.dir = dir; + return this; + } + + public JImageTask option(String o) { + this.options.add(o); + return this; + } + + private String toPath(List paths) { + return paths.stream() + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + } + + private String[] optionsJImage(String cmd) { + List options = new ArrayList<>(); + options.add(cmd); + if (dir != null) { + options.add("--dir"); + options.add(dir.toString()); + } + if (!pluginModulePath.isEmpty()) { + options.add(PLUGINS_MODULE_PATH); + options.add(toPath(pluginModulePath)); + } + options.addAll(this.options); + options.add(image.toString()); + return options.toArray(new String[options.size()]); + } + + private Result cmd(String cmd, Path returnPath) { + String[] args = optionsJImage(cmd); + System.err.println("jimage options: " + optionsPrettyPrint(args)); + StringWriter writer = new StringWriter(); + int exitCode = jdk.tools.jimage.Main.run(args, new PrintWriter(writer)); + return new Result(exitCode, writer.toString(), returnPath); + } + + public Result extract() { + return cmd("extract", dir); + } + + public Result recreate() { + return cmd("recreate", image); + } + } + + public static class JLinkTask { + + private final List jars = new ArrayList<>(); + private final List jmods = new ArrayList<>(); + private final List pluginModulePath = new ArrayList<>(); + private final List addMods = new ArrayList<>(); + private final List limitMods = new ArrayList<>(); + private final List options = new ArrayList<>(); + private String modulePath; + private Path output; + private Path existing; + + public JLinkTask modulePath(String modulePath) { + this.modulePath = modulePath; + return this; + } + + public JLinkTask addJars(Path jars) { + this.jars.add(jars); + return this; + } + + public JLinkTask addJmods(Path jmods) { + this.jmods.add(jmods); + return this; + } + + public JLinkTask pluginModulePath(Path p) { + this.pluginModulePath.add(p); + return this; + } + + public JLinkTask addMods(String moduleName) { + this.addMods.add(moduleName); + return this; + } + + public JLinkTask limitMods(String moduleName) { + this.limitMods.add(moduleName); + return this; + } + + public JLinkTask output(Path output) { + this.output = output; + return this; + } + + public JLinkTask existing(Path existing) { + this.existing = existing; + return this; + } + + public JLinkTask option(String o) { + this.options.add(o); + return this; + } + + private String modulePath() { + // This is expect FIRST jmods THEN jars, if you change this, some tests could fail + String jmods = toPath(this.jmods); + String jars = toPath(this.jars); + return jmods + File.pathSeparator + jars; + } + + private String toPath(List paths) { + return paths.stream() + .map(Path::toString) + .collect(Collectors.joining(File.pathSeparator)); + } + + private String[] optionsJLink() { + List options = new ArrayList<>(); + if (output != null) { + options.add(OUTPUT_OPTION); + options.add(output.toString()); + } + if (!addMods.isEmpty()) { + options.add(ADD_MODS_OPTION); + options.add(addMods.stream().collect(Collectors.joining(","))); + } + if (!limitMods.isEmpty()) { + options.add(LIMIT_MODS_OPTION); + options.add(limitMods.stream().collect(Collectors.joining(","))); + } + if (!jars.isEmpty() || !jmods.isEmpty()) { + options.add(MODULE_PATH_OPTION); + options.add(modulePath()); + } + if (modulePath != null) { + options.add(MODULE_PATH_OPTION); + options.add(modulePath); + } + if (!pluginModulePath.isEmpty()) { + options.add(PLUGINS_MODULE_PATH); + options.add(toPath(pluginModulePath)); + } + options.addAll(this.options); + return options.toArray(new String[options.size()]); + } + + private String[] optionsPostProcessJLink() { + List options = new ArrayList<>(); + if (existing != null) { + options.add(POST_PROCESS_OPTION); + options.add(existing.toString()); + } + options.addAll(this.options); + return options.toArray(new String[options.size()]); + } + + public Result call() { + String[] args = optionsJLink(); + System.err.println("jlink options: " + optionsPrettyPrint(args)); + StringWriter writer = new StringWriter(); + int exitCode = jdk.tools.jlink.internal.Main.run(args, new PrintWriter(writer)); + return new Result(exitCode, writer.toString(), output); + } + + public Result callPostProcess() { + String[] args = optionsPostProcessJLink(); + System.err.println("jlink options: " + optionsPrettyPrint(args)); + StringWriter writer = new StringWriter(); + int exitCode = jdk.tools.jlink.internal.Main.run(args, new PrintWriter(writer)); + return new Result(exitCode, writer.toString(), output); + } + } + + public static class InMemorySourceFile { + public final String packageName; + public final String className; + public final String source; + + public InMemorySourceFile(String packageName, String simpleName, String source) { + this.packageName = packageName; + this.className = simpleName; + this.source = source; + } + } + + public static class InMemoryFile { + private final String path; + private final byte[] bytes; + + public String getPath() { + return path; + } + + public InputStream getBytes() { + return new ByteArrayInputStream(bytes); + } + + public InMemoryFile(String path, byte[] bytes) { + this.path = path; + this.bytes = bytes; + } + + public InMemoryFile(String path, InputStream is) throws IOException { + this(path, readAllBytes(is)); + } + } + + public static byte[] readAllBytes(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buf = new byte[1024]; + while (true) { + int n = is.read(buf); + if (n < 0) { + break; + } + baos.write(buf, 0, n); + } + return baos.toByteArray(); + } +} diff --git a/jdk/test/tools/lib/tests/JImageValidator.java b/jdk/test/tools/lib/tests/JImageValidator.java new file mode 100644 index 00000000000..69c6761b586 --- /dev/null +++ b/jdk/test/tools/lib/tests/JImageValidator.java @@ -0,0 +1,234 @@ +/* + * 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 tests; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.ConstantPoolException; +import jdk.internal.jimage.BasicImageReader; +import jdk.internal.jimage.ImageLocation; + +/** + * + * JDK Modular image validator + */ +public class JImageValidator { + + private static final String[] dirs = {"bin", "lib"}; + + private final File rootDir; + private final List expectedLocations; + private final String module; + private long moduleExecutionTime; + private long javaExecutionTime; + private final List unexpectedPaths; + private final List unexpectedFiles; + private final String[] expectedFiles; + + public JImageValidator(String module, List expectedLocations, + File rootDir, + List unexpectedPaths, + List unexpectedFiles) throws Exception { + this(module, expectedLocations, rootDir, unexpectedPaths, unexpectedFiles, null); + } + + public JImageValidator(String module, List expectedLocations, + File rootDir, + List unexpectedPaths, + List unexpectedFiles, + String[] expectedFiles) throws IOException { + if (!rootDir.exists()) { + throw new IOException("Image root dir not found " + + rootDir.getAbsolutePath()); + } + this.expectedLocations = expectedLocations; + this.rootDir = rootDir; + this.module = module; + this.unexpectedPaths = unexpectedPaths; + this.unexpectedFiles = unexpectedFiles; + this.expectedFiles = expectedFiles == null ? new String[0] : expectedFiles; + } + + public void validate() throws IOException { + for (String d : dirs) { + File dir = new File(rootDir, d); + if (!dir.isDirectory()) { + throw new IOException("Invalid directory " + d); + } + } + + //check jimage file + Path path = rootDir.toPath().resolve("lib").resolve("modules"); + if (!Files.isRegularFile(path)) { + throw new IOException(path + " No jimage file generated"); + } + + // Check binary file + File launcher = new File(rootDir, "bin" + File.separator + module); + if (launcher.exists()) { + ProcessBuilder builder = new ProcessBuilder("sh", launcher.getAbsolutePath()); + long t = System.currentTimeMillis(); + Process process = builder.inheritIO().start(); + int ret = waitFor(process); + moduleExecutionTime += System.currentTimeMillis() - t; + if (ret != 0) { + throw new IOException("Image " + module + " execution failed, check logs."); + } + } + + for (String f : expectedFiles) { + File dd = new File(rootDir, f); + if (!dd.exists()) { + throw new IOException("Expected File " + f + " not found"); + } + } + + //Walk and check that unexpected files are not there + try (java.util.stream.Stream stream = Files.walk(rootDir.toPath())) { + stream.forEach((p) -> { + for (String u : unexpectedFiles) { + if (p.toString().equals(u)) { + throw new RuntimeException("Seen unexpected path " + p); + } + } + }); + } + + File javaLauncher = new File(rootDir, "bin" + File.separator + + (isWindows() ? "java.exe" : "java")); + if (javaLauncher.exists()) { + ProcessBuilder builder = new ProcessBuilder(javaLauncher.getAbsolutePath(), + "-version"); + long t = System.currentTimeMillis(); + Process process = builder.start(); + int ret = waitFor(process); + javaExecutionTime += System.currentTimeMillis() - t; + if (ret != 0) { + throw new RuntimeException("java launcher execution failed, check logs."); + } + } else { + throw new IOException("java launcher not found."); + } + + // Check release file + File release = new File(rootDir, "release"); + if (!release.exists()) { + throw new IOException("Release file not generated"); + } else { + Properties props = new Properties(); + try (FileInputStream fs = new FileInputStream(release)) { + props.load(fs); + String s = props.getProperty("MODULES"); + if (s == null) { + throw new IOException("No MODULES property in release"); + } + if (!s.contains(module)) { + throw new IOException("Module not found in release file " + s); + } + } + } + + } + + private int waitFor(Process process) { + try { + return process.waitFor(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private static boolean isWindows() { + return System.getProperty("os.name").startsWith("Windows"); + } + + public static void validate(Path jimage, List expectedLocations, + List unexpectedPaths) throws IOException { + BasicImageReader reader = BasicImageReader.open(jimage); + // Validate expected locations + List seenLocations = new ArrayList<>(); + for (String loc : expectedLocations) { + ImageLocation il = reader.findLocation(loc); + if (il == null) { + throw new IOException("Location " + loc + " not present in " + jimage); + } + } + seenLocations.addAll(expectedLocations); + + for (String s : reader.getEntryNames()) { + if (s.endsWith(".class") && !s.endsWith("module-info.class")) { + ImageLocation il = reader.findLocation(s); + try { + byte[] r = reader.getResource(il); + if(r == null) { + System.out.println("IL, compressed " + + il.getCompressedSize() + " uncompressed " + + il.getUncompressedSize()); + throw new IOException("NULL RESOURCE " + s); + } + readClass(r); + } catch (IOException ex) { + System.err.println(s + " ERROR " + ex); + throw ex; + } + } + if (seenLocations.contains(s)) { + seenLocations.remove(s); + } + for(String p : unexpectedPaths) { + if (s.equals(p)) { + throw new IOException("Seen unexpected path " + s); + } + } + } + if (!seenLocations.isEmpty()) { + throw new IOException("ImageReader did not return " + seenLocations); + } + } + + public long getJavaLauncherExecutionTime() { + return javaExecutionTime; + } + + public long getModuleLauncherExecutionTime() { + return moduleExecutionTime; + } + + public static void readClass(byte[] clazz) throws IOException { + try (InputStream stream = new ByteArrayInputStream(clazz)) { + ClassFile.read(stream); + } catch (ConstantPoolException e) { + throw new IOException(e); + } + } +} diff --git a/jdk/test/tools/lib/tests/Result.java b/jdk/test/tools/lib/tests/Result.java new file mode 100644 index 00000000000..0854fff12dc --- /dev/null +++ b/jdk/test/tools/lib/tests/Result.java @@ -0,0 +1,84 @@ +/* + * 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 tests; + +import java.nio.file.Path; + +public class Result { + private final int exitCode; + private final String message; + private final Path imageFile; + + public Result(int exitCode, String message, Path imageFile) { + this.exitCode = exitCode; + this.message = message; + this.imageFile = imageFile; + } + + public int getExitCode() { + return exitCode; + } + + public String getMessage() { + return message; + } + + public Path getFile() { + return imageFile; + } + + public void assertFailure() { + assertFailure(null); + } + + public void assertFailure(String expected) { + if (getExitCode() == 0) { + System.err.println(getMessage()); + throw new AssertionError("Failure expected: " + getFile()); + } + if (getExitCode() != 1 && getExitCode() != 2) { + System.err.println(getMessage()); + throw new AssertionError("Abnormal exit: " + getFile()); + } + if (expected != null) { + if (expected.isEmpty()) { + throw new AssertionError("Expected error is empty"); + } + if (!getMessage().matches(expected) && !getMessage().contains(expected)) { + System.err.println(getMessage()); + throw new AssertionError("Output does not fit regexp: " + expected); + } + } + System.err.println("Failed as expected. " + (expected != null ? expected : "")); + System.err.println(getMessage()); + } + + public Path assertSuccess() { + if (getExitCode() != 0) { + System.err.println(getMessage()); + throw new AssertionError("Unexpected failure: " + getExitCode()); + } + return getFile(); + } +} diff --git a/jdk/test/tools/pack200/ModuleAttributes.java b/jdk/test/tools/pack200/ModuleAttributes.java new file mode 100644 index 00000000000..a3df72bf766 --- /dev/null +++ b/jdk/test/tools/pack200/ModuleAttributes.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +/* + * @test + * @bug 8048100 + * @summary test the new Module attributes + * @compile -XDignore.symbol.file Utils.java ModuleAttributes.java + * @run main ModuleAttributes + */ +public class ModuleAttributes { + + public static void main(String... args) throws Exception { + new ModuleAttributes().run(); + } + + public void run() throws Exception { + File file = createModuleJar(); + Utils.testWithRepack(file, + "--effort=1", + "--unknown-attribute=error"); + } + + File createModuleJar() throws IOException { + File libDir = new File(Utils.JavaHome, "lib"); + File modules = new File(libDir, "modules"); + File outDir = new File("out"); + + List cmdList = new ArrayList<>(); + cmdList.add(Utils.getJimageCmd()); + cmdList.add("extract"); + cmdList.add(modules.getAbsolutePath()); + cmdList.add("--dir"); + cmdList.add(outDir.getName()); + Utils.runExec(cmdList); + + FileFilter filter = (File file) -> file.getName().equals("module-info.class"); + List mfiles = Utils.findFiles(outDir, filter); + + List contents = new ArrayList<>(mfiles.size()); + mfiles.stream().forEach((f) -> { + contents.add(f.getAbsolutePath()); + }); + + File listFile = new File("mfiles.list"); + Utils.createFile(listFile, contents); + File testFile = new File("test.jar"); + Utils.jar("cvf", testFile.getName(), "@" + listFile.getName()); + Utils.recursiveDelete(outDir); + return testFile; + } +} diff --git a/jdk/test/tools/pack200/Utils.java b/jdk/test/tools/pack200/Utils.java index 60f2d0c50bc..663cdc38247 100644 --- a/jdk/test/tools/pack200/Utils.java +++ b/jdk/test/tools/pack200/Utils.java @@ -101,6 +101,7 @@ class Utils { compiler("-d", XCLASSES.getName(), + "-XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED", "@" + tmpFile.getAbsolutePath()); jar("cvfe", @@ -137,6 +138,7 @@ class Utils { init(); List cmds = new ArrayList(); cmds.add(getJavaCmd()); + cmds.add("-XaddExports:jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED"); cmds.add("-cp"); cmds.add(VerifierJar.getName()); cmds.add("sun.tools.pack.verify.Main"); @@ -561,13 +563,12 @@ class Utils { } static File createRtJar() throws IOException { - File LibDir = new File(JavaHome, "lib"); - File ModuleDir = new File(LibDir, "modules"); - File BootModules = new File(ModuleDir, "bootmodules.jimage"); + File libDir = new File(JavaHome, "lib"); + File modules = new File(libDir, "modules"); List cmdList = new ArrayList<>(); cmdList.add(getJimageCmd()); cmdList.add("extract"); - cmdList.add(BootModules.getAbsolutePath()); + cmdList.add(modules.getAbsolutePath()); cmdList.add("--dir"); cmdList.add("out"); runExec(cmdList); diff --git a/jdk/test/tools/pack200/pack200-verifier/make/build.xml b/jdk/test/tools/pack200/pack200-verifier/make/build.xml index b783ffda881..2bb786b8e87 100644 --- a/jdk/test/tools/pack200/pack200-verifier/make/build.xml +++ b/jdk/test/tools/pack200/pack200-verifier/make/build.xml @@ -1,4 +1,4 @@ - + @@ -21,30 +21,35 @@ - + + + - - + + + - - - - + + + + + + + diff --git a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java index 02b0a7eb230..ac54c143435 100644 --- a/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java +++ b/jdk/test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -26,7 +26,11 @@ package xmlkit; // -*- mode: java; indent-tabs-mode: nil -*- import com.sun.tools.classfile.AccessFlags; import com.sun.tools.classfile.Annotation; -import com.sun.tools.classfile.Annotation.*; +import com.sun.tools.classfile.Annotation.Annotation_element_value; +import com.sun.tools.classfile.Annotation.Array_element_value; +import com.sun.tools.classfile.Annotation.Class_element_value; +import com.sun.tools.classfile.Annotation.Enum_element_value; +import com.sun.tools.classfile.Annotation.Primitive_element_value; import com.sun.tools.classfile.AnnotationDefault_attribute; import com.sun.tools.classfile.Attribute; import com.sun.tools.classfile.Attributes; @@ -35,8 +39,24 @@ import com.sun.tools.classfile.CharacterRangeTable_attribute; import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.Code_attribute; import com.sun.tools.classfile.CompilationID_attribute; +import com.sun.tools.classfile.ConcealedPackages_attribute; import com.sun.tools.classfile.ConstantPool; -import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Class_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Double_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Fieldref_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Float_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Integer_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_InterfaceMethodref_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_InvokeDynamic_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Long_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodHandle_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_MethodType_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Methodref_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_NameAndType_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_String_info; +import com.sun.tools.classfile.ConstantPool.CONSTANT_Utf8_info; +import com.sun.tools.classfile.ConstantPool.CPInfo; +import com.sun.tools.classfile.ConstantPool.InvalidIndex; import com.sun.tools.classfile.ConstantPoolException; import com.sun.tools.classfile.ConstantValue_attribute; import com.sun.tools.classfile.DefaultAttribute; @@ -45,6 +65,8 @@ import com.sun.tools.classfile.Descriptor.InvalidDescriptor; import com.sun.tools.classfile.EnclosingMethod_attribute; import com.sun.tools.classfile.Exceptions_attribute; import com.sun.tools.classfile.Field; +import com.sun.tools.classfile.Hashes_attribute; +import com.sun.tools.classfile.Hashes_attribute.Entry; import com.sun.tools.classfile.InnerClasses_attribute; import com.sun.tools.classfile.InnerClasses_attribute.Info; import com.sun.tools.classfile.Instruction; @@ -52,8 +74,13 @@ import com.sun.tools.classfile.Instruction.TypeKind; import com.sun.tools.classfile.LineNumberTable_attribute; import com.sun.tools.classfile.LocalVariableTable_attribute; import com.sun.tools.classfile.LocalVariableTypeTable_attribute; +import com.sun.tools.classfile.MainClass_attribute; import com.sun.tools.classfile.Method; import com.sun.tools.classfile.MethodParameters_attribute; +import com.sun.tools.classfile.Module_attribute; +import com.sun.tools.classfile.Module_attribute.ExportsEntry; +import com.sun.tools.classfile.Module_attribute.ProvidesEntry; +import com.sun.tools.classfile.Module_attribute.RequiresEntry; import com.sun.tools.classfile.Opcode; import com.sun.tools.classfile.RuntimeInvisibleAnnotations_attribute; import com.sun.tools.classfile.RuntimeInvisibleParameterAnnotations_attribute; @@ -66,14 +93,22 @@ import com.sun.tools.classfile.SourceDebugExtension_attribute; import com.sun.tools.classfile.SourceFile_attribute; import com.sun.tools.classfile.SourceID_attribute; import com.sun.tools.classfile.StackMapTable_attribute; -import com.sun.tools.classfile.StackMapTable_attribute.*; +import com.sun.tools.classfile.StackMapTable_attribute.append_frame; +import com.sun.tools.classfile.StackMapTable_attribute.chop_frame; +import com.sun.tools.classfile.StackMapTable_attribute.full_frame; +import com.sun.tools.classfile.StackMapTable_attribute.same_frame; +import com.sun.tools.classfile.StackMapTable_attribute.same_frame_extended; +import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame; +import com.sun.tools.classfile.StackMapTable_attribute.same_locals_1_stack_item_frame_extended; import com.sun.tools.classfile.StackMap_attribute; import com.sun.tools.classfile.Synthetic_attribute; +import com.sun.tools.classfile.TargetPlatform_attribute; import com.sun.tools.classfile.TypeAnnotation; import com.sun.tools.classfile.TypeAnnotation.Position; import static com.sun.tools.classfile.TypeAnnotation.TargetType.THROWS; -import java.util.*; +import com.sun.tools.classfile.Version_attribute; import java.io.*; +import java.util.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; import xmlkit.XMLKit.Element; @@ -383,7 +418,9 @@ public class ClassReader { AccessFlags af = new AccessFlags(c.access_flags.flags); klass.setAttr("flags", flagString(af, klass)); if (!"java/lang/Object".equals(thisk)) { - klass.setAttr("super", c.getSuperclassName()); + if (c.super_class != 0) { + klass.setAttr("super", c.getSuperclassName()); + } } for (int i : c.interfaces) { klass.add(new Element("Interface", "name", getCpString(i))); @@ -854,7 +891,6 @@ class ConstantPoolVisitor implements ConstantPool.Visitor { } } - class AttributeVisitor implements Attribute.Visitor { final ClassFile cf; final ClassReader x; @@ -980,6 +1016,21 @@ class AttributeVisitor implements Attribute.Visitor { return null; } + @Override + public Element visitConcealedPackages(ConcealedPackages_attribute attr, Element p) { + Element e = new Element(x.getCpString(attr.attribute_name_index)); + for (int i : attr.packages_index) { + Element ee = new Element("Package"); + String pkg = x.getCpString(i); + ee.setAttr("package", pkg); + e.add(ee); + } + e.trimToSize(); + e.sort(); + p.add(e); + return null; + } + @Override public Element visitConstantValue(ConstantValue_attribute cv, Element p) { Element e = new Element(x.getCpString(cv.attribute_name_index)); @@ -1063,6 +1114,52 @@ class AttributeVisitor implements Attribute.Visitor { return null; // already added to parent } + private void parseModuleRequires(RequiresEntry[] res, Element p) { + for (RequiresEntry re : res) { + Element er = new Element("Requires"); + er.setAttr("module", x.getCpString(re.requires_index)); + er.setAttr("flags", Integer.toString(re.requires_flags)); + p.add(er); + } + } + + private void parseModuleExports(ExportsEntry[] exports, Element p) { + Element ex = new Element("Exports"); + for (ExportsEntry export : exports) { + Element exto = new Element("exports"); + exto.setAttr("package", x.getCpString(export.exports_index)); + for ( int idx : export.exports_to_index) { + exto.setAttr("module", x.getCpString(idx)); + } + ex.add(exto); + } + p.add(ex); + } + + private void parseModuleProvides(ProvidesEntry[] provides, Element p) { + Element ex = new Element("Provides"); + for (ProvidesEntry provide : provides) { + ex.setAttr("provides", x.getCpString(provide.provides_index)); + ex.setAttr("with", x.getCpString(provide.with_index)); + } + p.add(ex); + } + + @Override + public Element visitModule(Module_attribute m, Element p) { + Element e = new Element(x.getCpString(m.attribute_name_index)); + parseModuleRequires(m.requires, e); + parseModuleExports(m.exports, e); + for (int idx : m.uses_index) { + Element ei = new Element("Uses"); + ei.setAttr("used_class", x.getCpString(idx)); + e.add(ei); + } + parseModuleProvides(m.provides, e); + p.add(e); + return null; + } + @Override public Element visitLocalVariableTypeTable(LocalVariableTypeTable_attribute lvtt, Element p) { @@ -1362,6 +1459,52 @@ class AttributeVisitor implements Attribute.Visitor { p.add(e); return null; } + + @Override + public Element visitHashes(Hashes_attribute attr, Element p) { + Element e = new Element(x.getCpString(attr.attribute_name_index)); + e.setAttr("Algorithm", x.getCpString(attr.algorithm_index)); + for (Entry entry : attr.hashes_table) { + Element ee = new Element("Entry"); + String requires = x.getCpString(entry.requires_index); + String hashValue = x.getCpString(entry.hash_index); + ee.setAttr(requires, hashValue); + e.add(ee); + } + e.trimToSize(); + e.sort(); + p.add(e); + return null; + } + + @Override + public Element visitMainClass(MainClass_attribute attr, Element p) { + Element e = new Element(x.getCpString(attr.attribute_name_index)); + e.add(x.getCpString(attr.main_class_index)); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitTargetPlatform(TargetPlatform_attribute attr, Element p) { + Element e = new Element(x.getCpString(attr.attribute_name_index)); + e.add(x.getCpString(attr.os_name_index)); + e.add(x.getCpString(attr.os_arch_index)); + e.add(x.getCpString(attr.os_version_index)); + e.trimToSize(); + p.add(e); + return null; + } + + @Override + public Element visitVersion(Version_attribute attr, Element p) { + Element e = new Element(x.getCpString(attr.attribute_name_index)); + e.add(x.getCpString(attr.version_index)); + e.trimToSize(); + p.add(e); + return null; + } } class StackMapVisitor implements StackMapTable_attribute.stack_map_frame.Visitor { diff --git a/langtools/.hgtags b/langtools/.hgtags index 08776ccc375..a0b11305bf4 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -351,3 +351,5 @@ cb73b474703e2de266542b505cffd658bcc052da jdk-9+99 dd05d3761a341143ef4a6b1a245e0960cc125b76 jdk-9+106 7a0c343551497bd0e38ad69a77cc57d9f396615a jdk-9+107 fd18a155ad22f62e06a9b74850ab8609d415c752 jdk-9+108 +f5991c73ed73b9a355a090b65c8d7fb9a1901f89 jdk-9+109 +9b4c916633f8d61509a3dc6175efdf185b421343 jdk-9+110 diff --git a/langtools/make/CompileInterim.gmk b/langtools/make/CompileInterim.gmk index 2ccd58feaa2..06a13d92ba8 100644 --- a/langtools/make/CompileInterim.gmk +++ b/langtools/make/CompileInterim.gmk @@ -32,23 +32,35 @@ include JavaCompilation.gmk include SetupJavaCompilers.gmk ################################################################################ -# Setup the rules to build the interim langtools jar, which is compiled by -# the boot javac and can be run on the boot jdk. This will be used to compile -# the rest of the product. Include the Genstubs build tool in this compilation -# as it will be used together with the interim javac. -$(eval $(call SetupJavaCompilation,BUILD_INTERIM_LANGTOOLS, \ - SETUP := BOOT_JAVAC, \ - DISABLE_SJAVAC := true, \ - SRC := $(LANGTOOLS_TOPDIR)/src/java.compiler/share/classes \ - $(LANGTOOLS_TOPDIR)/src/jdk.compiler/share/classes \ - $(LANGTOOLS_TOPDIR)/src/jdk.javadoc/share/classes \ - $(LANGTOOLS_TOPDIR)/src/jdk.jdeps/share/classes \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.compiler \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.javadoc \ - $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdeps, \ - EXCLUDES := sun, \ - COPY := .gif .png .xml .css .js javax.tools.JavaCompilerTool, \ - BIN := $(BUILDTOOLS_OUTPUTDIR)/langtools_interim_classes, \ - JAR := $(INTERIM_LANGTOOLS_JAR))) +# Setup the rules to build interim langtools, which is compiled by the boot +# javac and can be run on the boot jdk. This will be used to compile +# the rest of the product. Each module is compiled separately to allow a modular +# boot jdk to override system classes using -Xoverride:. -all: $(BUILD_INTERIM_LANGTOOLS) +# Param 1 - Name of module to compile +# Param 2 - Name of modules to depend on +define SetupInterimModule + $$(eval $$(call SetupJavaCompilation,BUILD_INTERIM_$(strip $1), \ + SETUP := BOOT_JAVAC, \ + DISABLE_SJAVAC := true, \ + SRC := $(LANGTOOLS_TOPDIR)/src/$(strip $1)/share/classes \ + $$(wildcard $(SUPPORT_OUTPUTDIR)/gensrc/$(strip $1)), \ + EXCLUDES := sun com/sun/tools/jdeps com/sun/tools/javap, \ + EXCLUDE_FILES := module-info.java, \ + COPY := .gif .png .xml .css .js javax.tools.JavaCompilerTool, \ + BIN := $(BUILDTOOLS_OUTPUTDIR)/override_modules/$(strip $1), \ + ADD_JAVAC_FLAGS := -Xbootclasspath/p:$$(call PathList, \ + $$(foreach m, $2, $(BUILDTOOLS_OUTPUTDIR)/override_modules/$$m)), \ + )) + + $$(BUILD_INTERIM_$(strip $1)): $$(foreach m, $2, $$(BUILD_INTERIM_$(strip $$m))) + + TARGETS += $$(BUILD_INTERIM_$(strip $1)) +endef + +$(eval $(call SetupInterimModule, java.compiler)) +$(eval $(call SetupInterimModule, jdk.compiler, java.compiler)) +$(eval $(call SetupInterimModule, jdk.jdeps, jdk.compiler java.compiler)) +$(eval $(call SetupInterimModule, jdk.javadoc, java.compiler jdk.compiler)) + +all: $(TARGETS) diff --git a/langtools/make/build.properties b/langtools/make/build.properties index fdc1aa05c0b..38939fa856f 100644 --- a/langtools/make/build.properties +++ b/langtools/make/build.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -24,58 +24,13 @@ # #javac configuration for "normal build" (these will be passed to the bootstrap compiler): -javac.debug = true -javac.debuglevel = source,lines,vars -javac.extra.opts=-XDignore.symbol.file=true -javac.includes= -javac.lint.opts = -Xlint:all,-deprecation -Werror -javac.source = 8 -javac.target = 8 +javac.opts = -XDignore.symbol.file=true -Xlint:all,-deprecation,-options -Werror -g:source,lines,vars +javac.source = 9 +javac.target = 9 -#javac configuration for bootstrap build (these will be passed to the compiler from the given boot JDK): -boot.javac.extra.opts=-XDignore.symbol.file=true -boot.javac.includes = \ - javax/annotation/processing/ \ - javax/lang/model/ \ - javax/tools/ \ - jdk/ \ - com/sun/source/ \ - com/sun/tools/javac/ \ - com/sun/tools/doclint/ -boot.javac.lint.opts= -boot.javac.source = 8 -boot.javac.target = 8 - -#configuration of submodules (share by both the bootstrap and normal compilation): -langtools.modules=java.compiler:jdk.compiler:jdk.jdeps:jdk.javadoc:jdk.jshell:jdk.internal.le:jdk.jdi -java.compiler.dependencies= -jdk.compiler.dependencies=java.compiler -jdk.javadoc.dependencies=java.compiler:jdk.compiler -jdk.jdeps.dependencies=java.compiler:jdk.compiler -jdk.internal.le.dependencies= -jdk.jdi.dependencies= -jdk.jshell.dependencies=java.compiler:jdk.internal.le:jdk.compiler:jdk.jdi - -tool.javac.main.class=com.sun.tools.javac.Main -tool.javadoc.main.class=com.sun.tools.javadoc.Main -tool.javap.main.class=com.sun.tools.javap.Main -tool.javah.main.class=com.sun.tools.javah.Main -tool.sjavac.main.class=com.sun.tools.sjavac.Main -tool.jshell.main.class=jdk.internal.jshell.tool.JShellTool - -javac.resource.includes = \ +langtools.resource.includes = \ com/sun/tools/javac/resources/compiler.properties -#test configuration: -jtreg.tests= -boot.javac.tests = tools/javac -crules.tests = ../make/test/crules - -#javadoc configuration -javadoc.jls.cite=The Java™ Language Specification -javadoc.jls.option=-tag "jls:a:See <cite>${javadoc.jls.cite}</cite>:" \ - -tag "implNote:a:Implementation Note:" - # Version info -- override as needed jdk.version = 9 build.number = b00 @@ -89,3 +44,14 @@ milestone = internal # FIXME -- need to include openjdk as needed release = ${jdk.version}-${milestone} full.version = ${release}+${build.number} + +#tools configuration: +tool.javac.main.class=com.sun.tools.javac.Main +tool.javadoc.main.class=jdk.javadoc.internal.tool.Main +tool.javap.main.class=com.sun.tools.javap.Main +tool.javah.main.class=com.sun.tools.javah.Main +tool.sjavac.main.class=com.sun.tools.sjavac.Main +tool.jshell.main.class=jdk.internal.jshell.tool.JShellTool + +#test configuration: +jtreg.tests= diff --git a/langtools/make/build.xml b/langtools/make/build.xml index 051eae55c68..ee0c3281c49 100644 --- a/langtools/make/build.xml +++ b/langtools/make/build.xml @@ -1,28 +1,28 @@ + ~ Copyright (c) 2007, 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. + --> @@ -80,25 +70,19 @@ - - - - - - - - - - + + - + + + + + + + - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ant.home = ${ant.home} - boot.java.home = ${boot.java.home} - target.java.home = ${target.java.home} - jtreg.home = ${jtreg.home} - findbugs.home = ${findbugs.home} - checkstyle.home = ${checkstyle.home} - - - - - - - - - - - - - - - - - - crules.CodingRulesAnalyzerPlugin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Unofficial Javadoc generated from developer sources for preview purposes only]]>
        - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        -
        -
        -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + @@ -917,5 +143,207 @@ -
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        diff --git a/langtools/make/gendata/Gendata-jdk.compiler.gmk b/langtools/make/gendata/Gendata-jdk.compiler.gmk index 2e89ce75b33..613e7133a05 100644 --- a/langtools/make/gendata/Gendata-jdk.compiler.gmk +++ b/langtools/make/gendata/Gendata-jdk.compiler.gmk @@ -39,6 +39,10 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \ BIN := $(BUILDTOOLS_OUTPUTDIR)/create_symbols, \ )) +ifeq ($(BOOT_JDK_MODULAR), true) + COMPILECREATESYMBOLS_ADD_EXPORTS := -XaddExports:jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED,jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED,jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED +endif + $(SUPPORT_OUTPUTDIR)/symbols/ct.sym-files/_the.symbols: \ $(COMPILE_CREATE_SYMBOLS) \ $(wildcard $(LANGTOOLS_TOPDIR)/make/data/symbols/*) @@ -46,6 +50,7 @@ $(SUPPORT_OUTPUTDIR)/symbols/ct.sym-files/_the.symbols: \ $(MKDIR) -p $(@D) $(ECHO) Creating ct.sym classes $(JAVA) $(INTERIM_LANGTOOLS_ARGS) \ + $(COMPILECREATESYMBOLS_ADD_EXPORTS) \ -classpath $(BUILDTOOLS_OUTPUTDIR)/create_symbols \ build.tools.symbolgenerator.CreateSymbols \ build-ctsym \ diff --git a/langtools/make/intellij/ant.xml b/langtools/make/intellij/ant.xml index a0570d25d90..e052d8b04b1 100644 --- a/langtools/make/intellij/ant.xml +++ b/langtools/make/intellij/ant.xml @@ -3,16 +3,12 @@ - - + - - + - - diff --git a/langtools/make/intellij/build.xml b/langtools/make/intellij/build.xml index 2be2b302942..a6f1bd2fea8 100644 --- a/langtools/make/intellij/build.xml +++ b/langtools/make/intellij/build.xml @@ -15,8 +15,7 @@ - - + @@ -28,18 +27,13 @@ - - - - - + - + - diff --git a/langtools/make/intellij/langtools.iml b/langtools/make/intellij/langtools.iml index 582abf11192..29ff589f35c 100644 --- a/langtools/make/intellij/langtools.iml +++ b/langtools/make/intellij/langtools.iml @@ -8,12 +8,11 @@ - - - - - + + + + diff --git a/langtools/make/intellij/src/idea/LangtoolsIdeaAntLogger.java b/langtools/make/intellij/src/idea/LangtoolsIdeaAntLogger.java index 759e5bf7c28..ba4ce9500a6 100644 --- a/langtools/make/intellij/src/idea/LangtoolsIdeaAntLogger.java +++ b/langtools/make/intellij/src/idea/LangtoolsIdeaAntLogger.java @@ -124,8 +124,8 @@ public final class LangtoolsIdeaAntLogger extends DefaultLogger { * This enum is used to represent the list of tasks we need to keep track of during logging. */ enum Task { - /** javac task - invoked during compilation */ - JAVAC("javac", MessageKind.JAVAC_ERROR, MessageKind.JAVAC_WARNING, MessageKind.JAVAC_NOTE, + /** exec task - invoked during compilation */ + JAVAC("exec", MessageKind.JAVAC_ERROR, MessageKind.JAVAC_WARNING, MessageKind.JAVAC_NOTE, MessageKind.JAVAC_NESTED_DIAG, MessageKind.JAVAC_CRASH), /** jtreg task - invoked during test execution */ JTREG("jtreg", MessageKind.JTREG_TEST_PASSED, MessageKind.JTREG_TEST_FAILED, MessageKind.JTREG_TEST_ERROR, MessageKind.JTREG_TEST_REPORT), diff --git a/langtools/make/intellij/workspace.xml b/langtools/make/intellij/workspace.xml index c2d0742f23e..dc21405c632 100644 --- a/langtools/make/intellij/workspace.xml +++ b/langtools/make/intellij/workspace.xml @@ -7,14 +7,14 @@