This commit is contained in:
J. Duke 2017-07-05 21:27:59 +02:00
commit f5225b6550
1523 changed files with 113507 additions and 17140 deletions

View File

@ -352,3 +352,4 @@ be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105
4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107
c7be2a78c31b3b6132f2f5e9e4b3d3bb1c20245c jdk-9+108
1787bdaabb2b6f4193406e25a50cb0419ea8e8f3 jdk-9+109
925be13b3740d07a5958ccb5ab3c0ae1baba7055 jdk-9+110

View File

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

View File

@ -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)
])

View File

@ -25,6 +25,8 @@
# Support for building boot cycle builds
BOOT_JDK_MODULAR := true
# First include the real base spec.gmk file
include @SPEC@

View File

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

View File

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

View File

@ -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)
])

File diff suppressed because it is too large Load Diff

View File

@ -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)
])

View File

@ -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..?

View File

@ -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)
])

View File

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

View File

@ -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"

View File

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

View File

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

View File

@ -512,3 +512,4 @@ c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103
c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107
934f6793f5f7dca44f69b4559d525fa64b31840d jdk-9+108
7e7e50ac4faf19899fc811569e32cfa478759ebb jdk-9+109
2f5d1578b24060ea06bd1f340a124db95d1475b2 jdk-9+110

View File

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

View File

@ -45,6 +45,7 @@ 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 \

View File

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

View File

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

View File

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

View File

@ -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(" <no option>\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 <file> <args...>
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);
}
}

View File

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

View File

@ -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() {

View File

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

View File

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

View File

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

View File

@ -1,3 +0,0 @@
jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory
jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory
jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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<Klass*>* 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<count; k++) {
unsigned char b0 = buffer[i];
unsigned char b1 = buffer[i+1];
unsigned char b2 = buffer[i+2];
unsigned char b3 = buffer[i+3];
// For an unsigned char v,
// (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
// (v | v - 1) is >= 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 <clinit>. Note that method names may not be <init> or <clinit> 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<Method*>* 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)) {

View File

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

View File

@ -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"
@ -138,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<char*>* ClassLoader::_boot_modules_array = NULL;
GrowableArray<char*>* 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);
@ -162,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) {
@ -356,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);
@ -409,11 +449,11 @@ 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) {
@ -480,7 +520,7 @@ void ClassLoader::setup_bootstrap_search_path() {
_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
@ -500,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) {
@ -512,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);
@ -616,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;
@ -641,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) {
@ -654,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 {
@ -760,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<mtClass> {
public:
const char* _pkgname; // Package name
int _classpath_index; // Index of directory or JAR file loaded from
PackageInfo* next() {
return (PackageInfo*)BasicHashtableEntry<mtClass>::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<mtClass> {
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<mtClass>::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<mtClass>(table_size, sizeof(PackageInfo)) {}
PackageHashtable(int table_size, HashtableBucket<mtClass>* t, int number_of_entries)
: BasicHashtable<mtClass>(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<mtClass>::new_entry(hash);
pp->set_pkgname(pkgname);
return pp;
}
void add_entry(PackageInfo* pp) {
int index = hash_to_index(pp->hash());
BasicHashtable<mtClass>::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<mtClass>::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<char*>(INITIAL_BOOT_MODULES_ARRAY_SIZE, true);
_platform_modules_array = new (ResourceObj::C_HEAP, mtInternal)
GrowableArray<char*>(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<PackageEntry*>* loaded_class_pkgs = new GrowableArray<PackageEntry*>(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) {
@ -1018,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");
@ -1037,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:<dirs>]; [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;
}
}
@ -1085,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<mtClass> *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<mtClass>),
"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) {
@ -1258,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
//
@ -1325,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);
@ -1350,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);
@ -1366,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();

View File

@ -33,8 +33,17 @@
// The VM class loader.
#include <sys/stat.h>
// 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 <MEMFLAGS F> 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<char*>* _boot_modules_array;)
// Array of module names associated with the platform class loader
CDS_ONLY(static GrowableArray<char*>* _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<mtClass> *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,7 +364,12 @@ 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);
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);
@ -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;

View File

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

View File

@ -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<mtClass> {
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<mtClass> {
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<mtClass> {
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<mtClass> {
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);

View File

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

View File

@ -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<Klass*>* list =
new (ResourceObj::C_HEAP, mtClass) GrowableArray<Klass*>(500, true);
set_fixup_module_field_list(list);
}
fixup_module_field_list()->push(k());
}
} else {
if (fixup_mirror_list() == NULL) {
GrowableArray<Klass*>* 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<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
GrowableArray<Klass*>* 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

View File

@ -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<Klass*>* _fixup_mirror_list;
static GrowableArray<Klass*>* _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<Klass*>* fixup_mirror_list() {
return _fixup_mirror_list;
}
static void set_fixup_mirror_list(GrowableArray<Klass*>* v) {
_fixup_mirror_list = v;
}
static GrowableArray<Klass*>* fixup_module_field_list() {
return _fixup_module_field_list;
}
static void set_fixup_module_field_list(GrowableArray<Klass*>* 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

View File

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

View File

@ -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);
* ...

View File

@ -103,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,
@ -125,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;

View File

@ -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<ModuleEntry*>(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<Symbol*, mtClass>(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<Symbol*, mtClass>::add_entry(index, (HashtableEntry<Symbol*, mtClass>*)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 <Klass*>* 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.");
}

View File

@ -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<Symbol*, mtClass> {
private:
jobject _module; // java.lang.reflect.Module
jobject _pd; // java.security.ProtectionDomain, cached
// for shared classes from this module
ClassLoaderData* _loader;
GrowableArray<ModuleEntry*>* _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<Symbol*, mtClass>::next();
}
ModuleEntry** next_addr() {
return (ModuleEntry**)HashtableEntry<Symbol*, mtClass>::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<Symbol*, mtClass> {
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<mtClass>::entry_size(); }
ModuleEntry** bucket_addr(int i) {
return (ModuleEntry**)Hashtable<Symbol*, mtClass>::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<Symbol*, mtClass>::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

View File

@ -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:<dirs> was specified. If so, prepend each <dir>/module_name,
// if it exists, to bootpath so boot loader can find the class files. Also, if
// using exploded modules, append <java.home>/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 <patch-dir>/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/<module-name>
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<Symbol*>* pkg_list = new GrowableArray<Symbol*>(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<Symbol*>* pkg_list = new GrowableArray<Symbol*>(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:<path> was specified. If
// so prepend <path>/module_name, if it exists, to bootpath. Also, if using
// exploded modules, prepend <java.home>/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();
}
}
}

View File

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

View File

@ -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<ModuleEntry*>(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<Symbol*, mtClass>(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<Symbol*, mtClass>::add_entry(index, (HashtableEntry<Symbol*, mtClass>*)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<Symbol*> *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));
}
}
}

View File

@ -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<Symbol*, mtClass> {
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<ModuleEntry*>* _exported_pending_delete; // transitioned from qualified to unqualified, delete at safepoint
GrowableArray<ModuleEntry*>* _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<Symbol*, mtClass>::next();
}
PackageEntry** next_addr() {
return (PackageEntry**)HashtableEntry<Symbol*, mtClass>::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<Symbol*, mtClass> {
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<mtClass>::entry_size(); }
PackageEntry** bucket_addr(int i) {
return (PackageEntry**)Hashtable<Symbol*, mtClass>::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<Symbol*, mtClass>::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<Symbol*> *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

View File

@ -77,7 +77,7 @@ void SharedPathsMiscInfo::print_path(int type, const char* path) {
outputStream* out = LogHandle(classpath)::info_stream();
switch (type) {
case BOOT:
out->print("Expecting -Dsun.boot.class.path=%s", path);
out->print("Expecting BOOT path=%s", path);
break;
case NON_EXIST:
out->print("Expecting that %s does not exist", path);
@ -126,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

View File

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

View File

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

View File

@ -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,

View File

@ -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") \

View File

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

View File

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

View File

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

View File

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

View File

@ -62,6 +62,7 @@
LOG_TAG(logging) \
LOG_TAG(marking) \
LOG_TAG(metaspace) \
LOG_TAG(modules) \
LOG_TAG(monitorinflation) \
LOG_TAG(os) \
LOG_TAG(phases) \

View File

@ -226,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;
}
}
@ -282,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;
@ -291,7 +300,7 @@ 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);
}
}
@ -871,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;

View File

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

View File

@ -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<mtClass>*)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);

View File

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

View File

@ -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!");

View File

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

View File

@ -95,11 +95,18 @@ ArrayKlass::ArrayKlass(Symbol* name) :
// 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<Klass*>* ArrayKlass::compute_secondary_supers(int num_extra_slots) {

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -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<Method*>* 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 =

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -319,8 +319,6 @@ class LibraryCallKit : public GraphKit {
bool inline_profileBoolean();
bool inline_isCompileConstant();
bool inline_deoptimize();
};
//---------------------------make_vm_intrinsic----------------------------
@ -821,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.
@ -6754,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;
}

View File

@ -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"

View File

@ -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"
@ -3443,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,
@ -3722,7 +3765,13 @@ struct JNINativeInterface_ jni_NativeInterface = {
// New 1_6 features
jni_GetObjectRefType
jni_GetObjectRefType,
// Module features
jni_GetModule,
jni_AddModuleReads,
jni_CanReadModule
};

View File

@ -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 */
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 //////////////////////////////////////////////////////////////////////////////

View File

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

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="jvmti.xsl"?>
<!--
Copyright (c) 2002, 2013, 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
@ -21,7 +21,7 @@
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
or visit www.oracle.com if you need additional information or have any
questions.
-->
<!DOCTYPE specification [
@ -356,9 +356,9 @@
]>
<specification label="JVM(TM) Tool Interface"
majorversion="1"
minorversion="2"
microversion="3">
majorversion="9"
minorversion="0"
microversion="0">
<title subtitle="Version">
<tm>JVM</tm> Tool Interface
</title>
@ -863,6 +863,23 @@ Agent_OnUnload_L(JavaVM *vm)</example>
to be instrumented by the use of wrapper methods.
</intro>
<intro id="bcimodules" label="Bytecode Instrumentation of code in modules">
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 <code>public</code> and in a package that is exported by its module.
Agents can use the JNI functions <code>CanReadModule</code> and
<code>AddModuleReads</code> to test and update a module to read another.
<p/>
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 <eventlink id="ClassFileLoadHook"/> event to
read the unnamed module of both class loaders.
</intro>
<intro id="mUTF" label="Modified UTF-8 String Encoding">
<jvmti/> uses modified UTF-8 to encode character strings.
This is the same encoding used by JNI.
@ -1880,10 +1897,6 @@ jvmtiEnv *jvmti;
<outptr><struct>jvmtiThreadInfo</struct></outptr>
<description>
On return, filled with information describing the specified thread.
<p/>
For JDK 1.1 implementations that don't
recognize context class loaders,
the <code>context_class_loader</code> field will be NULL.
</description>
</param>
</parameters>
@ -6460,6 +6473,43 @@ class C2 extends C1 implements I2 {
</function>
</category>
<category id="module" label="Module">
<intro>
</intro>
<function id="GetAllModules" num="3" since="9">
<synopsis>Get All Modules</synopsis>
<description>
Return an array of all modules loaded in the virtual machine.
The number of modules in the array is returned via
<code>module_count_ptr</code>, and the array itself via
<code>modules_ptr</code>.
<p/>
</description>
<origin>new</origin>
<capabilities>
</capabilities>
<parameters>
<param id="module_count_ptr">
<outptr><jint/></outptr>
<description>
On return, points to the number of returned modules.
</description>
</param>
<param id="modules_ptr">
<allocbuf outcount="module_count_ptr"><jobject/></allocbuf>
<description>
On return, points to an array of references, one
for each module.
</description>
</param>
</parameters>
<errors>
</errors>
</function>
</category>
<category id="class" label="Class">
<intro>
@ -6508,9 +6558,6 @@ class C2 extends C1 implements I2 {
either by defining it directly or by delegation to another class loader.
See <vmspec chapter="5.3"/>.
<p/>
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
<code>class_count_ptr</code>, and the array itself via
<code>classes_ptr</code>.
@ -9941,6 +9988,12 @@ myInit() {
See <eventlink id="ResourceExhausted"/>.
</description>
</capabilityfield>
<capabilityfield id="can_generate_early_vmstart" since="9">
<description>
Can generate the <code>VMStart</code> event early.
See <eventlink id="VMStart"/>.
</description>
</capabilityfield>
</capabilitiestypedef>
<function id="GetPotentialCapabilities" jkernel="yes" phase="onload" num="140">
@ -12351,7 +12404,7 @@ myInit() {
</parameters>
</event>
<event label="Class File Load Hook" phase="any"
<event label="Class File Load Hook" phase="start"
id="ClassFileLoadHook" const="JVMTI_EVENT_CLASS_FILE_LOAD_HOOK" num="54">
<description>
This event is sent when the VM obtains class file data,
@ -12367,9 +12420,9 @@ myInit() {
<internallink id="bci">bytecode instrumentation</internallink>
for usage information.
<p/>
This event may be sent before the VM is initialized (the primordial
<functionlink id="GetPhase">phase</functionlink>). 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
<functionlink id="GetPhase">phase</functionlink>).
Some classes might not be compatible
with the function (eg. ROMized classes) and this event will not be
generated for these classes.
<p/>
@ -12378,9 +12431,7 @@ myInit() {
using the memory allocation function
<functionlink id="Allocate"></functionlink> because the
VM is responsible for freeing the new class file data buffer
using <functionlink id="Deallocate"></functionlink>.
Note that <functionlink id="Allocate"></functionlink>
is permitted during the primordial phase.
using <functionlink id="Deallocate"></functionlink>.
<p/>
If the agent wishes to modify the class file, it must set
<code>new_class_data</code> to point
@ -12427,8 +12478,6 @@ myInit() {
</outptr>
<description>
The JNI environment of the event (current) thread.
Will be <code>NULL</code> if sent during the primordial
<functionlink id="GetPhase">phase</functionlink>.
</description>
</param>
<param id="class_being_redefined">
@ -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,
<jvmti/> functions permitted in the start phase may be called.
<p/>
The timing of this event may depend on whether the agent has added the
<internallink id="jvmtiCapabilities.can_generate_early_vmstart">
<code>can_generate_early_vmstart</code></internallink> 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
<code>java.base</code>. 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
<code>FindClass</code> as it may not be possible to load classes that are
not in the <code>java.base</code> 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
<code>java.base</code> 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.
<p/>
In the case of VM start-up failure, this event will not be sent.
</description>
<origin>jvmdi</origin>
@ -12576,7 +12644,7 @@ myInit() {
</parameters>
</event>
<event label="Compiled Method Load"
<event label="Compiled Method Load" phase="start"
id="CompiledMethodLoad" const="JVMTI_EVENT_COMPILED_METHOD_LOAD" num="68">
<description>
Sent when a method is compiled and loaded into memory by the VM.
@ -12667,7 +12735,7 @@ myInit() {
</parameters>
</event>
<event label="Compiled Method Unload"
<event label="Compiled Method Unload" phase="start"
id="CompiledMethodUnload" const="JVMTI_EVENT_COMPILED_METHOD_UNLOAD" num="69">
<description>
Sent when a compiled method is unloaded from memory.
@ -14340,6 +14408,17 @@ typedef void (JNICALL *jvmtiEventVMInit)
<change date="19 June 2013" version="1.2.3">
Added support for statically linked agents.
</change>
<change date="20 January 2016" version="9.0.0">
Support for modules:
- The majorversion is 9 now
- The ClassFileLoadHook events are not sent during the primordial phase anymore.
- Add new function GetAllModules
</change>
<change date="17 February 2016" version="9.0.0">
Support for modules:
- Add new capability can_generate_early_vmstart
- Allow CompiledMethodLoad events at start phase
</change>
</changehistory>
</specification>

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
Copyright (c) 2002, 2006, 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
@ -1801,7 +1801,7 @@ typedef struct {
<xsl:text>) (jvmtiEnv* env</xsl:text>
<xsl:apply-templates select="$thisFunction/parameters" mode="signature">
<xsl:with-param name="comma">
<xsl:text>, &#xA; </xsl:text>
<xsl:text>,&#xA; </xsl:text>
</xsl:with-param>
</xsl:apply-templates>
<xsl:text>);</xsl:text>

View File

@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
Copyright (c) 2002, 2015, 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
@ -517,7 +517,7 @@ static jvmtiError JNICALL
}</xsl:text>
</xsl:if>
<xsl:if test="contains(@phase,'start')">
<xsl:text> if(JvmtiEnv::get_phase()!=JVMTI_PHASE_START &amp;&amp; JvmtiEnv::get_phase()!=JVMTI_PHASE_LIVE) {
<xsl:text> if(JvmtiEnv::get_phase(env)!=JVMTI_PHASE_START &amp;&amp; JvmtiEnv::get_phase()!=JVMTI_PHASE_LIVE) {
</xsl:text>
<xsl:if test="$trace='Trace'">
<xsl:text> if (trace_flags) {

View File

@ -186,6 +186,20 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) {
return JVMTI_ERROR_NONE;
} /* end GetThreadLocalStorage */
//
// Module functions
//
// module_count_ptr - pre-checked for NULL
// modules_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetAllModules(jint* module_count_ptr, jobject** modules_ptr) {
JvmtiModuleClosure jmc;
return jmc.get_all_modules(this, module_count_ptr, modules_ptr);
} /* end GetAllModules */
//
// Class functions
//
@ -563,7 +577,7 @@ JvmtiEnv::AddToSystemClassLoaderSearch(const char* segment) {
// phase_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetPhase(jvmtiPhase* phase_ptr) {
*phase_ptr = get_phase();
*phase_ptr = phase();
return JVMTI_ERROR_NONE;
} /* end GetPhase */
@ -3489,7 +3503,7 @@ JvmtiEnv::SetSystemProperty(const char* property, const char* value_ptr) {
for (SystemProperty* p = Arguments::system_properties(); p != NULL; p = p->next()) {
if (strcmp(property, p->key()) == 0) {
if (p->set_value(value_ptr)) {
if (p->set_writeable_value(value_ptr)) {
err = JVMTI_ERROR_NONE;
}
}

View File

@ -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
@ -114,6 +114,17 @@ JvmtiEnvBase::initialize() {
}
}
jvmtiPhase
JvmtiEnvBase::phase() {
// For the JVMTI environments possessed the can_generate_early_vmstart:
// replace JVMTI_PHASE_PRIMORDIAL with JVMTI_PHASE_START
if (_phase == JVMTI_PHASE_PRIMORDIAL &&
JvmtiExport::early_vmstart_recorded() &&
early_vmstart_env()) {
return JVMTI_PHASE_START;
}
return _phase; // Normal case
}
bool
JvmtiEnvBase::is_valid() {
@ -1475,3 +1486,35 @@ JvmtiMonitorClosure::do_monitor(ObjectMonitor* mon) {
}
}
}
GrowableArray<jobject>* JvmtiModuleClosure::_tbl = NULL;
jvmtiError
JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr) {
ResourceMark rm;
MutexLocker ml(Module_lock);
_tbl = new GrowableArray<jobject>(77);
if (_tbl == NULL) {
return JVMTI_ERROR_OUT_OF_MEMORY;
}
// Iterate over all the modules loaded to the system.
ClassLoaderDataGraph::modules_do(&do_module);
jint len = _tbl->length();
guarantee(len > 0, "at least one module must be present");
jobject* array = (jobject*)env->jvmtiMalloc((jlong)(len * sizeof(jobject)));
if (array == NULL) {
return JVMTI_ERROR_OUT_OF_MEMORY;
}
for (jint idx = 0; idx < len; idx++) {
array[idx] = _tbl->at(idx);
}
_tbl = NULL;
*modules_ptr = array;
*module_count_ptr = len;
return JVMTI_ERROR_NONE;
}

View File

@ -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
@ -75,6 +75,7 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
};
static jvmtiPhase get_phase() { return _phase; }
static jvmtiPhase get_phase(jvmtiEnv* env) { return ((JvmtiEnvBase*)JvmtiEnv_from_jvmti_env(env))->phase(); }
static void set_phase(jvmtiPhase phase) { _phase = phase; }
static bool is_vm_live() { return _phase == JVMTI_PHASE_LIVE; }
@ -140,6 +141,7 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
public:
jvmtiPhase phase();
bool is_valid();
bool use_version_1_0_semantics(); // agent asked for version 1.0
@ -160,6 +162,10 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
jvmtiCapabilities *get_prohibited_capabilities() { return &_prohibited_capabilities; }
bool early_vmstart_env() {
return get_capabilities()->can_generate_early_vmstart != 0;
}
static char** get_all_native_method_prefixes(int* count_ptr);
// This test will answer true when all environments have been disposed and some have
@ -689,4 +695,21 @@ class JvmtiMonitorClosure: public MonitorClosure {
jvmtiError error() { return _error;}
};
// Jvmti module closure to collect all modules loaded to the system.
class JvmtiModuleClosure : public StackObj {
private:
static GrowableArray<jobject> *_tbl; // Protected with Module_lock
static void do_module(ModuleEntry* entry) {
assert_locked_or_safepoint(Module_lock);
jobject module = entry->module();
guarantee(module != NULL, "module object is NULL");
_tbl->push(module);
}
public:
jvmtiError get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobject** modules_ptr);
};
#endif // SHARE_VM_PRIMS_JVMTIENVBASE_HPP

View File

@ -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
@ -98,6 +98,7 @@ static const jlong NEED_THREAD_LIFE_EVENTS = THREAD_FILTERED_EVENT_BITS | THREA
static const jlong EARLY_EVENT_BITS = CLASS_FILE_LOAD_HOOK_BIT |
VM_START_BIT | VM_INIT_BIT | VM_DEATH_BIT | NATIVE_METHOD_BIND_BIT |
THREAD_START_BIT | THREAD_END_BIT |
COMPILED_METHOD_LOAD_BIT | COMPILED_METHOD_UNLOAD_BIT |
DYNAMIC_CODE_GENERATED_BIT;
static const jlong GLOBAL_EVENT_BITS = ~THREAD_FILTERED_EVENT_BITS;
static const jlong SHOULD_POST_ON_EXCEPTIONS_BITS = EXCEPTION_BITS | METHOD_EXIT_BIT | FRAME_POP_BIT;
@ -409,7 +410,7 @@ JvmtiEventControllerPrivate::recompute_env_enabled(JvmtiEnvBase* env) {
env->env_event_enable()->_event_callback_enabled.get_bits() &
env->env_event_enable()->_event_user_enabled.get_bits();
switch (JvmtiEnv::get_phase()) {
switch (env->phase()) {
case JVMTI_PHASE_PRIMORDIAL:
case JVMTI_PHASE_ONLOAD:
// only these events allowed in primordial or onload phase
@ -576,8 +577,6 @@ JvmtiEventControllerPrivate::recompute_enabled() {
// filtered events and there weren't last time
if ( (any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) != 0 &&
(was_any_env_thread_enabled & THREAD_FILTERED_EVENT_BITS) == 0) {
assert(JvmtiEnv::is_vm_live() || (JvmtiEnv::get_phase()==JVMTI_PHASE_START),
"thread filtered events should not be enabled when VM not in start or live phase");
{
MutexLocker mu(Threads_lock); //hold the Threads_lock for the iteration
for (JavaThread *tp = Threads::first(); tp != NULL; tp = tp->next()) {

View File

@ -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
@ -46,6 +46,7 @@
#include "runtime/arguments.hpp"
#include "runtime/handles.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/objectMonitor.inline.hpp"
#include "runtime/os.inline.hpp"
@ -369,6 +370,14 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
return JNI_EVERSION; // unsupported minor version number
}
break;
case 9:
switch (minor) {
case 0: // version 9.0.<micro> is recognized
break;
default:
return JNI_EVERSION; // unsupported minor version number
}
break;
default:
return JNI_EVERSION; // unsupported major version number
}
@ -397,6 +406,28 @@ JvmtiExport::get_jvmti_interface(JavaVM *jvm, void **penv, jint version) {
}
}
void
JvmtiExport::add_default_read_edges(Handle h_module, TRAPS) {
if (!Universe::is_module_initialized()) {
return; // extra safety
}
assert(!h_module.is_null(), "module should always be set");
// Invoke the transformedByAgent method
JavaValue result(T_VOID);
JavaCalls::call_static(&result,
SystemDictionary::module_Modules_klass(),
vmSymbols::transformedByAgent_name(),
vmSymbols::transformedByAgent_signature(),
h_module,
THREAD);
if (HAS_PENDING_EXCEPTION) {
java_lang_Throwable::print(PENDING_EXCEPTION, tty);
CLEAR_PENDING_EXCEPTION;
return;
}
}
void
JvmtiExport::decode_version_values(jint version, int * major, int * minor,
@ -410,6 +441,11 @@ void JvmtiExport::enter_primordial_phase() {
JvmtiEnvBase::set_phase(JVMTI_PHASE_PRIMORDIAL);
}
void JvmtiExport::enter_early_start_phase() {
JvmtiManageCapabilities::recompute_always_capabilities();
set_early_vmstart_recorded(true);
}
void JvmtiExport::enter_start_phase() {
JvmtiManageCapabilities::recompute_always_capabilities();
JvmtiEnvBase::set_phase(JVMTI_PHASE_START);
@ -428,6 +464,28 @@ void JvmtiExport::enter_live_phase() {
// and call the agent's premain() for java.lang.instrument.
//
void JvmtiExport::post_early_vm_start() {
EVT_TRIG_TRACE(JVMTI_EVENT_VM_START, ("JVMTI Trg Early VM start event triggered" ));
// can now enable some events
JvmtiEventController::vm_start();
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
// Only early vmstart envs post early VMStart event
if (env->early_vmstart_env() && env->is_enabled(JVMTI_EVENT_VM_START)) {
EVT_TRACE(JVMTI_EVENT_VM_START, ("JVMTI Evt Early VM start event sent" ));
JavaThread *thread = JavaThread::current();
JvmtiThreadEventMark jem(thread);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventVMStart callback = env->callbacks()->VMStart;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jem.jni_env());
}
}
}
}
void JvmtiExport::post_vm_start() {
EVT_TRIG_TRACE(JVMTI_EVENT_VM_START, ("JVMTI Trg VM start event triggered" ));
@ -436,7 +494,8 @@ void JvmtiExport::post_vm_start() {
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
if (env->is_enabled(JVMTI_EVENT_VM_START)) {
// Early vmstart envs do not post normal VMStart event
if (!env->early_vmstart_env() && env->is_enabled(JVMTI_EVENT_VM_START)) {
EVT_TRACE(JVMTI_EVENT_VM_START, ("JVMTI Evt VM start event sent" ));
JavaThread *thread = JavaThread::current();
@ -544,6 +603,21 @@ class JvmtiClassFileLoadHookPoster : public StackObj {
if (_state != NULL) {
_h_class_being_redefined = _state->get_class_being_redefined();
_load_kind = _state->get_class_load_kind();
Klass* klass = (_h_class_being_redefined == NULL) ? NULL : (*_h_class_being_redefined)();
if (_load_kind != jvmti_class_load_kind_load && klass != NULL) {
ModuleEntry* module_entry = InstanceKlass::cast(klass)->module();
assert(module_entry != NULL, "module_entry should always be set");
if (module_entry->is_named() &&
module_entry->module() != NULL &&
!module_entry->has_default_read_edges()) {
if (!module_entry->set_has_default_read_edges()) {
// We won a potential race.
// Add read edges to the unnamed modules of the bootstrap and app class loaders
Handle class_module(_thread, JNIHandles::resolve(module_entry->module())); // Obtain j.l.r.Module
JvmtiExport::add_default_read_edges(class_module, _thread);
}
}
}
// Clear class_being_redefined flag here. The action
// from agent handler could generate a new class file load
// hook event and if it is not cleared the new event generated
@ -591,6 +665,9 @@ class JvmtiClassFileLoadHookPoster : public StackObj {
}
void post_to_env(JvmtiEnv* env, bool caching_needed) {
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
return;
}
unsigned char *new_data = NULL;
jint new_len = 0;
// EVT_TRACE(JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
@ -602,11 +679,9 @@ class JvmtiClassFileLoadHookPoster : public StackObj {
_h_protection_domain,
_h_class_being_redefined);
JvmtiJavaThreadEventTransition jet(_thread);
JNIEnv* jni_env = (JvmtiEnv::get_phase() == JVMTI_PHASE_PRIMORDIAL)?
NULL : jem.jni_env();
jvmtiEventClassFileLoadHook callback = env->callbacks()->ClassFileLoadHook;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jni_env,
(*callback)(env->jvmti_external(), jem.jni_env(),
jem.class_being_redefined(),
jem.jloader(), jem.class_name(),
jem.protection_domain(),
@ -668,6 +743,10 @@ void JvmtiExport::post_class_file_load_hook(Symbol* h_name,
unsigned char **data_ptr,
unsigned char **end_ptr,
JvmtiCachedClassFileData **cache_ptr) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
JvmtiClassFileLoadHookPoster poster(h_name, class_loader,
h_protection_domain,
data_ptr, end_ptr,
@ -756,6 +835,9 @@ public:
void JvmtiExport::post_compiled_method_unload(
jmethodID method, const void *code_begin) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
JavaThread* thread = JavaThread::current();
EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
("JVMTI [%s] method compile unload event triggered",
@ -765,7 +847,9 @@ void JvmtiExport::post_compiled_method_unload(
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_UNLOAD)) {
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT,
JvmtiTrace::safe_get_thread_name(thread), p2i(method)));
@ -838,6 +922,8 @@ bool JvmtiExport::_can_post_method_exit = fals
bool JvmtiExport::_can_pop_frame = false;
bool JvmtiExport::_can_force_early_return = false;
bool JvmtiExport::_early_vmstart_recorded = false;
bool JvmtiExport::_should_post_single_step = false;
bool JvmtiExport::_should_post_field_access = false;
bool JvmtiExport::_should_post_field_modification = false;
@ -912,6 +998,9 @@ bool JvmtiExport::hide_single_stepping(JavaThread *thread) {
}
void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
HandleMark hm(thread);
KlassHandle kh(thread, klass);
@ -924,11 +1013,13 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) {
JvmtiEnvThreadStateIterator it(state);
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
if (ets->is_enabled(JVMTI_EVENT_CLASS_LOAD)) {
JvmtiEnv *env = ets->get_env();
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
EVT_TRACE(JVMTI_EVENT_CLASS_LOAD, ("JVMTI [%s] Evt Class Load sent %s",
JvmtiTrace::safe_get_thread_name(thread),
kh()==NULL? "NULL" : kh()->external_name() ));
JvmtiEnv *env = ets->get_env();
JvmtiClassEventMark jem(thread, kh());
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventClassLoad callback = env->callbacks()->ClassLoad;
@ -941,6 +1032,9 @@ void JvmtiExport::post_class_load(JavaThread *thread, Klass* klass) {
void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
HandleMark hm(thread);
KlassHandle kh(thread, klass);
@ -953,11 +1047,13 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) {
JvmtiEnvThreadStateIterator it(state);
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
if (ets->is_enabled(JVMTI_EVENT_CLASS_PREPARE)) {
JvmtiEnv *env = ets->get_env();
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
EVT_TRACE(JVMTI_EVENT_CLASS_PREPARE, ("JVMTI [%s] Evt Class Prepare sent %s",
JvmtiTrace::safe_get_thread_name(thread),
kh()==NULL? "NULL" : kh()->external_name() ));
JvmtiEnv *env = ets->get_env();
JvmtiClassEventMark jem(thread, kh());
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventClassPrepare callback = env->callbacks()->ClassPrepare;
@ -969,6 +1065,9 @@ void JvmtiExport::post_class_prepare(JavaThread *thread, Klass* klass) {
}
void JvmtiExport::post_class_unload(Klass* klass) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
Thread *thread = Thread::current();
HandleMark hm(thread);
KlassHandle kh(thread, klass);
@ -983,6 +1082,9 @@ void JvmtiExport::post_class_unload(Klass* klass) {
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
if (env->is_enabled((jvmtiEvent)EXT_EVENT_CLASS_UNLOAD)) {
EVT_TRACE(EXT_EVENT_CLASS_UNLOAD, ("JVMTI [?] Evt Class Unload sent %s",
kh()==NULL? "NULL" : kh()->external_name() ));
@ -1018,6 +1120,9 @@ void JvmtiExport::post_class_unload(Klass* klass) {
void JvmtiExport::post_thread_start(JavaThread *thread) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
assert(thread->thread_state() == _thread_in_vm, "must be in vm state");
EVT_TRIG_TRACE(JVMTI_EVENT_THREAD_START, ("JVMTI [%s] Trg Thread Start event triggered",
@ -1031,6 +1136,9 @@ void JvmtiExport::post_thread_start(JavaThread *thread) {
!thread->is_hidden_from_external_view()) {
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
if (env->is_enabled(JVMTI_EVENT_THREAD_START)) {
EVT_TRACE(JVMTI_EVENT_THREAD_START, ("JVMTI [%s] Evt Thread Start event sent",
JvmtiTrace::safe_get_thread_name(thread) ));
@ -1048,6 +1156,9 @@ void JvmtiExport::post_thread_start(JavaThread *thread) {
void JvmtiExport::post_thread_end(JavaThread *thread) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
EVT_TRIG_TRACE(JVMTI_EVENT_THREAD_END, ("JVMTI [%s] Trg Thread End event triggered",
JvmtiTrace::safe_get_thread_name(thread)));
@ -1063,10 +1174,13 @@ void JvmtiExport::post_thread_end(JavaThread *thread) {
JvmtiEnvThreadStateIterator it(state);
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
if (ets->is_enabled(JVMTI_EVENT_THREAD_END)) {
JvmtiEnv *env = ets->get_env();
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
EVT_TRACE(JVMTI_EVENT_THREAD_END, ("JVMTI [%s] Evt Thread End event sent",
JvmtiTrace::safe_get_thread_name(thread) ));
JvmtiEnv *env = ets->get_env();
JvmtiThreadEventMark jem(thread);
JvmtiJavaThreadEventTransition jet(thread);
jvmtiEventThreadEnd callback = env->callbacks()->ThreadEnd;
@ -1705,7 +1819,7 @@ void JvmtiExport::post_native_method_bind(Method* method, address* function_ptr)
JvmtiMethodEventMark jem(thread, mh);
JvmtiJavaThreadEventTransition jet(thread);
JNIEnv* jni_env = JvmtiEnv::get_phase() == JVMTI_PHASE_PRIMORDIAL? NULL : jem.jni_env();
JNIEnv* jni_env = (env->phase() == JVMTI_PHASE_PRIMORDIAL) ? NULL : jem.jni_env();
jvmtiEventNativeMethodBind callback = env->callbacks()->NativeMethodBind;
if (callback != NULL) {
(*callback)(env->jvmti_external(), jni_env, jem.jni_thread(),
@ -1758,6 +1872,9 @@ jvmtiCompiledMethodLoadInlineRecord* create_inline_record(nmethod* nm) {
}
void JvmtiExport::post_compiled_method_load(nmethod *nm) {
if (JvmtiEnv::get_phase() < JVMTI_PHASE_PRIMORDIAL) {
return;
}
JavaThread* thread = JavaThread::current();
EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
@ -1767,7 +1884,9 @@ void JvmtiExport::post_compiled_method_load(nmethod *nm) {
JvmtiEnvIterator it;
for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) {
if (env->phase() == JVMTI_PHASE_PRIMORDIAL) {
continue;
}
EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
("JVMTI [%s] class compile method load event sent %s.%s ",
JvmtiTrace::safe_get_thread_name(thread),
@ -1797,6 +1916,9 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID metho
const void *code_begin, const jint map_length,
const jvmtiAddrLocationMap* map)
{
if (env->phase() <= JVMTI_PHASE_PRIMORDIAL) {
return;
}
JavaThread* thread = JavaThread::current();
EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD,
("JVMTI [%s] method compile load event triggered (by GenerateEvents)",

View File

@ -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
@ -91,6 +91,8 @@ class JvmtiExport : public AllStatic {
JVMTI_SUPPORT_FLAG(can_pop_frame)
JVMTI_SUPPORT_FLAG(can_force_early_return)
JVMTI_SUPPORT_FLAG(early_vmstart_recorded)
friend class JvmtiEventControllerPrivate; // should only modify these flags
JVMTI_SUPPORT_FLAG(should_post_single_step)
JVMTI_SUPPORT_FLAG(should_post_field_access)
@ -213,6 +215,8 @@ class JvmtiExport : public AllStatic {
_all_dependencies_are_recorded = (on != 0);
}
// Add read edges to the unnamed modules of the bootstrap and app class loaders
static void add_default_read_edges(Handle h_module, TRAPS) NOT_JVMTI_RETURN;
// let JVMTI know that the JVM_OnLoad code is running
static void enter_onload_phase() NOT_JVMTI_RETURN;
@ -221,6 +225,7 @@ class JvmtiExport : public AllStatic {
static void enter_primordial_phase() NOT_JVMTI_RETURN;
// let JVMTI know that the VM isn't up yet but JNI is live
static void enter_early_start_phase() NOT_JVMTI_RETURN;
static void enter_start_phase() NOT_JVMTI_RETURN;
// let JVMTI know that the VM is fully up and running now
@ -270,6 +275,7 @@ class JvmtiExport : public AllStatic {
static bool hide_single_stepping(JavaThread *thread) NOT_JVMTI_RETURN_(false);
// Methods that notify the debugger that something interesting has happened in the VM.
static void post_early_vm_start () NOT_JVMTI_RETURN;
static void post_vm_start () NOT_JVMTI_RETURN;
static void post_vm_initialized () NOT_JVMTI_RETURN;
static void post_vm_death () NOT_JVMTI_RETURN;

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2002, 2010, 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
@ -113,6 +113,7 @@ enum {
JVMTI_VERSION_1_0 = 0x30010000,
JVMTI_VERSION_1_1 = 0x30010100,
JVMTI_VERSION_1_2 = 0x30010200,
JVMTI_VERSION_9 = 0x30090000,
JVMTI_VERSION = 0x30000000 + (</xsl:text>
<xsl:value-of select="//specification/@majorversion"/>
@ -137,21 +138,21 @@ enum {
<xsl:text> */
};
JNIEXPORT jint JNICALL
JNIEXPORT jint JNICALL
Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
JNIEXPORT jint JNICALL
Agent_OnAttach(JavaVM* vm, char* options, void* reserved);
JNIEXPORT void JNICALL
JNIEXPORT void JNICALL
Agent_OnUnload(JavaVM *vm);
/* Forward declaration of the environment */
struct _jvmtiEnv;
struct jvmtiInterface_1_;
#ifdef __cplusplus
typedef _jvmtiEnv jvmtiEnv;
#else
@ -169,7 +170,6 @@ typedef const struct jvmtiInterface_1_ *jvmtiEnv;
#endif /* __cplusplus */
#endif /* !_JAVA_JVMTI_H_ */
</xsl:text>
</xsl:template>
@ -238,7 +238,7 @@ typedef void (JNICALL *jvmtiEvent</xsl:text>
(jvmtiEnv *jvmti_env</xsl:text>
<xsl:apply-templates select="parameters" mode="signature">
<xsl:with-param name="comma">
<xsl:text>,
<xsl:text>,
</xsl:text>
</xsl:with-param>
</xsl:apply-templates>
@ -250,7 +250,7 @@ typedef void (JNICALL *jvmtiEvent</xsl:text>
<xsl:text>
/* Function Interface */
typedef struct jvmtiInterface_1_ {
</xsl:text>
@ -290,7 +290,7 @@ struct _jvmtiEnv {
<xsl:text>) (jvmtiEnv* env</xsl:text>
<xsl:apply-templates select="$thisFunction/parameters" mode="signature">
<xsl:with-param name="comma">
<xsl:text>,
<xsl:text>,
</xsl:text>
</xsl:with-param>
</xsl:apply-templates>
@ -365,7 +365,7 @@ struct _jvmtiEnv {
/* </xsl:text>
<xsl:value-of select="@label"/>
<xsl:text> */
<xsl:text> */
</xsl:text>
<xsl:choose>
<xsl:when test="@kind='enum'">

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
@ -44,20 +44,20 @@
</xsl:template>
<xsl:template name="copyrightComment">
<xsl:text>/* </xsl:text>
<xsl:text>/*</xsl:text>
<!-- Copy the Copyright comment from jvmti.xml -->
<xsl:value-of select="/comment()[position()=1]"/>
<xsl:text> */ &#xA;&#xA;</xsl:text>
<xsl:text> */&#xA;&#xA;</xsl:text>
</xsl:template>
<xsl:template name="includeHeader">
<xsl:call-template name="copyrightComment"/>
<xsl:text> /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ &#xA;</xsl:text>
<xsl:text> /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */&#xA;</xsl:text>
</xsl:template>
<xsl:template name="sourceHeader">
<xsl:call-template name="copyrightComment"/>
<xsl:text> // AUTOMATICALLY GENERATED FILE - DO NOT EDIT &#xA;</xsl:text>
<xsl:text> // AUTOMATICALLY GENERATED FILE - DO NOT EDIT&#xA;</xsl:text>
</xsl:template>

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@
#include <new>
#include "classfile/classLoaderData.hpp"
#include "classfile/modules.hpp"
#include "classfile/stringTable.hpp"
#include "code/codeCache.hpp"
#include "compiler/methodMatcher.hpp"
@ -1250,6 +1251,43 @@ WB_ENTRY(void, WB_FreeMetaspace(JNIEnv* env, jobject wb, jobject class_loader, j
MetadataFactory::free_array(cld, (Array<u1>*)(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(),
@ -1278,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 :
@ -1287,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();
@ -1417,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
@ -1528,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 },
@ -1649,6 +1685,24 @@ 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 },
@ -1675,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 },
};

View File

@ -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();
@ -542,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);
@ -562,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.
@ -580,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);
}
@ -637,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).
@ -659,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];
@ -672,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");
@ -706,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;
@ -1375,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
@ -2553,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;
@ -2572,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;
@ -2587,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;
}
@ -2647,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;
@ -2700,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) {
@ -2761,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
@ -3029,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);
@ -3294,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
@ -3329,7 +3452,7 @@ 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
}
}
@ -3380,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();
@ -3416,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.
@ -3766,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");
}
@ -4455,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;
}

View File

@ -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<mtInternal> {
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<mtInternal> {
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<mtInternal> {
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<mtInternal> {
}
// 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) {
@ -569,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(); }
@ -625,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() {

View File

@ -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,6 +669,13 @@ 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

View File

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

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