mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-31 13:15:26 +00:00
Merge
This commit is contained in:
commit
0f687b0bd5
1
.hgtags
1
.hgtags
@ -352,3 +352,4 @@ db483b34fa7148d257a429acddbde9c13687dcae jdk-9+105
|
||||
1c076468bf7dad5b8f2ee5dcf66e2279caa3e208 jdk-9+107
|
||||
257b579d813201682931d6b42f0445ffe5b4210d jdk-9+108
|
||||
c870cb782aca71093d2584376f27f0cfbfec0e3a jdk-9+109
|
||||
4a95f4b1bd8bfce85dc02a593896749feab96c34 jdk-9+110
|
||||
|
||||
@ -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"
|
||||
},
|
||||
|
||||
|
||||
@ -352,3 +352,4 @@ e385e95e6101711d5c63e7b1a827e99b6ec7a1cc jdk-9+104
|
||||
49202432b69445164a42be7cbdf74ed5fce98157 jdk-9+107
|
||||
84f2862a25eb3232ff36c376b4e2bf2a83dfced3 jdk-9+108
|
||||
b75afa17aefe480c23c616a6a2497063312f7189 jdk-9+109
|
||||
9666775734fb6028ee86df9972626b3667b6a318 jdk-9+110
|
||||
|
||||
@ -47,7 +47,7 @@ $(eval $(call SetupJavaCompilation,BUILD_IDLJ, \
|
||||
BIN := $(BUILDTOOLS_OUTPUTDIR)/idlj_classes, \
|
||||
COPY := .prp, \
|
||||
INCLUDES := com/sun/tools/corba/se/idl, \
|
||||
EXCLUDE_FILES := ResourceBundleUtil.java))
|
||||
EXCLUDE_FILES := ResourceBundleUtil.java module-info.java))
|
||||
|
||||
# Force the language to english for predictable source code generation.
|
||||
TOOL_IDLJ_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/idlj_classes \
|
||||
|
||||
77
corba/src/java.corba/share/classes/module-info.java
Normal file
77
corba/src/java.corba/share/classes/module-info.java
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
module java.corba {
|
||||
requires public java.desktop;
|
||||
requires public java.rmi;
|
||||
requires java.logging;
|
||||
requires java.naming;
|
||||
requires java.transaction;
|
||||
|
||||
exports javax.activity;
|
||||
exports javax.rmi;
|
||||
exports javax.rmi.CORBA;
|
||||
exports org.omg.CORBA;
|
||||
exports org.omg.CORBA.DynAnyPackage;
|
||||
exports org.omg.CORBA.ORBPackage;
|
||||
exports org.omg.CORBA.TypeCodePackage;
|
||||
exports org.omg.CORBA.portable;
|
||||
exports org.omg.CORBA_2_3;
|
||||
exports org.omg.CORBA_2_3.portable;
|
||||
exports org.omg.CosNaming;
|
||||
exports org.omg.CosNaming.NamingContextExtPackage;
|
||||
exports org.omg.CosNaming.NamingContextPackage;
|
||||
exports org.omg.Dynamic;
|
||||
exports org.omg.DynamicAny;
|
||||
exports org.omg.DynamicAny.DynAnyFactoryPackage;
|
||||
exports org.omg.DynamicAny.DynAnyPackage;
|
||||
exports org.omg.IOP;
|
||||
exports org.omg.IOP.CodecFactoryPackage;
|
||||
exports org.omg.IOP.CodecPackage;
|
||||
exports org.omg.Messaging;
|
||||
exports org.omg.PortableInterceptor;
|
||||
exports org.omg.PortableInterceptor.ORBInitInfoPackage;
|
||||
exports org.omg.PortableServer;
|
||||
exports org.omg.PortableServer.CurrentPackage;
|
||||
exports org.omg.PortableServer.POAManagerPackage;
|
||||
exports org.omg.PortableServer.POAPackage;
|
||||
exports org.omg.PortableServer.ServantLocatorPackage;
|
||||
exports org.omg.PortableServer.portable;
|
||||
exports org.omg.SendingContext;
|
||||
exports org.omg.stub.java.rmi;
|
||||
exports com.sun.corba.se.impl.util to
|
||||
jdk.rmic;
|
||||
exports com.sun.jndi.cosnaming to
|
||||
java.naming;
|
||||
exports com.sun.jndi.url.corbaname to
|
||||
java.naming;
|
||||
exports com.sun.jndi.url.iiop to
|
||||
java.naming;
|
||||
exports com.sun.jndi.url.iiopname to
|
||||
java.naming;
|
||||
|
||||
provides javax.naming.spi.InitialContextFactory
|
||||
with com.sun.jndi.cosnaming.CNCtxFactory;
|
||||
}
|
||||
@ -512,3 +512,4 @@ c5f55130b1b69510d9a6f4a3105b58e21cd7ffe1 jdk-9+103
|
||||
c5146d4da417f76edfc43097d2e2ced042a65b4e jdk-9+107
|
||||
934f6793f5f7dca44f69b4559d525fa64b31840d jdk-9+108
|
||||
7e7e50ac4faf19899fc811569e32cfa478759ebb jdk-9+109
|
||||
2f5d1578b24060ea06bd1f340a124db95d1475b2 jdk-9+110
|
||||
|
||||
@ -91,7 +91,7 @@ else ifeq ($(OPENJDK_TARGET_OS), windows)
|
||||
ifeq ($(OPENJDK_TARGET_CPU), x86_64)
|
||||
SA_CXXFLAGS += -DWIN64
|
||||
else
|
||||
SA_CXXFLAGS += -RTC1 -ZI
|
||||
SA_CXXFLAGS += -RTC1
|
||||
SA_LDFLAGS += -SAFESEH
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -167,3 +167,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 \
|
||||
|
||||
@ -849,8 +849,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ bind(L1);
|
||||
|
||||
if (direction == copy_forwards) {
|
||||
__ add(s, s, 2 * wordSize);
|
||||
__ add(d, d, 2 * wordSize);
|
||||
__ add(s, s, bias);
|
||||
__ add(d, d, bias);
|
||||
}
|
||||
|
||||
__ tbz(count, 1, L2);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ public class SALauncher {
|
||||
}
|
||||
|
||||
private static boolean jsnapHelp() {
|
||||
System.out.println(" <no option>\tdump performance counters");
|
||||
System.out.println(" --all\tto print all performance counters");
|
||||
return commonHelp();
|
||||
}
|
||||
|
||||
@ -331,7 +331,7 @@ public class SALauncher {
|
||||
|
||||
private static void runJSNAP(String[] oldArgs) {
|
||||
SAGetopt sg = new SAGetopt(oldArgs);
|
||||
String[] longOpts = {"exe=", "core=", "pid="};
|
||||
String[] longOpts = {"exe=", "core=", "pid=", "all"};
|
||||
|
||||
ArrayList<String> newArgs = new ArrayList();
|
||||
String exe = null;
|
||||
@ -352,6 +352,10 @@ public class SALauncher {
|
||||
pid = sg.getOptarg();
|
||||
continue;
|
||||
}
|
||||
if (s.equals("all")) {
|
||||
newArgs.add("-a");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
buildAttachArgs(newArgs, pid, exe, core);
|
||||
|
||||
@ -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,11 +25,15 @@
|
||||
package sun.jvm.hotspot.tools;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
import sun.jvm.hotspot.debugger.JVMDebugger;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
|
||||
public class JSnap extends Tool {
|
||||
|
||||
private boolean all;
|
||||
|
||||
public JSnap() {
|
||||
super();
|
||||
}
|
||||
@ -45,7 +49,7 @@ public class JSnap extends Tool {
|
||||
if (prologue.accessible()) {
|
||||
PerfMemory.iterate(new PerfMemory.PerfDataEntryVisitor() {
|
||||
public boolean visit(PerfDataEntry pde) {
|
||||
if (pde.supported()) {
|
||||
if (all || pde.supported()) {
|
||||
out.print(pde.name());
|
||||
out.print('=');
|
||||
out.println(pde.valueAsString());
|
||||
@ -62,8 +66,24 @@ public class JSnap extends Tool {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void printFlagsUsage() {
|
||||
System.out.println(" -a\tto print all performance counters");
|
||||
super.printFlagsUsage();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
JSnap js = new JSnap();
|
||||
js.all = Arrays.stream(args)
|
||||
.anyMatch(s -> s.equals("-a"));
|
||||
|
||||
if (js.all) {
|
||||
args = Arrays.stream(args)
|
||||
.filter(s -> !s.equals("-a"))
|
||||
.collect(Collectors.toList())
|
||||
.toArray(new String[0]);
|
||||
}
|
||||
|
||||
js.execute(args);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -339,7 +339,7 @@ public class HotSpotConstantReflectionProvider implements ConstantReflectionProv
|
||||
|
||||
public JavaConstant readStableFieldValue(ResolvedJavaField field, JavaConstant receiver, boolean isDefaultStable) {
|
||||
JavaConstant fieldValue = readNonStableFieldValue(field, receiver);
|
||||
if (fieldValue.isNonNull()) {
|
||||
if (fieldValue != null && fieldValue.isNonNull()) {
|
||||
JavaType declaredType = field.getType();
|
||||
if (declaredType.getComponentType() != null) {
|
||||
int stableDimension = getArrayDimension(declaredType);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@ package jdk.vm.ci.hotspot;
|
||||
import jdk.vm.ci.code.CompilationRequest;
|
||||
import jdk.vm.ci.code.CompilationRequestResult;
|
||||
import jdk.vm.ci.common.JVMCIError;
|
||||
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
|
||||
import jdk.vm.ci.runtime.JVMCICompiler;
|
||||
import jdk.vm.ci.runtime.JVMCICompilerFactory;
|
||||
import jdk.vm.ci.runtime.JVMCIRuntime;
|
||||
@ -47,29 +48,33 @@ final class HotSpotJVMCICompilerConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory of the selected system compiler.
|
||||
*/
|
||||
private static JVMCICompilerFactory compilerFactory;
|
||||
|
||||
/**
|
||||
* Selects the system compiler.
|
||||
* Gets the selected system compiler factory.
|
||||
*
|
||||
* Called from VM. This method has an object return type to allow it to be called with a VM
|
||||
* utility function used to call other static initialization methods.
|
||||
* @return the selected system compiler factory
|
||||
*/
|
||||
static Boolean selectCompiler(String compilerName) {
|
||||
assert compilerFactory == null;
|
||||
for (JVMCICompilerFactory factory : Services.load(JVMCICompilerFactory.class)) {
|
||||
if (factory.getCompilerName().equals(compilerName)) {
|
||||
compilerFactory = factory;
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
throw new JVMCIError("JVMCI compiler '%s' not found", compilerName);
|
||||
}
|
||||
|
||||
static JVMCICompilerFactory getCompilerFactory() {
|
||||
if (compilerFactory == null) {
|
||||
compilerFactory = new DummyCompilerFactory();
|
||||
JVMCICompilerFactory factory = null;
|
||||
String compilerName = Option.Compiler.getString();
|
||||
if (compilerName != null) {
|
||||
for (JVMCICompilerFactory f : Services.load(JVMCICompilerFactory.class)) {
|
||||
if (f.getCompilerName().equals(compilerName)) {
|
||||
factory = f;
|
||||
}
|
||||
}
|
||||
if (factory == null) {
|
||||
throw new JVMCIError("JVMCI compiler '%s' not found", compilerName);
|
||||
}
|
||||
} else {
|
||||
factory = new DummyCompilerFactory();
|
||||
}
|
||||
compilerFactory = factory;
|
||||
}
|
||||
return compilerFactory;
|
||||
}
|
||||
|
||||
@ -91,6 +91,7 @@ public final class HotSpotJVMCIRuntime implements HotSpotJVMCIRuntimeProvider, H
|
||||
* A list of all supported JVMCI options.
|
||||
*/
|
||||
public enum Option {
|
||||
Compiler(String.class, null, "Selects the system compiler."),
|
||||
ImplicitStableValues(boolean.class, true, "Mark well-known stable fields as such."),
|
||||
// Note: The following one is not used (see InitTimer.ENABLED).
|
||||
InitTimer(boolean.class, false, "Specifies if initialization timing is enabled."),
|
||||
|
||||
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*);
|
||||
|
||||
@ -26,44 +26,108 @@
|
||||
#ifndef OS_CPU_LINUX_AARCH64_VM_COPY_LINUX_AARCH64_INLINE_HPP
|
||||
#define OS_CPU_LINUX_AARCH64_VM_COPY_LINUX_AARCH64_INLINE_HPP
|
||||
|
||||
#define COPY_SMALL(from, to, count) \
|
||||
{ \
|
||||
long tmp0, tmp1, tmp2, tmp3; \
|
||||
long tmp4, tmp5, tmp6, tmp7; \
|
||||
__asm volatile( \
|
||||
" adr %[t0], 0f;" \
|
||||
" add %[t0], %[t0], %[cnt], lsl #5;" \
|
||||
" br %[t0];" \
|
||||
" .align 5;" \
|
||||
"0:" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldr %[t0], [%[s], #0];" \
|
||||
" str %[t0], [%[d], #0];" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldp %[t0], %[t1], [%[s], #0];" \
|
||||
" stp %[t0], %[t1], [%[d], #0];" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldp %[t0], %[t1], [%[s], #0];" \
|
||||
" ldr %[t2], [%[s], #16];" \
|
||||
" stp %[t0], %[t1], [%[d], #0];" \
|
||||
" str %[t2], [%[d], #16];" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldp %[t0], %[t1], [%[s], #0];" \
|
||||
" ldp %[t2], %[t3], [%[s], #16];" \
|
||||
" stp %[t0], %[t1], [%[d], #0];" \
|
||||
" stp %[t2], %[t3], [%[d], #16];" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldp %[t0], %[t1], [%[s], #0];" \
|
||||
" ldp %[t2], %[t3], [%[s], #16];" \
|
||||
" ldr %[t4], [%[s], #32];" \
|
||||
" stp %[t0], %[t1], [%[d], #0];" \
|
||||
" stp %[t2], %[t3], [%[d], #16];" \
|
||||
" str %[t4], [%[d], #32];" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldp %[t0], %[t1], [%[s], #0];" \
|
||||
" ldp %[t2], %[t3], [%[s], #16];" \
|
||||
" ldp %[t4], %[t5], [%[s], #32];" \
|
||||
"2:" \
|
||||
" stp %[t0], %[t1], [%[d], #0];" \
|
||||
" stp %[t2], %[t3], [%[d], #16];" \
|
||||
" stp %[t4], %[t5], [%[d], #32];" \
|
||||
" b 1f;" \
|
||||
" .align 5;" \
|
||||
" ldr %[t6], [%[s], #0];" \
|
||||
" ldp %[t0], %[t1], [%[s], #8];" \
|
||||
" ldp %[t2], %[t3], [%[s], #24];" \
|
||||
" ldp %[t4], %[t5], [%[s], #40];" \
|
||||
" str %[t6], [%[d]], #8;" \
|
||||
" b 2b;" \
|
||||
" .align 5;" \
|
||||
" ldp %[t0], %[t1], [%[s], #0];" \
|
||||
" ldp %[t2], %[t3], [%[s], #16];" \
|
||||
" ldp %[t4], %[t5], [%[s], #32];" \
|
||||
" ldp %[t6], %[t7], [%[s], #48];" \
|
||||
" stp %[t0], %[t1], [%[d], #0];" \
|
||||
" stp %[t2], %[t3], [%[d], #16];" \
|
||||
" stp %[t4], %[t5], [%[d], #32];" \
|
||||
" stp %[t6], %[t7], [%[d], #48];" \
|
||||
"1:" \
|
||||
\
|
||||
: [s]"+r"(from), [d]"+r"(to), [cnt]"+r"(count), \
|
||||
[t0]"=&r"(tmp0), [t1]"=&r"(tmp1), [t2]"=&r"(tmp2), [t3]"=&r"(tmp3), \
|
||||
[t4]"=&r"(tmp4), [t5]"=&r"(tmp5), [t6]"=&r"(tmp6), [t7]"=&r"(tmp7) \
|
||||
: \
|
||||
: "memory", "cc"); \
|
||||
}
|
||||
|
||||
static void pd_conjoint_words(HeapWord* from, HeapWord* to, size_t count) {
|
||||
(void)memmove(to, from, count * HeapWordSize);
|
||||
__asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory");
|
||||
if (__builtin_expect(count <= 8, 1)) {
|
||||
COPY_SMALL(from, to, count);
|
||||
return;
|
||||
}
|
||||
_Copy_conjoint_words(from, to, count);
|
||||
}
|
||||
|
||||
static void pd_disjoint_words(HeapWord* from, HeapWord* to, size_t count) {
|
||||
switch (count) {
|
||||
case 8: to[7] = from[7];
|
||||
case 7: to[6] = from[6];
|
||||
case 6: to[5] = from[5];
|
||||
case 5: to[4] = from[4];
|
||||
case 4: to[3] = from[3];
|
||||
case 3: to[2] = from[2];
|
||||
case 2: to[1] = from[1];
|
||||
case 1: to[0] = from[0];
|
||||
case 0: break;
|
||||
default:
|
||||
(void)memcpy(to, from, count * HeapWordSize);
|
||||
break;
|
||||
if (__builtin_constant_p(count)) {
|
||||
memcpy(to, from, count * sizeof(HeapWord));
|
||||
return;
|
||||
}
|
||||
__asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory");
|
||||
if (__builtin_expect(count <= 8, 1)) {
|
||||
COPY_SMALL(from, to, count);
|
||||
return;
|
||||
}
|
||||
_Copy_disjoint_words(from, to, count);
|
||||
}
|
||||
|
||||
static void pd_disjoint_words_atomic(HeapWord* from, HeapWord* to, size_t count) {
|
||||
switch (count) {
|
||||
case 8: to[7] = from[7];
|
||||
case 7: to[6] = from[6];
|
||||
case 6: to[5] = from[5];
|
||||
case 5: to[4] = from[4];
|
||||
case 4: to[3] = from[3];
|
||||
case 3: to[2] = from[2];
|
||||
case 2: to[1] = from[1];
|
||||
case 1: to[0] = from[0];
|
||||
case 0: break;
|
||||
default:
|
||||
while (count-- > 0) {
|
||||
*to++ = *from++;
|
||||
}
|
||||
break;
|
||||
__asm volatile( "prfm pldl1strm, [%[s], #0];" :: [s]"r"(from) : "memory");
|
||||
if (__builtin_expect(count <= 8, 1)) {
|
||||
COPY_SMALL(from, to, count);
|
||||
return;
|
||||
}
|
||||
_Copy_disjoint_words(from, to, count);
|
||||
}
|
||||
|
||||
static void pd_aligned_conjoint_words(HeapWord* from, HeapWord* to, size_t count) {
|
||||
|
||||
236
hotspot/src/os_cpu/linux_aarch64/vm/copy_linux_aarch64.s
Normal file
236
hotspot/src/os_cpu/linux_aarch64/vm/copy_linux_aarch64.s
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Linaro Ltd. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
.global _Copy_conjoint_words
|
||||
.global _Copy_disjoint_words
|
||||
|
||||
s .req x0
|
||||
d .req x1
|
||||
count .req x2
|
||||
t0 .req x3
|
||||
t1 .req x4
|
||||
t2 .req x5
|
||||
t3 .req x6
|
||||
t4 .req x7
|
||||
t5 .req x8
|
||||
t6 .req x9
|
||||
t7 .req x10
|
||||
|
||||
.align 6
|
||||
_Copy_disjoint_words:
|
||||
// Ensure 2 word aligned
|
||||
tbz s, #3, fwd_copy_aligned
|
||||
ldr t0, [s], #8
|
||||
str t0, [d], #8
|
||||
sub count, count, #1
|
||||
|
||||
fwd_copy_aligned:
|
||||
// Bias s & d so we only pre index on the last copy
|
||||
sub s, s, #16
|
||||
sub d, d, #16
|
||||
|
||||
ldp t0, t1, [s, #16]
|
||||
ldp t2, t3, [s, #32]
|
||||
ldp t4, t5, [s, #48]
|
||||
ldp t6, t7, [s, #64]!
|
||||
|
||||
subs count, count, #16
|
||||
blo fwd_copy_drain
|
||||
|
||||
fwd_copy_again:
|
||||
prfm pldl1keep, [s, #256]
|
||||
stp t0, t1, [d, #16]
|
||||
ldp t0, t1, [s, #16]
|
||||
stp t2, t3, [d, #32]
|
||||
ldp t2, t3, [s, #32]
|
||||
stp t4, t5, [d, #48]
|
||||
ldp t4, t5, [s, #48]
|
||||
stp t6, t7, [d, #64]!
|
||||
ldp t6, t7, [s, #64]!
|
||||
subs count, count, #8
|
||||
bhs fwd_copy_again
|
||||
|
||||
fwd_copy_drain:
|
||||
stp t0, t1, [d, #16]
|
||||
stp t2, t3, [d, #32]
|
||||
stp t4, t5, [d, #48]
|
||||
stp t6, t7, [d, #64]!
|
||||
|
||||
// count is now -8..-1 for 0..7 words to copy
|
||||
adr t0, 0f
|
||||
add t0, t0, count, lsl #5
|
||||
br t0
|
||||
|
||||
.align 5
|
||||
ret // -8 == 0 words
|
||||
.align 5
|
||||
ldr t0, [s, #16] // -7 == 1 word
|
||||
str t0, [d, #16]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #16] // -6 = 2 words
|
||||
stp t0, t1, [d, #16]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #16] // -5 = 3 words
|
||||
ldr t2, [s, #32]
|
||||
stp t0, t1, [d, #16]
|
||||
str t2, [d, #32]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #16] // -4 = 4 words
|
||||
ldp t2, t3, [s, #32]
|
||||
stp t0, t1, [d, #16]
|
||||
stp t2, t3, [d, #32]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #16] // -3 = 5 words
|
||||
ldp t2, t3, [s, #32]
|
||||
ldr t4, [s, #48]
|
||||
stp t0, t1, [d, #16]
|
||||
stp t2, t3, [d, #32]
|
||||
str t4, [d, #48]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #16] // -2 = 6 words
|
||||
ldp t2, t3, [s, #32]
|
||||
ldp t4, t5, [s, #48]
|
||||
stp t0, t1, [d, #16]
|
||||
stp t2, t3, [d, #32]
|
||||
stp t4, t5, [d, #48]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #16] // -1 = 7 words
|
||||
ldp t2, t3, [s, #32]
|
||||
ldp t4, t5, [s, #48]
|
||||
ldr t6, [s, #64]
|
||||
stp t0, t1, [d, #16]
|
||||
stp t2, t3, [d, #32]
|
||||
stp t4, t5, [d, #48]
|
||||
str t6, [d, #64]
|
||||
// Is always aligned here, code for 7 words is one instruction
|
||||
// too large so it just falls through.
|
||||
.align 5
|
||||
0:
|
||||
ret
|
||||
|
||||
.align 6
|
||||
_Copy_conjoint_words:
|
||||
sub t0, d, s
|
||||
cmp t0, count, lsl #3
|
||||
bhs _Copy_disjoint_words
|
||||
|
||||
add s, s, count, lsl #3
|
||||
add d, d, count, lsl #3
|
||||
|
||||
// Ensure 2 word aligned
|
||||
tbz s, #3, bwd_copy_aligned
|
||||
ldr t0, [s, #-8]!
|
||||
str t0, [d, #-8]!
|
||||
sub count, count, #1
|
||||
|
||||
bwd_copy_aligned:
|
||||
ldp t0, t1, [s, #-16]
|
||||
ldp t2, t3, [s, #-32]
|
||||
ldp t4, t5, [s, #-48]
|
||||
ldp t6, t7, [s, #-64]!
|
||||
|
||||
subs count, count, #16
|
||||
blo bwd_copy_drain
|
||||
|
||||
bwd_copy_again:
|
||||
prfm pldl1keep, [s, #-256]
|
||||
stp t0, t1, [d, #-16]
|
||||
ldp t0, t1, [s, #-16]
|
||||
stp t2, t3, [d, #-32]
|
||||
ldp t2, t3, [s, #-32]
|
||||
stp t4, t5, [d, #-48]
|
||||
ldp t4, t5, [s, #-48]
|
||||
stp t6, t7, [d, #-64]!
|
||||
ldp t6, t7, [s, #-64]!
|
||||
subs count, count, #8
|
||||
bhs bwd_copy_again
|
||||
|
||||
bwd_copy_drain:
|
||||
stp t0, t1, [d, #-16]
|
||||
stp t2, t3, [d, #-32]
|
||||
stp t4, t5, [d, #-48]
|
||||
stp t6, t7, [d, #-64]!
|
||||
|
||||
// count is now -8..-1 for 0..7 words to copy
|
||||
adr t0, 0f
|
||||
add t0, t0, count, lsl #5
|
||||
br t0
|
||||
|
||||
.align 5
|
||||
ret // -8 == 0 words
|
||||
.align 5
|
||||
ldr t0, [s, #-8] // -7 == 1 word
|
||||
str t0, [d, #-8]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #-16] // -6 = 2 words
|
||||
stp t0, t1, [d, #-16]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #-16] // -5 = 3 words
|
||||
ldr t2, [s, #-24]
|
||||
stp t0, t1, [d, #-16]
|
||||
str t2, [d, #-24]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #-16] // -4 = 4 words
|
||||
ldp t2, t3, [s, #-32]
|
||||
stp t0, t1, [d, #-16]
|
||||
stp t2, t3, [d, #-32]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #-16] // -3 = 5 words
|
||||
ldp t2, t3, [s, #-32]
|
||||
ldr t4, [s, #-40]
|
||||
stp t0, t1, [d, #-16]
|
||||
stp t2, t3, [d, #-32]
|
||||
str t4, [d, #-40]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #-16] // -2 = 6 words
|
||||
ldp t2, t3, [s, #-32]
|
||||
ldp t4, t5, [s, #-48]
|
||||
stp t0, t1, [d, #-16]
|
||||
stp t2, t3, [d, #-32]
|
||||
stp t4, t5, [d, #-48]
|
||||
ret
|
||||
.align 5
|
||||
ldp t0, t1, [s, #-16] // -1 = 7 words
|
||||
ldp t2, t3, [s, #-32]
|
||||
ldp t4, t5, [s, #-48]
|
||||
ldr t6, [s, #-56]
|
||||
stp t0, t1, [d, #-16]
|
||||
stp t2, t3, [d, #-32]
|
||||
stp t4, t5, [d, #-48]
|
||||
str t6, [d, #-56]
|
||||
// Is always aligned here, code for 7 words is one instruction
|
||||
// too large so it just falls through.
|
||||
.align 5
|
||||
0:
|
||||
ret
|
||||
@ -257,7 +257,38 @@ void Canonicalizer::do_ArrayLength (ArrayLength* x) {
|
||||
}
|
||||
}
|
||||
|
||||
void Canonicalizer::do_LoadIndexed (LoadIndexed* x) {}
|
||||
void Canonicalizer::do_LoadIndexed (LoadIndexed* x) {
|
||||
StableArrayConstant* array = x->array()->type()->as_StableArrayConstant();
|
||||
IntConstant* index = x->index()->type()->as_IntConstant();
|
||||
|
||||
assert(array == NULL || FoldStableValues, "not enabled");
|
||||
|
||||
// Constant fold loads from stable arrays.
|
||||
if (array != NULL && index != NULL) {
|
||||
jint idx = index->value();
|
||||
if (idx < 0 || idx >= array->value()->length()) {
|
||||
// Leave the load as is. The range check will handle it.
|
||||
return;
|
||||
}
|
||||
|
||||
ciConstant field_val = array->value()->element_value(idx);
|
||||
if (!field_val.is_null_or_zero()) {
|
||||
jint dimension = array->dimension();
|
||||
assert(dimension <= array->value()->array_type()->dimension(), "inconsistent info");
|
||||
ValueType* value = NULL;
|
||||
if (dimension > 1) {
|
||||
// Preserve information about the dimension for the element.
|
||||
assert(field_val.as_object()->is_array(), "not an array");
|
||||
value = new StableArrayConstant(field_val.as_object()->as_array(), dimension - 1);
|
||||
} else {
|
||||
assert(dimension == 1, "sanity");
|
||||
value = as_ValueType(field_val);
|
||||
}
|
||||
set_canonical(new Constant(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Canonicalizer::do_StoreIndexed (StoreIndexed* x) {
|
||||
// If a value is going to be stored into a field or array some of
|
||||
// the conversions emitted by javac are unneeded because the fields
|
||||
|
||||
@ -1519,6 +1519,29 @@ void GraphBuilder::method_return(Value x) {
|
||||
append(new Return(x));
|
||||
}
|
||||
|
||||
Value GraphBuilder::make_constant(ciConstant field_value, ciField* field) {
|
||||
BasicType field_type = field_value.basic_type();
|
||||
ValueType* value = as_ValueType(field_value);
|
||||
|
||||
// Attach dimension info to stable arrays.
|
||||
if (FoldStableValues &&
|
||||
field->is_stable() && field_type == T_ARRAY && !field_value.is_null_or_zero()) {
|
||||
ciArray* array = field_value.as_object()->as_array();
|
||||
jint dimension = field->type()->as_array_klass()->dimension();
|
||||
value = new StableArrayConstant(array, dimension);
|
||||
}
|
||||
|
||||
switch (field_type) {
|
||||
case T_ARRAY:
|
||||
case T_OBJECT:
|
||||
if (field_value.as_object()->should_be_constant()) {
|
||||
return new Constant(value);
|
||||
}
|
||||
return NULL; // Not a constant.
|
||||
default:
|
||||
return new Constant(value);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
bool will_link;
|
||||
@ -1563,22 +1586,13 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
switch (code) {
|
||||
case Bytecodes::_getstatic: {
|
||||
// check for compile-time constants, i.e., initialized static final fields
|
||||
Instruction* constant = NULL;
|
||||
Value constant = NULL;
|
||||
if (field->is_constant() && !PatchALot) {
|
||||
ciConstant field_val = field->constant_value();
|
||||
BasicType field_type = field_val.basic_type();
|
||||
switch (field_type) {
|
||||
case T_ARRAY:
|
||||
case T_OBJECT:
|
||||
if (field_val.as_object()->should_be_constant()) {
|
||||
constant = new Constant(as_ValueType(field_val));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
constant = new Constant(as_ValueType(field_val));
|
||||
}
|
||||
ciConstant field_value = field->constant_value();
|
||||
// Stable static fields are checked for non-default values in ciField::initialize_from().
|
||||
assert(!field->is_stable() || !field_value.is_null_or_zero(),
|
||||
"stable static w/ default value shouldn't be a constant");
|
||||
constant = make_constant(field_value, field);
|
||||
}
|
||||
if (constant != NULL) {
|
||||
push(type, append(constant));
|
||||
@ -1591,38 +1605,29 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Bytecodes::_putstatic:
|
||||
{ Value val = pop(type);
|
||||
if (state_before == NULL) {
|
||||
state_before = copy_state_for_exception();
|
||||
}
|
||||
append(new StoreField(append(obj), offset, field, val, true, state_before, needs_patching));
|
||||
case Bytecodes::_putstatic: {
|
||||
Value val = pop(type);
|
||||
if (state_before == NULL) {
|
||||
state_before = copy_state_for_exception();
|
||||
}
|
||||
append(new StoreField(append(obj), offset, field, val, true, state_before, needs_patching));
|
||||
break;
|
||||
}
|
||||
case Bytecodes::_getfield: {
|
||||
// Check for compile-time constants, i.e., trusted final non-static fields.
|
||||
Instruction* constant = NULL;
|
||||
Value constant = NULL;
|
||||
obj = apop();
|
||||
ObjectType* obj_type = obj->type()->as_ObjectType();
|
||||
if (obj_type->is_constant() && !PatchALot) {
|
||||
ciObject* const_oop = obj_type->constant_value();
|
||||
if (!const_oop->is_null_object() && const_oop->is_loaded()) {
|
||||
if (field->is_constant()) {
|
||||
ciConstant field_val = field->constant_value_of(const_oop);
|
||||
BasicType field_type = field_val.basic_type();
|
||||
switch (field_type) {
|
||||
case T_ARRAY:
|
||||
case T_OBJECT:
|
||||
if (field_val.as_object()->should_be_constant()) {
|
||||
constant = new Constant(as_ValueType(field_val));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
constant = new Constant(as_ValueType(field_val));
|
||||
}
|
||||
if (FoldStableValues && field->is_stable() && field_val.is_null_or_zero()) {
|
||||
ciConstant field_value = field->constant_value_of(const_oop);
|
||||
if (FoldStableValues && field->is_stable() && field_value.is_null_or_zero()) {
|
||||
// Stable field with default value can't be constant.
|
||||
constant = NULL;
|
||||
} else {
|
||||
constant = make_constant(field_value, field);
|
||||
}
|
||||
} else {
|
||||
// For CallSite objects treat the target field as a compile time constant.
|
||||
@ -3942,7 +3947,7 @@ bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, Bytecode
|
||||
|
||||
|
||||
bool GraphBuilder::try_method_handle_inline(ciMethod* callee) {
|
||||
ValueStack* state_before = state()->copy_for_parsing();
|
||||
ValueStack* state_before = copy_state_before();
|
||||
vmIntrinsics::ID iid = callee->intrinsic_id();
|
||||
switch (iid) {
|
||||
case vmIntrinsics::_invokeBasic:
|
||||
@ -4032,7 +4037,7 @@ bool GraphBuilder::try_method_handle_inline(ciMethod* callee) {
|
||||
fatal("unexpected intrinsic %d: %s", iid, vmIntrinsics::name_at(iid));
|
||||
break;
|
||||
}
|
||||
set_state(state_before);
|
||||
set_state(state_before->copy_for_parsing());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -276,6 +276,7 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
|
||||
void iterate_all_blocks(bool start_in_current_block_for_inlining = false);
|
||||
Dependencies* dependency_recorder() const; // = compilation()->dependencies()
|
||||
bool direct_compare(ciKlass* k);
|
||||
Value make_constant(ciConstant value, ciField* field);
|
||||
|
||||
void kill_all();
|
||||
|
||||
|
||||
@ -335,6 +335,7 @@ JRT_ENTRY(void, Runtime1::new_instance(JavaThread* thread, Klass* klass))
|
||||
NOT_PRODUCT(_new_instance_slowcase_cnt++;)
|
||||
|
||||
assert(klass->is_klass(), "not a class");
|
||||
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
|
||||
instanceKlassHandle h(thread, klass);
|
||||
h->check_valid_for_instantiation(true, CHECK);
|
||||
// make sure klass is initialized
|
||||
@ -370,6 +371,7 @@ JRT_ENTRY(void, Runtime1::new_object_array(JavaThread* thread, Klass* array_klas
|
||||
// anymore after new_objArray() and no GC can happen before.
|
||||
// (This may have to change if this code changes!)
|
||||
assert(array_klass->is_klass(), "not a class");
|
||||
Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive
|
||||
Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass();
|
||||
objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
@ -386,6 +388,7 @@ JRT_ENTRY(void, Runtime1::new_multi_array(JavaThread* thread, Klass* klass, int
|
||||
|
||||
assert(klass->is_klass(), "not a class");
|
||||
assert(rank >= 1, "rank must be nonzero");
|
||||
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
|
||||
oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
JRT_END
|
||||
@ -661,7 +664,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
|
||||
|
||||
@ -45,6 +45,7 @@ class ObjectType;
|
||||
class ObjectConstant;
|
||||
class ArrayType;
|
||||
class ArrayConstant;
|
||||
class StableArrayConstant;
|
||||
class InstanceType;
|
||||
class InstanceConstant;
|
||||
class MetadataType;
|
||||
@ -168,6 +169,7 @@ class ValueType: public CompilationResourceObj {
|
||||
virtual MethodConstant* as_MethodConstant() { return NULL; }
|
||||
virtual MethodDataConstant* as_MethodDataConstant() { return NULL; }
|
||||
virtual ArrayConstant* as_ArrayConstant() { return NULL; }
|
||||
virtual StableArrayConstant* as_StableArrayConstant() { return NULL; }
|
||||
virtual AddressConstant* as_AddressConstant() { return NULL; }
|
||||
|
||||
// type operations
|
||||
@ -355,6 +357,20 @@ class ArrayConstant: public ArrayType {
|
||||
virtual ciType* exact_type() const;
|
||||
};
|
||||
|
||||
class StableArrayConstant: public ArrayConstant {
|
||||
private:
|
||||
jint _dimension;
|
||||
|
||||
public:
|
||||
StableArrayConstant(ciArray* value, jint dimension) : ArrayConstant(value) {
|
||||
assert(dimension > 0, "not a stable array");
|
||||
_dimension = dimension;
|
||||
}
|
||||
|
||||
jint dimension() const { return _dimension; }
|
||||
|
||||
virtual StableArrayConstant* as_StableArrayConstant() { return this; }
|
||||
};
|
||||
|
||||
class InstanceType: public ObjectType {
|
||||
public:
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
|
||||
void ciMethodData::load_extra_data() {
|
||||
MethodData* mdo = get_MethodData();
|
||||
|
||||
MutexLocker(mdo->extra_data_lock());
|
||||
MutexLocker ml(mdo->extra_data_lock());
|
||||
|
||||
// speculative trap entries also hold a pointer to a Method so need to be translated
|
||||
DataLayout* dp_src = mdo->extra_data_base();
|
||||
@ -103,16 +103,13 @@ void ciMethodData::load_extra_data() {
|
||||
|
||||
switch(tag) {
|
||||
case DataLayout::speculative_trap_data_tag: {
|
||||
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
|
||||
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
|
||||
|
||||
data_dst->translate_from(data_src);
|
||||
|
||||
#ifdef ASSERT
|
||||
SpeculativeTrapData* data_src2 = new SpeculativeTrapData(dp_src);
|
||||
assert(data_src2->method() == data_src->method() && data_src2->bci() == data_src->bci(), "entries changed while translating");
|
||||
#endif
|
||||
ciSpeculativeTrapData data_dst(dp_dst);
|
||||
SpeculativeTrapData data_src(dp_src);
|
||||
|
||||
{ // During translation a safepoint can happen or VM lock can be taken (e.g., Compile_lock).
|
||||
MutexUnlocker ml(mdo->extra_data_lock());
|
||||
data_dst.translate_from(&data_src);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DataLayout::bit_data_tag:
|
||||
@ -120,9 +117,11 @@ void ciMethodData::load_extra_data() {
|
||||
case DataLayout::no_tag:
|
||||
case DataLayout::arg_info_data_tag:
|
||||
// An empty slot or ArgInfoData entry marks the end of the trap data
|
||||
return;
|
||||
{
|
||||
return; // Need a block to avoid SS compiler bug
|
||||
}
|
||||
default:
|
||||
fatal("bad tag = %d", dp_dst->tag());
|
||||
fatal("bad tag = %d", tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(Debug, 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"
|
||||
@ -513,7 +515,6 @@ char* java_lang_String::as_quoted_ascii(oop java_string) {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) {
|
||||
oop obj = java_string();
|
||||
typeArrayOop value = java_lang_String::value(obj);
|
||||
@ -753,7 +754,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,
|
||||
@ -774,7 +775,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
|
||||
@ -834,11 +835,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 =
|
||||
@ -849,6 +864,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");
|
||||
@ -916,6 +935,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)
|
||||
@ -1101,6 +1130,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.
|
||||
@ -1722,28 +1755,48 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m
|
||||
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) {
|
||||
@ -1755,7 +1808,6 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m
|
||||
st->print_cr("%s", buf);
|
||||
}
|
||||
|
||||
|
||||
void java_lang_Throwable::print_stack_element(outputStream *st, const methodHandle& method, int bci) {
|
||||
Handle mirror = method->method_holder()->java_mirror();
|
||||
int method_id = method->orig_method_idnum();
|
||||
@ -2103,6 +2155,20 @@ void java_lang_StackTraceElement::fill_in(Handle element,
|
||||
oop methodname = StringTable::intern(sym, CHECK);
|
||||
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);
|
||||
java_lang_StackTraceElement::set_moduleName(element(), module_name);
|
||||
oop module_version;
|
||||
if (module->version() != NULL) {
|
||||
module_version = StringTable::intern(module->version(), CHECK);
|
||||
} 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);
|
||||
@ -2754,6 +2820,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();
|
||||
@ -3353,6 +3493,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");
|
||||
@ -3372,6 +3513,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);
|
||||
}
|
||||
|
||||
@ -3439,6 +3583,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() {
|
||||
@ -3471,11 +3619,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::stackTrace_offset;
|
||||
@ -3535,6 +3685,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;
|
||||
@ -3576,6 +3728,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 +3873,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;
|
||||
@ -3753,6 +3915,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();
|
||||
|
||||
@ -3900,7 +4063,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
|
||||
|
||||
|
||||
@ -205,12 +205,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);
|
||||
@ -221,10 +223,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);
|
||||
@ -262,18 +267,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
|
||||
@ -750,6 +766,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:
|
||||
@ -1195,6 +1244,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();
|
||||
@ -1219,6 +1269,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
|
||||
@ -1258,18 +1310,24 @@ 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;
|
||||
static int lineNumber_offset;
|
||||
|
||||
// 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);
|
||||
@ -1450,8 +1508,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"
|
||||
@ -172,13 +174,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());
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1145,6 +1147,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
|
||||
@ -1237,13 +1240,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) {
|
||||
@ -1251,6 +1329,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).
|
||||
@ -1304,12 +1388,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()) {
|
||||
@ -1330,7 +1422,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.
|
||||
@ -1345,7 +1498,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
|
||||
@ -1672,7 +1825,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();
|
||||
}
|
||||
@ -1943,6 +2096,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") \
|
||||
@ -447,14 +456,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") \
|
||||
@ -532,6 +549,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") \
|
||||
@ -551,6 +569,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;") \
|
||||
@ -575,6 +594,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") \
|
||||
@ -633,7 +655,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") \
|
||||
@ -1065,11 +1090,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") \
|
||||
|
||||
@ -369,7 +369,6 @@ void DebugInformationRecorder::describe_scope(int pc_offset,
|
||||
assert(method == NULL ||
|
||||
(method->is_native() && bci == 0) ||
|
||||
(!method->is_native() && 0 <= bci && bci < method->code_size()) ||
|
||||
(method->is_compiled_lambda_form() && bci == -99) || // this might happen in C1
|
||||
bci == -1, "illegal bci");
|
||||
|
||||
// serialize the locals/expressions/monitors
|
||||
|
||||
@ -840,12 +840,8 @@ void CompileBroker::compile_method_base(const methodHandle& method,
|
||||
const methodHandle& hot_method,
|
||||
int hot_count,
|
||||
const char* comment,
|
||||
bool blocking,
|
||||
Thread* thread) {
|
||||
// do nothing if compiler thread(s) is not available
|
||||
if (!_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
guarantee(!method->is_abstract(), "cannot compile abstract methods");
|
||||
assert(method->method_holder()->is_instance_klass(),
|
||||
"sanity check");
|
||||
@ -918,7 +914,6 @@ void CompileBroker::compile_method_base(const methodHandle& method,
|
||||
|
||||
// Outputs from the following MutexLocker block:
|
||||
CompileTask* task = NULL;
|
||||
bool blocking = false;
|
||||
CompileQueue* queue = compile_queue(comp_level);
|
||||
|
||||
// Acquire our lock.
|
||||
@ -948,9 +943,6 @@ void CompileBroker::compile_method_base(const methodHandle& method,
|
||||
return;
|
||||
}
|
||||
|
||||
// Should this thread wait for completion of the compile?
|
||||
blocking = is_compile_blocking();
|
||||
|
||||
#if INCLUDE_JVMCI
|
||||
if (UseJVMCICompiler) {
|
||||
if (blocking) {
|
||||
@ -1036,11 +1028,28 @@ void CompileBroker::compile_method_base(const methodHandle& method,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
|
||||
int comp_level,
|
||||
const methodHandle& hot_method, int hot_count,
|
||||
const char* comment, Thread* THREAD) {
|
||||
// do nothing if compilebroker is not available
|
||||
if (!_initialized) {
|
||||
return NULL;
|
||||
}
|
||||
AbstractCompiler *comp = CompileBroker::compiler(comp_level);
|
||||
assert(comp != NULL, "Ensure we don't compile before compilebroker init");
|
||||
DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, comp);
|
||||
nmethod* nm = CompileBroker::compile_method(method, osr_bci, comp_level, hot_method, hot_count, comment, directive, THREAD);
|
||||
DirectivesStack::release(directive);
|
||||
return nm;
|
||||
}
|
||||
|
||||
nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
|
||||
int comp_level,
|
||||
const methodHandle& hot_method, int hot_count,
|
||||
const char* comment, DirectiveSet* directive,
|
||||
Thread* THREAD) {
|
||||
|
||||
// make sure arguments make sense
|
||||
assert(method->method_holder()->is_instance_klass(), "not an instance method");
|
||||
assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range");
|
||||
@ -1053,8 +1062,8 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
|
||||
// lock, make sure that the compilation
|
||||
// isn't prohibited in a straightforward way.
|
||||
AbstractCompiler *comp = CompileBroker::compiler(comp_level);
|
||||
if (comp == NULL || !comp->can_compile_method(method) ||
|
||||
compilation_is_prohibited(method, osr_bci, comp_level)) {
|
||||
if (!comp->can_compile_method(method) ||
|
||||
compilation_is_prohibited(method, osr_bci, comp_level, directive->ExcludeOption)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1162,7 +1171,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci,
|
||||
CompilationPolicy::policy()->delay_compilation(method());
|
||||
return NULL;
|
||||
}
|
||||
compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, THREAD);
|
||||
compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, !directive->BackgroundCompilationOption, THREAD);
|
||||
}
|
||||
|
||||
// return requested nmethod
|
||||
@ -1219,7 +1228,7 @@ bool CompileBroker::compilation_is_in_queue(const methodHandle& method) {
|
||||
// CompileBroker::compilation_is_prohibited
|
||||
//
|
||||
// See if this compilation is not allowed.
|
||||
bool CompileBroker::compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level) {
|
||||
bool CompileBroker::compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded) {
|
||||
bool is_native = method->is_native();
|
||||
// Some compilers may not support the compilation of natives.
|
||||
AbstractCompiler *comp = compiler(comp_level);
|
||||
@ -1237,11 +1246,6 @@ bool CompileBroker::compilation_is_prohibited(const methodHandle& method, int os
|
||||
return true;
|
||||
}
|
||||
|
||||
// Breaking the abstraction - directives are only used inside a compilation otherwise.
|
||||
DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, comp);
|
||||
bool excluded = directive->ExcludeOption;
|
||||
DirectivesStack::release(directive);
|
||||
|
||||
// The method may be explicitly excluded by the user.
|
||||
double scale;
|
||||
if (excluded || (CompilerOracle::has_option_value(method, "CompileThresholdScaling", scale) && scale == 0)) {
|
||||
@ -1306,16 +1310,6 @@ uint CompileBroker::assign_compile_id_unlocked(Thread* thread, const methodHandl
|
||||
return assign_compile_id(method, osr_bci);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should the current thread block until this compilation request
|
||||
* has been fulfilled?
|
||||
*/
|
||||
bool CompileBroker::is_compile_blocking() {
|
||||
assert(!ReferencePendingListLocker::is_locked_by_self(), "possible deadlock");
|
||||
return !BackgroundCompilation;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// CompileBroker::preload_classes
|
||||
void CompileBroker::preload_classes(const methodHandle& method, TRAPS) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -222,8 +222,7 @@ class CompileBroker: AllStatic {
|
||||
static JavaThread* make_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, bool compiler_thread, TRAPS);
|
||||
static void init_compiler_sweeper_threads(int c1_compiler_count, int c2_compiler_count);
|
||||
static bool compilation_is_complete (const methodHandle& method, int osr_bci, int comp_level);
|
||||
static bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level);
|
||||
static bool is_compile_blocking();
|
||||
static bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded);
|
||||
static void preload_classes (const methodHandle& method, TRAPS);
|
||||
|
||||
static CompileTask* create_compile_task(CompileQueue* queue,
|
||||
@ -253,6 +252,7 @@ class CompileBroker: AllStatic {
|
||||
const methodHandle& hot_method,
|
||||
int hot_count,
|
||||
const char* comment,
|
||||
bool blocking,
|
||||
Thread* thread);
|
||||
|
||||
static CompileQueue* compile_queue(int comp_level);
|
||||
@ -291,6 +291,15 @@ public:
|
||||
int hot_count,
|
||||
const char* comment, Thread* thread);
|
||||
|
||||
static nmethod* compile_method(const methodHandle& method,
|
||||
int osr_bci,
|
||||
int comp_level,
|
||||
const methodHandle& hot_method,
|
||||
int hot_count,
|
||||
const char* comment,
|
||||
DirectiveSet* directive,
|
||||
Thread* thread);
|
||||
|
||||
// Acquire any needed locks and assign a compile id
|
||||
static uint assign_compile_id_unlocked(Thread* thread, const methodHandle& method, int osr_bci);
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -472,9 +472,12 @@ void DirectivesStack::push(CompilerDirectives* directive) {
|
||||
_depth++;
|
||||
}
|
||||
|
||||
void DirectivesStack::pop() {
|
||||
void DirectivesStack::pop(int count) {
|
||||
MutexLockerEx locker(DirectivesStack_lock, Mutex::_no_safepoint_check_flag);
|
||||
pop_inner();
|
||||
assert(count > -1, "No negative values");
|
||||
for (int i = 0; i < count; i++) {
|
||||
pop_inner();
|
||||
}
|
||||
}
|
||||
|
||||
void DirectivesStack::pop_inner() {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -42,6 +42,7 @@
|
||||
cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \
|
||||
cflags(PrintInlining, bool, PrintInlining, PrintInlining) \
|
||||
cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \
|
||||
cflags(BackgroundCompilation, bool, BackgroundCompilation, BackgroundCompilation) \
|
||||
cflags(ReplayInline, bool, false, ReplayInline) \
|
||||
cflags(DumpReplay, bool, false, DumpReplay) \
|
||||
cflags(DumpInline, bool, false, DumpInline) \
|
||||
@ -87,7 +88,7 @@ public:
|
||||
static DirectiveSet* getMatchingDirective(methodHandle mh, AbstractCompiler* comp);
|
||||
static DirectiveSet* getDefaultDirective(AbstractCompiler* comp);
|
||||
static void push(CompilerDirectives* directive);
|
||||
static void pop();
|
||||
static void pop(int count);
|
||||
static bool check_capacity(int request_size, outputStream* st);
|
||||
static void clear();
|
||||
static void print(outputStream* st);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -55,7 +55,7 @@ void DirectivesParser::clean_tmp() {
|
||||
assert(_tmp_depth == 0, "Consistency");
|
||||
}
|
||||
|
||||
bool DirectivesParser::parse_string(const char* text, outputStream* st) {
|
||||
int DirectivesParser::parse_string(const char* text, outputStream* st) {
|
||||
DirectivesParser cd(text, st);
|
||||
if (cd.valid()) {
|
||||
return cd.install_directives();
|
||||
@ -63,7 +63,7 @@ bool DirectivesParser::parse_string(const char* text, outputStream* st) {
|
||||
cd.clean_tmp();
|
||||
st->flush();
|
||||
st->print_cr("Parsing of compiler directives failed");
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,17 +97,17 @@ bool DirectivesParser::parse_from_file_inner(const char* filename, outputStream*
|
||||
buffer[num_read] = '\0';
|
||||
// close file
|
||||
os::close(file_handle);
|
||||
return parse_string(buffer, stream);
|
||||
return parse_string(buffer, stream) > 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DirectivesParser::install_directives() {
|
||||
int DirectivesParser::install_directives() {
|
||||
// Check limit
|
||||
if (!DirectivesStack::check_capacity(_tmp_depth, _st)) {
|
||||
clean_tmp();
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pop from internal temporary stack and push to compileBroker.
|
||||
@ -120,14 +120,14 @@ bool DirectivesParser::install_directives() {
|
||||
}
|
||||
if (i == 0) {
|
||||
_st->print_cr("No directives in file");
|
||||
return false;
|
||||
return 0;
|
||||
} else {
|
||||
_st->print_cr("%i compiler directives added", i);
|
||||
if (CompilerDirectivesPrint) {
|
||||
// Print entire directives stack after new has been pushed.
|
||||
DirectivesStack::print(_st);
|
||||
}
|
||||
return true;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -51,8 +51,8 @@ public:
|
||||
static bool has_file();
|
||||
static bool parse_from_flag();
|
||||
static bool parse_from_file(const char* filename, outputStream* st);
|
||||
static bool parse_string(const char* string, outputStream* st);
|
||||
bool install_directives();
|
||||
static int parse_string(const char* string, outputStream* st);
|
||||
int install_directives();
|
||||
|
||||
private:
|
||||
DirectivesParser(const char* text, outputStream* st);
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -381,7 +381,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -162,6 +162,9 @@ void JVMCICompiler::compile_method(const methodHandle& method, int entry_bci, JV
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
|
||||
java_lang_Throwable::java_printStackTrace(exception, THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
}
|
||||
|
||||
env->set_failure("exception throw", false);
|
||||
} else {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL;
|
||||
bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false;
|
||||
bool JVMCIRuntime::_well_known_classes_initialized = false;
|
||||
const char* JVMCIRuntime::_compiler = NULL;
|
||||
int JVMCIRuntime::_trivial_prefixes_count = 0;
|
||||
char** JVMCIRuntime::_trivial_prefixes = NULL;
|
||||
bool JVMCIRuntime::_shutdown_called = false;
|
||||
@ -104,6 +103,7 @@ static void deopt_caller() {
|
||||
JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass))
|
||||
JRT_BLOCK;
|
||||
assert(klass->is_klass(), "not a class");
|
||||
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
|
||||
instanceKlassHandle h(thread, klass);
|
||||
h->check_valid_for_instantiation(true, CHECK);
|
||||
// make sure klass is initialized
|
||||
@ -129,6 +129,7 @@ JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_k
|
||||
BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type();
|
||||
obj = oopFactory::new_typeArray(elt_type, length, CHECK);
|
||||
} else {
|
||||
Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive
|
||||
Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass();
|
||||
obj = oopFactory::new_objArray(elem_klass, length, CHECK);
|
||||
}
|
||||
@ -172,6 +173,7 @@ void JVMCIRuntime::new_store_pre_barrier(JavaThread* thread) {
|
||||
JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims))
|
||||
assert(klass->is_klass(), "not a class");
|
||||
assert(rank >= 1, "rank must be nonzero");
|
||||
Handle holder(THREAD, klass->klass_holder()); // keep the klass alive
|
||||
oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK);
|
||||
thread->set_vm_result(obj);
|
||||
JRT_END
|
||||
@ -642,15 +644,6 @@ void JVMCIRuntime::initialize_HotSpotJVMCIRuntime(TRAPS) {
|
||||
"HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization");
|
||||
#endif
|
||||
|
||||
if (_compiler != NULL) {
|
||||
JavaCallArguments args;
|
||||
oop compiler = java_lang_String::create_oop_from_str(_compiler, CHECK);
|
||||
args.push_oop(compiler);
|
||||
callStatic("jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig",
|
||||
"selectCompiler",
|
||||
"(Ljava/lang/String;)Ljava/lang/Boolean;", &args, CHECK);
|
||||
}
|
||||
|
||||
Handle result = callStatic("jdk/vm/ci/hotspot/HotSpotJVMCIRuntime",
|
||||
"runtime",
|
||||
"()Ljdk/vm/ci/hotspot/HotSpotJVMCIRuntime;", NULL, CHECK);
|
||||
@ -783,66 +776,6 @@ JVM_ENTRY(void, JVM_RegisterJVMCINatives(JNIEnv *env, jclass c2vmClass))
|
||||
}
|
||||
JVM_END
|
||||
|
||||
/**
|
||||
* Closure for parsing a line from a *.properties file in jre/lib/jvmci/properties.
|
||||
* The line must match the regular expression "[^=]+=.*". That is one or more
|
||||
* characters other than '=' followed by '=' followed by zero or more characters.
|
||||
* Everything before the '=' is the property name and everything after '=' is the value.
|
||||
* Lines that start with '#' are treated as comments and ignored.
|
||||
* No special processing of whitespace or any escape characters is performed.
|
||||
* The last definition of a property "wins" (i.e., it overrides all earlier
|
||||
* definitions of the property).
|
||||
*/
|
||||
class JVMCIPropertiesFileClosure : public ParseClosure {
|
||||
SystemProperty** _plist;
|
||||
public:
|
||||
JVMCIPropertiesFileClosure(SystemProperty** plist) : _plist(plist) {}
|
||||
void do_line(char* line) {
|
||||
if (line[0] == '#') {
|
||||
// skip comment
|
||||
return;
|
||||
}
|
||||
size_t len = strlen(line);
|
||||
char* sep = strchr(line, '=');
|
||||
if (sep == NULL) {
|
||||
warn_and_abort("invalid format: could not find '=' character");
|
||||
return;
|
||||
}
|
||||
if (sep == line) {
|
||||
warn_and_abort("invalid format: name cannot be empty");
|
||||
return;
|
||||
}
|
||||
*sep = '\0';
|
||||
const char* name = line;
|
||||
char* value = sep + 1;
|
||||
Arguments::PropertyList_unique_add(_plist, name, value);
|
||||
}
|
||||
};
|
||||
|
||||
void JVMCIRuntime::init_system_properties(SystemProperty** plist) {
|
||||
char jvmciDir[JVM_MAXPATHLEN];
|
||||
const char* fileSep = os::file_separator();
|
||||
jio_snprintf(jvmciDir, sizeof(jvmciDir), "%s%slib%sjvmci",
|
||||
Arguments::get_java_home(), fileSep, fileSep, fileSep);
|
||||
DIR* dir = os::opendir(jvmciDir);
|
||||
if (dir != NULL) {
|
||||
struct dirent *entry;
|
||||
char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(jvmciDir), mtInternal);
|
||||
JVMCIPropertiesFileClosure closure(plist);
|
||||
const unsigned suffix_len = (unsigned)strlen(".properties");
|
||||
while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL && !closure.is_aborted()) {
|
||||
const char* name = entry->d_name;
|
||||
if (strlen(name) > suffix_len && strcmp(name + strlen(name) - suffix_len, ".properties") == 0) {
|
||||
char propertiesFilePath[JVM_MAXPATHLEN];
|
||||
jio_snprintf(propertiesFilePath, sizeof(propertiesFilePath), "%s%s%s",jvmciDir, fileSep, name);
|
||||
JVMCIRuntime::parse_lines(propertiesFilePath, &closure, false);
|
||||
}
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(char, dbuf);
|
||||
os::closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_WARN_ABORT_(message) THREAD); \
|
||||
if (HAS_PENDING_EXCEPTION) { \
|
||||
warning(message); \
|
||||
@ -853,12 +786,6 @@ void JVMCIRuntime::init_system_properties(SystemProperty** plist) {
|
||||
} \
|
||||
(void)(0
|
||||
|
||||
void JVMCIRuntime::save_compiler(const char* compiler) {
|
||||
assert(compiler != NULL, "npe");
|
||||
assert(_compiler == NULL, "cannot reassign JVMCI compiler");
|
||||
_compiler = compiler;
|
||||
}
|
||||
|
||||
void JVMCIRuntime::shutdown(TRAPS) {
|
||||
if (_HotSpotJVMCIRuntime_instance != NULL) {
|
||||
_shutdown_called = true;
|
||||
@ -884,69 +811,3 @@ bool JVMCIRuntime::treat_as_trivial(Method* method) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void JVMCIRuntime::parse_lines(char* path, ParseClosure* closure, bool warnStatFailure) {
|
||||
struct stat st;
|
||||
if (::stat(path, &st) == 0 && (st.st_mode & S_IFREG) == S_IFREG) { // exists & is regular file
|
||||
int file_handle = ::open(path, os::default_file_open_flags(), 0);
|
||||
if (file_handle != -1) {
|
||||
char* buffer = NEW_C_HEAP_ARRAY(char, st.st_size + 1, mtInternal);
|
||||
int num_read;
|
||||
num_read = (int) ::read(file_handle, (char*) buffer, st.st_size);
|
||||
if (num_read == -1) {
|
||||
warning("Error reading file %s due to %s", path, strerror(errno));
|
||||
} else if (num_read != st.st_size) {
|
||||
warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path);
|
||||
}
|
||||
::close(file_handle);
|
||||
closure->set_filename(path);
|
||||
if (num_read == st.st_size) {
|
||||
buffer[num_read] = '\0';
|
||||
|
||||
char* line = buffer;
|
||||
while (line - buffer < num_read && !closure->is_aborted()) {
|
||||
// find line end (\r, \n or \r\n)
|
||||
char* nextline = NULL;
|
||||
char* cr = strchr(line, '\r');
|
||||
char* lf = strchr(line, '\n');
|
||||
if (cr != NULL && lf != NULL) {
|
||||
char* min = MIN2(cr, lf);
|
||||
*min = '\0';
|
||||
if (lf == cr + 1) {
|
||||
nextline = lf + 1;
|
||||
} else {
|
||||
nextline = min + 1;
|
||||
}
|
||||
} else if (cr != NULL) {
|
||||
*cr = '\0';
|
||||
nextline = cr + 1;
|
||||
} else if (lf != NULL) {
|
||||
*lf = '\0';
|
||||
nextline = lf + 1;
|
||||
}
|
||||
// trim left
|
||||
while (*line == ' ' || *line == '\t') line++;
|
||||
char* end = line + strlen(line);
|
||||
// trim right
|
||||
while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--;
|
||||
*end = '\0';
|
||||
// skip comments and empty lines
|
||||
if (*line != '#' && strlen(line) > 0) {
|
||||
closure->parse_line(line);
|
||||
}
|
||||
if (nextline != NULL) {
|
||||
line = nextline;
|
||||
} else {
|
||||
// File without newline at the end
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(char, buffer);
|
||||
} else {
|
||||
warning("Error opening file %s due to %s", path, strerror(errno));
|
||||
}
|
||||
} else if (warnStatFailure) {
|
||||
warning("Could not stat file %s due to %s", path, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -70,7 +70,6 @@ class JVMCIRuntime: public AllStatic {
|
||||
static jobject _HotSpotJVMCIRuntime_instance;
|
||||
static bool _HotSpotJVMCIRuntime_initialized;
|
||||
static bool _well_known_classes_initialized;
|
||||
static const char* _compiler;
|
||||
|
||||
static int _trivial_prefixes_count;
|
||||
static char** _trivial_prefixes;
|
||||
@ -85,19 +84,9 @@ class JVMCIRuntime: public AllStatic {
|
||||
static Handle create_Service(const char* name, TRAPS);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Parses *.properties files in jre/lib/jvmci/ and adds the properties to plist.
|
||||
*/
|
||||
static void init_system_properties(SystemProperty** plist);
|
||||
|
||||
/**
|
||||
* Saves the value of the "jvmci.compiler" system property for processing
|
||||
* when JVMCI is initialized.
|
||||
*/
|
||||
static void save_compiler(const char* compiler);
|
||||
|
||||
static bool is_HotSpotJVMCIRuntime_initialized() { return _HotSpotJVMCIRuntime_initialized; }
|
||||
static bool is_HotSpotJVMCIRuntime_initialized() {
|
||||
return _HotSpotJVMCIRuntime_initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the singleton HotSpotJVMCIRuntime instance, initializing it if necessary
|
||||
@ -136,7 +125,6 @@ class JVMCIRuntime: public AllStatic {
|
||||
}
|
||||
|
||||
static bool treat_as_trivial(Method* method);
|
||||
static void parse_lines(char* path, ParseClosure* closure, bool warnStatFailure);
|
||||
|
||||
static BasicType kindToBasicType(Handle kind, TRAPS);
|
||||
|
||||
|
||||
@ -63,6 +63,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);
|
||||
|
||||
@ -154,6 +154,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;
|
||||
@ -665,7 +666,6 @@ jint universe_init() {
|
||||
} else {
|
||||
SymbolTable::create_table();
|
||||
StringTable::create_table();
|
||||
ClassLoader::create_package_info_table();
|
||||
|
||||
if (DumpSharedSpaces) {
|
||||
MetaspaceShared::prepare_for_dumping();
|
||||
@ -884,6 +884,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1330,7 +1330,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
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user