Merge
This commit is contained in:
commit
f5225b6550
@ -352,3 +352,4 @@ be58b02c11f90b88c67e4d0e2cb5e4cf2d9b3c57 jdk-9+105
|
||||
4d65eba233a8730f913734a6804910b842d2cb54 jdk-9+107
|
||||
c7be2a78c31b3b6132f2f5e9e4b3d3bb1c20245c jdk-9+108
|
||||
1787bdaabb2b6f4193406e25a50cb0419ea8e8f3 jdk-9+109
|
||||
925be13b3740d07a5958ccb5ab3c0ae1baba7055 jdk-9+110
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
])
|
||||
|
@ -25,6 +25,8 @@
|
||||
|
||||
# Support for building boot cycle builds
|
||||
|
||||
BOOT_JDK_MODULAR := true
|
||||
|
||||
# First include the real base spec.gmk file
|
||||
include @SPEC@
|
||||
|
||||
|
148
common/autoconf/buildjdk-spec.gmk.in
Normal file
148
common/autoconf/buildjdk-spec.gmk.in
Normal 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
|
@ -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
|
||||
|
@ -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
@ -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)
|
||||
])
|
||||
|
@ -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..?
|
||||
|
@ -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)
|
||||
])
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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...
|
||||
|
@ -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"
|
||||
},
|
||||
|
||||
|
@ -512,3 +512,4 @@ c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103
|
||||
c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107
|
||||
934f6793f5f7dca44f69b4559d525fa64b31840d jdk-9+108
|
||||
7e7e50ac4faf19899fc811569e32cfa478759ebb jdk-9+109
|
||||
2f5d1578b24060ea06bd1f340a124db95d1475b2 jdk-9+110
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
49
hotspot/src/jdk.hotspot.agent/share/classes/module-info.java
Normal file
49
hotspot/src/jdk.hotspot.agent/share/classes/module-info.java
Normal 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,3 +0,0 @@
|
||||
jdk.vm.ci.hotspot.aarch64.AArch64HotSpotJVMCIBackendFactory
|
||||
jdk.vm.ci.hotspot.amd64.AMD64HotSpotJVMCIBackendFactory
|
||||
jdk.vm.ci.hotspot.sparc.SPARCHotSpotJVMCIBackendFactory
|
37
hotspot/src/jdk.vm.ci/share/classes/module-info.java
Normal file
37
hotspot/src/jdk.vm.ci/share/classes/module-info.java
Normal 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;
|
||||
}
|
@ -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*);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
* ...
|
||||
|
@ -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;
|
||||
|
405
hotspot/src/share/vm/classfile/moduleEntry.cpp
Normal file
405
hotspot/src/share/vm/classfile/moduleEntry.cpp
Normal 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.");
|
||||
}
|
230
hotspot/src/share/vm/classfile/moduleEntry.hpp
Normal file
230
hotspot/src/share/vm/classfile/moduleEntry.hpp
Normal 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
|
964
hotspot/src/share/vm/classfile/modules.cpp
Normal file
964
hotspot/src/share/vm/classfile/modules.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
151
hotspot/src/share/vm/classfile/modules.hpp
Normal file
151
hotspot/src/share/vm/classfile/modules.hpp
Normal 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
|
322
hotspot/src/share/vm/classfile/packageEntry.cpp
Normal file
322
hotspot/src/share/vm/classfile/packageEntry.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
202
hotspot/src/share/vm/classfile/packageEntry.hpp
Normal file
202
hotspot/src/share/vm/classfile/packageEntry.hpp
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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") \
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -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;
|
||||
|
@ -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> {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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!");
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 //////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>, 
 </xsl:text>
|
||||
<xsl:text>,
 </xsl:text>
|
||||
</xsl:with-param>
|
||||
</xsl:apply-templates>
|
||||
<xsl:text>);</xsl:text>
|
||||
|
@ -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 && JvmtiEnv::get_phase()!=JVMTI_PHASE_LIVE) {
|
||||
<xsl:text> if(JvmtiEnv::get_phase(env)!=JVMTI_PHASE_START && JvmtiEnv::get_phase()!=JVMTI_PHASE_LIVE) {
|
||||
</xsl:text>
|
||||
<xsl:if test="$trace='Trace'">
|
||||
<xsl:text> if (trace_flags) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()) {
|
||||
|
@ -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)",
|
||||
|
@ -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;
|
||||
|
@ -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'">
|
||||
|
@ -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> */ 

</xsl:text>
|
||||
<xsl:text> */

</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="includeHeader">
|
||||
<xsl:call-template name="copyrightComment"/>
|
||||
<xsl:text> /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */ 
</xsl:text>
|
||||
<xsl:text> /* AUTOMATICALLY GENERATED FILE - DO NOT EDIT */
</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="sourceHeader">
|
||||
<xsl:call-template name="copyrightComment"/>
|
||||
<xsl:text> // AUTOMATICALLY GENERATED FILE - DO NOT EDIT 
</xsl:text>
|
||||
<xsl:text> // AUTOMATICALLY GENERATED FILE - DO NOT EDIT
</xsl:text>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 },
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user