mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
Merge
This commit is contained in:
commit
88a48fe2a6
466 changed files with 5339 additions and 6165 deletions
1
.hgtags
1
.hgtags
|
@ -514,3 +514,4 @@ ef57958c7c511162da8d9a75f0b977f0f7ac464e jdk-12+7
|
||||||
f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11
|
f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11
|
||||||
15094d12a632f452a2064318a4e416d0c7a9ce0c jdk-12+12
|
15094d12a632f452a2064318a4e416d0c7a9ce0c jdk-12+12
|
||||||
511a9946f83e3e3c7b9dbe1840367063fb39b4e1 jdk-12+13
|
511a9946f83e3e3c7b9dbe1840367063fb39b4e1 jdk-12+13
|
||||||
|
8897e41b327c0a5601c6ba2bba5d07f15a3ffc91 jdk-12+14
|
||||||
|
|
107
make/Jprt.gmk
107
make/Jprt.gmk
|
@ -1,107 +0,0 @@
|
||||||
#
|
|
||||||
# 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
|
|
||||||
# under the terms of the GNU General Public License version 2 only, as
|
|
||||||
# published by the Free Software Foundation. Oracle designates this
|
|
||||||
# particular file as subject to the "Classpath" exception as provided
|
|
||||||
# by Oracle in the LICENSE file that accompanied this code.
|
|
||||||
#
|
|
||||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
||||||
# version 2 for more details (a copy is included in the LICENSE file that
|
|
||||||
# accompanied this code).
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License version
|
|
||||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
|
||||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
||||||
# or visit www.oracle.com if you need additional information or have any
|
|
||||||
# questions.
|
|
||||||
#
|
|
||||||
|
|
||||||
# This file contains targets and utilities needed by JPRT.
|
|
||||||
|
|
||||||
# Cygpath is only defined when running on Cygwin
|
|
||||||
ifneq ($(CYGPATH), )
|
|
||||||
# If we get JPRT_ARCHIVE_*BUNDLE externally, make sure they have /cygdrive
|
|
||||||
# style paths
|
|
||||||
ifdef JPRT_ARCHIVE_BUNDLE
|
|
||||||
override JPRT_ARCHIVE_BUNDLE := $(shell $(CYGPATH) -u $(JPRT_ARCHIVE_BUNDLE))
|
|
||||||
endif
|
|
||||||
ifdef JPRT_ARCHIVE_TEST_BUNDLE
|
|
||||||
override JPRT_ARCHIVE_TEST_BUNDLE := \
|
|
||||||
$(shell $(CYGPATH) -u $(JPRT_ARCHIVE_TEST_BUNDLE))
|
|
||||||
endif
|
|
||||||
ifdef JPRT_ARCHIVE_SYMBOLS_BUNDLE
|
|
||||||
override JPRT_ARCHIVE_SYMBOLS_BUNDLE := \
|
|
||||||
$(shell $(CYGPATH) -u $(JPRT_ARCHIVE_SYMBOLS_BUNDLE))
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
# When running in JPRT these will be provided. Need defaults so that this makefile
|
|
||||||
# is valid anyway.
|
|
||||||
ifndef JPRT_ARCHIVE_BUNDLE
|
|
||||||
JPRT_ARCHIVE_BUNDLE=/tmp/jprt_bundles/jdk-image.zip
|
|
||||||
endif
|
|
||||||
ifndef JPRT_ARCHIVE_TEST_BUNDLE
|
|
||||||
JPRT_ARCHIVE_TEST_BUNDLE=/tmp/jprt_bundles/test-image.zip
|
|
||||||
endif
|
|
||||||
ifndef JPRT_ARCHIVE_SYMBOLS_BUNDLE
|
|
||||||
JPRT_ARCHIVE_SYMBOLS_BUNDLE=/tmp/jprt_bundles/symbols-image.zip
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(SKIP_BOOT_CYCLE), false)
|
|
||||||
jprt_bundle: bootcycle-images
|
|
||||||
endif
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# JPRT specific bundling targets
|
|
||||||
JPRT_TARGET ?= $(DEFAULT_MAKE_TARGET)
|
|
||||||
ifeq ($(JPRT_TARGET), $(DEFAULT_MAKE_TARGET))
|
|
||||||
jprt_bundle: $(DEFAULT_MAKE_TARGET) $(JPRT_ARCHIVE_BUNDLE) \
|
|
||||||
$(JPRT_ARCHIVE_TEST_BUNDLE)
|
|
||||||
|
|
||||||
SRC_JDK_IMAGE_DIR := $(JDK_IMAGE_DIR)
|
|
||||||
SRC_TEST_IMAGE_DIR := $(TEST_IMAGE_DIR)
|
|
||||||
|
|
||||||
# This target must be called in the context of a SPEC file
|
|
||||||
$(JPRT_ARCHIVE_BUNDLE): product-images
|
|
||||||
$(call MakeDir, $(@D))
|
|
||||||
$(CD) $(SRC_JDK_IMAGE_DIR) && $(ZIPEXE) -y -q -r $@ .
|
|
||||||
|
|
||||||
$(JPRT_ARCHIVE_TEST_BUNDLE): test-image
|
|
||||||
$(call MakeDir, $(@D))
|
|
||||||
$(CD) $(SRC_TEST_IMAGE_DIR) && $(ZIPEXE) -y -q -r $@ .
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
# Optional symbols bundle
|
|
||||||
ifeq ($(GCOV_ENABLED), true)
|
|
||||||
jprt_bundle: $(JPRT_ARCHIVE_SYMBOLS_BUNDLE)
|
|
||||||
|
|
||||||
$(JPRT_ARCHIVE_SYMBOLS_BUNDLE): product-images
|
|
||||||
$(call MakeDir, $(@D))
|
|
||||||
$(CD) $(SYMBOLS_IMAGE_DIR) && $(ZIPEXE) -y -q -r $@ .
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
else
|
|
||||||
# Just fake the main bundle to satisfy JPRT
|
|
||||||
jprt_bundle: $(JPRT_TARGET)
|
|
||||||
@$(call TargetEnter)
|
|
||||||
$(MKDIR) -p $(OUTPUTDIR)/bundles
|
|
||||||
$(CD) $(TOPDIR) && $(TAR) cf - README | $(GZIP) > \
|
|
||||||
$(JPRT_ARCHIVE_BUNDLE)
|
|
||||||
@$(call TargetExit)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ALL_TARGETS += jprt_bundle
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
$(eval $(call IncludeCustomExtension, Jprt.gmk))
|
|
|
@ -1131,11 +1131,6 @@ ALL_TARGETS += $(addsuffix -only, $(filter-out dist-clean clean%, $(ALL_TARGETS)
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
# Include JPRT targets
|
|
||||||
include $(TOPDIR)/make/Jprt.gmk
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
# The following targets are intentionally not added to ALL_TARGETS since they
|
# The following targets are intentionally not added to ALL_TARGETS since they
|
||||||
# are internal only, to support Init.gmk.
|
# are internal only, to support Init.gmk.
|
||||||
|
|
||||||
|
|
|
@ -351,6 +351,11 @@ AC_DEFUN_ONCE([HOTSPOT_SETUP_JVM_FEATURES],
|
||||||
AC_MSG_RESULT([no])
|
AC_MSG_RESULT([no])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Disable unsupported GCs for Zero
|
||||||
|
if HOTSPOT_CHECK_JVM_VARIANT(zero); then
|
||||||
|
DISABLED_JVM_FEATURES="$DISABLED_JVM_FEATURES epsilongc g1gc zgc"
|
||||||
|
fi
|
||||||
|
|
||||||
# Turn on additional features based on other parts of configure
|
# Turn on additional features based on other parts of configure
|
||||||
if test "x$INCLUDE_DTRACE" = "xtrue"; then
|
if test "x$INCLUDE_DTRACE" = "xtrue"; then
|
||||||
JVM_FEATURES="$JVM_FEATURES dtrace"
|
JVM_FEATURES="$JVM_FEATURES dtrace"
|
||||||
|
|
|
@ -525,8 +525,7 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||||
profiles[maketestName].default_make_targets = [ "test-make" ];
|
profiles[maketestName].default_make_targets = [ "test-make" ];
|
||||||
});
|
});
|
||||||
|
|
||||||
// Profiles for building the zero jvm variant. These are used for verification
|
// Profiles for building the zero jvm variant. These are used for verification.
|
||||||
// in JPRT.
|
|
||||||
var zeroProfiles = {
|
var zeroProfiles = {
|
||||||
"linux-x64-zero": {
|
"linux-x64-zero": {
|
||||||
target_os: "linux",
|
target_os: "linux",
|
||||||
|
@ -733,18 +732,8 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Profiles used to run tests. Used in JPRT and Mach 5.
|
// Profiles used to run tests.
|
||||||
var testOnlyProfiles = {
|
var testOnlyProfiles = {
|
||||||
"run-test-jprt": {
|
|
||||||
target_os: input.build_os,
|
|
||||||
target_cpu: input.build_cpu,
|
|
||||||
dependencies: [ "jtreg", "gnumake", "boot_jdk", "devkit", "jib" ],
|
|
||||||
labels: "test",
|
|
||||||
environment: {
|
|
||||||
"JT_JAVA": common.boot_jdk_home
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"run-test": {
|
"run-test": {
|
||||||
target_os: input.build_os,
|
target_os: input.build_os,
|
||||||
target_cpu: input.build_cpu,
|
target_cpu: input.build_cpu,
|
||||||
|
@ -806,7 +795,6 @@ var getJibProfilesProfiles = function (input, common, data) {
|
||||||
+ "/Xcode.app/Contents/Developer/usr/bin"
|
+ "/Xcode.app/Contents/Developer/usr/bin"
|
||||||
};
|
};
|
||||||
profiles["run-test"] = concatObjects(profiles["run-test"], macosxRunTestExtra);
|
profiles["run-test"] = concatObjects(profiles["run-test"], macosxRunTestExtra);
|
||||||
profiles["run-test-jprt"] = concatObjects(profiles["run-test-jprt"], macosxRunTestExtra);
|
|
||||||
profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], macosxRunTestExtra);
|
profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"], macosxRunTestExtra);
|
||||||
}
|
}
|
||||||
// On windows we want the debug symbols available at test time
|
// On windows we want the debug symbols available at test time
|
||||||
|
|
|
@ -1,503 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
||||||
#
|
|
||||||
# This code is free software; you can redistribute 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
##############
|
|
||||||
#
|
|
||||||
# Global settings
|
|
||||||
#
|
|
||||||
|
|
||||||
# Install test bundle for targets in jprt.test.bundle.targets set
|
|
||||||
jprt.selective.test.bundle.installation=true
|
|
||||||
|
|
||||||
# The current release name
|
|
||||||
jprt.tools.default.release=jdk9
|
|
||||||
|
|
||||||
# Allow concurrent changes to be merged in prior to pushing
|
|
||||||
jprt.sync.push=true
|
|
||||||
|
|
||||||
# Directories to be excluded from the source bundles
|
|
||||||
jprt.bundle.exclude.src.dirs=build dist webrev ${jprt.bundle.exclude.src.dirs.extra}
|
|
||||||
|
|
||||||
# Use configure when building
|
|
||||||
jprt.build.use.configure=true
|
|
||||||
jprt.build.use.jib=true
|
|
||||||
jprt.test.use.jib=true
|
|
||||||
jprt.jib.launcher=bin/jib.sh
|
|
||||||
jprt.build.use.jib.publish=true
|
|
||||||
|
|
||||||
# Clear out all the build needs as JIB handles this
|
|
||||||
jprt.jdk9.build.needs=
|
|
||||||
jprt.macosx.jdk9.build.needs=
|
|
||||||
jprt.windows_i586.jdk9.build.needs=
|
|
||||||
jprt.windows_x64.jdk9.build.needs=
|
|
||||||
jprt.solaris.jdk9.build.needs=
|
|
||||||
jprt.linux_i586.jdk9.build.needs=
|
|
||||||
jprt.linux_x64.jdk9.build.needs=
|
|
||||||
jprt.linux_armv6.jdk9.build.needs=
|
|
||||||
jprt.linux_armvh.jdk9.build.needs=
|
|
||||||
jprt.linux_arm64.jdk9.build.needs=
|
|
||||||
jprt.linux_armsflt.jdk9.build.needs=
|
|
||||||
jprt.linux_armvfpsflt.jdk9.build.needs=
|
|
||||||
jprt.linux_armvfphflt.jdk9.build.needs=
|
|
||||||
jprt.linux_armv6vfphflt.jdk9.build.needs=
|
|
||||||
jprt.solaris.client.build.needs=
|
|
||||||
jprt.linux.client.build.needs=
|
|
||||||
jprt.solaris.jdk9.compiler=
|
|
||||||
jprt.linux.jdk9.compiler=
|
|
||||||
jprt.jdk9.test.needs=
|
|
||||||
|
|
||||||
# Disable the need for preinstalled Visual Studio and Xcode
|
|
||||||
jprt.windows.jdk9.compiler=
|
|
||||||
jprt.windows.6.2.jdk9.compiler=
|
|
||||||
jprt.windows.6.3.jdk9.compiler=
|
|
||||||
jprt.windows.jdk9.target.attribute.compilerVS2013.appliesTo.builds=none
|
|
||||||
jprt.macosx.jdk9.target.attribute.compilerXcode511.appliesTo.builds=none
|
|
||||||
|
|
||||||
# Set up the run flavors (jvm variants)
|
|
||||||
jprt.run.flavors=c2,default,${my.additional.run.flavors}
|
|
||||||
|
|
||||||
# Setup jib profiles
|
|
||||||
jprt.linux_i586.product.build.jib.profile=linux-x86
|
|
||||||
jprt.linux_x64.product.build.jib.profile=linux-x64
|
|
||||||
jprt.macosx_x64.product.build.jib.profile=macosx-x64
|
|
||||||
jprt.solaris_sparcv9.product.build.jib.profile=solaris-sparcv9
|
|
||||||
jprt.solaris_x64.product.build.jib.profile=solaris-x64
|
|
||||||
jprt.windows_i586.product.build.jib.profile=windows-x86
|
|
||||||
jprt.windows_x64.product.build.jib.profile=windows-x64
|
|
||||||
|
|
||||||
jprt.linux_i586.fastdebug.build.jib.profile=linux-x86-debug
|
|
||||||
jprt.linux_x64.fastdebug.build.jib.profile=linux-x64-debug
|
|
||||||
jprt.macosx_x64.fastdebug.build.jib.profile=macosx-x64-debug
|
|
||||||
jprt.solaris_sparcv9.fastdebug.build.jib.profile=solaris-sparcv9-debug
|
|
||||||
jprt.solaris_x64.fastdebug.build.jib.profile=solaris-x64-debug
|
|
||||||
jprt.windows_i586.fastdebug.build.jib.profile=windows-x86-debug
|
|
||||||
jprt.windows_x64.fastdebug.build.jib.profile=windows-x64-debug
|
|
||||||
|
|
||||||
jprt.linux_i586.slowdebug.build.jib.profile=linux-x86-slowdebug
|
|
||||||
jprt.linux_x64.slowdebug.build.jib.profile=linux-x64-slowdebug
|
|
||||||
jprt.macosx_x64.slowdebug.build.jib.profile=macosx-x64-slowdebug
|
|
||||||
jprt.solaris_sparcv9.slowdebug.build.jib.profile=solaris-sparcv9-slowdebug
|
|
||||||
jprt.solaris_x64.slowdebug.build.jib.profile=solaris-x64-slowdebug
|
|
||||||
jprt.windows_i586.slowdebug.build.jib.profile=windows-x86-slowdebug
|
|
||||||
jprt.windows_x64.slowdebug.build.jib.profile=windows-x64-slowdebug
|
|
||||||
|
|
||||||
jprt.linux_i586.productOpen.build.jib.profile=linux-x86-open
|
|
||||||
jprt.linux_x64.productOpen.build.jib.profile=linux-x64-open
|
|
||||||
jprt.macosx_x64.productOpen.build.jib.profile=macosx-x64-open
|
|
||||||
jprt.solaris_sparcv9.productOpen.build.jib.profile=solaris-sparcv9-open
|
|
||||||
jprt.solaris_x64.productOpen.build.jib.profile=solaris-x64-open
|
|
||||||
jprt.windows_i586.productOpen.build.jib.profile=windows-x86-open
|
|
||||||
jprt.windows_x64.productOpen.build.jib.profile=windows-x64-open
|
|
||||||
|
|
||||||
jprt.linux_i586.fastdebugOpen.build.jib.profile=linux-x86-open-debug
|
|
||||||
jprt.linux_x64.fastdebugOpen.build.jib.profile=linux-x64-open-debug
|
|
||||||
jprt.macosx_x64.fastdebugOpen.build.jib.profile=macosx-x64-open-debug
|
|
||||||
jprt.solaris_sparcv9.fastdebugOpen.build.jib.profile=solaris-sparcv9-open-debug
|
|
||||||
jprt.solaris_x64.fastdebugOpen.build.jib.profile=solaris-x64-open-debug
|
|
||||||
jprt.windows_i586.fastdebugOpen.build.jib.profile=windows-x86-open-debug
|
|
||||||
jprt.windows_x64.fastdebugOpen.build.jib.profile=windows-x64-open-debug
|
|
||||||
|
|
||||||
jprt.linux_i586.productZero.build.jib.profile=linux-x86-zero
|
|
||||||
jprt.linux_x64.productZero.build.jib.profile=linux-x64-zero
|
|
||||||
|
|
||||||
jprt.linux_i586.fastdebugZero.build.jib.profile=linux-x86-zero-debug
|
|
||||||
jprt.linux_x64.fastdebugZero.build.jib.profile=linux-x64-zero-debug
|
|
||||||
|
|
||||||
jprt.test.jib.profile=run-test-jprt
|
|
||||||
|
|
||||||
# Set make target to use for different build flavors
|
|
||||||
jprt.build.flavor.fastdebugOpen.target=jprt_bundle
|
|
||||||
jprt.build.flavor.fastdebug.target=jprt_bundle
|
|
||||||
jprt.build.flavor.product.target=jprt_bundle
|
|
||||||
jprt.build.flavor.productOpen.target=jprt_bundle
|
|
||||||
jprt.build.flavor.optimized.target=jprt_bundle
|
|
||||||
jprt.build.flavor.optimizedOpen.target=jprt_bundle
|
|
||||||
jprt.build.flavor.slowdebug.target=jprt_bundle
|
|
||||||
jprt.build.flavor.productZero.target=jprt_bundle
|
|
||||||
jprt.build.flavor.fastdebugZero.target=jprt_bundle
|
|
||||||
|
|
||||||
# Use these configure args to define debug level or provide specific
|
|
||||||
# configuration details not covered by Jib profiles.
|
|
||||||
jprt.slowdebug.build.configure.args=
|
|
||||||
jprt.fastdebug.build.configure.args=--disable-precompiled-headers
|
|
||||||
# Don't disable precompiled headers on windows. It's simply too slow.
|
|
||||||
jprt.windows_i586.fastdebug.build.configure.args=
|
|
||||||
jprt.windows_x64.fastdebug.build.configure.args=
|
|
||||||
jprt.windows_i586.fastdebugOpen.build.configure.args=
|
|
||||||
jprt.windows_x64.fastdebugOpen.build.configure.args=
|
|
||||||
jprt.product.build.configure.args=
|
|
||||||
jprt.optimized.build.configure.args=--with-debug-level=optimized
|
|
||||||
jprt.slowdebugOpen.build.configure.args=${jprt.slowdebug.build.configure.args}
|
|
||||||
jprt.fastdebugOpen.build.configure.args=${jprt.fastdebug.build.configure.args}
|
|
||||||
jprt.productOpen.build.configure.args=${jprt.product.build.configure.args}
|
|
||||||
jprt.optimizedOpen.build.configure.args=${jprt.product.build.configure.args}
|
|
||||||
|
|
||||||
|
|
||||||
# hotspot testset has custom build flavors and build targets
|
|
||||||
my.jprt.testsetHasCustomBuildFlavors.hotspot=true
|
|
||||||
my.jprt.testsetHasCustomBuildTargets.hotspot=true
|
|
||||||
my.jprt.testsetHasCustomBuildFlavors.buildinfra=true
|
|
||||||
my.jprt.testsetHasCustomBuildTargets.buildinfra=true
|
|
||||||
|
|
||||||
# determine if the specified testset has custom build flavors or build targets
|
|
||||||
my.jprt.testsetHasCustomBuildFlavors=${my.jprt.testsetHasCustomBuildFlavors.${jprt.test.set}}
|
|
||||||
my.jprt.testsetHasCustomBuildTargets=${my.jprt.testsetHasCustomBuildTargets.${jprt.test.set}}
|
|
||||||
|
|
||||||
# Select build flavors and build targets based on the specified testset
|
|
||||||
jprt.build.flavors=${my.jprt.testsetHasCustomBuildFlavors ? \
|
|
||||||
${my.build.flavors.${jprt.test.set}} : ${my.build.flavors.default}}
|
|
||||||
jprt.build.targets=${my.jprt.testsetHasCustomBuildTargets ? \
|
|
||||||
${my.build.targets.${jprt.test.set}} : ${my.build.targets.default}}
|
|
||||||
|
|
||||||
# Select test targets - jprt default for jprt.test.set is "default"
|
|
||||||
jprt.test.targets=${my.test.targets.${jprt.test.set}}
|
|
||||||
jprt.make.rule.test.targets=${my.make.rule.test.targets.${jprt.test.set}}
|
|
||||||
|
|
||||||
# Not all test targets need the test image
|
|
||||||
jprt.test.bundle.targets=\
|
|
||||||
${my.make.rule.test.targets.svc}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.gtest} \
|
|
||||||
${my.make.rule.test.targets.nativesanity} \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_lang} \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_nio}
|
|
||||||
|
|
||||||
# 7155453: Work-around to prevent popups on OSX from blocking test completion
|
|
||||||
# but the work-around is added to all platforms to be consistent
|
|
||||||
jprt.jbb.options=-Djava.awt.headless=true
|
|
||||||
|
|
||||||
########
|
|
||||||
#
|
|
||||||
# Build options (generic)
|
|
||||||
#
|
|
||||||
|
|
||||||
# Configure args common to all builds
|
|
||||||
# Also allows for additional, testset specific configure arguments to be set
|
|
||||||
jprt.build.configure.args= \
|
|
||||||
--with-output-sync=recurse \
|
|
||||||
--with-jobs=$ALT_PARALLEL_COMPILE_JOBS \
|
|
||||||
--with-version-opt=$JPRT_JOB_ID \
|
|
||||||
${my.additional.build.configure.args.${jprt.test.set}} \
|
|
||||||
${my.custom.build.configure.args}
|
|
||||||
|
|
||||||
########
|
|
||||||
#
|
|
||||||
# Build targets and options (default/jdk)
|
|
||||||
#
|
|
||||||
|
|
||||||
# The default build flavors
|
|
||||||
my.build.flavors.default=fastdebug,product
|
|
||||||
|
|
||||||
# Standard list of jprt build targets for this source tree
|
|
||||||
my.build.targets.default= \
|
|
||||||
solaris_sparcv9_5.11-{product|fastdebug}, \
|
|
||||||
solaris_x64_5.11-{product|fastdebug}, \
|
|
||||||
linux_i586_3.8-{product|fastdebug}, \
|
|
||||||
linux_x64_3.8-{product|fastdebug}, \
|
|
||||||
macosx_x64_10.9-{product|fastdebug}, \
|
|
||||||
windows_i586_6.3-{product|fastdebug}, \
|
|
||||||
windows_x64_6.3-{product|fastdebug}, \
|
|
||||||
${my.additional.build.targets.default}
|
|
||||||
|
|
||||||
# Test target list (no fastdebug & limited c2 testing)
|
|
||||||
my.test.target.set= \
|
|
||||||
solaris_sparcv9_5.11-product-c2-TESTNAME, \
|
|
||||||
solaris_x64_5.11-product-c2-TESTNAME, \
|
|
||||||
linux_i586_3.8-product-c2-TESTNAME, \
|
|
||||||
linux_x64_3.8-product-c2-TESTNAME, \
|
|
||||||
macosx_x64_10.9-product-c2-TESTNAME, \
|
|
||||||
windows_i586_6.3-product-c2-TESTNAME, \
|
|
||||||
windows_x64_6.3-product-c2-TESTNAME
|
|
||||||
|
|
||||||
# Default vm test targets (testset=default)
|
|
||||||
my.test.targets.default= \
|
|
||||||
${my.test.target.set:TESTNAME=jvm98}, \
|
|
||||||
${my.test.target.set:TESTNAME=scimark}
|
|
||||||
|
|
||||||
# Default jdk test targets (testset=default)
|
|
||||||
my.make.rule.test.targets.default= \
|
|
||||||
${my.test.target.set:TESTNAME=langtools_jtreg}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_lang}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_math}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_util}
|
|
||||||
|
|
||||||
# Default vm test targets (testset=core)
|
|
||||||
my.test.targets.core=
|
|
||||||
|
|
||||||
# Core jdk test targets (testset=core)
|
|
||||||
my.make.rule.test.targets.core= \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_lang}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_math}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_util}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_io}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_net}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_nio}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_security1}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_security2}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_security3}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_security4}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_rmi}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_text}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_time}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_other}, \
|
|
||||||
${my.test.target.set:TESTNAME=core_tools}
|
|
||||||
|
|
||||||
# Svc vm test targets (testset=svc)
|
|
||||||
my.test.targets.svc=
|
|
||||||
|
|
||||||
# Core jdk test targets (testset=svc)
|
|
||||||
my.make.rule.test.targets.svc= \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_management}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_instrument}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_jmx}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_jdi}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_jfr}, \
|
|
||||||
${my.test.target.set:TESTNAME=svc_tools}, \
|
|
||||||
${my.make.rule.test.targets.svc.extra}
|
|
||||||
|
|
||||||
# JAXP vm test targets (testset=jaxp)
|
|
||||||
my.test.targets.jaxp=
|
|
||||||
|
|
||||||
# JAXP test targets (testset=jaxp)
|
|
||||||
my.make.rule.test.targets.jaxp= \
|
|
||||||
${my.test.target.set:TESTNAME=jaxp_all}
|
|
||||||
|
|
||||||
# All vm test targets (testset=all)
|
|
||||||
my.test.targets.all= \
|
|
||||||
${my.test.targets.default}, \
|
|
||||||
${my.test.target.set:TESTNAME=runThese}, \
|
|
||||||
${my.test.target.set:TESTNAME=jbb_default}
|
|
||||||
|
|
||||||
# All jdk test targets (testset=all)
|
|
||||||
my.make.rule.test.targets.all= \
|
|
||||||
${my.make.rule.test.targets.core}, \
|
|
||||||
${my.make.rule.test.targets.svc}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_awt}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_beans}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_sound}, \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_swing}
|
|
||||||
|
|
||||||
# PIT vm test targets (testset=pit)
|
|
||||||
my.test.targets.pit= \
|
|
||||||
${my.test.targets.all}
|
|
||||||
|
|
||||||
# PIT jdk test targets (testset=pit)
|
|
||||||
my.make.rule.test.targets.pit= \
|
|
||||||
${my.test.target.set:TESTNAME=langtools_jtreg}, \
|
|
||||||
${my.make.rule.test.targets.core}, \
|
|
||||||
${my.make.rule.test.targets.svc} \
|
|
||||||
${my.make.rule.test.targets.jaxp}
|
|
||||||
|
|
||||||
# JCK test targets in test/Makefile (no windows)
|
|
||||||
my.test.target.set.jck= \
|
|
||||||
solaris_sparcv9_5.11-product-c2-JCK7TESTRULE, \
|
|
||||||
solaris_x64_5.11-product-c2-JCK7TESTRULE, \
|
|
||||||
linux_i586_3.8-product-c2-JCK7TESTRULE, \
|
|
||||||
linux_x64_3.8-product-c2-JCK7TESTRULE
|
|
||||||
|
|
||||||
# JCK testset targets
|
|
||||||
my.make.rule.test.targets.jck= \
|
|
||||||
${my.test.target.set.jck:JCK7TESTRULE=jck7devtools}, \
|
|
||||||
${my.test.target.set.jck:JCK7TESTRULE=jck7runtime}, \
|
|
||||||
${my.test.target.set.jck:JCK7TESTRULE=jck7compiler}
|
|
||||||
|
|
||||||
|
|
||||||
#############
|
|
||||||
#
|
|
||||||
# Hotspot related settings (testset=hotspot)
|
|
||||||
#
|
|
||||||
|
|
||||||
# The hotspot build flavors
|
|
||||||
my.build.flavors.hotspot= \
|
|
||||||
fastdebugOpen,fastdebug,product,productOpen,optimized,optimizedOpen \
|
|
||||||
${my.additional.build.flavors.hotspot}
|
|
||||||
|
|
||||||
# Platforms built for hotspot push jobs
|
|
||||||
my.build.targets.hotspot= \
|
|
||||||
solaris_sparcv9_5.11-{product|fastdebug}, \
|
|
||||||
solaris_x64_5.11-{product|fastdebug}, \
|
|
||||||
linux_i586_3.8-{product|fastdebug}, \
|
|
||||||
linux_x64_3.8-{product|fastdebug}, \
|
|
||||||
macosx_x64_10.9-{product|fastdebug}, \
|
|
||||||
windows_i586_6.3-{product|fastdebug}, \
|
|
||||||
windows_x64_6.3-{product|fastdebug}, \
|
|
||||||
solaris_x64_5.11-{fastdebugOpen}, \
|
|
||||||
linux_x64_3.8-{productOpen}, \
|
|
||||||
${my.additional.build.targets.hotspot}
|
|
||||||
|
|
||||||
# Tests to run on the various platforms for hotspot push jobs
|
|
||||||
my.test.targets.hotspot.solaris.sparcv9= \
|
|
||||||
solaris_sparcv9_5.11-{product|fastdebug}-c2-jvm98, \
|
|
||||||
solaris_sparcv9_5.11-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
solaris_sparcv9_5.11-{product|fastdebug}-c2-scimark, \
|
|
||||||
solaris_sparcv9_5.11-product-c2-runThese8,
|
|
||||||
|
|
||||||
my.test.targets.hotspot.solaris.x64= \
|
|
||||||
solaris_x64_5.11-{product|fastdebug}-c2-jvm98, \
|
|
||||||
solaris_x64_5.11-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
solaris_x64_5.11-{product|fastdebug}-c2-scimark, \
|
|
||||||
solaris_x64_5.11-product-c2-runThese8, \
|
|
||||||
solaris_x64_5.11-product-c2-runThese8_Xcomp_lang, \
|
|
||||||
solaris_x64_5.11-product-c2-runThese8_Xcomp_vm,
|
|
||||||
|
|
||||||
my.test.targets.hotspot.linux.i586= \
|
|
||||||
linux_i586_3.8-{product|fastdebug}-c2-jvm98, \
|
|
||||||
linux_i586_3.8-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
linux_i586_3.8-{product|fastdebug}-c2-scimark, \
|
|
||||||
linux_i586_3.8-fastdebug-c2-runThese8_Xcomp_lang, \
|
|
||||||
linux_i586_3.8-fastdebug-c2-runThese8_Xcomp_vm
|
|
||||||
|
|
||||||
my.test.targets.hotspot.linux.x64= \
|
|
||||||
linux_x64_3.8-{product|fastdebug}-c2-jvm98, \
|
|
||||||
linux_x64_3.8-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
linux_x64_3.8-{product|fastdebug}-c2-scimark
|
|
||||||
|
|
||||||
my.test.targets.hotspot.macosx.x64= \
|
|
||||||
macosx_x64_10.9-{product|fastdebug}-c2-jvm98, \
|
|
||||||
macosx_x64_10.9-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
macosx_x64_10.9-{product|fastdebug}-c2-scimark
|
|
||||||
|
|
||||||
my.test.targets.hotspot.windows.i586= \
|
|
||||||
windows_i586_6.3-{product|fastdebug}-c2-jvm98, \
|
|
||||||
windows_i586_6.3-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
windows_i586_6.3-{product|fastdebug}-c2-scimark, \
|
|
||||||
windows_i586_6.3-product-c2-runThese8, \
|
|
||||||
windows_i586_6.3-product-c2-runThese8_Xcomp_lang, \
|
|
||||||
windows_i586_6.3-product-c2-runThese8_Xcomp_vm,
|
|
||||||
|
|
||||||
my.test.targets.hotspot.windows.x64= \
|
|
||||||
windows_x64_6.3-{product|fastdebug}-c2-jvm98, \
|
|
||||||
windows_x64_6.3-{product|fastdebug}-c2-jvm98_nontiered, \
|
|
||||||
windows_x64_6.3-{product|fastdebug}-c2-scimark, \
|
|
||||||
windows_x64_6.3-product-c2-runThese8, \
|
|
||||||
windows_x64_6.3-product-c2-runThese8_Xcomp_lang, \
|
|
||||||
windows_x64_6.3-product-c2-runThese8_Xcomp_vm,
|
|
||||||
|
|
||||||
# Some basic "smoke" tests for OpenJDK builds
|
|
||||||
my.test.targets.hotspot.open= \
|
|
||||||
solaris_x64_5.11-{productOpen|fastdebugOpen}-c2-jvm98, \
|
|
||||||
linux_x64_3.8-{productOpen|fastdebugOpen}-c2-jvm98
|
|
||||||
|
|
||||||
# The complete list of test targets for jprt
|
|
||||||
my.test.targets.hotspot= \
|
|
||||||
${my.test.targets.hotspot.open}, \
|
|
||||||
${my.test.targets.hotspot.solaris.sparcv9}, \
|
|
||||||
${my.test.targets.hotspot.solaris.x64}, \
|
|
||||||
${my.test.targets.hotspot.linux.i586}, \
|
|
||||||
${my.test.targets.hotspot.linux.x64}, \
|
|
||||||
${my.test.targets.hotspot.macosx.x64}, \
|
|
||||||
${my.test.targets.hotspot.windows.i586}, \
|
|
||||||
${my.test.targets.hotspot.windows.x64}, \
|
|
||||||
${my.test.targets.hotspot.solaris.sparcv9}, \
|
|
||||||
${my.test.targets.hotspot.solaris.x64}, \
|
|
||||||
${my.test.targets.hotspot.linux.x64}, \
|
|
||||||
${my.test.targets.hotspot.windows.i586}, \
|
|
||||||
${my.test.targets.hotspot.windows.x64}, \
|
|
||||||
${my.additional.test.targets.hotspot}
|
|
||||||
|
|
||||||
|
|
||||||
# Make file based test targets
|
|
||||||
|
|
||||||
my.make.rule.test.targets.hotspot.gtest= \
|
|
||||||
linux_i586_3.8-*-default-hotspot_gtest, \
|
|
||||||
linux_x64_3.8-*-default-hotspot_gtest, \
|
|
||||||
macosx_x64_10.9-*-default-hotspot_gtest, \
|
|
||||||
solaris_sparcv9_5.11-*-default-hotspot_gtest, \
|
|
||||||
solaris_x64_5.11-*-default-hotspot_gtest, \
|
|
||||||
windows_i586_6.3-*-default-hotspot_gtest, \
|
|
||||||
windows_x64_6.3-*-default-hotspot_gtest, \
|
|
||||||
${my.additional.make.rule.test.targets.hotspot.gtest}
|
|
||||||
|
|
||||||
my.make.rule.test.targets.hotspot.reg.group= \
|
|
||||||
solaris_sparcv9_5.11-fastdebug-c2-GROUP, \
|
|
||||||
solaris_x64_5.11-fastdebug-c2-GROUP, \
|
|
||||||
linux_i586_3.8-fastdebug-c2-GROUP, \
|
|
||||||
linux_x64_3.8-fastdebug-c2-GROUP, \
|
|
||||||
macosx_x64_10.9-fastdebug-c2-GROUP, \
|
|
||||||
windows_i586_6.3-fastdebug-c2-GROUP, \
|
|
||||||
windows_x64_6.3-fastdebug-c2-GROUP
|
|
||||||
|
|
||||||
# Hotspot jtreg tests
|
|
||||||
my.make.rule.test.targets.hotspot.reg= \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_compiler_1}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_compiler_2}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_compiler_3}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_compiler_closed}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_gc_1}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_gc_2}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_gc_closed}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_gc_gcold}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_gc_gcbasher}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_runtime}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=hotspot_tier1_serviceability}, \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg.group:GROUP=jdk_svc_sanity}, \
|
|
||||||
solaris_sparcv9_5.11-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
solaris_x64_5.11-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
linux_i586_3.8-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
linux_x64_3.8-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
macosx_x64_10.9-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
windows_i586_6.3-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
windows_x64_6.3-product-c2-hotspot_tier1_gc_gcbasher, \
|
|
||||||
${my.additional.make.rule.test.targets.hotspot.reg}
|
|
||||||
|
|
||||||
# Other Makefile based Hotspot tests
|
|
||||||
my.make.rule.test.targets.hotspot.other= \
|
|
||||||
${my.make.rule.test.targets.hotspot.gtest}, \
|
|
||||||
${my.additional.make.rule.test.targets.hotspot.other}
|
|
||||||
|
|
||||||
# All the makefile based tests to run
|
|
||||||
my.make.rule.test.targets.hotspot= \
|
|
||||||
${my.make.rule.test.targets.hotspot.reg} \
|
|
||||||
${my.make.rule.test.targets.hotspot.other}
|
|
||||||
|
|
||||||
# Native jdk and hotspot test targets (testset=nativesanity)
|
|
||||||
my.make.rule.test.targets.nativesanity= \
|
|
||||||
${my.test.target.set:TESTNAME=jdk_native_sanity}, \
|
|
||||||
${my.test.target.set:TESTNAME=hotspot_native_sanity}
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Testset buildinfra
|
|
||||||
my.build.flavors.buildinfra = \
|
|
||||||
product,fastdebug,slowdebug,productZero,fastdebugZero \
|
|
||||||
${my.additional.build.flavors.buildinfra}
|
|
||||||
|
|
||||||
# Platforms built for hotspot push jobs
|
|
||||||
my.build.targets.buildinfra = \
|
|
||||||
solaris_sparcv9_5.11-{product|fastdebug|slowdebug}, \
|
|
||||||
solaris_x64_5.11-{product|fastdebug|slowdebug}, \
|
|
||||||
linux_i586_3.8-{product|fastdebug|slowdebug|productZero|fastdebugZero}, \
|
|
||||||
linux_x64_3.8-{product|fastdebug|slowdebug|productZero|fastdebugZero}, \
|
|
||||||
macosx_x64_10.9-{product|fastdebug|slowdebug}, \
|
|
||||||
windows_i586_6.3-{product|fastdebug|slowdebug}, \
|
|
||||||
windows_x64_6.3-{product|fastdebug|slowdebug}, \
|
|
||||||
${my.additional.build.targets.buildinfra}
|
|
||||||
|
|
||||||
my.test.targets.buildinfra = \
|
|
||||||
${my.test.targets.default}, \
|
|
||||||
${my.test.targets.hotspot}
|
|
||||||
|
|
||||||
my.make.rule.test.targets.buildinfra = \
|
|
||||||
${my.make.rule.test.targets.default}, \
|
|
||||||
${my.make.rule.test.targets.hotspot}
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
package propertiesparser.gen;
|
package propertiesparser.gen;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
import propertiesparser.parser.Message;
|
import propertiesparser.parser.Message;
|
||||||
import propertiesparser.parser.MessageFile;
|
import propertiesparser.parser.MessageFile;
|
||||||
import propertiesparser.parser.MessageInfo;
|
import propertiesparser.parser.MessageInfo;
|
||||||
|
@ -44,11 +46,12 @@ import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -150,7 +153,11 @@ public class ClassGenerator {
|
||||||
public void generateFactory(MessageFile messageFile, File outDir) {
|
public void generateFactory(MessageFile messageFile, File outDir) {
|
||||||
Map<FactoryKind, List<Map.Entry<String, Message>>> groupedEntries =
|
Map<FactoryKind, List<Map.Entry<String, Message>>> groupedEntries =
|
||||||
messageFile.messages.entrySet().stream()
|
messageFile.messages.entrySet().stream()
|
||||||
.collect(Collectors.groupingBy(e -> FactoryKind.parseFrom(e.getKey().split("\\.")[1])));
|
.collect(
|
||||||
|
Collectors.groupingBy(
|
||||||
|
e -> FactoryKind.parseFrom(e.getKey().split("\\.")[1]),
|
||||||
|
TreeMap::new,
|
||||||
|
toList()));
|
||||||
//generate nested classes
|
//generate nested classes
|
||||||
List<String> nestedDecls = new ArrayList<>();
|
List<String> nestedDecls = new ArrayList<>();
|
||||||
Set<String> importedTypes = new TreeSet<>();
|
Set<String> importedTypes = new TreeSet<>();
|
||||||
|
|
|
@ -477,6 +477,7 @@ public class GenerateJfrFiles {
|
||||||
out.write("");
|
out.write("");
|
||||||
out.write("#else // !INCLUDE_JFR");
|
out.write("#else // !INCLUDE_JFR");
|
||||||
out.write("");
|
out.write("");
|
||||||
|
out.write("template <typename T>");
|
||||||
out.write("class JfrEvent {");
|
out.write("class JfrEvent {");
|
||||||
out.write(" public:");
|
out.write(" public:");
|
||||||
out.write(" JfrEvent() {}");
|
out.write(" JfrEvent() {}");
|
||||||
|
@ -497,103 +498,83 @@ public class GenerateJfrFiles {
|
||||||
|
|
||||||
private static void printTypes(Printer out, Metadata metadata, boolean empty) {
|
private static void printTypes(Printer out, Metadata metadata, boolean empty) {
|
||||||
for (TypeElement t : metadata.getStructs()) {
|
for (TypeElement t : metadata.getStructs()) {
|
||||||
if (empty) {
|
printType(out, t, empty);
|
||||||
out.write("");
|
|
||||||
printEmptyType(out, t);
|
|
||||||
} else {
|
|
||||||
printType(out, t);
|
|
||||||
}
|
|
||||||
out.write("");
|
out.write("");
|
||||||
}
|
}
|
||||||
for (EventElement e : metadata.getEvents()) {
|
for (EventElement e : metadata.getEvents()) {
|
||||||
if (empty) {
|
printEvent(out, e, empty);
|
||||||
printEmptyEvent(out, e);
|
|
||||||
} else {
|
|
||||||
printEvent(out, e);
|
|
||||||
}
|
|
||||||
out.write("");
|
out.write("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printEmptyEvent(Printer out, EventElement event) {
|
private static void printType(Printer out, TypeElement t, boolean empty) {
|
||||||
out.write("class Event" + event.name + " : public JfrEvent");
|
|
||||||
out.write("{");
|
|
||||||
out.write(" public:");
|
|
||||||
out.write(" Event" + event.name + "(EventStartTime ignore=TIMED) {}");
|
|
||||||
if (event.startTime) {
|
|
||||||
StringJoiner sj = new StringJoiner(",\n ");
|
|
||||||
for (FieldElement f : event.fields) {
|
|
||||||
sj.add(f.getParameterType());
|
|
||||||
}
|
|
||||||
out.write(" Event" + event.name + "(");
|
|
||||||
out.write(" " + sj.toString() + ") { }");
|
|
||||||
}
|
|
||||||
for (FieldElement f : event.fields) {
|
|
||||||
out.write(" void set_" + f.name + "(" + f.getParameterType() + ") { }");
|
|
||||||
}
|
|
||||||
out.write("};");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void printEmptyType(Printer out, TypeElement t) {
|
|
||||||
out.write("struct JfrStruct" + t.name);
|
out.write("struct JfrStruct" + t.name);
|
||||||
out.write("{");
|
out.write("{");
|
||||||
|
if (!empty) {
|
||||||
|
out.write(" private:");
|
||||||
|
for (FieldElement f : t.fields) {
|
||||||
|
printField(out, f);
|
||||||
|
}
|
||||||
|
out.write("");
|
||||||
|
}
|
||||||
out.write(" public:");
|
out.write(" public:");
|
||||||
for (FieldElement f : t.fields) {
|
for (FieldElement f : t.fields) {
|
||||||
out.write(" void set_" + f.name + "(" + f.getParameterType() + ") { }");
|
printTypeSetter(out, f, empty);
|
||||||
}
|
|
||||||
out.write("};");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void printType(Printer out, TypeElement t) {
|
|
||||||
out.write("struct JfrStruct" + t.name);
|
|
||||||
out.write("{");
|
|
||||||
out.write(" private:");
|
|
||||||
for (FieldElement f : t.fields) {
|
|
||||||
printField(out, f);
|
|
||||||
}
|
}
|
||||||
out.write("");
|
out.write("");
|
||||||
out.write(" public:");
|
if (!empty) {
|
||||||
for (FieldElement f : t.fields) {
|
printWriteData(out, t.fields);
|
||||||
printTypeSetter(out, f);
|
|
||||||
}
|
}
|
||||||
out.write("");
|
|
||||||
printWriteData(out, t.fields);
|
|
||||||
out.write("};");
|
out.write("};");
|
||||||
out.write("");
|
out.write("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printEvent(Printer out, EventElement event) {
|
private static void printEvent(Printer out, EventElement event, boolean empty) {
|
||||||
out.write("class Event" + event.name + " : public JfrEvent<Event" + event.name + ">");
|
out.write("class Event" + event.name + " : public JfrEvent<Event" + event.name + ">");
|
||||||
out.write("{");
|
out.write("{");
|
||||||
out.write(" private:");
|
if (!empty) {
|
||||||
for (FieldElement f : event.fields) {
|
out.write(" private:");
|
||||||
printField(out, f);
|
for (FieldElement f : event.fields) {
|
||||||
|
printField(out, f);
|
||||||
|
}
|
||||||
|
out.write("");
|
||||||
}
|
}
|
||||||
out.write("");
|
|
||||||
out.write(" public:");
|
out.write(" public:");
|
||||||
out.write(" static const bool hasThread = " + event.thread + ";");
|
if (!empty) {
|
||||||
out.write(" static const bool hasStackTrace = " + event.stackTrace + ";");
|
out.write(" static const bool hasThread = " + event.thread + ";");
|
||||||
out.write(" static const bool isInstant = " + !event.startTime + ";");
|
out.write(" static const bool hasStackTrace = " + event.stackTrace + ";");
|
||||||
out.write(" static const bool hasCutoff = " + event.cutoff + ";");
|
out.write(" static const bool isInstant = " + !event.startTime + ";");
|
||||||
out.write(" static const bool isRequestable = " + event.periodic + ";");
|
out.write(" static const bool hasCutoff = " + event.cutoff + ";");
|
||||||
out.write(" static const JfrEventId eventId = Jfr" + event.name + "Event;");
|
out.write(" static const bool isRequestable = " + event.periodic + ";");
|
||||||
out.write("");
|
out.write(" static const JfrEventId eventId = Jfr" + event.name + "Event;");
|
||||||
out.write(" Event" + event.name + "(EventStartTime timing=TIMED) : JfrEvent<Event" + event.name + ">(timing) {}");
|
out.write("");
|
||||||
|
}
|
||||||
|
if (!empty) {
|
||||||
|
out.write(" Event" + event.name + "(EventStartTime timing=TIMED) : JfrEvent<Event" + event.name + ">(timing) {}");
|
||||||
|
} else {
|
||||||
|
out.write(" Event" + event.name + "(EventStartTime timing=TIMED) {}");
|
||||||
|
}
|
||||||
out.write("");
|
out.write("");
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (FieldElement f : event.fields) {
|
for (FieldElement f : event.fields) {
|
||||||
out.write(" void set_" + f.name + "(" + f.getParameterType() + " " + f.getParameterName() + ") {");
|
out.write(" void set_" + f.name + "(" + f.getParameterType() + " " + f.getParameterName() + ") {");
|
||||||
out.write(" this->_" + f.name + " = " + f.getParameterName() + ";");
|
if (!empty) {
|
||||||
out.write(" DEBUG_ONLY(set_field_bit(" + index++ + "));");
|
out.write(" this->_" + f.name + " = " + f.getParameterName() + ";");
|
||||||
|
out.write(" DEBUG_ONLY(set_field_bit(" + index++ + "));");
|
||||||
|
}
|
||||||
out.write(" }");
|
out.write(" }");
|
||||||
}
|
}
|
||||||
out.write("");
|
out.write("");
|
||||||
printWriteData(out, event.fields);
|
if (!empty) {
|
||||||
out.write("");
|
printWriteData(out, event.fields);
|
||||||
|
out.write("");
|
||||||
|
}
|
||||||
out.write(" using JfrEvent<Event" + event.name + ">::commit; // else commit() is hidden by overloaded versions in this class");
|
out.write(" using JfrEvent<Event" + event.name + ">::commit; // else commit() is hidden by overloaded versions in this class");
|
||||||
printConstructor2(out, event);
|
printConstructor2(out, event, empty);
|
||||||
printCommitMethod(out, event);
|
printCommitMethod(out, event, empty);
|
||||||
printVerify(out, event.fields);
|
if (!empty) {
|
||||||
|
printVerify(out, event.fields);
|
||||||
|
}
|
||||||
out.write("};");
|
out.write("};");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,8 +591,12 @@ public class GenerateJfrFiles {
|
||||||
out.write(" }");
|
out.write(" }");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printTypeSetter(Printer out, FieldElement field) {
|
private static void printTypeSetter(Printer out, FieldElement field, boolean empty) {
|
||||||
out.write(" void set_" + field.name + "(" + field.getParameterType() + " new_value) { this->_" + field.name + " = new_value; }");
|
if (!empty) {
|
||||||
|
out.write(" void set_" + field.name + "(" + field.getParameterType() + " new_value) { this->_" + field.name + " = new_value; }");
|
||||||
|
} else {
|
||||||
|
out.write(" void set_" + field.name + "(" + field.getParameterType() + " new_value) { }");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printVerify(Printer out, List<FieldElement> fields) {
|
private static void printVerify(Printer out, List<FieldElement> fields) {
|
||||||
|
@ -626,7 +611,7 @@ public class GenerateJfrFiles {
|
||||||
out.write("#endif");
|
out.write("#endif");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printCommitMethod(Printer out, EventElement event) {
|
private static void printCommitMethod(Printer out, EventElement event, boolean empty) {
|
||||||
if (event.startTime) {
|
if (event.startTime) {
|
||||||
StringJoiner sj = new StringJoiner(",\n ");
|
StringJoiner sj = new StringJoiner(",\n ");
|
||||||
for (FieldElement f : event.fields) {
|
for (FieldElement f : event.fields) {
|
||||||
|
@ -634,12 +619,14 @@ public class GenerateJfrFiles {
|
||||||
}
|
}
|
||||||
out.write("");
|
out.write("");
|
||||||
out.write(" void commit(" + sj.toString() + ") {");
|
out.write(" void commit(" + sj.toString() + ") {");
|
||||||
out.write(" if (should_commit()) {");
|
if (!empty) {
|
||||||
for (FieldElement f : event.fields) {
|
out.write(" if (should_commit()) {");
|
||||||
out.write(" set_" + f.name + "(" + f.name + ");");
|
for (FieldElement f : event.fields) {
|
||||||
|
out.write(" set_" + f.name + "(" + f.name + ");");
|
||||||
|
}
|
||||||
|
out.write(" commit();");
|
||||||
|
out.write(" }");
|
||||||
}
|
}
|
||||||
out.write(" commit();");
|
|
||||||
out.write(" }");
|
|
||||||
out.write(" }");
|
out.write(" }");
|
||||||
}
|
}
|
||||||
out.write("");
|
out.write("");
|
||||||
|
@ -652,22 +639,24 @@ public class GenerateJfrFiles {
|
||||||
sj.add(f.getParameterType() + " " + f.name);
|
sj.add(f.getParameterType() + " " + f.name);
|
||||||
}
|
}
|
||||||
out.write(" static void commit(" + sj.toString() + ") {");
|
out.write(" static void commit(" + sj.toString() + ") {");
|
||||||
out.write(" Event" + event.name + " me(UNTIMED);");
|
if (!empty) {
|
||||||
out.write("");
|
out.write(" Event" + event.name + " me(UNTIMED);");
|
||||||
out.write(" if (me.should_commit()) {");
|
out.write("");
|
||||||
if (event.startTime) {
|
out.write(" if (me.should_commit()) {");
|
||||||
out.write(" me.set_starttime(startTicks);");
|
if (event.startTime) {
|
||||||
out.write(" me.set_endtime(endTicks);");
|
out.write(" me.set_starttime(startTicks);");
|
||||||
|
out.write(" me.set_endtime(endTicks);");
|
||||||
|
}
|
||||||
|
for (FieldElement f : event.fields) {
|
||||||
|
out.write(" me.set_" + f.name + "(" + f.name + ");");
|
||||||
|
}
|
||||||
|
out.write(" me.commit();");
|
||||||
|
out.write(" }");
|
||||||
}
|
}
|
||||||
for (FieldElement f : event.fields) {
|
|
||||||
out.write(" me.set_" + f.name + "(" + f.name + ");");
|
|
||||||
}
|
|
||||||
out.write(" me.commit();");
|
|
||||||
out.write(" }");
|
|
||||||
out.write(" }");
|
out.write(" }");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void printConstructor2(Printer out, EventElement event) {
|
private static void printConstructor2(Printer out, EventElement event, boolean empty) {
|
||||||
if (!event.startTime) {
|
if (!event.startTime) {
|
||||||
out.write("");
|
out.write("");
|
||||||
out.write("");
|
out.write("");
|
||||||
|
@ -679,12 +668,16 @@ public class GenerateJfrFiles {
|
||||||
for (FieldElement f : event.fields) {
|
for (FieldElement f : event.fields) {
|
||||||
sj.add(f.getParameterType() + " " + f.name);
|
sj.add(f.getParameterType() + " " + f.name);
|
||||||
}
|
}
|
||||||
out.write(" " + sj.toString() + ") : JfrEvent<Event" + event.name + ">(TIMED) {");
|
if (!empty) {
|
||||||
out.write(" if (should_commit()) {");
|
out.write(" " + sj.toString() + ") : JfrEvent<Event" + event.name + ">(TIMED) {");
|
||||||
for (FieldElement f : event.fields) {
|
out.write(" if (should_commit()) {");
|
||||||
out.write(" set_" + f.name + "(" + f.name + ");");
|
for (FieldElement f : event.fields) {
|
||||||
|
out.write(" set_" + f.name + "(" + f.name + ");");
|
||||||
|
}
|
||||||
|
out.write(" }");
|
||||||
|
} else {
|
||||||
|
out.write(" " + sj.toString() + ") {");
|
||||||
}
|
}
|
||||||
out.write(" }");
|
|
||||||
out.write(" }");
|
out.write(" }");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1709,6 +1709,7 @@ void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr
|
||||||
default: ShouldNotReachHere();
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -584,8 +584,8 @@ void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
|
||||||
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
||||||
case longTag: do_ArithmeticOp_Long(x); return;
|
case longTag: do_ArithmeticOp_Long(x); return;
|
||||||
case intTag: do_ArithmeticOp_Int(x); return;
|
case intTag: do_ArithmeticOp_Int(x); return;
|
||||||
|
default: ShouldNotReachHere(); return;
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
|
// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
|
||||||
|
@ -792,9 +792,13 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
|
||||||
__ abs(value.result(), dst, LIR_OprFact::illegalOpr);
|
__ abs(value.result(), dst, LIR_OprFact::illegalOpr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved.
|
* Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
|
@ -195,9 +195,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
|
||||||
void CompiledDirectStaticCall::verify() {
|
void CompiledDirectStaticCall::verify() {
|
||||||
// Verify call.
|
// Verify call.
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify stub.
|
// Verify stub.
|
||||||
address stub = find_stub(false /* is_aot */);
|
address stub = find_stub(false /* is_aot */);
|
||||||
|
|
|
@ -1505,7 +1505,7 @@ void MacroAssembler::movptr(Register r, uintptr_t imm64) {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
{
|
{
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%"PRIX64, imm64);
|
snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64);
|
||||||
block_comment(buffer);
|
block_comment(buffer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1568,7 +1568,7 @@ void MacroAssembler::mov_immediate64(Register dst, u_int64_t imm64)
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
{
|
{
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%"PRIX64, imm64);
|
snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64);
|
||||||
block_comment(buffer);
|
block_comment(buffer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1681,7 +1681,7 @@ void MacroAssembler::mov_immediate32(Register dst, u_int32_t imm32)
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
{
|
{
|
||||||
char buffer[64];
|
char buffer[64];
|
||||||
snprintf(buffer, sizeof(buffer), "0x%"PRIX32, imm32);
|
snprintf(buffer, sizeof(buffer), "0x%" PRIX32, imm32);
|
||||||
block_comment(buffer);
|
block_comment(buffer);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1950,24 +1950,20 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
// didn't see any synchronization is progress, and escapes.
|
// didn't see any synchronization is progress, and escapes.
|
||||||
__ mov(rscratch1, _thread_in_native_trans);
|
__ mov(rscratch1, _thread_in_native_trans);
|
||||||
|
|
||||||
if(os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
|
||||||
__ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset()));
|
|
||||||
|
|
||||||
// Force this write out before the read below
|
|
||||||
__ dmb(Assembler::ISH);
|
|
||||||
} else {
|
|
||||||
__ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
|
|
||||||
__ stlrw(rscratch1, rscratch2);
|
|
||||||
|
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
|
||||||
// We use the current thread pointer to calculate a thread specific
|
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
|
||||||
// due to cache line collision.
|
|
||||||
__ serialize_memory(rthread, r2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
__ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset()));
|
__ strw(rscratch1, Address(rthread, JavaThread::thread_state_offset()));
|
||||||
|
|
||||||
|
// Force this write out before the read below
|
||||||
|
__ dmb(Assembler::ISH);
|
||||||
|
} else {
|
||||||
|
__ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
|
||||||
|
__ stlrw(rscratch1, rscratch2);
|
||||||
|
|
||||||
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
|
// We use the current thread pointer to calculate a thread specific
|
||||||
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
|
// due to cache line collision.
|
||||||
|
__ serialize_memory(rthread, r2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for safepoint operation in progress and/or pending suspend requests
|
// check for safepoint operation in progress and/or pending suspend requests
|
||||||
|
|
|
@ -1394,17 +1394,15 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||||
__ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
|
__ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
|
||||||
__ stlrw(rscratch1, rscratch2);
|
__ stlrw(rscratch1, rscratch2);
|
||||||
|
|
||||||
if (os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
// Force this write out before the read below
|
||||||
// Force this write out before the read below
|
__ dmb(Assembler::ISH);
|
||||||
__ dmb(Assembler::ISH);
|
} else {
|
||||||
} else {
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// due to cache line collision.
|
||||||
// due to cache line collision.
|
__ serialize_memory(rthread, rscratch2);
|
||||||
__ serialize_memory(rthread, rscratch2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for safepoint operation in progress and/or pending suspend requests
|
// check for safepoint operation in progress and/or pending suspend requests
|
||||||
|
|
|
@ -412,7 +412,7 @@ void TemplateTable::fast_aldc(bool wide)
|
||||||
// Stash null_sentinel address to get its value later
|
// Stash null_sentinel address to get its value later
|
||||||
__ movptr(rarg, (uintptr_t)Universe::the_null_sentinel_addr());
|
__ movptr(rarg, (uintptr_t)Universe::the_null_sentinel_addr());
|
||||||
__ ldr(tmp, Address(rarg));
|
__ ldr(tmp, Address(rarg));
|
||||||
__ cmp(result, tmp);
|
__ cmpoop(result, tmp);
|
||||||
__ br(Assembler::NE, notNull);
|
__ br(Assembler::NE, notNull);
|
||||||
__ mov(result, 0); // NULL object reference
|
__ mov(result, 0); // NULL object reference
|
||||||
__ bind(notNull);
|
__ bind(notNull);
|
||||||
|
@ -2329,6 +2329,7 @@ void TemplateTable::resolve_cache_and_index(int byte_no,
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
||||||
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
|
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
|
||||||
|
@ -2953,6 +2954,7 @@ void TemplateTable::jvmti_post_fast_field_mod()
|
||||||
case Bytecodes::_fast_dputfield: __ pop_d(); break;
|
case Bytecodes::_fast_dputfield: __ pop_d(); break;
|
||||||
case Bytecodes::_fast_fputfield: __ pop_f(); break;
|
case Bytecodes::_fast_fputfield: __ pop_f(); break;
|
||||||
case Bytecodes::_fast_lputfield: __ pop_l(r0); break;
|
case Bytecodes::_fast_lputfield: __ pop_l(r0); break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
__ bind(L2);
|
__ bind(L2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5316,8 +5316,7 @@ instruct loadConD(regD dst, immD src, iRegP tmp) %{
|
||||||
// Prefetch instructions.
|
// Prefetch instructions.
|
||||||
// Must be safe to execute with invalid address (cannot fault).
|
// Must be safe to execute with invalid address (cannot fault).
|
||||||
|
|
||||||
instruct prefetchAlloc_mp( memoryP mem ) %{
|
instruct prefetchAlloc( memoryP mem ) %{
|
||||||
predicate(os::is_MP());
|
|
||||||
match( PrefetchAllocation mem );
|
match( PrefetchAllocation mem );
|
||||||
ins_cost(MEMORY_REF_COST);
|
ins_cost(MEMORY_REF_COST);
|
||||||
size(4);
|
size(4);
|
||||||
|
@ -5333,23 +5332,6 @@ instruct prefetchAlloc_mp( memoryP mem ) %{
|
||||||
ins_pipe(iload_mem);
|
ins_pipe(iload_mem);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
instruct prefetchAlloc_sp( memoryP mem ) %{
|
|
||||||
predicate(!os::is_MP());
|
|
||||||
match( PrefetchAllocation mem );
|
|
||||||
ins_cost(MEMORY_REF_COST);
|
|
||||||
size(4);
|
|
||||||
|
|
||||||
format %{ "PLD $mem\t! Prefetch allocation" %}
|
|
||||||
ins_encode %{
|
|
||||||
#ifdef AARCH64
|
|
||||||
__ prfm(pstl1keep, $mem$$Address);
|
|
||||||
#else
|
|
||||||
__ pld($mem$$Address);
|
|
||||||
#endif
|
|
||||||
%}
|
|
||||||
ins_pipe(iload_mem);
|
|
||||||
%}
|
|
||||||
|
|
||||||
//----------Store Instructions-------------------------------------------------
|
//----------Store Instructions-------------------------------------------------
|
||||||
// Store Byte
|
// Store Byte
|
||||||
instruct storeB(memoryB mem, store_RegI src) %{
|
instruct storeB(memoryB mem, store_RegI src) %{
|
||||||
|
|
|
@ -870,8 +870,8 @@ void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
|
||||||
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
||||||
case longTag: do_ArithmeticOp_Long(x); return;
|
case longTag: do_ArithmeticOp_Long(x); return;
|
||||||
case intTag: do_ArithmeticOp_Int(x); return;
|
case intTag: do_ArithmeticOp_Int(x); return;
|
||||||
|
default: ShouldNotReachHere(); return;
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -155,9 +155,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
|
||||||
void CompiledDirectStaticCall::verify() {
|
void CompiledDirectStaticCall::verify() {
|
||||||
// Verify call.
|
// Verify call.
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify stub.
|
// Verify stub.
|
||||||
address stub = find_stub(/*is_aot*/ false);
|
address stub = find_stub(/*is_aot*/ false);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -127,13 +127,9 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
__ bic(R1, R1, JNIHandles::weak_tag_mask);
|
__ bic(R1, R1, JNIHandles::weak_tag_mask);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (os::is_MP()) {
|
// Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier
|
||||||
// Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier
|
__ andr(Rtmp1, Rsafept_cnt, (unsigned)1);
|
||||||
__ andr(Rtmp1, Rsafept_cnt, (unsigned)1);
|
__ ldr(Robj, Address(R1, Rtmp1));
|
||||||
__ ldr(Robj, Address(R1, Rtmp1));
|
|
||||||
} else {
|
|
||||||
__ ldr(Robj, Address(R1));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
__ add(Robj, Robj, AsmOperand(R2, lsr, 2));
|
__ add(Robj, Robj, AsmOperand(R2, lsr, 2));
|
||||||
|
@ -198,25 +194,21 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(os::is_MP()) {
|
// Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier
|
||||||
// Address dependency restricts memory access ordering. It's cheaper than explicit LoadLoad barrier
|
|
||||||
#if defined(__ABI_HARD__) && !defined(AARCH64)
|
#if defined(__ABI_HARD__) && !defined(AARCH64)
|
||||||
if (type == T_FLOAT || type == T_DOUBLE) {
|
if (type == T_FLOAT || type == T_DOUBLE) {
|
||||||
__ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
|
__ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
|
||||||
__ fmrrd(Rres, Rres_hi, D0);
|
__ fmrrd(Rres, Rres_hi, D0);
|
||||||
__ eor(Rtmp2, Rres, Rres);
|
__ eor(Rtmp2, Rres, Rres);
|
||||||
__ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr, Rtmp2));
|
__ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr, Rtmp2));
|
||||||
} else
|
} else
|
||||||
#endif // __ABI_HARD__ && !AARCH64
|
#endif // __ABI_HARD__ && !AARCH64
|
||||||
{
|
{
|
||||||
#ifndef AARCH64
|
#ifndef AARCH64
|
||||||
__ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
|
__ ldr_literal(Rsafepoint_counter_addr, safepoint_counter_addr);
|
||||||
#endif // !AARCH64
|
#endif // !AARCH64
|
||||||
__ eor(Rtmp2, Rres, Rres);
|
__ eor(Rtmp2, Rres, Rres);
|
||||||
__ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr, Rtmp2));
|
__ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr, Rtmp2));
|
||||||
}
|
|
||||||
} else {
|
|
||||||
__ ldr_s32(Rsafept_cnt2, Address(Rsafepoint_counter_addr));
|
|
||||||
}
|
}
|
||||||
__ cmp(Rsafept_cnt2, Rsafept_cnt);
|
__ cmp(Rsafept_cnt2, Rsafept_cnt);
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
|
|
|
@ -1563,8 +1563,6 @@ FixedSizeCodeBlock::~FixedSizeCodeBlock() {
|
||||||
// Serializes memory.
|
// Serializes memory.
|
||||||
// tmp register is not used on AArch64, this parameter is provided solely for better compatibility with 32-bit ARM
|
// tmp register is not used on AArch64, this parameter is provided solely for better compatibility with 32-bit ARM
|
||||||
void MacroAssembler::membar(Membar_mask_bits order_constraint, Register tmp) {
|
void MacroAssembler::membar(Membar_mask_bits order_constraint, Register tmp) {
|
||||||
if (!os::is_MP()) return;
|
|
||||||
|
|
||||||
// TODO-AARCH64 investigate dsb vs dmb effects
|
// TODO-AARCH64 investigate dsb vs dmb effects
|
||||||
if (order_constraint == StoreStore) {
|
if (order_constraint == StoreStore) {
|
||||||
dmb(DMB_st);
|
dmb(DMB_st);
|
||||||
|
@ -1585,7 +1583,6 @@ void MacroAssembler::membar(Membar_mask_bits order_constraint,
|
||||||
Register tmp,
|
Register tmp,
|
||||||
bool preserve_flags,
|
bool preserve_flags,
|
||||||
Register load_tgt) {
|
Register load_tgt) {
|
||||||
if (!os::is_MP()) return;
|
|
||||||
|
|
||||||
if (order_constraint == StoreStore) {
|
if (order_constraint == StoreStore) {
|
||||||
dmb(DMB_st, tmp);
|
dmb(DMB_st, tmp);
|
||||||
|
|
|
@ -2996,6 +2996,7 @@ void TemplateTable::resolve_cache_and_index(int byte_no,
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
||||||
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
|
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
|
||||||
|
@ -3145,15 +3146,11 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
||||||
const Register Rindex = R5_tmp;
|
const Register Rindex = R5_tmp;
|
||||||
const Register Rflags = R5_tmp;
|
const Register Rflags = R5_tmp;
|
||||||
|
|
||||||
const bool gen_volatile_check = os::is_MP();
|
|
||||||
|
|
||||||
resolve_cache_and_index(byte_no, Rcache, Rindex, sizeof(u2));
|
resolve_cache_and_index(byte_no, Rcache, Rindex, sizeof(u2));
|
||||||
jvmti_post_field_access(Rcache, Rindex, is_static, false);
|
jvmti_post_field_access(Rcache, Rindex, is_static, false);
|
||||||
load_field_cp_cache_entry(Rcache, Rindex, Roffset, Rflags, Robj, is_static);
|
load_field_cp_cache_entry(Rcache, Rindex, Roffset, Rflags, Robj, is_static);
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
__ mov(Rflagsav, Rflags);
|
||||||
__ mov(Rflagsav, Rflags);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_static) pop_and_check_object(Robj);
|
if (!is_static) pop_and_check_object(Robj);
|
||||||
|
|
||||||
|
@ -3390,16 +3387,13 @@ void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteContr
|
||||||
|
|
||||||
__ bind(Done);
|
__ bind(Done);
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
// Check for volatile field
|
||||||
// Check for volatile field
|
Label notVolatile;
|
||||||
Label notVolatile;
|
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
||||||
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
|
||||||
|
|
||||||
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
|
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
|
||||||
|
|
||||||
__ bind(notVolatile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
__ bind(notVolatile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TemplateTable::getfield(int byte_no) {
|
void TemplateTable::getfield(int byte_no) {
|
||||||
|
@ -3491,22 +3485,18 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
||||||
const Register Rindex = R5_tmp;
|
const Register Rindex = R5_tmp;
|
||||||
const Register Rflags = R5_tmp;
|
const Register Rflags = R5_tmp;
|
||||||
|
|
||||||
const bool gen_volatile_check = os::is_MP();
|
|
||||||
|
|
||||||
resolve_cache_and_index(byte_no, Rcache, Rindex, sizeof(u2));
|
resolve_cache_and_index(byte_no, Rcache, Rindex, sizeof(u2));
|
||||||
jvmti_post_field_mod(Rcache, Rindex, is_static);
|
jvmti_post_field_mod(Rcache, Rindex, is_static);
|
||||||
load_field_cp_cache_entry(Rcache, Rindex, Roffset, Rflags, Robj, is_static);
|
load_field_cp_cache_entry(Rcache, Rindex, Roffset, Rflags, Robj, is_static);
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
// Check for volatile field
|
||||||
// Check for volatile field
|
Label notVolatile;
|
||||||
Label notVolatile;
|
__ mov(Rflagsav, Rflags);
|
||||||
__ mov(Rflagsav, Rflags);
|
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
||||||
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
|
||||||
|
|
||||||
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
|
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
|
||||||
|
|
||||||
__ bind(notVolatile);
|
__ bind(notVolatile);
|
||||||
}
|
|
||||||
|
|
||||||
Label Done, Lint, shouldNotReachHere;
|
Label Done, Lint, shouldNotReachHere;
|
||||||
Label Ltable, Lbtos, Lztos, Lctos, Lstos, Litos, Lltos, Lftos, Ldtos, Latos;
|
Label Ltable, Lbtos, Lztos, Lctos, Lstos, Litos, Lltos, Lftos, Ldtos, Latos;
|
||||||
|
@ -3732,36 +3722,33 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
|
||||||
|
|
||||||
__ bind(Done);
|
__ bind(Done);
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
Label notVolatile2;
|
||||||
Label notVolatile;
|
if (is_static) {
|
||||||
if (is_static) {
|
// Just check for volatile. Memory barrier for static final field
|
||||||
// Just check for volatile. Memory barrier for static final field
|
// is handled by class initialization.
|
||||||
// is handled by class initialization.
|
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile2);
|
||||||
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
|
||||||
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
|
__ bind(notVolatile2);
|
||||||
__ bind(notVolatile);
|
} else {
|
||||||
} else {
|
// Check for volatile field and final field
|
||||||
// Check for volatile field and final field
|
Label skipMembar;
|
||||||
Label skipMembar;
|
|
||||||
|
|
||||||
__ tst(Rflagsav, 1 << ConstantPoolCacheEntry::is_volatile_shift |
|
__ tst(Rflagsav, 1 << ConstantPoolCacheEntry::is_volatile_shift |
|
||||||
1 << ConstantPoolCacheEntry::is_final_shift);
|
1 << ConstantPoolCacheEntry::is_final_shift);
|
||||||
__ b(skipMembar, eq);
|
__ b(skipMembar, eq);
|
||||||
|
|
||||||
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
__ tbz(Rflagsav, ConstantPoolCacheEntry::is_volatile_shift, notVolatile2);
|
||||||
|
|
||||||
// StoreLoad barrier after volatile field write
|
// StoreLoad barrier after volatile field write
|
||||||
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
|
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
|
||||||
__ b(skipMembar);
|
__ b(skipMembar);
|
||||||
|
|
||||||
// StoreStore barrier after final field write
|
// StoreStore barrier after final field write
|
||||||
__ bind(notVolatile);
|
__ bind(notVolatile2);
|
||||||
volatile_barrier(MacroAssembler::StoreStore, Rtemp);
|
volatile_barrier(MacroAssembler::StoreStore, Rtemp);
|
||||||
|
|
||||||
__ bind(skipMembar);
|
__ bind(skipMembar);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TemplateTable::putfield(int byte_no) {
|
void TemplateTable::putfield(int byte_no) {
|
||||||
|
@ -3831,31 +3818,25 @@ void TemplateTable::fast_storefield(TosState state) {
|
||||||
const Register Rflags = Rtmp_save0; // R4/R19
|
const Register Rflags = Rtmp_save0; // R4/R19
|
||||||
const Register Robj = R5_tmp;
|
const Register Robj = R5_tmp;
|
||||||
|
|
||||||
const bool gen_volatile_check = os::is_MP();
|
|
||||||
|
|
||||||
// access constant pool cache
|
// access constant pool cache
|
||||||
__ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
|
__ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
|
||||||
|
|
||||||
__ add(Rcache, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
|
__ add(Rcache, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
// load flags to test volatile
|
||||||
// load flags to test volatile
|
__ ldr_u32(Rflags, Address(Rcache, base + ConstantPoolCacheEntry::flags_offset()));
|
||||||
__ ldr_u32(Rflags, Address(Rcache, base + ConstantPoolCacheEntry::flags_offset()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// replace index with field offset from cache entry
|
// replace index with field offset from cache entry
|
||||||
__ ldr(Roffset, Address(Rcache, base + ConstantPoolCacheEntry::f2_offset()));
|
__ ldr(Roffset, Address(Rcache, base + ConstantPoolCacheEntry::f2_offset()));
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
// Check for volatile store
|
||||||
// Check for volatile store
|
Label notVolatile;
|
||||||
Label notVolatile;
|
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
||||||
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
|
||||||
|
|
||||||
// TODO-AARCH64 on AArch64, store-release instructions can be used to get rid of this explict barrier
|
// TODO-AARCH64 on AArch64, store-release instructions can be used to get rid of this explict barrier
|
||||||
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
|
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore | MacroAssembler::LoadStore), Rtemp);
|
||||||
|
|
||||||
__ bind(notVolatile);
|
__ bind(notVolatile);
|
||||||
}
|
|
||||||
|
|
||||||
// Get object from stack
|
// Get object from stack
|
||||||
pop_and_check_object(Robj);
|
pop_and_check_object(Robj);
|
||||||
|
@ -3902,28 +3883,25 @@ void TemplateTable::fast_storefield(TosState state) {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
Label notVolatile2;
|
||||||
Label notVolatile;
|
Label skipMembar;
|
||||||
Label skipMembar;
|
__ tst(Rflags, 1 << ConstantPoolCacheEntry::is_volatile_shift |
|
||||||
__ tst(Rflags, 1 << ConstantPoolCacheEntry::is_volatile_shift |
|
1 << ConstantPoolCacheEntry::is_final_shift);
|
||||||
1 << ConstantPoolCacheEntry::is_final_shift);
|
__ b(skipMembar, eq);
|
||||||
__ b(skipMembar, eq);
|
|
||||||
|
|
||||||
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile2);
|
||||||
|
|
||||||
// StoreLoad barrier after volatile field write
|
// StoreLoad barrier after volatile field write
|
||||||
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
|
volatile_barrier(MacroAssembler::StoreLoad, Rtemp);
|
||||||
__ b(skipMembar);
|
__ b(skipMembar);
|
||||||
|
|
||||||
// StoreStore barrier after final field write
|
// StoreStore barrier after final field write
|
||||||
__ bind(notVolatile);
|
__ bind(notVolatile2);
|
||||||
volatile_barrier(MacroAssembler::StoreStore, Rtemp);
|
volatile_barrier(MacroAssembler::StoreStore, Rtemp);
|
||||||
|
|
||||||
__ bind(skipMembar);
|
__ bind(skipMembar);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TemplateTable::fast_accessfield(TosState state) {
|
void TemplateTable::fast_accessfield(TosState state) {
|
||||||
transition(atos, state);
|
transition(atos, state);
|
||||||
|
|
||||||
|
@ -3953,18 +3931,14 @@ void TemplateTable::fast_accessfield(TosState state) {
|
||||||
const Register Rindex = R3_tmp;
|
const Register Rindex = R3_tmp;
|
||||||
const Register Roffset = R3_tmp;
|
const Register Roffset = R3_tmp;
|
||||||
|
|
||||||
const bool gen_volatile_check = os::is_MP();
|
|
||||||
|
|
||||||
// access constant pool cache
|
// access constant pool cache
|
||||||
__ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
|
__ get_cache_and_index_at_bcp(Rcache, Rindex, 1);
|
||||||
// replace index with field offset from cache entry
|
// replace index with field offset from cache entry
|
||||||
__ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
|
__ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
|
||||||
__ ldr(Roffset, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset()));
|
__ ldr(Roffset, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset()));
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
// load flags to test volatile
|
||||||
// load flags to test volatile
|
__ ldr_u32(Rflags, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
|
||||||
__ ldr_u32(Rflags, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
|
|
||||||
}
|
|
||||||
|
|
||||||
__ verify_oop(Robj);
|
__ verify_oop(Robj);
|
||||||
__ null_check(Robj, Rtemp);
|
__ null_check(Robj, Rtemp);
|
||||||
|
@ -4007,16 +3981,14 @@ void TemplateTable::fast_accessfield(TosState state) {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen_volatile_check) {
|
// Check for volatile load
|
||||||
// Check for volatile load
|
Label notVolatile;
|
||||||
Label notVolatile;
|
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
||||||
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
|
||||||
|
|
||||||
// TODO-AARCH64 on AArch64, load-acquire instructions can be used to get rid of this explict barrier
|
// TODO-AARCH64 on AArch64, load-acquire instructions can be used to get rid of this explict barrier
|
||||||
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
|
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
|
||||||
|
|
||||||
__ bind(notVolatile);
|
__ bind(notVolatile);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4038,12 +4010,8 @@ void TemplateTable::fast_xaccess(TosState state) {
|
||||||
__ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
|
__ add(Rtemp, Rcache, AsmOperand(Rindex, lsl, LogBytesPerWord));
|
||||||
__ ldr(Roffset, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset()));
|
__ ldr(Roffset, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f2_offset()));
|
||||||
|
|
||||||
const bool gen_volatile_check = os::is_MP();
|
// load flags to test volatile
|
||||||
|
__ ldr_u32(Rflags, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
|
||||||
if (gen_volatile_check) {
|
|
||||||
// load flags to test volatile
|
|
||||||
__ ldr_u32(Rflags, Address(Rtemp, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure exception is reported in correct bcp range (getfield is next instruction)
|
// make sure exception is reported in correct bcp range (getfield is next instruction)
|
||||||
__ add(Rbcp, Rbcp, 1);
|
__ add(Rbcp, Rbcp, 1);
|
||||||
|
@ -4051,32 +4019,30 @@ void TemplateTable::fast_xaccess(TosState state) {
|
||||||
__ sub(Rbcp, Rbcp, 1);
|
__ sub(Rbcp, Rbcp, 1);
|
||||||
|
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
if (gen_volatile_check) {
|
Label notVolatile;
|
||||||
Label notVolatile;
|
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
||||||
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
|
||||||
|
|
||||||
__ add(Rtemp, Robj, Roffset);
|
__ add(Rtemp, Robj, Roffset);
|
||||||
|
|
||||||
if (state == itos) {
|
if (state == itos) {
|
||||||
|
__ ldar_w(R0_tos, Rtemp);
|
||||||
|
} else if (state == atos) {
|
||||||
|
if (UseCompressedOops) {
|
||||||
__ ldar_w(R0_tos, Rtemp);
|
__ ldar_w(R0_tos, Rtemp);
|
||||||
} else if (state == atos) {
|
__ decode_heap_oop(R0_tos);
|
||||||
if (UseCompressedOops) {
|
|
||||||
__ ldar_w(R0_tos, Rtemp);
|
|
||||||
__ decode_heap_oop(R0_tos);
|
|
||||||
} else {
|
|
||||||
__ ldar(R0_tos, Rtemp);
|
|
||||||
}
|
|
||||||
__ verify_oop(R0_tos);
|
|
||||||
} else if (state == ftos) {
|
|
||||||
__ ldar_w(R0_tos, Rtemp);
|
|
||||||
__ fmov_sw(S0_tos, R0_tos);
|
|
||||||
} else {
|
} else {
|
||||||
ShouldNotReachHere();
|
__ ldar(R0_tos, Rtemp);
|
||||||
}
|
}
|
||||||
__ b(done);
|
__ verify_oop(R0_tos);
|
||||||
|
} else if (state == ftos) {
|
||||||
__ bind(notVolatile);
|
__ ldar_w(R0_tos, Rtemp);
|
||||||
|
__ fmov_sw(S0_tos, R0_tos);
|
||||||
|
} else {
|
||||||
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
__ b(done);
|
||||||
|
|
||||||
|
__ bind(notVolatile);
|
||||||
#endif // AARCH64
|
#endif // AARCH64
|
||||||
|
|
||||||
if (state == itos) {
|
if (state == itos) {
|
||||||
|
@ -4099,15 +4065,13 @@ void TemplateTable::fast_xaccess(TosState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef AARCH64
|
#ifndef AARCH64
|
||||||
if (gen_volatile_check) {
|
// Check for volatile load
|
||||||
// Check for volatile load
|
Label notVolatile;
|
||||||
Label notVolatile;
|
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
||||||
__ tbz(Rflags, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
|
|
||||||
|
|
||||||
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
|
volatile_barrier(MacroAssembler::Membar_mask_bits(MacroAssembler::LoadLoad | MacroAssembler::LoadStore), Rtemp);
|
||||||
|
|
||||||
__ bind(notVolatile);
|
__ bind(notVolatile);
|
||||||
}
|
|
||||||
#endif // !AARCH64
|
#endif // !AARCH64
|
||||||
|
|
||||||
__ bind(done);
|
__ bind(done);
|
||||||
|
|
|
@ -535,8 +535,8 @@ void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
|
||||||
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
||||||
case longTag: do_ArithmeticOp_Long(x); return;
|
case longTag: do_ArithmeticOp_Long(x); return;
|
||||||
case intTag: do_ArithmeticOp_Int(x); return;
|
case intTag: do_ArithmeticOp_Int(x); return;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -735,39 +735,39 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
|
||||||
break;
|
break;
|
||||||
} // else fallthru
|
} // else fallthru
|
||||||
}
|
}
|
||||||
|
case vmIntrinsics::_dsin: // fall through
|
||||||
|
case vmIntrinsics::_dcos: // fall through
|
||||||
|
case vmIntrinsics::_dtan: // fall through
|
||||||
|
case vmIntrinsics::_dlog: // fall through
|
||||||
case vmIntrinsics::_dlog10: // fall through
|
case vmIntrinsics::_dlog10: // fall through
|
||||||
case vmIntrinsics::_dlog: // fall through
|
|
||||||
case vmIntrinsics::_dsin: // fall through
|
|
||||||
case vmIntrinsics::_dtan: // fall through
|
|
||||||
case vmIntrinsics::_dcos: // fall through
|
|
||||||
case vmIntrinsics::_dexp: {
|
case vmIntrinsics::_dexp: {
|
||||||
assert(x->number_of_arguments() == 1, "wrong type");
|
assert(x->number_of_arguments() == 1, "wrong type");
|
||||||
|
|
||||||
address runtime_entry = NULL;
|
address runtime_entry = NULL;
|
||||||
switch (x->id()) {
|
switch (x->id()) {
|
||||||
case vmIntrinsics::_dsqrt:
|
case vmIntrinsics::_dsqrt:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dsin:
|
case vmIntrinsics::_dsin:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dcos:
|
case vmIntrinsics::_dcos:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dtan:
|
case vmIntrinsics::_dtan:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dlog:
|
case vmIntrinsics::_dlog:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dlog10:
|
case vmIntrinsics::_dlog10:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dexp:
|
case vmIntrinsics::_dexp:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL);
|
LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL);
|
||||||
|
@ -781,6 +781,8 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
|
||||||
set_result(x, result);
|
set_result(x, result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -215,9 +215,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
|
||||||
void CompiledDirectStaticCall::verify() {
|
void CompiledDirectStaticCall::verify() {
|
||||||
// Verify call.
|
// Verify call.
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify stub.
|
// Verify stub.
|
||||||
address stub = find_stub(/*is_aot*/ false);
|
address stub = find_stub(/*is_aot*/ false);
|
||||||
|
|
|
@ -2430,17 +2430,15 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||||
{
|
{
|
||||||
Label no_block, sync;
|
Label no_block, sync;
|
||||||
|
|
||||||
if (os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
// Force this write out before the read below.
|
||||||
// Force this write out before the read below.
|
__ fence();
|
||||||
__ fence();
|
} else {
|
||||||
} else {
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// due to cache line collision.
|
||||||
// due to cache line collision.
|
__ serialize_memory(R16_thread, r_temp_4, r_temp_5);
|
||||||
__ serialize_memory(R16_thread, r_temp_4, r_temp_5);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Register sync_state_addr = r_temp_4;
|
Register sync_state_addr = r_temp_4;
|
||||||
|
|
|
@ -2236,8 +2236,10 @@ void TemplateTable::resolve_cache_and_index(int byte_no, Register Rcache, Regist
|
||||||
|
|
||||||
Bytecodes::Code code = bytecode();
|
Bytecodes::Code code = bytecode();
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
||||||
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
|
assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range");
|
||||||
|
|
|
@ -121,14 +121,14 @@ Assembler::branch_condition Assembler::inverse_float_condition(Assembler::branch
|
||||||
case bcondNotOrdered : inverse_cc = bcondOrdered; break; // 14
|
case bcondNotOrdered : inverse_cc = bcondOrdered; break; // 14
|
||||||
case bcondOrdered : inverse_cc = bcondNotOrdered; break; // 1
|
case bcondOrdered : inverse_cc = bcondNotOrdered; break; // 1
|
||||||
|
|
||||||
case bcondEqual : inverse_cc = (branch_condition)(bcondNotEqual + bcondNotOrdered); break; // 8
|
case bcondEqual : inverse_cc = bcondNotEqualOrNotOrdered; break; // 8
|
||||||
case bcondNotEqual + bcondNotOrdered : inverse_cc = bcondEqual; break; // 7
|
case bcondNotEqualOrNotOrdered : inverse_cc = bcondEqual; break; // 7
|
||||||
|
|
||||||
case bcondLow + bcondNotOrdered : inverse_cc = (branch_condition)(bcondHigh + bcondEqual); break; // 5
|
case bcondLowOrNotOrdered : inverse_cc = bcondNotLow; break; // 5
|
||||||
case bcondNotLow : inverse_cc = (branch_condition)(bcondLow + bcondNotOrdered); break; // 10
|
case bcondNotLow : inverse_cc = bcondLowOrNotOrdered; break; // 10
|
||||||
|
|
||||||
case bcondHigh : inverse_cc = (branch_condition)(bcondLow + bcondNotOrdered + bcondEqual); break; // 2
|
case bcondHigh : inverse_cc = bcondNotHighOrNotOrdered; break; // 2
|
||||||
case bcondNotHigh + bcondNotOrdered : inverse_cc = bcondHigh; break; // 13
|
case bcondNotHighOrNotOrdered : inverse_cc = bcondHigh; break; // 13
|
||||||
|
|
||||||
default :
|
default :
|
||||||
fprintf(stderr, "inverse_float_condition(%d)\n", (int)cc);
|
fprintf(stderr, "inverse_float_condition(%d)\n", (int)cc);
|
||||||
|
|
|
@ -1442,8 +1442,11 @@ class Assembler : public AbstractAssembler {
|
||||||
bcondNotPositive = bcondNotHigh,
|
bcondNotPositive = bcondNotHigh,
|
||||||
bcondNotOrdered = 1, // float comparisons
|
bcondNotOrdered = 1, // float comparisons
|
||||||
bcondOrdered = 14, // float comparisons
|
bcondOrdered = 14, // float comparisons
|
||||||
bcondLowOrNotOrdered = bcondLow|bcondNotOrdered, // float comparisons
|
bcondLowOrNotOrdered = bcondLow | bcondNotOrdered, // float comparisons
|
||||||
bcondHighOrNotOrdered = bcondHigh|bcondNotOrdered, // float comparisons
|
bcondHighOrNotOrdered = bcondHigh | bcondNotOrdered, // float comparisons
|
||||||
|
bcondNotLowOrNotOrdered = bcondNotLow | bcondNotOrdered, // float comparisons
|
||||||
|
bcondNotHighOrNotOrdered = bcondNotHigh | bcondNotOrdered, // float comparisons
|
||||||
|
bcondNotEqualOrNotOrdered = bcondNotEqual | bcondNotOrdered, // float comparisons
|
||||||
// unsigned arithmetic calculation instructions
|
// unsigned arithmetic calculation instructions
|
||||||
// Mask bit#0 is not used by these instructions.
|
// Mask bit#0 is not used by these instructions.
|
||||||
// There is no indication of overflow for these instr.
|
// There is no indication of overflow for these instr.
|
||||||
|
|
|
@ -529,8 +529,9 @@ void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) {
|
||||||
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
case doubleTag: do_ArithmeticOp_FPU(x); return;
|
||||||
case longTag: do_ArithmeticOp_Long(x); return;
|
case longTag: do_ArithmeticOp_Long(x); return;
|
||||||
case intTag: do_ArithmeticOp_Int(x); return;
|
case intTag: do_ArithmeticOp_Int(x); return;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
|
// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr
|
||||||
|
@ -634,47 +635,49 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
|
||||||
LIR_Opr dst = rlock_result(x);
|
LIR_Opr dst = rlock_result(x);
|
||||||
|
|
||||||
switch (x->id()) {
|
switch (x->id()) {
|
||||||
case vmIntrinsics::_dsqrt: {
|
case vmIntrinsics::_dsqrt: {
|
||||||
__ sqrt(value.result(), dst, LIR_OprFact::illegalOpr);
|
__ sqrt(value.result(), dst, LIR_OprFact::illegalOpr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case vmIntrinsics::_dabs: {
|
case vmIntrinsics::_dabs: {
|
||||||
__ abs(value.result(), dst, LIR_OprFact::illegalOpr);
|
__ abs(value.result(), dst, LIR_OprFact::illegalOpr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case vmIntrinsics::_dsin: // fall through
|
||||||
|
case vmIntrinsics::_dcos: // fall through
|
||||||
|
case vmIntrinsics::_dtan: // fall through
|
||||||
|
case vmIntrinsics::_dlog: // fall through
|
||||||
case vmIntrinsics::_dlog10: // fall through
|
case vmIntrinsics::_dlog10: // fall through
|
||||||
case vmIntrinsics::_dlog: // fall through
|
|
||||||
case vmIntrinsics::_dsin: // fall through
|
|
||||||
case vmIntrinsics::_dtan: // fall through
|
|
||||||
case vmIntrinsics::_dcos: // fall through
|
|
||||||
case vmIntrinsics::_dexp: {
|
case vmIntrinsics::_dexp: {
|
||||||
assert(x->number_of_arguments() == 1, "wrong type");
|
assert(x->number_of_arguments() == 1, "wrong type");
|
||||||
|
|
||||||
address runtime_entry = NULL;
|
address runtime_entry = NULL;
|
||||||
switch (x->id()) {
|
switch (x->id()) {
|
||||||
case vmIntrinsics::_dsin:
|
case vmIntrinsics::_dsin:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dcos:
|
case vmIntrinsics::_dcos:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dtan:
|
case vmIntrinsics::_dtan:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dlog:
|
case vmIntrinsics::_dlog:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dlog10:
|
case vmIntrinsics::_dlog10:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_dexp:
|
case vmIntrinsics::_dexp:
|
||||||
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
|
runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dexp);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL);
|
LIR_Opr result = call_runtime(x->argument_at(0), runtime_entry, x->type(), NULL);
|
||||||
|
@ -688,6 +691,8 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) {
|
||||||
set_result(x, result);
|
set_result(x, result);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* Copyright (c) 2016 SAP SE. All rights reserved.
|
* Copyright (c) 2016 SAP SE. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
|
@ -145,9 +145,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
|
||||||
void CompiledDirectStaticCall::verify() {
|
void CompiledDirectStaticCall::verify() {
|
||||||
// Verify call.
|
// Verify call.
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify stub.
|
// Verify stub.
|
||||||
address stub = find_stub(/*is_aot*/ false);
|
address stub = find_stub(/*is_aot*/ false);
|
||||||
|
|
|
@ -593,7 +593,6 @@ class MacroAssembler: public Assembler {
|
||||||
static int call_far_patchable_ret_addr_offset() { return call_far_patchable_size(); }
|
static int call_far_patchable_ret_addr_offset() { return call_far_patchable_size(); }
|
||||||
|
|
||||||
static bool call_far_patchable_requires_alignment_nop(address pc) {
|
static bool call_far_patchable_requires_alignment_nop(address pc) {
|
||||||
if (!os::is_MP()) return false;
|
|
||||||
int size = call_far_patchable_size();
|
int size = call_far_patchable_size();
|
||||||
return ((intptr_t)(pc + size) & 0x03L) != 0;
|
return ((intptr_t)(pc + size) & 0x03L) != 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -587,6 +587,9 @@ void SharedRuntime::save_native_result(MacroAssembler * masm,
|
||||||
case T_DOUBLE:
|
case T_DOUBLE:
|
||||||
__ freg2mem_opt(Z_FRET, memaddr);
|
__ freg2mem_opt(Z_FRET, memaddr);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -616,6 +619,9 @@ void SharedRuntime::restore_native_result(MacroAssembler *masm,
|
||||||
case T_DOUBLE:
|
case T_DOUBLE:
|
||||||
__ mem2freg_opt(Z_FRET, memaddr);
|
__ mem2freg_opt(Z_FRET, memaddr);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2155,18 +2161,17 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||||
|
|
||||||
save_native_result(masm, ret_type, workspace_slot_offset); // Make Z_R2 available as work reg.
|
save_native_result(masm, ret_type, workspace_slot_offset); // Make Z_R2 available as work reg.
|
||||||
|
|
||||||
if (os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
// Force this write out before the read below.
|
||||||
// Force this write out before the read below.
|
__ z_fence();
|
||||||
__ z_fence();
|
} else {
|
||||||
} else {
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// due to cache line collision.
|
||||||
// due to cache line collision.
|
__ serialize_memory(Z_thread, Z_R1, Z_R2);
|
||||||
__ serialize_memory(Z_thread, Z_R1, Z_R2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__ safepoint_poll(sync, Z_R1);
|
__ safepoint_poll(sync, Z_R1);
|
||||||
|
|
||||||
__ load_and_test_int(Z_R0, Address(Z_thread, JavaThread::suspend_flags_offset()));
|
__ load_and_test_int(Z_R0, Address(Z_thread, JavaThread::suspend_flags_offset()));
|
||||||
|
|
|
@ -2417,6 +2417,8 @@ void TemplateTable::resolve_cache_and_index(int byte_no,
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break;
|
||||||
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -3213,6 +3215,8 @@ void TemplateTable::jvmti_post_fast_field_mod() {
|
||||||
case Bytecodes::_fast_lputfield:
|
case Bytecodes::_fast_lputfield:
|
||||||
__ pop_l(Z_tos);
|
__ pop_l(Z_tos);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
__ bind(exit);
|
__ bind(exit);
|
||||||
|
|
|
@ -142,9 +142,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
|
||||||
void CompiledDirectStaticCall::verify() {
|
void CompiledDirectStaticCall::verify() {
|
||||||
// Verify call.
|
// Verify call.
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify stub.
|
// Verify stub.
|
||||||
address stub = find_stub(/*is_aot*/ false);
|
address stub = find_stub(/*is_aot*/ false);
|
||||||
|
|
|
@ -2786,7 +2786,7 @@ void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark,
|
||||||
delayed()->
|
delayed()->
|
||||||
st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
st_ptr(G0, Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
||||||
|
|
||||||
if (os::is_MP()) { membar(StoreLoad); }
|
membar(StoreLoad);
|
||||||
// Check that _succ is (or remains) non-zero
|
// Check that _succ is (or remains) non-zero
|
||||||
ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
|
ld_ptr(Address(Rmark, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), Rscratch);
|
||||||
andcc(Rscratch, Rscratch, G0);
|
andcc(Rscratch, Rscratch, G0);
|
||||||
|
|
|
@ -614,17 +614,12 @@ inline void MacroAssembler::ldfl(FloatRegisterImpl::Width w, Register s1, Regist
|
||||||
// returns if membar generates anything, obviously this code should mirror
|
// returns if membar generates anything, obviously this code should mirror
|
||||||
// membar below.
|
// membar below.
|
||||||
inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) {
|
inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) {
|
||||||
if (!os::is_MP())
|
|
||||||
return false; // Not needed on single CPU
|
|
||||||
const Membar_mask_bits effective_mask =
|
const Membar_mask_bits effective_mask =
|
||||||
Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
|
Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
|
||||||
return (effective_mask != 0);
|
return (effective_mask != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MacroAssembler::membar( Membar_mask_bits const7a ) {
|
inline void MacroAssembler::membar( Membar_mask_bits const7a ) {
|
||||||
// Uniprocessors do not need memory barriers
|
|
||||||
if (!os::is_MP())
|
|
||||||
return;
|
|
||||||
// Weakened for current Sparcs and TSO. See the v9 manual, sections 8.4.3,
|
// Weakened for current Sparcs and TSO. See the v9 manual, sections 8.4.3,
|
||||||
// 8.4.4.3, a.31 and a.50.
|
// 8.4.4.3, a.31 and a.50.
|
||||||
// Under TSO, setting bit 3, 2, or 0 is redundant, so the only value
|
// Under TSO, setting bit 3, 2, or 0 is redundant, so the only value
|
||||||
|
|
|
@ -2371,17 +2371,16 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
// didn't see any synchronization is progress, and escapes.
|
// didn't see any synchronization is progress, and escapes.
|
||||||
__ set(_thread_in_native_trans, G3_scratch);
|
__ set(_thread_in_native_trans, G3_scratch);
|
||||||
__ st(G3_scratch, G2_thread, JavaThread::thread_state_offset());
|
__ st(G3_scratch, G2_thread, JavaThread::thread_state_offset());
|
||||||
if(os::is_MP()) {
|
|
||||||
if (UseMembar) {
|
if (UseMembar) {
|
||||||
// Force this write out before the read below
|
// Force this write out before the read below
|
||||||
__ membar(Assembler::StoreLoad);
|
__ membar(Assembler::StoreLoad);
|
||||||
} else {
|
} else {
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// due to cache line collision.
|
// due to cache line collision.
|
||||||
__ serialize_memory(G2_thread, G1_scratch, G3_scratch);
|
__ serialize_memory(G2_thread, G1_scratch, G3_scratch);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label L;
|
Label L;
|
||||||
|
|
|
@ -1373,17 +1373,16 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||||
// didn't see any synchronization is progress, and escapes.
|
// didn't see any synchronization is progress, and escapes.
|
||||||
__ set(_thread_in_native_trans, G3_scratch);
|
__ set(_thread_in_native_trans, G3_scratch);
|
||||||
__ st(G3_scratch, thread_state);
|
__ st(G3_scratch, thread_state);
|
||||||
if (os::is_MP()) {
|
|
||||||
if (UseMembar) {
|
if (UseMembar) {
|
||||||
// Force this write out before the read below
|
// Force this write out before the read below
|
||||||
__ membar(Assembler::StoreLoad);
|
__ membar(Assembler::StoreLoad);
|
||||||
} else {
|
} else {
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// due to cache line collision.
|
// due to cache line collision.
|
||||||
__ serialize_memory(G2_thread, G1_scratch, G3_scratch);
|
__ serialize_memory(G2_thread, G1_scratch, G3_scratch);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label L;
|
Label L;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -871,11 +871,6 @@ private:
|
||||||
void clear_managed(void) { _is_managed = false; }
|
void clear_managed(void) { _is_managed = false; }
|
||||||
bool is_managed(void) { return _is_managed; }
|
bool is_managed(void) { return _is_managed; }
|
||||||
|
|
||||||
// Following functions are for stub code use only
|
|
||||||
void set_vector_masking(void) { _vector_masking = true; }
|
|
||||||
void clear_vector_masking(void) { _vector_masking = false; }
|
|
||||||
bool is_vector_masking(void) { return _vector_masking; }
|
|
||||||
|
|
||||||
void lea(Register dst, Address src);
|
void lea(Register dst, Address src);
|
||||||
|
|
||||||
void mov(Register dst, Register src);
|
void mov(Register dst, Register src);
|
||||||
|
@ -1350,40 +1345,38 @@ private:
|
||||||
|
|
||||||
// Serializes memory and blows flags
|
// Serializes memory and blows flags
|
||||||
void membar(Membar_mask_bits order_constraint) {
|
void membar(Membar_mask_bits order_constraint) {
|
||||||
if (os::is_MP()) {
|
// We only have to handle StoreLoad
|
||||||
// We only have to handle StoreLoad
|
if (order_constraint & StoreLoad) {
|
||||||
if (order_constraint & StoreLoad) {
|
// All usable chips support "locked" instructions which suffice
|
||||||
// All usable chips support "locked" instructions which suffice
|
// as barriers, and are much faster than the alternative of
|
||||||
// as barriers, and are much faster than the alternative of
|
// using cpuid instruction. We use here a locked add [esp-C],0.
|
||||||
// using cpuid instruction. We use here a locked add [esp-C],0.
|
// This is conveniently otherwise a no-op except for blowing
|
||||||
// This is conveniently otherwise a no-op except for blowing
|
// flags, and introducing a false dependency on target memory
|
||||||
// flags, and introducing a false dependency on target memory
|
// location. We can't do anything with flags, but we can avoid
|
||||||
// location. We can't do anything with flags, but we can avoid
|
// memory dependencies in the current method by locked-adding
|
||||||
// memory dependencies in the current method by locked-adding
|
// somewhere else on the stack. Doing [esp+C] will collide with
|
||||||
// somewhere else on the stack. Doing [esp+C] will collide with
|
// something on stack in current method, hence we go for [esp-C].
|
||||||
// something on stack in current method, hence we go for [esp-C].
|
// It is convenient since it is almost always in data cache, for
|
||||||
// It is convenient since it is almost always in data cache, for
|
// any small C. We need to step back from SP to avoid data
|
||||||
// any small C. We need to step back from SP to avoid data
|
// dependencies with other things on below SP (callee-saves, for
|
||||||
// dependencies with other things on below SP (callee-saves, for
|
// example). Without a clear way to figure out the minimal safe
|
||||||
// example). Without a clear way to figure out the minimal safe
|
// distance from SP, it makes sense to step back the complete
|
||||||
// distance from SP, it makes sense to step back the complete
|
// cache line, as this will also avoid possible second-order effects
|
||||||
// cache line, as this will also avoid possible second-order effects
|
// with locked ops against the cache line. Our choice of offset
|
||||||
// with locked ops against the cache line. Our choice of offset
|
// is bounded by x86 operand encoding, which should stay within
|
||||||
// is bounded by x86 operand encoding, which should stay within
|
// [-128; +127] to have the 8-byte displacement encoding.
|
||||||
// [-128; +127] to have the 8-byte displacement encoding.
|
//
|
||||||
//
|
// Any change to this code may need to revisit other places in
|
||||||
// Any change to this code may need to revisit other places in
|
// the code where this idiom is used, in particular the
|
||||||
// the code where this idiom is used, in particular the
|
// orderAccess code.
|
||||||
// orderAccess code.
|
|
||||||
|
|
||||||
int offset = -VM_Version::L1_line_size();
|
int offset = -VM_Version::L1_line_size();
|
||||||
if (offset < -128) {
|
if (offset < -128) {
|
||||||
offset = -128;
|
offset = -128;
|
||||||
}
|
|
||||||
|
|
||||||
lock();
|
|
||||||
addl(Address(rsp, offset), 0);// Assert the lock# signal here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lock();
|
||||||
|
addl(Address(rsp, offset), 0);// Assert the lock# signal here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2210,7 +2203,7 @@ public:
|
||||||
int vector_len, // The length of vector to be applied in encoding - for both AVX and EVEX
|
int vector_len, // The length of vector to be applied in encoding - for both AVX and EVEX
|
||||||
bool rex_vex_w, // Width of data: if 32-bits or less, false, else if 64-bit or specially defined, true
|
bool rex_vex_w, // Width of data: if 32-bits or less, false, else if 64-bit or specially defined, true
|
||||||
bool legacy_mode, // Details if either this instruction is conditionally encoded to AVX or earlier if true else possibly EVEX
|
bool legacy_mode, // Details if either this instruction is conditionally encoded to AVX or earlier if true else possibly EVEX
|
||||||
bool no_reg_mask, // when true, k0 is used when EVEX encoding is chosen, else k1 is used under the same condition
|
bool no_reg_mask, // when true, k0 is used when EVEX encoding is chosen, else embedded_opmask_register_specifier is used
|
||||||
bool uses_vl) // This instruction may have legacy constraints based on vector length for EVEX
|
bool uses_vl) // This instruction may have legacy constraints based on vector length for EVEX
|
||||||
:
|
:
|
||||||
_avx_vector_len(vector_len),
|
_avx_vector_len(vector_len),
|
||||||
|
@ -2225,7 +2218,7 @@ public:
|
||||||
_evex_encoding(0),
|
_evex_encoding(0),
|
||||||
_is_clear_context(true),
|
_is_clear_context(true),
|
||||||
_is_extended_context(false),
|
_is_extended_context(false),
|
||||||
_embedded_opmask_register_specifier(1), // hard code k1, it will be initialized for now
|
_embedded_opmask_register_specifier(0), // hard code k0
|
||||||
_current_assembler(NULL) {
|
_current_assembler(NULL) {
|
||||||
if (UseAVX < 3) _legacy_mode = true;
|
if (UseAVX < 3) _legacy_mode = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1906,9 +1906,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
|
||||||
assert(op->new_value()->as_register_lo() == rbx, "wrong register");
|
assert(op->new_value()->as_register_lo() == rbx, "wrong register");
|
||||||
assert(op->new_value()->as_register_hi() == rcx, "wrong register");
|
assert(op->new_value()->as_register_hi() == rcx, "wrong register");
|
||||||
Register addr = op->addr()->as_register();
|
Register addr = op->addr()->as_register();
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
NOT_LP64(__ cmpxchg8(Address(addr, 0)));
|
NOT_LP64(__ cmpxchg8(Address(addr, 0)));
|
||||||
|
|
||||||
} else if (op->code() == lir_cas_int || op->code() == lir_cas_obj ) {
|
} else if (op->code() == lir_cas_int || op->code() == lir_cas_obj ) {
|
||||||
|
@ -1928,24 +1926,18 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
|
||||||
__ encode_heap_oop(cmpval);
|
__ encode_heap_oop(cmpval);
|
||||||
__ mov(rscratch1, newval);
|
__ mov(rscratch1, newval);
|
||||||
__ encode_heap_oop(rscratch1);
|
__ encode_heap_oop(rscratch1);
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
// cmpval (rax) is implicitly used by this instruction
|
// cmpval (rax) is implicitly used by this instruction
|
||||||
__ cmpxchgl(rscratch1, Address(addr, 0));
|
__ cmpxchgl(rscratch1, Address(addr, 0));
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
__ cmpxchgptr(newval, Address(addr, 0));
|
__ cmpxchgptr(newval, Address(addr, 0));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(op->code() == lir_cas_int, "lir_cas_int expected");
|
assert(op->code() == lir_cas_int, "lir_cas_int expected");
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
__ cmpxchgl(newval, Address(addr, 0));
|
__ cmpxchgl(newval, Address(addr, 0));
|
||||||
}
|
}
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
|
@ -1958,9 +1950,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) {
|
||||||
assert(cmpval != newval, "cmp and new values must be in different registers");
|
assert(cmpval != newval, "cmp and new values must be in different registers");
|
||||||
assert(cmpval != addr, "cmp and addr must be in different registers");
|
assert(cmpval != addr, "cmp and addr must be in different registers");
|
||||||
assert(newval != addr, "new value and addr must be in different registers");
|
assert(newval != addr, "new value and addr must be in different registers");
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
__ cmpxchgq(newval, Address(addr, 0));
|
__ cmpxchgq(newval, Address(addr, 0));
|
||||||
#endif // _LP64
|
#endif // _LP64
|
||||||
} else {
|
} else {
|
||||||
|
@ -2403,8 +2393,9 @@ void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr tmp, LIR_
|
||||||
if (UseAVX > 2 && !VM_Version::supports_avx512vl()) {
|
if (UseAVX > 2 && !VM_Version::supports_avx512vl()) {
|
||||||
assert(tmp->is_valid(), "need temporary");
|
assert(tmp->is_valid(), "need temporary");
|
||||||
__ vpandn(dest->as_xmm_double_reg(), tmp->as_xmm_double_reg(), value->as_xmm_double_reg(), 2);
|
__ vpandn(dest->as_xmm_double_reg(), tmp->as_xmm_double_reg(), value->as_xmm_double_reg(), 2);
|
||||||
} else {
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
if (dest->as_xmm_double_reg() != value->as_xmm_double_reg()) {
|
if (dest->as_xmm_double_reg() != value->as_xmm_double_reg()) {
|
||||||
__ movdbl(dest->as_xmm_double_reg(), value->as_xmm_double_reg());
|
__ movdbl(dest->as_xmm_double_reg(), value->as_xmm_double_reg());
|
||||||
}
|
}
|
||||||
|
@ -2803,28 +2794,26 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op
|
||||||
|
|
||||||
|
|
||||||
void LIR_Assembler::align_call(LIR_Code code) {
|
void LIR_Assembler::align_call(LIR_Code code) {
|
||||||
if (os::is_MP()) {
|
// make sure that the displacement word of the call ends up word aligned
|
||||||
// make sure that the displacement word of the call ends up word aligned
|
int offset = __ offset();
|
||||||
int offset = __ offset();
|
switch (code) {
|
||||||
switch (code) {
|
case lir_static_call:
|
||||||
case lir_static_call:
|
case lir_optvirtual_call:
|
||||||
case lir_optvirtual_call:
|
case lir_dynamic_call:
|
||||||
case lir_dynamic_call:
|
offset += NativeCall::displacement_offset;
|
||||||
offset += NativeCall::displacement_offset;
|
break;
|
||||||
break;
|
case lir_icvirtual_call:
|
||||||
case lir_icvirtual_call:
|
offset += NativeCall::displacement_offset + NativeMovConstReg::instruction_size;
|
||||||
offset += NativeCall::displacement_offset + NativeMovConstReg::instruction_size;
|
break;
|
||||||
break;
|
case lir_virtual_call: // currently, sparc-specific for niagara
|
||||||
case lir_virtual_call: // currently, sparc-specific for niagara
|
default: ShouldNotReachHere();
|
||||||
default: ShouldNotReachHere();
|
|
||||||
}
|
|
||||||
__ align(BytesPerWord, offset);
|
|
||||||
}
|
}
|
||||||
|
__ align(BytesPerWord, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
|
void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
|
||||||
assert(!os::is_MP() || (__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0,
|
assert((__ offset() + NativeCall::displacement_offset) % BytesPerWord == 0,
|
||||||
"must be aligned");
|
"must be aligned");
|
||||||
__ call(AddressLiteral(op->addr(), rtype));
|
__ call(AddressLiteral(op->addr(), rtype));
|
||||||
add_call_info(code_offset(), op->info());
|
add_call_info(code_offset(), op->info());
|
||||||
|
@ -2834,8 +2823,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
|
||||||
void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
|
void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
|
||||||
__ ic_call(op->addr());
|
__ ic_call(op->addr());
|
||||||
add_call_info(code_offset(), op->info());
|
add_call_info(code_offset(), op->info());
|
||||||
assert(!os::is_MP() ||
|
assert((__ offset() - NativeCall::instruction_size + NativeCall::displacement_offset) % BytesPerWord == 0,
|
||||||
(__ offset() - NativeCall::instruction_size + NativeCall::displacement_offset) % BytesPerWord == 0,
|
|
||||||
"must be aligned");
|
"must be aligned");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2855,14 +2843,13 @@ void LIR_Assembler::emit_static_call_stub() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int start = __ offset();
|
int start = __ offset();
|
||||||
if (os::is_MP()) {
|
|
||||||
// make sure that the displacement word of the call ends up word aligned
|
// make sure that the displacement word of the call ends up word aligned
|
||||||
__ align(BytesPerWord, __ offset() + NativeMovConstReg::instruction_size + NativeCall::displacement_offset);
|
__ align(BytesPerWord, __ offset() + NativeMovConstReg::instruction_size + NativeCall::displacement_offset);
|
||||||
}
|
|
||||||
__ relocate(static_stub_Relocation::spec(call_pc, false /* is_aot */));
|
__ relocate(static_stub_Relocation::spec(call_pc, false /* is_aot */));
|
||||||
__ mov_metadata(rbx, (Metadata*)NULL);
|
__ mov_metadata(rbx, (Metadata*)NULL);
|
||||||
// must be set to -1 at code generation time
|
// must be set to -1 at code generation time
|
||||||
assert(!os::is_MP() || ((__ offset() + 1) % BytesPerWord) == 0, "must be aligned on MP");
|
assert(((__ offset() + 1) % BytesPerWord) == 0, "must be aligned");
|
||||||
// On 64bit this will die since it will take a movq & jmp, must be only a jmp
|
// On 64bit this will die since it will take a movq & jmp, must be only a jmp
|
||||||
__ jump(RuntimeAddress(__ pc()));
|
__ jump(RuntimeAddress(__ pc()));
|
||||||
|
|
||||||
|
@ -3991,9 +3978,7 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr
|
||||||
|
|
||||||
if (data->type() == T_INT) {
|
if (data->type() == T_INT) {
|
||||||
if (code == lir_xadd) {
|
if (code == lir_xadd) {
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
__ xaddl(as_Address(src->as_address_ptr()), data->as_register());
|
__ xaddl(as_Address(src->as_address_ptr()), data->as_register());
|
||||||
} else {
|
} else {
|
||||||
__ xchgl(data->as_register(), as_Address(src->as_address_ptr()));
|
__ xchgl(data->as_register(), as_Address(src->as_address_ptr()));
|
||||||
|
@ -4016,9 +4001,7 @@ void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
assert(data->as_register_lo() == data->as_register_hi(), "should be a single register");
|
assert(data->as_register_lo() == data->as_register_hi(), "should be a single register");
|
||||||
if (code == lir_xadd) {
|
if (code == lir_xadd) {
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
__ xaddq(as_Address(src->as_address_ptr()), data->as_register_lo());
|
__ xaddq(as_Address(src->as_address_ptr()), data->as_register_lo());
|
||||||
} else {
|
} else {
|
||||||
__ xchgq(data->as_register_lo(), as_Address(src->as_address_ptr()));
|
__ xchgq(data->as_register_lo(), as_Address(src->as_address_ptr()));
|
||||||
|
|
|
@ -65,7 +65,7 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
|
||||||
// test if object header is still the same (i.e. unlocked), and if so, store the
|
// test if object header is still the same (i.e. unlocked), and if so, store the
|
||||||
// displaced header address in the object header - if it is not the same, get the
|
// displaced header address in the object header - if it is not the same, get the
|
||||||
// object header instead
|
// object header instead
|
||||||
if (os::is_MP()) MacroAssembler::lock(); // must be immediately before cmpxchg!
|
MacroAssembler::lock(); // must be immediately before cmpxchg!
|
||||||
cmpxchgptr(disp_hdr, Address(obj, hdr_offset));
|
cmpxchgptr(disp_hdr, Address(obj, hdr_offset));
|
||||||
// if the object header was the same, we're done
|
// if the object header was the same, we're done
|
||||||
if (PrintBiasedLockingStatistics) {
|
if (PrintBiasedLockingStatistics) {
|
||||||
|
@ -126,7 +126,7 @@ void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_
|
||||||
// test if object header is pointing to the displaced header, and if so, restore
|
// test if object header is pointing to the displaced header, and if so, restore
|
||||||
// the displaced header in the object - if the object header is not pointing to
|
// the displaced header in the object - if the object header is not pointing to
|
||||||
// the displaced header, get the object header instead
|
// the displaced header, get the object header instead
|
||||||
if (os::is_MP()) MacroAssembler::lock(); // must be immediately before cmpxchg!
|
MacroAssembler::lock(); // must be immediately before cmpxchg!
|
||||||
cmpxchgptr(hdr, Address(obj, hdr_offset));
|
cmpxchgptr(hdr, Address(obj, hdr_offset));
|
||||||
// if the object header was not pointing to the displaced header,
|
// if the object header was not pointing to the displaced header,
|
||||||
// we do unlocking via runtime call
|
// we do unlocking via runtime call
|
||||||
|
|
|
@ -198,9 +198,7 @@ void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_
|
||||||
void CompiledDirectStaticCall::verify() {
|
void CompiledDirectStaticCall::verify() {
|
||||||
// Verify call.
|
// Verify call.
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
|
CodeBlob *cb = CodeCache::find_blob_unsafe((address) _call);
|
||||||
|
|
|
@ -1191,7 +1191,7 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg) {
|
||||||
assert(lock_offset == 0,
|
assert(lock_offset == 0,
|
||||||
"displaced header must be first word in BasicObjectLock");
|
"displaced header must be first word in BasicObjectLock");
|
||||||
|
|
||||||
if (os::is_MP()) lock();
|
lock();
|
||||||
cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||||
if (PrintBiasedLockingStatistics) {
|
if (PrintBiasedLockingStatistics) {
|
||||||
cond_inc32(Assembler::zero,
|
cond_inc32(Assembler::zero,
|
||||||
|
@ -1288,7 +1288,7 @@ void InterpreterMacroAssembler::unlock_object(Register lock_reg) {
|
||||||
jcc(Assembler::zero, done);
|
jcc(Assembler::zero, done);
|
||||||
|
|
||||||
// Atomic swap back the old header
|
// Atomic swap back the old header
|
||||||
if (os::is_MP()) lock();
|
lock();
|
||||||
cmpxchgptr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
cmpxchgptr(header_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||||
|
|
||||||
// zero for simple unlock of a stack-lock case
|
// zero for simple unlock of a stack-lock case
|
||||||
|
|
|
@ -75,15 +75,11 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
__ mov32 (rcx, counter);
|
__ mov32 (rcx, counter);
|
||||||
__ testb (rcx, 1);
|
__ testb (rcx, 1);
|
||||||
__ jcc (Assembler::notZero, slow);
|
__ jcc (Assembler::notZero, slow);
|
||||||
if (os::is_MP()) {
|
__ mov(rax, rcx);
|
||||||
__ mov(rax, rcx);
|
__ andptr(rax, 1); // rax, must end up 0
|
||||||
__ andptr(rax, 1); // rax, must end up 0
|
__ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize));
|
||||||
__ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize));
|
// obj, notice rax, is 0.
|
||||||
// obj, notice rax, is 0.
|
// rdx is data dependent on rcx.
|
||||||
// rdx is data dependent on rcx.
|
|
||||||
} else {
|
|
||||||
__ movptr (rdx, Address(rsp, 2*wordSize)); // obj
|
|
||||||
}
|
|
||||||
__ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID
|
__ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID
|
||||||
|
|
||||||
__ clear_jweak_tag(rdx);
|
__ clear_jweak_tag(rdx);
|
||||||
|
@ -103,17 +99,13 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Address ca1;
|
Address ca1;
|
||||||
if (os::is_MP()) {
|
__ lea(rdx, counter);
|
||||||
__ lea(rdx, counter);
|
__ xorptr(rdx, rax);
|
||||||
__ xorptr(rdx, rax);
|
__ xorptr(rdx, rax);
|
||||||
__ xorptr(rdx, rax);
|
__ cmp32(rcx, Address(rdx, 0));
|
||||||
__ cmp32(rcx, Address(rdx, 0));
|
// ca1 is the same as ca because
|
||||||
// ca1 is the same as ca because
|
// rax, ^ counter_addr ^ rax, = address
|
||||||
// rax, ^ counter_addr ^ rax, = address
|
// ca1 is data dependent on rax,.
|
||||||
// ca1 is data dependent on rax,.
|
|
||||||
} else {
|
|
||||||
__ cmp32(rcx, counter);
|
|
||||||
}
|
|
||||||
__ jcc (Assembler::notEqual, slow);
|
__ jcc (Assembler::notEqual, slow);
|
||||||
|
|
||||||
#ifndef _WINDOWS
|
#ifndef _WINDOWS
|
||||||
|
@ -131,7 +123,8 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break;
|
case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break;
|
||||||
case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break;
|
case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break;
|
||||||
case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break;
|
case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break;
|
||||||
case T_INT: slow_case_addr = jni_GetIntField_addr();
|
case T_INT: slow_case_addr = jni_GetIntField_addr(); break;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
// tail call
|
// tail call
|
||||||
__ jump (ExternalAddress(slow_case_addr));
|
__ jump (ExternalAddress(slow_case_addr));
|
||||||
|
@ -195,15 +188,11 @@ address JNI_FastGetField::generate_fast_get_long_field() {
|
||||||
__ mov32 (rcx, counter);
|
__ mov32 (rcx, counter);
|
||||||
__ testb (rcx, 1);
|
__ testb (rcx, 1);
|
||||||
__ jcc (Assembler::notZero, slow);
|
__ jcc (Assembler::notZero, slow);
|
||||||
if (os::is_MP()) {
|
__ mov(rax, rcx);
|
||||||
__ mov(rax, rcx);
|
__ andptr(rax, 1); // rax, must end up 0
|
||||||
__ andptr(rax, 1); // rax, must end up 0
|
__ movptr(rdx, Address(rsp, rax, Address::times_1, 3*wordSize));
|
||||||
__ movptr(rdx, Address(rsp, rax, Address::times_1, 3*wordSize));
|
// obj, notice rax, is 0.
|
||||||
// obj, notice rax, is 0.
|
// rdx is data dependent on rcx.
|
||||||
// rdx is data dependent on rcx.
|
|
||||||
} else {
|
|
||||||
__ movptr(rdx, Address(rsp, 3*wordSize)); // obj
|
|
||||||
}
|
|
||||||
__ movptr(rsi, Address(rsp, 4*wordSize)); // jfieldID
|
__ movptr(rsi, Address(rsp, 4*wordSize)); // jfieldID
|
||||||
|
|
||||||
__ clear_jweak_tag(rdx);
|
__ clear_jweak_tag(rdx);
|
||||||
|
@ -219,19 +208,15 @@ address JNI_FastGetField::generate_fast_get_long_field() {
|
||||||
__ movl(rdx, Address(rdx, rsi, Address::times_1, 4));
|
__ movl(rdx, Address(rdx, rsi, Address::times_1, 4));
|
||||||
#endif // _LP64
|
#endif // _LP64
|
||||||
|
|
||||||
if (os::is_MP()) {
|
__ lea(rsi, counter);
|
||||||
__ lea(rsi, counter);
|
__ xorptr(rsi, rdx);
|
||||||
__ xorptr(rsi, rdx);
|
__ xorptr(rsi, rax);
|
||||||
__ xorptr(rsi, rax);
|
__ xorptr(rsi, rdx);
|
||||||
__ xorptr(rsi, rdx);
|
__ xorptr(rsi, rax);
|
||||||
__ xorptr(rsi, rax);
|
__ cmp32(rcx, Address(rsi, 0));
|
||||||
__ cmp32(rcx, Address(rsi, 0));
|
// ca1 is the same as ca because
|
||||||
// ca1 is the same as ca because
|
// rax, ^ rdx ^ counter_addr ^ rax, ^ rdx = address
|
||||||
// rax, ^ rdx ^ counter_addr ^ rax, ^ rdx = address
|
// ca1 is data dependent on both rax, and rdx.
|
||||||
// ca1 is data dependent on both rax, and rdx.
|
|
||||||
} else {
|
|
||||||
__ cmp32(rcx, counter);
|
|
||||||
}
|
|
||||||
__ jcc (Assembler::notEqual, slow);
|
__ jcc (Assembler::notEqual, slow);
|
||||||
|
|
||||||
__ pop (rsi);
|
__ pop (rsi);
|
||||||
|
@ -287,15 +272,11 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
|
||||||
__ mov32 (rcx, counter);
|
__ mov32 (rcx, counter);
|
||||||
__ testb (rcx, 1);
|
__ testb (rcx, 1);
|
||||||
__ jcc (Assembler::notZero, slow);
|
__ jcc (Assembler::notZero, slow);
|
||||||
if (os::is_MP()) {
|
__ mov(rax, rcx);
|
||||||
__ mov(rax, rcx);
|
__ andptr(rax, 1); // rax, must end up 0
|
||||||
__ andptr(rax, 1); // rax, must end up 0
|
__ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize));
|
||||||
__ movptr(rdx, Address(rsp, rax, Address::times_1, 2*wordSize));
|
// obj, notice rax, is 0.
|
||||||
// obj, notice rax, is 0.
|
// rdx is data dependent on rcx.
|
||||||
// rdx is data dependent on rcx.
|
|
||||||
} else {
|
|
||||||
__ movptr(rdx, Address(rsp, 2*wordSize)); // obj
|
|
||||||
}
|
|
||||||
__ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID
|
__ movptr(rax, Address(rsp, 3*wordSize)); // jfieldID
|
||||||
|
|
||||||
__ clear_jweak_tag(rdx);
|
__ clear_jweak_tag(rdx);
|
||||||
|
@ -317,20 +298,16 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Address ca1;
|
Address ca1;
|
||||||
if (os::is_MP()) {
|
__ fst_s (Address(rsp, -4));
|
||||||
__ fst_s (Address(rsp, -4));
|
__ lea(rdx, counter);
|
||||||
__ lea(rdx, counter);
|
__ movl (rax, Address(rsp, -4));
|
||||||
__ movl (rax, Address(rsp, -4));
|
// garbage hi-order bits on 64bit are harmless.
|
||||||
// garbage hi-order bits on 64bit are harmless.
|
__ xorptr(rdx, rax);
|
||||||
__ xorptr(rdx, rax);
|
__ xorptr(rdx, rax);
|
||||||
__ xorptr(rdx, rax);
|
__ cmp32(rcx, Address(rdx, 0));
|
||||||
__ cmp32(rcx, Address(rdx, 0));
|
// rax, ^ counter_addr ^ rax, = address
|
||||||
// rax, ^ counter_addr ^ rax, = address
|
// ca1 is data dependent on the field
|
||||||
// ca1 is data dependent on the field
|
// access.
|
||||||
// access.
|
|
||||||
} else {
|
|
||||||
__ cmp32(rcx, counter);
|
|
||||||
}
|
|
||||||
__ jcc (Assembler::notEqual, slow_with_pop);
|
__ jcc (Assembler::notEqual, slow_with_pop);
|
||||||
|
|
||||||
#ifndef _WINDOWS
|
#ifndef _WINDOWS
|
||||||
|
|
|
@ -77,12 +77,11 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
__ mov (robj, c_rarg1);
|
__ mov (robj, c_rarg1);
|
||||||
__ testb (rcounter, 1);
|
__ testb (rcounter, 1);
|
||||||
__ jcc (Assembler::notZero, slow);
|
__ jcc (Assembler::notZero, slow);
|
||||||
if (os::is_MP()) {
|
|
||||||
__ xorptr(robj, rcounter);
|
__ xorptr(robj, rcounter);
|
||||||
__ xorptr(robj, rcounter); // obj, since
|
__ xorptr(robj, rcounter); // obj, since
|
||||||
// robj ^ rcounter ^ rcounter == robj
|
// robj ^ rcounter ^ rcounter == robj
|
||||||
// robj is data dependent on rcounter.
|
// robj is data dependent on rcounter.
|
||||||
}
|
|
||||||
|
|
||||||
__ mov (roffset, c_rarg2);
|
__ mov (roffset, c_rarg2);
|
||||||
__ shrptr(roffset, 2); // offset
|
__ shrptr(roffset, 2); // offset
|
||||||
|
@ -104,15 +103,12 @@ address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) {
|
||||||
default: ShouldNotReachHere();
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os::is_MP()) {
|
// create data dependency on rax
|
||||||
__ lea(rcounter_addr, counter);
|
__ lea(rcounter_addr, counter);
|
||||||
// ca is data dependent on rax.
|
__ xorptr(rcounter_addr, rax);
|
||||||
__ xorptr(rcounter_addr, rax);
|
__ xorptr(rcounter_addr, rax);
|
||||||
__ xorptr(rcounter_addr, rax);
|
__ cmpl (rcounter, Address(rcounter_addr, 0));
|
||||||
__ cmpl (rcounter, Address(rcounter_addr, 0));
|
|
||||||
} else {
|
|
||||||
__ cmp32 (rcounter, counter);
|
|
||||||
}
|
|
||||||
__ jcc (Assembler::notEqual, slow);
|
__ jcc (Assembler::notEqual, slow);
|
||||||
|
|
||||||
__ ret (0);
|
__ ret (0);
|
||||||
|
@ -181,12 +177,11 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
|
||||||
__ mov (robj, c_rarg1);
|
__ mov (robj, c_rarg1);
|
||||||
__ testb (rcounter, 1);
|
__ testb (rcounter, 1);
|
||||||
__ jcc (Assembler::notZero, slow);
|
__ jcc (Assembler::notZero, slow);
|
||||||
if (os::is_MP()) {
|
|
||||||
__ xorptr(robj, rcounter);
|
__ xorptr(robj, rcounter);
|
||||||
__ xorptr(robj, rcounter); // obj, since
|
__ xorptr(robj, rcounter); // obj, since
|
||||||
// robj ^ rcounter ^ rcounter == robj
|
// robj ^ rcounter ^ rcounter == robj
|
||||||
// robj is data dependent on rcounter.
|
// robj is data dependent on rcounter.
|
||||||
}
|
|
||||||
|
|
||||||
// Both robj and rtmp are clobbered by try_resolve_jobject_in_native.
|
// Both robj and rtmp are clobbered by try_resolve_jobject_in_native.
|
||||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||||
|
@ -204,16 +199,12 @@ address JNI_FastGetField::generate_fast_get_float_field0(BasicType type) {
|
||||||
default: ShouldNotReachHere();
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (os::is_MP()) {
|
__ lea(rcounter_addr, counter);
|
||||||
__ lea(rcounter_addr, counter);
|
__ movdq (rax, xmm0);
|
||||||
__ movdq (rax, xmm0);
|
// counter address is data dependent on xmm0.
|
||||||
// counter address is data dependent on xmm0.
|
__ xorptr(rcounter_addr, rax);
|
||||||
__ xorptr(rcounter_addr, rax);
|
__ xorptr(rcounter_addr, rax);
|
||||||
__ xorptr(rcounter_addr, rax);
|
__ cmpl (rcounter, Address(rcounter_addr, 0));
|
||||||
__ cmpl (rcounter, Address(rcounter_addr, 0));
|
|
||||||
} else {
|
|
||||||
__ cmp32 (rcounter, counter);
|
|
||||||
}
|
|
||||||
__ jcc (Assembler::notEqual, slow);
|
__ jcc (Assembler::notEqual, slow);
|
||||||
|
|
||||||
__ ret (0);
|
__ ret (0);
|
||||||
|
|
|
@ -1030,8 +1030,7 @@ void MacroAssembler::andptr(Register dst, int32_t imm32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroAssembler::atomic_incl(Address counter_addr) {
|
void MacroAssembler::atomic_incl(Address counter_addr) {
|
||||||
if (os::is_MP())
|
lock();
|
||||||
lock();
|
|
||||||
incrementl(counter_addr);
|
incrementl(counter_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,8 +1045,7 @@ void MacroAssembler::atomic_incl(AddressLiteral counter_addr, Register scr) {
|
||||||
|
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
void MacroAssembler::atomic_incq(Address counter_addr) {
|
void MacroAssembler::atomic_incq(Address counter_addr) {
|
||||||
if (os::is_MP())
|
lock();
|
||||||
lock();
|
|
||||||
incrementq(counter_addr);
|
incrementq(counter_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1213,9 +1211,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
get_thread(tmp_reg);
|
get_thread(tmp_reg);
|
||||||
orptr(tmp_reg, swap_reg);
|
orptr(tmp_reg, swap_reg);
|
||||||
#endif
|
#endif
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
|
cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
|
||||||
// If the biasing toward our thread failed, this means that
|
// If the biasing toward our thread failed, this means that
|
||||||
// another thread succeeded in biasing it toward itself and we
|
// another thread succeeded in biasing it toward itself and we
|
||||||
|
@ -1248,9 +1244,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
orptr(tmp_reg, swap_reg);
|
orptr(tmp_reg, swap_reg);
|
||||||
movptr(swap_reg, saved_mark_addr);
|
movptr(swap_reg, saved_mark_addr);
|
||||||
#endif
|
#endif
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
|
cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
|
||||||
// If the biasing toward our thread failed, then another thread
|
// If the biasing toward our thread failed, then another thread
|
||||||
// succeeded in biasing it toward itself and we need to revoke that
|
// succeeded in biasing it toward itself and we need to revoke that
|
||||||
|
@ -1278,9 +1272,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||||
// bits in this situation. Should attempt to preserve them.
|
// bits in this situation. Should attempt to preserve them.
|
||||||
NOT_LP64( movptr(swap_reg, saved_mark_addr); )
|
NOT_LP64( movptr(swap_reg, saved_mark_addr); )
|
||||||
load_prototype_header(tmp_reg, obj_reg);
|
load_prototype_header(tmp_reg, obj_reg);
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
|
cmpxchgptr(tmp_reg, mark_addr); // compare tmp_reg and swap_reg
|
||||||
// Fall through to the normal CAS-based lock, because no matter what
|
// Fall through to the normal CAS-based lock, because no matter what
|
||||||
// the result of the above CAS, some thread must have succeeded in
|
// the result of the above CAS, some thread must have succeeded in
|
||||||
|
@ -1376,9 +1368,7 @@ void MacroAssembler::rtm_abort_ratio_calculation(Register tmpReg,
|
||||||
if (method_data != NULL) {
|
if (method_data != NULL) {
|
||||||
// set rtm_state to "no rtm" in MDO
|
// set rtm_state to "no rtm" in MDO
|
||||||
mov_metadata(tmpReg, method_data);
|
mov_metadata(tmpReg, method_data);
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), NoRTM);
|
orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), NoRTM);
|
||||||
}
|
}
|
||||||
jmpb(L_done);
|
jmpb(L_done);
|
||||||
|
@ -1392,9 +1382,7 @@ void MacroAssembler::rtm_abort_ratio_calculation(Register tmpReg,
|
||||||
if (method_data != NULL) {
|
if (method_data != NULL) {
|
||||||
// set rtm_state to "always rtm" in MDO
|
// set rtm_state to "always rtm" in MDO
|
||||||
mov_metadata(tmpReg, method_data);
|
mov_metadata(tmpReg, method_data);
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), UseRTM);
|
orl(Address(tmpReg, MethodData::rtm_state_offset_in_bytes()), UseRTM);
|
||||||
}
|
}
|
||||||
bind(L_done);
|
bind(L_done);
|
||||||
|
@ -1605,9 +1593,7 @@ void MacroAssembler::rtm_inflated_locking(Register objReg, Register boxReg, Regi
|
||||||
get_thread(scrReg);
|
get_thread(scrReg);
|
||||||
Register threadReg = scrReg;
|
Register threadReg = scrReg;
|
||||||
#endif
|
#endif
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(threadReg, Address(boxReg, owner_offset)); // Updates tmpReg
|
cmpxchgptr(threadReg, Address(boxReg, owner_offset)); // Updates tmpReg
|
||||||
|
|
||||||
if (RTMRetryCount > 0) {
|
if (RTMRetryCount > 0) {
|
||||||
|
@ -1767,9 +1753,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg
|
||||||
// Attempt stack-locking ...
|
// Attempt stack-locking ...
|
||||||
orptr (tmpReg, markOopDesc::unlocked_value);
|
orptr (tmpReg, markOopDesc::unlocked_value);
|
||||||
movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS
|
movptr(Address(boxReg, 0), tmpReg); // Anticipate successful CAS
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Updates tmpReg
|
cmpxchgptr(boxReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Updates tmpReg
|
||||||
if (counters != NULL) {
|
if (counters != NULL) {
|
||||||
cond_inc32(Assembler::equal,
|
cond_inc32(Assembler::equal,
|
||||||
|
@ -1826,9 +1810,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg
|
||||||
// we later store "Self" into m->Owner. Transiently storing a stack address
|
// we later store "Self" into m->Owner. Transiently storing a stack address
|
||||||
// (rsp or the address of the box) into m->owner is harmless.
|
// (rsp or the address of the box) into m->owner is harmless.
|
||||||
// Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
|
// Invariant: tmpReg == 0. tmpReg is EAX which is the implicit cmpxchg comparand.
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
cmpxchgptr(scrReg, Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
||||||
movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3
|
movptr(Address(scrReg, 0), 3); // box->_displaced_header = 3
|
||||||
// If we weren't able to swing _owner from NULL to the BasicLock
|
// If we weren't able to swing _owner from NULL to the BasicLock
|
||||||
|
@ -1851,9 +1833,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg
|
||||||
movq(scrReg, tmpReg);
|
movq(scrReg, tmpReg);
|
||||||
xorq(tmpReg, tmpReg);
|
xorq(tmpReg, tmpReg);
|
||||||
|
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(r15_thread, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
cmpxchgptr(r15_thread, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
||||||
// Unconditionally set box->_displaced_header = markOopDesc::unused_mark().
|
// Unconditionally set box->_displaced_header = markOopDesc::unused_mark().
|
||||||
// Without cast to int32_t movptr will destroy r10 which is typically obj.
|
// Without cast to int32_t movptr will destroy r10 which is typically obj.
|
||||||
|
@ -2000,9 +1980,7 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR
|
||||||
// The "box" value on the stack is stable, so we can reload
|
// The "box" value on the stack is stable, so we can reload
|
||||||
// and be assured we observe the same value as above.
|
// and be assured we observe the same value as above.
|
||||||
movptr(tmpReg, Address(boxReg, 0));
|
movptr(tmpReg, Address(boxReg, 0));
|
||||||
if (os::is_MP()) {
|
lock();
|
||||||
lock();
|
|
||||||
}
|
|
||||||
cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box
|
cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box
|
||||||
// Intention fall-thru into DONE_LABEL
|
// Intention fall-thru into DONE_LABEL
|
||||||
|
|
||||||
|
@ -2036,16 +2014,16 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR
|
||||||
|
|
||||||
xorptr(boxReg, boxReg);
|
xorptr(boxReg, boxReg);
|
||||||
movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD);
|
movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD);
|
||||||
if (os::is_MP()) {
|
|
||||||
// Memory barrier/fence
|
// Memory barrier/fence
|
||||||
// Dekker pivot point -- fulcrum : ST Owner; MEMBAR; LD Succ
|
// Dekker pivot point -- fulcrum : ST Owner; MEMBAR; LD Succ
|
||||||
// Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack.
|
// Instead of MFENCE we use a dummy locked add of 0 to the top-of-stack.
|
||||||
// This is faster on Nehalem and AMD Shanghai/Barcelona.
|
// This is faster on Nehalem and AMD Shanghai/Barcelona.
|
||||||
// See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences
|
// See https://blogs.oracle.com/dave/entry/instruction_selection_for_volatile_fences
|
||||||
// We might also restructure (ST Owner=0;barrier;LD _Succ) to
|
// We might also restructure (ST Owner=0;barrier;LD _Succ) to
|
||||||
// (mov box,0; xchgq box, &m->Owner; LD _succ) .
|
// (mov box,0; xchgq box, &m->Owner; LD _succ) .
|
||||||
lock(); addl(Address(rsp, 0), 0);
|
lock(); addl(Address(rsp, 0), 0);
|
||||||
}
|
|
||||||
cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD);
|
cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD);
|
||||||
jccb (Assembler::notZero, LSuccess);
|
jccb (Assembler::notZero, LSuccess);
|
||||||
|
|
||||||
|
@ -2063,7 +2041,7 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR
|
||||||
|
|
||||||
// box is really RAX -- the following CMPXCHG depends on that binding
|
// box is really RAX -- the following CMPXCHG depends on that binding
|
||||||
// cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R)
|
// cmpxchg R,[M] is equivalent to rax = CAS(M,rax,R)
|
||||||
if (os::is_MP()) { lock(); }
|
lock();
|
||||||
cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
cmpxchgptr(r15_thread, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
|
||||||
// There's no successor so we tried to regrab the lock.
|
// There's no successor so we tried to regrab the lock.
|
||||||
// If that didn't work, then another thread grabbed the
|
// If that didn't work, then another thread grabbed the
|
||||||
|
@ -2081,7 +2059,7 @@ void MacroAssembler::fast_unlock(Register objReg, Register boxReg, Register tmpR
|
||||||
|
|
||||||
bind (Stacked);
|
bind (Stacked);
|
||||||
movptr(tmpReg, Address (boxReg, 0)); // re-fetch
|
movptr(tmpReg, Address (boxReg, 0)); // re-fetch
|
||||||
if (os::is_MP()) { lock(); }
|
lock();
|
||||||
cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box
|
cmpxchgptr(tmpReg, Address(objReg, oopDesc::mark_offset_in_bytes())); // Uses RAX which is box
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2633,13 +2611,11 @@ void MacroAssembler::cmpoop(Register src1, jobject src2) {
|
||||||
|
|
||||||
void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr) {
|
void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr) {
|
||||||
if (reachable(adr)) {
|
if (reachable(adr)) {
|
||||||
if (os::is_MP())
|
lock();
|
||||||
lock();
|
|
||||||
cmpxchgptr(reg, as_Address(adr));
|
cmpxchgptr(reg, as_Address(adr));
|
||||||
} else {
|
} else {
|
||||||
lea(rscratch1, adr);
|
lea(rscratch1, adr);
|
||||||
if (os::is_MP())
|
lock();
|
||||||
lock();
|
|
||||||
cmpxchgptr(reg, Address(rscratch1, 0));
|
cmpxchgptr(reg, Address(rscratch1, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3266,7 +3242,9 @@ void MacroAssembler::movq(XMMRegister dst, AddressLiteral src) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef COMPILER2
|
||||||
void MacroAssembler::setvectmask(Register dst, Register src) {
|
void MacroAssembler::setvectmask(Register dst, Register src) {
|
||||||
|
guarantee(PostLoopMultiversioning, "must be");
|
||||||
Assembler::movl(dst, 1);
|
Assembler::movl(dst, 1);
|
||||||
Assembler::shlxl(dst, dst, src);
|
Assembler::shlxl(dst, dst, src);
|
||||||
Assembler::decl(dst);
|
Assembler::decl(dst);
|
||||||
|
@ -3275,8 +3253,10 @@ void MacroAssembler::setvectmask(Register dst, Register src) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroAssembler::restorevectmask() {
|
void MacroAssembler::restorevectmask() {
|
||||||
|
guarantee(PostLoopMultiversioning, "must be");
|
||||||
Assembler::knotwl(k1, k0);
|
Assembler::knotwl(k1, k0);
|
||||||
}
|
}
|
||||||
|
#endif // COMPILER2
|
||||||
|
|
||||||
void MacroAssembler::movdbl(XMMRegister dst, AddressLiteral src) {
|
void MacroAssembler::movdbl(XMMRegister dst, AddressLiteral src) {
|
||||||
if (reachable(src)) {
|
if (reachable(src)) {
|
||||||
|
@ -5026,12 +5006,15 @@ void MacroAssembler::restore_cpu_control_state_after_jni() {
|
||||||
// Clear upper bits of YMM registers to avoid SSE <-> AVX transition penalty.
|
// Clear upper bits of YMM registers to avoid SSE <-> AVX transition penalty.
|
||||||
vzeroupper();
|
vzeroupper();
|
||||||
// Reset k1 to 0xffff.
|
// Reset k1 to 0xffff.
|
||||||
if (VM_Version::supports_evex()) {
|
|
||||||
|
#ifdef COMPILER2
|
||||||
|
if (PostLoopMultiversioning && VM_Version::supports_evex()) {
|
||||||
push(rcx);
|
push(rcx);
|
||||||
movl(rcx, 0xffff);
|
movl(rcx, 0xffff);
|
||||||
kmovwl(k1, rcx);
|
kmovwl(k1, rcx);
|
||||||
pop(rcx);
|
pop(rcx);
|
||||||
}
|
}
|
||||||
|
#endif // COMPILER2
|
||||||
|
|
||||||
#ifndef _LP64
|
#ifndef _LP64
|
||||||
// Either restore the x87 floating pointer control word after returning
|
// Either restore the x87 floating pointer control word after returning
|
||||||
|
@ -6681,8 +6664,6 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
|
||||||
VM_Version::supports_avx512vlbw() &&
|
VM_Version::supports_avx512vlbw() &&
|
||||||
VM_Version::supports_bmi2()) {
|
VM_Version::supports_bmi2()) {
|
||||||
|
|
||||||
set_vector_masking(); // opening of the stub context for programming mask registers
|
|
||||||
|
|
||||||
Label test_64_loop, test_tail;
|
Label test_64_loop, test_tail;
|
||||||
Register tmp3_aliased = len;
|
Register tmp3_aliased = len;
|
||||||
|
|
||||||
|
@ -6711,15 +6692,12 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
|
||||||
testl(tmp1, -1);
|
testl(tmp1, -1);
|
||||||
jcc(Assembler::zero, FALSE_LABEL);
|
jcc(Assembler::zero, FALSE_LABEL);
|
||||||
|
|
||||||
// Save k1
|
|
||||||
kmovql(k3, k1);
|
|
||||||
|
|
||||||
// ~(~0 << len) applied up to two times (for 32-bit scenario)
|
// ~(~0 << len) applied up to two times (for 32-bit scenario)
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
mov64(tmp3_aliased, 0xFFFFFFFFFFFFFFFF);
|
mov64(tmp3_aliased, 0xFFFFFFFFFFFFFFFF);
|
||||||
shlxq(tmp3_aliased, tmp3_aliased, tmp1);
|
shlxq(tmp3_aliased, tmp3_aliased, tmp1);
|
||||||
notq(tmp3_aliased);
|
notq(tmp3_aliased);
|
||||||
kmovql(k1, tmp3_aliased);
|
kmovql(k3, tmp3_aliased);
|
||||||
#else
|
#else
|
||||||
Label k_init;
|
Label k_init;
|
||||||
jmp(k_init);
|
jmp(k_init);
|
||||||
|
@ -6728,7 +6706,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
|
||||||
// data required to compose 64 1's to the instruction stream
|
// data required to compose 64 1's to the instruction stream
|
||||||
// We emit 64 byte wide series of elements from 0..63 which later on would
|
// We emit 64 byte wide series of elements from 0..63 which later on would
|
||||||
// be used as a compare targets with tail count contained in tmp1 register.
|
// be used as a compare targets with tail count contained in tmp1 register.
|
||||||
// Result would be a k1 register having tmp1 consecutive number or 1
|
// Result would be a k register having tmp1 consecutive number or 1
|
||||||
// counting from least significant bit.
|
// counting from least significant bit.
|
||||||
address tmp = pc();
|
address tmp = pc();
|
||||||
emit_int64(0x0706050403020100);
|
emit_int64(0x0706050403020100);
|
||||||
|
@ -6744,18 +6722,14 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
|
||||||
lea(len, InternalAddress(tmp));
|
lea(len, InternalAddress(tmp));
|
||||||
// create mask to test for negative byte inside a vector
|
// create mask to test for negative byte inside a vector
|
||||||
evpbroadcastb(vec1, tmp1, Assembler::AVX_512bit);
|
evpbroadcastb(vec1, tmp1, Assembler::AVX_512bit);
|
||||||
evpcmpgtb(k1, vec1, Address(len, 0), Assembler::AVX_512bit);
|
evpcmpgtb(k3, vec1, Address(len, 0), Assembler::AVX_512bit);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
evpcmpgtb(k2, k1, vec2, Address(ary1, 0), Assembler::AVX_512bit);
|
evpcmpgtb(k2, k3, vec2, Address(ary1, 0), Assembler::AVX_512bit);
|
||||||
ktestq(k2, k1);
|
ktestq(k2, k3);
|
||||||
// Restore k1
|
|
||||||
kmovql(k1, k3);
|
|
||||||
jcc(Assembler::notZero, TRUE_LABEL);
|
jcc(Assembler::notZero, TRUE_LABEL);
|
||||||
|
|
||||||
jmp(FALSE_LABEL);
|
jmp(FALSE_LABEL);
|
||||||
|
|
||||||
clear_vector_masking(); // closing of the stub context for programming mask registers
|
|
||||||
} else {
|
} else {
|
||||||
movl(result, len); // copy
|
movl(result, len); // copy
|
||||||
|
|
||||||
|
@ -7197,10 +7171,6 @@ void MacroAssembler::generate_fill(BasicType t, bool aligned,
|
||||||
{
|
{
|
||||||
assert( UseSSE >= 2, "supported cpu only" );
|
assert( UseSSE >= 2, "supported cpu only" );
|
||||||
Label L_fill_32_bytes_loop, L_check_fill_8_bytes, L_fill_8_bytes_loop, L_fill_8_bytes;
|
Label L_fill_32_bytes_loop, L_check_fill_8_bytes, L_fill_8_bytes_loop, L_fill_8_bytes;
|
||||||
if (UseAVX > 2) {
|
|
||||||
movl(rtmp, 0xffff);
|
|
||||||
kmovwl(k1, rtmp);
|
|
||||||
}
|
|
||||||
movdl(xtmp, value);
|
movdl(xtmp, value);
|
||||||
if (UseAVX > 2 && UseUnalignedLoadStores) {
|
if (UseAVX > 2 && UseUnalignedLoadStores) {
|
||||||
// Fill 64-byte chunks
|
// Fill 64-byte chunks
|
||||||
|
@ -7945,7 +7915,6 @@ void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register
|
||||||
VM_Version::supports_avx512vlbw()) {
|
VM_Version::supports_avx512vlbw()) {
|
||||||
Label VECTOR64_LOOP, VECTOR64_NOT_EQUAL, VECTOR32_TAIL;
|
Label VECTOR64_LOOP, VECTOR64_NOT_EQUAL, VECTOR32_TAIL;
|
||||||
|
|
||||||
set_vector_masking(); // opening of the stub context for programming mask registers
|
|
||||||
cmpq(length, 64);
|
cmpq(length, 64);
|
||||||
jcc(Assembler::less, VECTOR32_TAIL);
|
jcc(Assembler::less, VECTOR32_TAIL);
|
||||||
movq(tmp1, length);
|
movq(tmp1, length);
|
||||||
|
@ -7968,19 +7937,15 @@ void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register
|
||||||
|
|
||||||
//bind(VECTOR64_TAIL);
|
//bind(VECTOR64_TAIL);
|
||||||
// AVX512 code to compare upto 63 byte vectors.
|
// AVX512 code to compare upto 63 byte vectors.
|
||||||
// Save k1
|
|
||||||
kmovql(k3, k1);
|
|
||||||
mov64(tmp2, 0xFFFFFFFFFFFFFFFF);
|
mov64(tmp2, 0xFFFFFFFFFFFFFFFF);
|
||||||
shlxq(tmp2, tmp2, tmp1);
|
shlxq(tmp2, tmp2, tmp1);
|
||||||
notq(tmp2);
|
notq(tmp2);
|
||||||
kmovql(k1, tmp2);
|
kmovql(k3, tmp2);
|
||||||
|
|
||||||
evmovdqub(rymm0, k1, Address(obja, result), Assembler::AVX_512bit);
|
evmovdqub(rymm0, k3, Address(obja, result), Assembler::AVX_512bit);
|
||||||
evpcmpeqb(k7, k1, rymm0, Address(objb, result), Assembler::AVX_512bit);
|
evpcmpeqb(k7, k3, rymm0, Address(objb, result), Assembler::AVX_512bit);
|
||||||
|
|
||||||
ktestql(k7, k1);
|
ktestql(k7, k3);
|
||||||
// Restore k1
|
|
||||||
kmovql(k1, k3);
|
|
||||||
jcc(Assembler::below, SAME_TILL_END); // not mismatch
|
jcc(Assembler::below, SAME_TILL_END); // not mismatch
|
||||||
|
|
||||||
bind(VECTOR64_NOT_EQUAL);
|
bind(VECTOR64_NOT_EQUAL);
|
||||||
|
@ -7991,7 +7956,6 @@ void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register
|
||||||
shrq(result);
|
shrq(result);
|
||||||
jmp(DONE);
|
jmp(DONE);
|
||||||
bind(VECTOR32_TAIL);
|
bind(VECTOR32_TAIL);
|
||||||
clear_vector_masking(); // closing of the stub context for programming mask registers
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmpq(length, 8);
|
cmpq(length, 8);
|
||||||
|
@ -8752,11 +8716,6 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, Regi
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
// context for the registers used, where all instructions below are using 128-bit mode
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
// On EVEX without VL and BW, these instructions will all be AVX.
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
movl(tmp, 0xffff);
|
|
||||||
kmovwl(k1, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
lea(table, ExternalAddress(StubRoutines::crc_table_addr()));
|
lea(table, ExternalAddress(StubRoutines::crc_table_addr()));
|
||||||
notl(crc); // ~crc
|
notl(crc); // ~crc
|
||||||
cmpl(len, 16);
|
cmpl(len, 16);
|
||||||
|
@ -9418,9 +9377,7 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||||
VM_Version::supports_avx512vlbw() &&
|
VM_Version::supports_avx512vlbw() &&
|
||||||
VM_Version::supports_bmi2()) {
|
VM_Version::supports_bmi2()) {
|
||||||
|
|
||||||
set_vector_masking(); // opening of the stub context for programming mask registers
|
Label copy_32_loop, copy_loop_tail, below_threshold;
|
||||||
|
|
||||||
Label copy_32_loop, copy_loop_tail, restore_k1_return_zero, below_threshold;
|
|
||||||
|
|
||||||
// alignment
|
// alignment
|
||||||
Label post_alignment;
|
Label post_alignment;
|
||||||
|
@ -9434,9 +9391,6 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||||
movl(result, 0x00FF);
|
movl(result, 0x00FF);
|
||||||
evpbroadcastw(tmp2Reg, result, Assembler::AVX_512bit);
|
evpbroadcastw(tmp2Reg, result, Assembler::AVX_512bit);
|
||||||
|
|
||||||
// Save k1
|
|
||||||
kmovql(k3, k1);
|
|
||||||
|
|
||||||
testl(len, -64);
|
testl(len, -64);
|
||||||
jcc(Assembler::zero, post_alignment);
|
jcc(Assembler::zero, post_alignment);
|
||||||
|
|
||||||
|
@ -9453,14 +9407,14 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||||
movl(result, 0xFFFFFFFF);
|
movl(result, 0xFFFFFFFF);
|
||||||
shlxl(result, result, tmp5);
|
shlxl(result, result, tmp5);
|
||||||
notl(result);
|
notl(result);
|
||||||
kmovdl(k1, result);
|
kmovdl(k3, result);
|
||||||
|
|
||||||
evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit);
|
evmovdquw(tmp1Reg, k3, Address(src, 0), Assembler::AVX_512bit);
|
||||||
evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
|
evpcmpuw(k2, k3, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
|
||||||
ktestd(k2, k1);
|
ktestd(k2, k3);
|
||||||
jcc(Assembler::carryClear, restore_k1_return_zero);
|
jcc(Assembler::carryClear, return_zero);
|
||||||
|
|
||||||
evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
|
evpmovwb(Address(dst, 0), k3, tmp1Reg, Assembler::AVX_512bit);
|
||||||
|
|
||||||
addptr(src, tmp5);
|
addptr(src, tmp5);
|
||||||
addptr(src, tmp5);
|
addptr(src, tmp5);
|
||||||
|
@ -9483,7 +9437,7 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||||
evmovdquw(tmp1Reg, Address(src, len, Address::times_2), Assembler::AVX_512bit);
|
evmovdquw(tmp1Reg, Address(src, len, Address::times_2), Assembler::AVX_512bit);
|
||||||
evpcmpuw(k2, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
|
evpcmpuw(k2, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
|
||||||
kortestdl(k2, k2);
|
kortestdl(k2, k2);
|
||||||
jcc(Assembler::carryClear, restore_k1_return_zero);
|
jcc(Assembler::carryClear, return_zero);
|
||||||
|
|
||||||
// All elements in current processed chunk are valid candidates for
|
// All elements in current processed chunk are valid candidates for
|
||||||
// compression. Write a truncated byte elements to the memory.
|
// compression. Write a truncated byte elements to the memory.
|
||||||
|
@ -9494,8 +9448,6 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||||
bind(copy_loop_tail);
|
bind(copy_loop_tail);
|
||||||
// bail out when there is nothing to be done
|
// bail out when there is nothing to be done
|
||||||
testl(tmp5, 0xFFFFFFFF);
|
testl(tmp5, 0xFFFFFFFF);
|
||||||
// Restore k1
|
|
||||||
kmovql(k1, k3);
|
|
||||||
jcc(Assembler::zero, return_length);
|
jcc(Assembler::zero, return_length);
|
||||||
|
|
||||||
movl(len, tmp5);
|
movl(len, tmp5);
|
||||||
|
@ -9505,25 +9457,16 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||||
shlxl(result, result, len);
|
shlxl(result, result, len);
|
||||||
notl(result);
|
notl(result);
|
||||||
|
|
||||||
kmovdl(k1, result);
|
kmovdl(k3, result);
|
||||||
|
|
||||||
evmovdquw(tmp1Reg, k1, Address(src, 0), Assembler::AVX_512bit);
|
evmovdquw(tmp1Reg, k3, Address(src, 0), Assembler::AVX_512bit);
|
||||||
evpcmpuw(k2, k1, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
|
evpcmpuw(k2, k3, tmp1Reg, tmp2Reg, Assembler::le, Assembler::AVX_512bit);
|
||||||
ktestd(k2, k1);
|
ktestd(k2, k3);
|
||||||
jcc(Assembler::carryClear, restore_k1_return_zero);
|
jcc(Assembler::carryClear, return_zero);
|
||||||
|
|
||||||
evpmovwb(Address(dst, 0), k1, tmp1Reg, Assembler::AVX_512bit);
|
evpmovwb(Address(dst, 0), k3, tmp1Reg, Assembler::AVX_512bit);
|
||||||
// Restore k1
|
|
||||||
kmovql(k1, k3);
|
|
||||||
jmp(return_length);
|
jmp(return_length);
|
||||||
|
|
||||||
bind(restore_k1_return_zero);
|
|
||||||
// Restore k1
|
|
||||||
kmovql(k1, k3);
|
|
||||||
jmp(return_zero);
|
|
||||||
|
|
||||||
clear_vector_masking(); // closing of the stub context for programming mask registers
|
|
||||||
|
|
||||||
bind(below_threshold);
|
bind(below_threshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9637,8 +9580,6 @@ void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len
|
||||||
VM_Version::supports_avx512vlbw() &&
|
VM_Version::supports_avx512vlbw() &&
|
||||||
VM_Version::supports_bmi2()) {
|
VM_Version::supports_bmi2()) {
|
||||||
|
|
||||||
set_vector_masking(); // opening of the stub context for programming mask registers
|
|
||||||
|
|
||||||
Label copy_32_loop, copy_tail;
|
Label copy_32_loop, copy_tail;
|
||||||
Register tmp3_aliased = len;
|
Register tmp3_aliased = len;
|
||||||
|
|
||||||
|
@ -9670,22 +9611,15 @@ void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len
|
||||||
testl(tmp2, -1); // we don't destroy the contents of tmp2 here
|
testl(tmp2, -1); // we don't destroy the contents of tmp2 here
|
||||||
jcc(Assembler::zero, done);
|
jcc(Assembler::zero, done);
|
||||||
|
|
||||||
// Save k1
|
|
||||||
kmovql(k2, k1);
|
|
||||||
|
|
||||||
// ~(~0 << length), where length is the # of remaining elements to process
|
// ~(~0 << length), where length is the # of remaining elements to process
|
||||||
movl(tmp3_aliased, -1);
|
movl(tmp3_aliased, -1);
|
||||||
shlxl(tmp3_aliased, tmp3_aliased, tmp2);
|
shlxl(tmp3_aliased, tmp3_aliased, tmp2);
|
||||||
notl(tmp3_aliased);
|
notl(tmp3_aliased);
|
||||||
kmovdl(k1, tmp3_aliased);
|
kmovdl(k2, tmp3_aliased);
|
||||||
evpmovzxbw(tmp1, k1, Address(src, 0), Assembler::AVX_512bit);
|
evpmovzxbw(tmp1, k2, Address(src, 0), Assembler::AVX_512bit);
|
||||||
evmovdquw(Address(dst, 0), k1, tmp1, Assembler::AVX_512bit);
|
evmovdquw(Address(dst, 0), k2, tmp1, Assembler::AVX_512bit);
|
||||||
|
|
||||||
// Restore k1
|
|
||||||
kmovql(k1, k2);
|
|
||||||
jmp(done);
|
jmp(done);
|
||||||
|
|
||||||
clear_vector_masking(); // closing of the stub context for programming mask registers
|
|
||||||
}
|
}
|
||||||
if (UseSSE42Intrinsics) {
|
if (UseSSE42Intrinsics) {
|
||||||
Label copy_16_loop, copy_8_loop, copy_bytes, copy_new_tail, copy_tail;
|
Label copy_16_loop, copy_8_loop, copy_bytes, copy_new_tail, copy_tail;
|
||||||
|
|
|
@ -156,9 +156,11 @@ class MacroAssembler: public Assembler {
|
||||||
void incrementq(Register reg, int value = 1);
|
void incrementq(Register reg, int value = 1);
|
||||||
void incrementq(Address dst, int value = 1);
|
void incrementq(Address dst, int value = 1);
|
||||||
|
|
||||||
|
#ifdef COMPILER2
|
||||||
// special instructions for EVEX
|
// special instructions for EVEX
|
||||||
void setvectmask(Register dst, Register src);
|
void setvectmask(Register dst, Register src);
|
||||||
void restorevectmask();
|
void restorevectmask();
|
||||||
|
#endif
|
||||||
|
|
||||||
// Support optimal SSE move instructions.
|
// Support optimal SSE move instructions.
|
||||||
void movflt(XMMRegister dst, XMMRegister src) {
|
void movflt(XMMRegister dst, XMMRegister src) {
|
||||||
|
|
|
@ -202,9 +202,7 @@ void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) {
|
||||||
assert (instr_addr != NULL, "illegal address for code patching");
|
assert (instr_addr != NULL, "illegal address for code patching");
|
||||||
|
|
||||||
NativeCall* n_call = nativeCall_at (instr_addr); // checking that it is a call
|
NativeCall* n_call = nativeCall_at (instr_addr); // checking that it is a call
|
||||||
if (os::is_MP()) {
|
guarantee((intptr_t)instr_addr % BytesPerWord == 0, "must be aligned");
|
||||||
guarantee((intptr_t)instr_addr % BytesPerWord == 0, "must be aligned");
|
|
||||||
}
|
|
||||||
|
|
||||||
// First patch dummy jmp in place
|
// First patch dummy jmp in place
|
||||||
unsigned char patch[4];
|
unsigned char patch[4];
|
||||||
|
@ -262,67 +260,14 @@ void NativeCall::set_destination_mt_safe(address dest) {
|
||||||
assert(Patching_lock->is_locked() ||
|
assert(Patching_lock->is_locked() ||
|
||||||
SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
|
SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
|
||||||
// Both C1 and C2 should now be generating code which aligns the patched address
|
// Both C1 and C2 should now be generating code which aligns the patched address
|
||||||
// to be within a single cache line except that C1 does not do the alignment on
|
// to be within a single cache line.
|
||||||
// uniprocessor systems.
|
|
||||||
bool is_aligned = ((uintptr_t)displacement_address() + 0) / cache_line_size ==
|
bool is_aligned = ((uintptr_t)displacement_address() + 0) / cache_line_size ==
|
||||||
((uintptr_t)displacement_address() + 3) / cache_line_size;
|
((uintptr_t)displacement_address() + 3) / cache_line_size;
|
||||||
|
|
||||||
guarantee(!os::is_MP() || is_aligned, "destination must be aligned");
|
guarantee(is_aligned, "destination must be aligned");
|
||||||
|
|
||||||
if (is_aligned) {
|
// The destination lies within a single cache line.
|
||||||
// Simple case: The destination lies within a single cache line.
|
set_destination(dest);
|
||||||
set_destination(dest);
|
|
||||||
} else if ((uintptr_t)instruction_address() / cache_line_size ==
|
|
||||||
((uintptr_t)instruction_address()+1) / cache_line_size) {
|
|
||||||
// Tricky case: The instruction prefix lies within a single cache line.
|
|
||||||
intptr_t disp = dest - return_address();
|
|
||||||
#ifdef AMD64
|
|
||||||
guarantee(disp == (intptr_t)(jint)disp, "must be 32-bit offset");
|
|
||||||
#endif // AMD64
|
|
||||||
|
|
||||||
int call_opcode = instruction_address()[0];
|
|
||||||
|
|
||||||
// First patch dummy jump in place:
|
|
||||||
{
|
|
||||||
u_char patch_jump[2];
|
|
||||||
patch_jump[0] = 0xEB; // jmp rel8
|
|
||||||
patch_jump[1] = 0xFE; // jmp to self
|
|
||||||
|
|
||||||
assert(sizeof(patch_jump)==sizeof(short), "sanity check");
|
|
||||||
*(short*)instruction_address() = *(short*)patch_jump;
|
|
||||||
}
|
|
||||||
// Invalidate. Opteron requires a flush after every write.
|
|
||||||
wrote(0);
|
|
||||||
|
|
||||||
// (Note: We assume any reader which has already started to read
|
|
||||||
// the unpatched call will completely read the whole unpatched call
|
|
||||||
// without seeing the next writes we are about to make.)
|
|
||||||
|
|
||||||
// Next, patch the last three bytes:
|
|
||||||
u_char patch_disp[5];
|
|
||||||
patch_disp[0] = call_opcode;
|
|
||||||
*(int32_t*)&patch_disp[1] = (int32_t)disp;
|
|
||||||
assert(sizeof(patch_disp)==instruction_size, "sanity check");
|
|
||||||
for (int i = sizeof(short); i < instruction_size; i++)
|
|
||||||
instruction_address()[i] = patch_disp[i];
|
|
||||||
|
|
||||||
// Invalidate. Opteron requires a flush after every write.
|
|
||||||
wrote(sizeof(short));
|
|
||||||
|
|
||||||
// (Note: We assume that any reader which reads the opcode we are
|
|
||||||
// about to repatch will also read the writes we just made.)
|
|
||||||
|
|
||||||
// Finally, overwrite the jump:
|
|
||||||
*(short*)instruction_address() = *(short*)patch_disp;
|
|
||||||
// Invalidate. Opteron requires a flush after every write.
|
|
||||||
wrote(0);
|
|
||||||
|
|
||||||
debug_only(verify());
|
|
||||||
guarantee(destination() == dest, "patch succeeded");
|
|
||||||
} else {
|
|
||||||
// Impossible: One or the other must be atomically writable.
|
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2007,12 +2007,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
// Save (object->mark() | 1) into BasicLock's displaced header
|
// Save (object->mark() | 1) into BasicLock's displaced header
|
||||||
__ movptr(Address(lock_reg, mark_word_offset), swap_reg);
|
__ movptr(Address(lock_reg, mark_word_offset), swap_reg);
|
||||||
|
|
||||||
if (os::is_MP()) {
|
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// src -> dest iff dest == rax, else rax, <- dest
|
// src -> dest iff dest == rax, else rax, <- dest
|
||||||
// *obj_reg = lock_reg iff *obj_reg == rax, else rax, = *(obj_reg)
|
// *obj_reg = lock_reg iff *obj_reg == rax, else rax, = *(obj_reg)
|
||||||
|
__ lock();
|
||||||
__ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
__ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||||
__ jcc(Assembler::equal, lock_done);
|
__ jcc(Assembler::equal, lock_done);
|
||||||
|
|
||||||
|
@ -2091,19 +2088,17 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
// didn't see any synchronization is progress, and escapes.
|
// didn't see any synchronization is progress, and escapes.
|
||||||
__ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
|
__ movl(Address(thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
|
||||||
|
|
||||||
if(os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
// Force this write out before the read below
|
||||||
// Force this write out before the read below
|
__ membar(Assembler::Membar_mask_bits(
|
||||||
__ membar(Assembler::Membar_mask_bits(
|
Assembler::LoadLoad | Assembler::LoadStore |
|
||||||
Assembler::LoadLoad | Assembler::LoadStore |
|
Assembler::StoreLoad | Assembler::StoreStore));
|
||||||
Assembler::StoreLoad | Assembler::StoreStore));
|
} else {
|
||||||
} else {
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// due to cache line collision.
|
||||||
// due to cache line collision.
|
__ serialize_memory(thread, rcx);
|
||||||
__ serialize_memory(thread, rcx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AlwaysRestoreFPU) {
|
if (AlwaysRestoreFPU) {
|
||||||
|
@ -2199,12 +2194,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
__ lea(rax, Address(rbp, lock_slot_rbp_offset));
|
__ lea(rax, Address(rbp, lock_slot_rbp_offset));
|
||||||
|
|
||||||
// Atomic swap old header if oop still contains the stack lock
|
// Atomic swap old header if oop still contains the stack lock
|
||||||
if (os::is_MP()) {
|
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// src -> dest iff dest == rax, else rax, <- dest
|
// src -> dest iff dest == rax, else rax, <- dest
|
||||||
// *obj_reg = rbx, iff *obj_reg == rax, else rax, = *(obj_reg)
|
// *obj_reg = rbx, iff *obj_reg == rax, else rax, = *(obj_reg)
|
||||||
|
__ lock();
|
||||||
__ cmpxchgptr(rbx, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
__ cmpxchgptr(rbx, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||||
__ jcc(Assembler::notEqual, slow_path_unlock);
|
__ jcc(Assembler::notEqual, slow_path_unlock);
|
||||||
|
|
||||||
|
|
|
@ -2464,11 +2464,8 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
// Save (object->mark() | 1) into BasicLock's displaced header
|
// Save (object->mark() | 1) into BasicLock's displaced header
|
||||||
__ movptr(Address(lock_reg, mark_word_offset), swap_reg);
|
__ movptr(Address(lock_reg, mark_word_offset), swap_reg);
|
||||||
|
|
||||||
if (os::is_MP()) {
|
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// src -> dest iff dest == rax else rax <- dest
|
// src -> dest iff dest == rax else rax <- dest
|
||||||
|
__ lock();
|
||||||
__ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
__ cmpxchgptr(lock_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||||
__ jcc(Assembler::equal, lock_done);
|
__ jcc(Assembler::equal, lock_done);
|
||||||
|
|
||||||
|
@ -2558,19 +2555,17 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
// didn't see any synchronization is progress, and escapes.
|
// didn't see any synchronization is progress, and escapes.
|
||||||
__ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
|
__ movl(Address(r15_thread, JavaThread::thread_state_offset()), _thread_in_native_trans);
|
||||||
|
|
||||||
if(os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
// Force this write out before the read below
|
||||||
// Force this write out before the read below
|
__ membar(Assembler::Membar_mask_bits(
|
||||||
__ membar(Assembler::Membar_mask_bits(
|
Assembler::LoadLoad | Assembler::LoadStore |
|
||||||
Assembler::LoadLoad | Assembler::LoadStore |
|
Assembler::StoreLoad | Assembler::StoreStore));
|
||||||
Assembler::StoreLoad | Assembler::StoreStore));
|
} else {
|
||||||
} else {
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// due to cache line collision.
|
||||||
// due to cache line collision.
|
__ serialize_memory(r15_thread, rcx);
|
||||||
__ serialize_memory(r15_thread, rcx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Label after_transition;
|
Label after_transition;
|
||||||
|
@ -2661,9 +2656,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||||
__ movptr(old_hdr, Address(rax, 0));
|
__ movptr(old_hdr, Address(rax, 0));
|
||||||
|
|
||||||
// Atomic swap old header if oop still contains the stack lock
|
// Atomic swap old header if oop still contains the stack lock
|
||||||
if (os::is_MP()) {
|
__ lock();
|
||||||
__ lock();
|
|
||||||
}
|
|
||||||
__ cmpxchgptr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
__ cmpxchgptr(old_hdr, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
|
||||||
__ jcc(Assembler::notEqual, slow_path_unlock);
|
__ jcc(Assembler::notEqual, slow_path_unlock);
|
||||||
|
|
||||||
|
|
|
@ -87,8 +87,8 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
case T_INT: inc_counter_np(SharedRuntime::_jint_array_copy_ctr); return;
|
case T_INT: inc_counter_np(SharedRuntime::_jint_array_copy_ctr); return;
|
||||||
case T_LONG: inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); return;
|
case T_LONG: inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); return;
|
||||||
case T_OBJECT: inc_counter_np(SharedRuntime::_oop_array_copy_ctr); return;
|
case T_OBJECT: inc_counter_np(SharedRuntime::_oop_array_copy_ctr); return;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
ShouldNotReachHere();
|
|
||||||
#endif //PRODUCT
|
#endif //PRODUCT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,12 +153,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ movptr(saved_rsi, rsi);
|
__ movptr(saved_rsi, rsi);
|
||||||
__ movptr(saved_rbx, rbx);
|
__ movptr(saved_rbx, rbx);
|
||||||
|
|
||||||
// provide initial value for required masks
|
|
||||||
if (UseAVX > 2) {
|
|
||||||
__ movl(rbx, 0xffff);
|
|
||||||
__ kmovwl(k1, rbx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save and initialize %mxcsr
|
// save and initialize %mxcsr
|
||||||
if (sse_save) {
|
if (sse_save) {
|
||||||
Label skip_ldmx;
|
Label skip_ldmx;
|
||||||
|
@ -679,12 +673,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
void xmm_copy_forward(Register from, Register to_from, Register qword_count) {
|
void xmm_copy_forward(Register from, Register to_from, Register qword_count) {
|
||||||
assert( UseSSE >= 2, "supported cpu only" );
|
assert( UseSSE >= 2, "supported cpu only" );
|
||||||
Label L_copy_64_bytes_loop, L_copy_64_bytes, L_copy_8_bytes, L_exit;
|
Label L_copy_64_bytes_loop, L_copy_64_bytes, L_copy_8_bytes, L_exit;
|
||||||
if (UseAVX > 2) {
|
|
||||||
__ push(rbx);
|
|
||||||
__ movl(rbx, 0xffff);
|
|
||||||
__ kmovwl(k1, rbx);
|
|
||||||
__ pop(rbx);
|
|
||||||
}
|
|
||||||
// Copy 64-byte chunks
|
// Copy 64-byte chunks
|
||||||
__ jmpb(L_copy_64_bytes);
|
__ jmpb(L_copy_64_bytes);
|
||||||
__ align(OptoLoopAlignment);
|
__ align(OptoLoopAlignment);
|
||||||
|
@ -2115,14 +2104,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rdx, 0xffff);
|
|
||||||
__ kmovdl(k1, rdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
__ movptr(from, from_param);
|
__ movptr(from, from_param);
|
||||||
__ movptr(key, key_param);
|
__ movptr(key, key_param);
|
||||||
|
|
||||||
|
@ -2222,14 +2203,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rdx, 0xffff);
|
|
||||||
__ kmovdl(k1, rdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
__ movptr(from, from_param);
|
__ movptr(from, from_param);
|
||||||
__ movptr(key, key_param);
|
__ movptr(key, key_param);
|
||||||
|
|
||||||
|
@ -2356,14 +2329,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
handleSOERegisters(true /*saving*/);
|
handleSOERegisters(true /*saving*/);
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rdx, 0xffff);
|
|
||||||
__ kmovdl(k1, rdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load registers from incoming parameters
|
// load registers from incoming parameters
|
||||||
const Address from_param(rbp, 8+0);
|
const Address from_param(rbp, 8+0);
|
||||||
const Address to_param (rbp, 8+4);
|
const Address to_param (rbp, 8+4);
|
||||||
|
@ -2532,14 +2497,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
handleSOERegisters(true /*saving*/);
|
handleSOERegisters(true /*saving*/);
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rdx, 0xffff);
|
|
||||||
__ kmovdl(k1, rdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load registers from incoming parameters
|
// load registers from incoming parameters
|
||||||
const Address from_param(rbp, 8+0);
|
const Address from_param(rbp, 8+0);
|
||||||
const Address to_param (rbp, 8+4);
|
const Address to_param (rbp, 8+4);
|
||||||
|
@ -2693,14 +2650,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
handleSOERegisters(true /*saving*/); // save rbx, rsi, rdi
|
handleSOERegisters(true /*saving*/); // save rbx, rsi, rdi
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rdx, 0xffff);
|
|
||||||
__ kmovdl(k1, rdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// load registers from incoming parameters
|
// load registers from incoming parameters
|
||||||
const Address from_param(rbp, 8+0);
|
const Address from_param(rbp, 8+0);
|
||||||
const Address to_param (rbp, 8+4);
|
const Address to_param (rbp, 8+4);
|
||||||
|
@ -3154,14 +3103,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ enter();
|
__ enter();
|
||||||
handleSOERegisters(true); // Save registers
|
handleSOERegisters(true); // Save registers
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rdx, 0xffff);
|
|
||||||
__ kmovdl(k1, rdx);
|
|
||||||
}
|
|
||||||
|
|
||||||
__ movptr(state, state_param);
|
__ movptr(state, state_param);
|
||||||
__ movptr(subkeyH, subkeyH_param);
|
__ movptr(subkeyH, subkeyH_param);
|
||||||
__ movptr(data, data_param);
|
__ movptr(data, data_param);
|
||||||
|
|
|
@ -254,10 +254,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ movptr(r13_save, r13);
|
__ movptr(r13_save, r13);
|
||||||
__ movptr(r14_save, r14);
|
__ movptr(r14_save, r14);
|
||||||
__ movptr(r15_save, r15);
|
__ movptr(r15_save, r15);
|
||||||
if (UseAVX > 2) {
|
|
||||||
__ movl(rbx, 0xffff);
|
|
||||||
__ kmovwl(k1, rbx);
|
|
||||||
}
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
int last_reg = 15;
|
int last_reg = 15;
|
||||||
if (UseAVX > 2) {
|
if (UseAVX > 2) {
|
||||||
|
@ -610,7 +607,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
address start = __ pc();
|
address start = __ pc();
|
||||||
|
|
||||||
__ movl(rax, c_rarg2);
|
__ movl(rax, c_rarg2);
|
||||||
if ( os::is_MP() ) __ lock();
|
__ lock();
|
||||||
__ cmpxchgl(c_rarg0, Address(c_rarg1, 0));
|
__ cmpxchgl(c_rarg0, Address(c_rarg1, 0));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
|
@ -636,7 +633,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
address start = __ pc();
|
address start = __ pc();
|
||||||
|
|
||||||
__ movsbq(rax, c_rarg2);
|
__ movsbq(rax, c_rarg2);
|
||||||
if ( os::is_MP() ) __ lock();
|
__ lock();
|
||||||
__ cmpxchgb(c_rarg0, Address(c_rarg1, 0));
|
__ cmpxchgb(c_rarg0, Address(c_rarg1, 0));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
|
@ -662,7 +659,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
address start = __ pc();
|
address start = __ pc();
|
||||||
|
|
||||||
__ movq(rax, c_rarg2);
|
__ movq(rax, c_rarg2);
|
||||||
if ( os::is_MP() ) __ lock();
|
__ lock();
|
||||||
__ cmpxchgq(c_rarg0, Address(c_rarg1, 0));
|
__ cmpxchgq(c_rarg0, Address(c_rarg1, 0));
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
|
||||||
|
@ -683,7 +680,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
address start = __ pc();
|
address start = __ pc();
|
||||||
|
|
||||||
__ movl(rax, c_rarg0);
|
__ movl(rax, c_rarg0);
|
||||||
if ( os::is_MP() ) __ lock();
|
__ lock();
|
||||||
__ xaddl(Address(c_rarg1, 0), c_rarg0);
|
__ xaddl(Address(c_rarg1, 0), c_rarg0);
|
||||||
__ addl(rax, c_rarg0);
|
__ addl(rax, c_rarg0);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
@ -705,7 +702,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
address start = __ pc();
|
address start = __ pc();
|
||||||
|
|
||||||
__ movptr(rax, c_rarg0); // Copy to eax we need a return value anyhow
|
__ movptr(rax, c_rarg0); // Copy to eax we need a return value anyhow
|
||||||
if ( os::is_MP() ) __ lock();
|
__ lock();
|
||||||
__ xaddptr(Address(c_rarg1, 0), c_rarg0);
|
__ xaddptr(Address(c_rarg1, 0), c_rarg0);
|
||||||
__ addptr(rax, c_rarg0);
|
__ addptr(rax, c_rarg0);
|
||||||
__ ret(0);
|
__ ret(0);
|
||||||
|
@ -1257,10 +1254,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ align(OptoLoopAlignment);
|
__ align(OptoLoopAlignment);
|
||||||
if (UseUnalignedLoadStores) {
|
if (UseUnalignedLoadStores) {
|
||||||
Label L_end;
|
Label L_end;
|
||||||
if (UseAVX > 2) {
|
|
||||||
__ movl(to, 0xffff);
|
|
||||||
__ kmovwl(k1, to);
|
|
||||||
}
|
|
||||||
// Copy 64-bytes per iteration
|
// Copy 64-bytes per iteration
|
||||||
__ BIND(L_loop);
|
__ BIND(L_loop);
|
||||||
if (UseAVX > 2) {
|
if (UseAVX > 2) {
|
||||||
|
@ -1341,10 +1334,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
__ align(OptoLoopAlignment);
|
__ align(OptoLoopAlignment);
|
||||||
if (UseUnalignedLoadStores) {
|
if (UseUnalignedLoadStores) {
|
||||||
Label L_end;
|
Label L_end;
|
||||||
if (UseAVX > 2) {
|
|
||||||
__ movl(to, 0xffff);
|
|
||||||
__ kmovwl(k1, to);
|
|
||||||
}
|
|
||||||
// Copy 64-bytes per iteration
|
// Copy 64-bytes per iteration
|
||||||
__ BIND(L_loop);
|
__ BIND(L_loop);
|
||||||
if (UseAVX > 2) {
|
if (UseAVX > 2) {
|
||||||
|
@ -3005,14 +2994,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rax, 0xffff);
|
|
||||||
__ kmovql(k1, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
// keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
|
// keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
|
||||||
__ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
|
__ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
|
||||||
|
|
||||||
|
@ -3107,14 +3088,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rax, 0xffff);
|
|
||||||
__ kmovql(k1, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
// keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
|
// keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
|
||||||
__ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
|
__ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
|
||||||
|
|
||||||
|
@ -3227,14 +3200,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rax, 0xffff);
|
|
||||||
__ kmovql(k1, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
// on win64, fill len_reg from stack position
|
// on win64, fill len_reg from stack position
|
||||||
__ movl(len_reg, len_mem);
|
__ movl(len_reg, len_mem);
|
||||||
|
@ -3428,14 +3393,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rax, 0xffff);
|
|
||||||
__ kmovql(k1, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
// on win64, fill len_reg from stack position
|
// on win64, fill len_reg from stack position
|
||||||
__ movl(len_reg, len_mem);
|
__ movl(len_reg, len_mem);
|
||||||
|
@ -3902,14 +3859,6 @@ class StubGenerator: public StubCodeGenerator {
|
||||||
|
|
||||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rax, 0xffff);
|
|
||||||
__ kmovql(k1, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
// allocate spill slots for r13, r14
|
// allocate spill slots for r13, r14
|
||||||
enum {
|
enum {
|
||||||
|
@ -4484,14 +4433,6 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
|
|
||||||
__ enter();
|
__ enter();
|
||||||
|
|
||||||
// For EVEX with VL and BW, provide a standard mask, VL = 128 will guide the merge
|
|
||||||
// context for the registers used, where all instructions below are using 128-bit mode
|
|
||||||
// On EVEX without VL and BW, these instructions will all be AVX.
|
|
||||||
if (VM_Version::supports_avx512vlbw()) {
|
|
||||||
__ movl(rax, 0xffff);
|
|
||||||
__ kmovql(k1, rax);
|
|
||||||
}
|
|
||||||
|
|
||||||
__ movdqu(xmm_temp10, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr()));
|
__ movdqu(xmm_temp10, ExternalAddress(StubRoutines::x86::ghash_long_swap_mask_addr()));
|
||||||
|
|
||||||
__ movdqu(xmm_temp0, Address(state, 0));
|
__ movdqu(xmm_temp0, Address(state, 0));
|
||||||
|
@ -4761,7 +4702,6 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
__ push(r13);
|
__ push(r13);
|
||||||
__ push(r14);
|
__ push(r14);
|
||||||
__ push(r15);
|
__ push(r15);
|
||||||
__ push(rbx);
|
|
||||||
|
|
||||||
// arguments
|
// arguments
|
||||||
const Register source = c_rarg0; // Source Array
|
const Register source = c_rarg0; // Source Array
|
||||||
|
@ -4790,8 +4730,6 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
__ cmpl(length, 0);
|
__ cmpl(length, 0);
|
||||||
__ jcc(Assembler::lessEqual, L_exit);
|
__ jcc(Assembler::lessEqual, L_exit);
|
||||||
|
|
||||||
// Save k1 value in rbx
|
|
||||||
__ kmovql(rbx, k1);
|
|
||||||
__ lea(r11, ExternalAddress(StubRoutines::x86::base64_charset_addr()));
|
__ lea(r11, ExternalAddress(StubRoutines::x86::base64_charset_addr()));
|
||||||
// check if base64 charset(isURL=0) or base64 url charset(isURL=1) needs to be loaded
|
// check if base64 charset(isURL=0) or base64 url charset(isURL=1) needs to be loaded
|
||||||
__ cmpl(isURL, 0);
|
__ cmpl(isURL, 0);
|
||||||
|
@ -4802,7 +4740,7 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
__ BIND(L_processdata);
|
__ BIND(L_processdata);
|
||||||
__ movdqu(xmm16, ExternalAddress(StubRoutines::x86::base64_gather_mask_addr()));
|
__ movdqu(xmm16, ExternalAddress(StubRoutines::x86::base64_gather_mask_addr()));
|
||||||
// Set 64 bits of K register.
|
// Set 64 bits of K register.
|
||||||
__ evpcmpeqb(k1, xmm16, xmm16, Assembler::AVX_512bit);
|
__ evpcmpeqb(k3, xmm16, xmm16, Assembler::AVX_512bit);
|
||||||
__ evmovdquq(xmm12, ExternalAddress(StubRoutines::x86::base64_bswap_mask_addr()), Assembler::AVX_256bit, r13);
|
__ evmovdquq(xmm12, ExternalAddress(StubRoutines::x86::base64_bswap_mask_addr()), Assembler::AVX_256bit, r13);
|
||||||
__ evmovdquq(xmm13, ExternalAddress(StubRoutines::x86::base64_right_shift_mask_addr()), Assembler::AVX_512bit, r13);
|
__ evmovdquq(xmm13, ExternalAddress(StubRoutines::x86::base64_right_shift_mask_addr()), Assembler::AVX_512bit, r13);
|
||||||
__ evmovdquq(xmm14, ExternalAddress(StubRoutines::x86::base64_left_shift_mask_addr()), Assembler::AVX_512bit, r13);
|
__ evmovdquq(xmm14, ExternalAddress(StubRoutines::x86::base64_left_shift_mask_addr()), Assembler::AVX_512bit, r13);
|
||||||
|
@ -4881,17 +4819,17 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
__ vextracti64x4(xmm4, xmm5, 1);
|
__ vextracti64x4(xmm4, xmm5, 1);
|
||||||
__ vpmovzxwd(xmm7, xmm4, Assembler::AVX_512bit);
|
__ vpmovzxwd(xmm7, xmm4, Assembler::AVX_512bit);
|
||||||
|
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm4, k2, Address(r11, xmm0, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm4, k2, Address(r11, xmm0, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm5, k2, Address(r11, xmm1, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm5, k2, Address(r11, xmm1, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm8, k2, Address(r11, xmm2, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm8, k2, Address(r11, xmm2, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm9, k2, Address(r11, xmm3, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm9, k2, Address(r11, xmm3, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm10, k2, Address(r11, xmm6, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm10, k2, Address(r11, xmm6, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm11, k2, Address(r11, xmm7, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm11, k2, Address(r11, xmm7, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
|
|
||||||
//Down convert dword to byte. Final output is 16*6 = 96 bytes long
|
//Down convert dword to byte. Final output is 16*6 = 96 bytes long
|
||||||
|
@ -4927,9 +4865,9 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
__ vpmovzxwd(xmm6, xmm9, Assembler::AVX_512bit);
|
__ vpmovzxwd(xmm6, xmm9, Assembler::AVX_512bit);
|
||||||
__ vextracti64x4(xmm9, xmm1, 1);
|
__ vextracti64x4(xmm9, xmm1, 1);
|
||||||
__ vpmovzxwd(xmm5, xmm9, Assembler::AVX_512bit);
|
__ vpmovzxwd(xmm5, xmm9, Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm8, k2, Address(r11, xmm6, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm8, k2, Address(r11, xmm6, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ kmovql(k2, k1);
|
__ kmovql(k2, k3);
|
||||||
__ evpgatherdd(xmm10, k2, Address(r11, xmm5, Address::times_4, 0), Assembler::AVX_512bit);
|
__ evpgatherdd(xmm10, k2, Address(r11, xmm5, Address::times_4, 0), Assembler::AVX_512bit);
|
||||||
__ evpmovdb(Address(dest, dp, Address::times_1, 0), xmm8, Assembler::AVX_512bit);
|
__ evpmovdb(Address(dest, dp, Address::times_1, 0), xmm8, Assembler::AVX_512bit);
|
||||||
__ evpmovdb(Address(dest, dp, Address::times_1, 16), xmm10, Assembler::AVX_512bit);
|
__ evpmovdb(Address(dest, dp, Address::times_1, 16), xmm10, Assembler::AVX_512bit);
|
||||||
|
@ -4985,9 +4923,6 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||||
__ addq(source, 3);
|
__ addq(source, 3);
|
||||||
__ jmp(L_process3);
|
__ jmp(L_process3);
|
||||||
__ BIND(L_exit);
|
__ BIND(L_exit);
|
||||||
// restore k1 register value
|
|
||||||
__ kmovql(k1, rbx);
|
|
||||||
__ pop(rbx);
|
|
||||||
__ pop(r15);
|
__ pop(r15);
|
||||||
__ pop(r14);
|
__ pop(r14);
|
||||||
__ pop(r13);
|
__ pop(r13);
|
||||||
|
|
|
@ -1090,19 +1090,17 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||||
__ movl(Address(thread, JavaThread::thread_state_offset()),
|
__ movl(Address(thread, JavaThread::thread_state_offset()),
|
||||||
_thread_in_native_trans);
|
_thread_in_native_trans);
|
||||||
|
|
||||||
if (os::is_MP()) {
|
if (UseMembar) {
|
||||||
if (UseMembar) {
|
// Force this write out before the read below
|
||||||
// Force this write out before the read below
|
__ membar(Assembler::Membar_mask_bits(
|
||||||
__ membar(Assembler::Membar_mask_bits(
|
Assembler::LoadLoad | Assembler::LoadStore |
|
||||||
Assembler::LoadLoad | Assembler::LoadStore |
|
Assembler::StoreLoad | Assembler::StoreStore));
|
||||||
Assembler::StoreLoad | Assembler::StoreStore));
|
} else {
|
||||||
} else {
|
// Write serialization page so VM thread can do a pseudo remote membar.
|
||||||
// Write serialization page so VM thread can do a pseudo remote membar.
|
// We use the current thread pointer to calculate a thread specific
|
||||||
// We use the current thread pointer to calculate a thread specific
|
// offset to write to within the page. This minimizes bus traffic
|
||||||
// offset to write to within the page. This minimizes bus traffic
|
// due to cache line collision.
|
||||||
// due to cache line collision.
|
__ serialize_memory(thread, rcx);
|
||||||
__ serialize_memory(thread, rcx);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _LP64
|
#ifndef _LP64
|
||||||
|
|
|
@ -448,7 +448,7 @@ void TemplateTable::fast_aldc(bool wide) {
|
||||||
Label notNull;
|
Label notNull;
|
||||||
ExternalAddress null_sentinel((address)Universe::the_null_sentinel_addr());
|
ExternalAddress null_sentinel((address)Universe::the_null_sentinel_addr());
|
||||||
__ movptr(tmp, null_sentinel);
|
__ movptr(tmp, null_sentinel);
|
||||||
__ cmpptr(tmp, result);
|
__ cmpoop(tmp, result);
|
||||||
__ jccb(Assembler::notEqual, notNull);
|
__ jccb(Assembler::notEqual, notNull);
|
||||||
__ xorptr(result, result); // NULL object reference
|
__ xorptr(result, result); // NULL object reference
|
||||||
__ bind(notNull);
|
__ bind(notNull);
|
||||||
|
@ -2714,7 +2714,6 @@ void TemplateTable::_return(TosState state) {
|
||||||
|
|
||||||
void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint ) {
|
void TemplateTable::volatile_barrier(Assembler::Membar_mask_bits order_constraint ) {
|
||||||
// Helper function to insert a is-volatile test and memory barrier
|
// Helper function to insert a is-volatile test and memory barrier
|
||||||
if(!os::is_MP()) return; // Not needed on single CPU
|
|
||||||
__ membar(order_constraint);
|
__ membar(order_constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3493,13 +3492,12 @@ void TemplateTable::fast_accessfield(TosState state) {
|
||||||
__ get_cache_and_index_at_bcp(rcx, rbx, 1);
|
__ get_cache_and_index_at_bcp(rcx, rbx, 1);
|
||||||
// replace index with field offset from cache entry
|
// replace index with field offset from cache entry
|
||||||
// [jk] not needed currently
|
// [jk] not needed currently
|
||||||
// if (os::is_MP()) {
|
// __ movl(rdx, Address(rcx, rbx, Address::times_8,
|
||||||
// __ movl(rdx, Address(rcx, rbx, Address::times_8,
|
// in_bytes(ConstantPoolCache::base_offset() +
|
||||||
// in_bytes(ConstantPoolCache::base_offset() +
|
// ConstantPoolCacheEntry::flags_offset())));
|
||||||
// ConstantPoolCacheEntry::flags_offset())));
|
// __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
|
||||||
// __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
|
// __ andl(rdx, 0x1);
|
||||||
// __ andl(rdx, 0x1);
|
//
|
||||||
// }
|
|
||||||
__ movptr(rbx, Address(rcx, rbx, Address::times_ptr,
|
__ movptr(rbx, Address(rcx, rbx, Address::times_ptr,
|
||||||
in_bytes(ConstantPoolCache::base_offset() +
|
in_bytes(ConstantPoolCache::base_offset() +
|
||||||
ConstantPoolCacheEntry::f2_offset())));
|
ConstantPoolCacheEntry::f2_offset())));
|
||||||
|
@ -3544,13 +3542,11 @@ void TemplateTable::fast_accessfield(TosState state) {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
// [jk] not needed currently
|
// [jk] not needed currently
|
||||||
// if (os::is_MP()) {
|
|
||||||
// Label notVolatile;
|
// Label notVolatile;
|
||||||
// __ testl(rdx, rdx);
|
// __ testl(rdx, rdx);
|
||||||
// __ jcc(Assembler::zero, notVolatile);
|
// __ jcc(Assembler::zero, notVolatile);
|
||||||
// __ membar(Assembler::LoadLoad);
|
// __ membar(Assembler::LoadLoad);
|
||||||
// __ bind(notVolatile);
|
// __ bind(notVolatile);
|
||||||
//};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TemplateTable::fast_xaccess(TosState state) {
|
void TemplateTable::fast_xaccess(TosState state) {
|
||||||
|
@ -3585,17 +3581,15 @@ void TemplateTable::fast_xaccess(TosState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// [jk] not needed currently
|
// [jk] not needed currently
|
||||||
// if (os::is_MP()) {
|
// Label notVolatile;
|
||||||
// Label notVolatile;
|
// __ movl(rdx, Address(rcx, rdx, Address::times_8,
|
||||||
// __ movl(rdx, Address(rcx, rdx, Address::times_8,
|
// in_bytes(ConstantPoolCache::base_offset() +
|
||||||
// in_bytes(ConstantPoolCache::base_offset() +
|
// ConstantPoolCacheEntry::flags_offset())));
|
||||||
// ConstantPoolCacheEntry::flags_offset())));
|
// __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
|
||||||
// __ shrl(rdx, ConstantPoolCacheEntry::is_volatile_shift);
|
// __ testl(rdx, 0x1);
|
||||||
// __ testl(rdx, 0x1);
|
// __ jcc(Assembler::zero, notVolatile);
|
||||||
// __ jcc(Assembler::zero, notVolatile);
|
// __ membar(Assembler::LoadLoad);
|
||||||
// __ membar(Assembler::LoadLoad);
|
// __ bind(notVolatile);
|
||||||
// __ bind(notVolatile);
|
|
||||||
// }
|
|
||||||
|
|
||||||
__ decrement(rbcp);
|
__ decrement(rbcp);
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,8 +401,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||||
// load value into all 64 bytes of zmm7 register
|
// load value into all 64 bytes of zmm7 register
|
||||||
__ movl(rcx, VM_Version::ymm_test_value());
|
__ movl(rcx, VM_Version::ymm_test_value());
|
||||||
__ movdl(xmm0, rcx);
|
__ movdl(xmm0, rcx);
|
||||||
__ movl(rcx, 0xffff);
|
|
||||||
__ kmovwl(k1, rcx);
|
|
||||||
__ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
|
__ vpbroadcastd(xmm0, xmm0, Assembler::AVX_512bit);
|
||||||
__ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
|
__ evmovdqul(xmm7, xmm0, Assembler::AVX_512bit);
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
|
|
|
@ -608,10 +608,10 @@ protected:
|
||||||
|
|
||||||
static bool os_supports_avx_vectors() {
|
static bool os_supports_avx_vectors() {
|
||||||
bool retVal = false;
|
bool retVal = false;
|
||||||
|
int nreg = 2 LP64_ONLY(+2);
|
||||||
if (supports_evex()) {
|
if (supports_evex()) {
|
||||||
// Verify that OS save/restore all bits of EVEX registers
|
// Verify that OS save/restore all bits of EVEX registers
|
||||||
// during signal processing.
|
// during signal processing.
|
||||||
int nreg = 2 LP64_ONLY(+2);
|
|
||||||
retVal = true;
|
retVal = true;
|
||||||
for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register
|
for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register
|
||||||
if (_cpuid_info.zmm_save[i] != ymm_test_value()) {
|
if (_cpuid_info.zmm_save[i] != ymm_test_value()) {
|
||||||
|
@ -622,7 +622,6 @@ protected:
|
||||||
} else if (supports_avx()) {
|
} else if (supports_avx()) {
|
||||||
// Verify that OS save/restore all bits of AVX registers
|
// Verify that OS save/restore all bits of AVX registers
|
||||||
// during signal processing.
|
// during signal processing.
|
||||||
int nreg = 2 LP64_ONLY(+2);
|
|
||||||
retVal = true;
|
retVal = true;
|
||||||
for (int i = 0; i < 8 * nreg; i++) { // 32 bytes per ymm register
|
for (int i = 0; i < 8 * nreg; i++) { // 32 bytes per ymm register
|
||||||
if (_cpuid_info.ymm_save[i] != ymm_test_value()) {
|
if (_cpuid_info.ymm_save[i] != ymm_test_value()) {
|
||||||
|
@ -634,7 +633,6 @@ protected:
|
||||||
if (retVal == false) {
|
if (retVal == false) {
|
||||||
// Verify that OS save/restore all bits of EVEX registers
|
// Verify that OS save/restore all bits of EVEX registers
|
||||||
// during signal processing.
|
// during signal processing.
|
||||||
int nreg = 2 LP64_ONLY(+2);
|
|
||||||
retVal = true;
|
retVal = true;
|
||||||
for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register
|
for (int i = 0; i < 16 * nreg; i++) { // 64 bytes per zmm register
|
||||||
if (_cpuid_info.zmm_save[i] != ymm_test_value()) {
|
if (_cpuid_info.zmm_save[i] != ymm_test_value()) {
|
||||||
|
|
|
@ -2804,11 +2804,7 @@ instruct onspinwait() %{
|
||||||
|
|
||||||
format %{
|
format %{
|
||||||
$$template
|
$$template
|
||||||
if (os::is_MP()) {
|
$$emit$$"pause\t! membar_onspinwait"
|
||||||
$$emit$$"pause\t! membar_onspinwait"
|
|
||||||
} else {
|
|
||||||
$$emit$$"MEMBAR-onspinwait ! (empty encoding)"
|
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
__ pause();
|
__ pause();
|
||||||
|
|
|
@ -2087,8 +2087,7 @@ encode %{
|
||||||
%}
|
%}
|
||||||
|
|
||||||
enc_class lock_prefix( ) %{
|
enc_class lock_prefix( ) %{
|
||||||
if( os::is_MP() )
|
emit_opcode(cbuf,0xF0); // [Lock]
|
||||||
emit_opcode(cbuf,0xF0); // [Lock]
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
// Cmp-xchg long value.
|
// Cmp-xchg long value.
|
||||||
|
@ -2102,8 +2101,7 @@ encode %{
|
||||||
emit_opcode(cbuf,0x87);
|
emit_opcode(cbuf,0x87);
|
||||||
emit_opcode(cbuf,0xD9);
|
emit_opcode(cbuf,0xD9);
|
||||||
// [Lock]
|
// [Lock]
|
||||||
if( os::is_MP() )
|
emit_opcode(cbuf,0xF0);
|
||||||
emit_opcode(cbuf,0xF0);
|
|
||||||
// CMPXCHG8 [Eptr]
|
// CMPXCHG8 [Eptr]
|
||||||
emit_opcode(cbuf,0x0F);
|
emit_opcode(cbuf,0x0F);
|
||||||
emit_opcode(cbuf,0xC7);
|
emit_opcode(cbuf,0xC7);
|
||||||
|
@ -2115,8 +2113,7 @@ encode %{
|
||||||
|
|
||||||
enc_class enc_cmpxchg(eSIRegP mem_ptr) %{
|
enc_class enc_cmpxchg(eSIRegP mem_ptr) %{
|
||||||
// [Lock]
|
// [Lock]
|
||||||
if( os::is_MP() )
|
emit_opcode(cbuf,0xF0);
|
||||||
emit_opcode(cbuf,0xF0);
|
|
||||||
|
|
||||||
// CMPXCHG [Eptr]
|
// CMPXCHG [Eptr]
|
||||||
emit_opcode(cbuf,0x0F);
|
emit_opcode(cbuf,0x0F);
|
||||||
|
@ -2126,8 +2123,7 @@ encode %{
|
||||||
|
|
||||||
enc_class enc_cmpxchgb(eSIRegP mem_ptr) %{
|
enc_class enc_cmpxchgb(eSIRegP mem_ptr) %{
|
||||||
// [Lock]
|
// [Lock]
|
||||||
if( os::is_MP() )
|
emit_opcode(cbuf,0xF0);
|
||||||
emit_opcode(cbuf,0xF0);
|
|
||||||
|
|
||||||
// CMPXCHGB [Eptr]
|
// CMPXCHGB [Eptr]
|
||||||
emit_opcode(cbuf,0x0F);
|
emit_opcode(cbuf,0x0F);
|
||||||
|
@ -2137,8 +2133,7 @@ encode %{
|
||||||
|
|
||||||
enc_class enc_cmpxchgw(eSIRegP mem_ptr) %{
|
enc_class enc_cmpxchgw(eSIRegP mem_ptr) %{
|
||||||
// [Lock]
|
// [Lock]
|
||||||
if( os::is_MP() )
|
emit_opcode(cbuf,0xF0);
|
||||||
emit_opcode(cbuf,0xF0);
|
|
||||||
|
|
||||||
// 16-bit mode
|
// 16-bit mode
|
||||||
emit_opcode(cbuf, 0x66);
|
emit_opcode(cbuf, 0x66);
|
||||||
|
@ -6764,11 +6759,7 @@ instruct membar_volatile(eFlagsReg cr) %{
|
||||||
|
|
||||||
format %{
|
format %{
|
||||||
$$template
|
$$template
|
||||||
if (os::is_MP()) {
|
$$emit$$"LOCK ADDL [ESP + #0], 0\t! membar_volatile"
|
||||||
$$emit$$"LOCK ADDL [ESP + #0], 0\t! membar_volatile"
|
|
||||||
} else {
|
|
||||||
$$emit$$"MEMBAR-volatile ! (empty encoding)"
|
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
__ membar(Assembler::StoreLoad);
|
__ membar(Assembler::StoreLoad);
|
||||||
|
@ -7373,8 +7364,7 @@ instruct storeLConditional( memory mem, eADXRegL oldval, eBCXRegL newval, eFlags
|
||||||
// rcx as the high order word of the new value to store but
|
// rcx as the high order word of the new value to store but
|
||||||
// our register encoding uses rbx.
|
// our register encoding uses rbx.
|
||||||
__ xchgl(as_Register(EBX_enc), as_Register(ECX_enc));
|
__ xchgl(as_Register(EBX_enc), as_Register(ECX_enc));
|
||||||
if( os::is_MP() )
|
__ lock();
|
||||||
__ lock();
|
|
||||||
__ cmpxchg8($mem$$Address);
|
__ cmpxchg8($mem$$Address);
|
||||||
__ xchgl(as_Register(EBX_enc), as_Register(ECX_enc));
|
__ xchgl(as_Register(EBX_enc), as_Register(ECX_enc));
|
||||||
%}
|
%}
|
||||||
|
@ -7499,7 +7489,7 @@ instruct xaddB_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDB [$mem],$add" %}
|
format %{ "ADDB [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addb($mem$$Address, $add$$constant);
|
__ addb($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7511,7 +7501,7 @@ instruct xaddB( memory mem, xRegI newval, eFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDB [$mem],$newval" %}
|
format %{ "XADDB [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddb($mem$$Address, $newval$$Register);
|
__ xaddb($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7523,7 +7513,7 @@ instruct xaddS_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDS [$mem],$add" %}
|
format %{ "ADDS [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addw($mem$$Address, $add$$constant);
|
__ addw($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7534,7 +7524,7 @@ instruct xaddS( memory mem, rRegI newval, eFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDS [$mem],$newval" %}
|
format %{ "XADDS [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddw($mem$$Address, $newval$$Register);
|
__ xaddw($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7546,7 +7536,7 @@ instruct xaddI_no_res( memory mem, Universe dummy, immI add, eFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDL [$mem],$add" %}
|
format %{ "ADDL [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addl($mem$$Address, $add$$constant);
|
__ addl($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7557,7 +7547,7 @@ instruct xaddI( memory mem, rRegI newval, eFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDL [$mem],$newval" %}
|
format %{ "XADDL [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddl($mem$$Address, $newval$$Register);
|
__ xaddl($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
// Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
//
|
//
|
||||||
// This code is free software; you can redistribute it and/or modify it
|
// This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -2341,9 +2341,7 @@ encode %{
|
||||||
|
|
||||||
enc_class lock_prefix()
|
enc_class lock_prefix()
|
||||||
%{
|
%{
|
||||||
if (os::is_MP()) {
|
emit_opcode(cbuf, 0xF0); // lock
|
||||||
emit_opcode(cbuf, 0xF0); // lock
|
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
enc_class REX_mem(memory mem)
|
enc_class REX_mem(memory mem)
|
||||||
|
@ -6601,11 +6599,7 @@ instruct membar_volatile(rFlagsReg cr) %{
|
||||||
|
|
||||||
format %{
|
format %{
|
||||||
$$template
|
$$template
|
||||||
if (os::is_MP()) {
|
$$emit$$"lock addl [rsp + #0], 0\t! membar_volatile"
|
||||||
$$emit$$"lock addl [rsp + #0], 0\t! membar_volatile"
|
|
||||||
} else {
|
|
||||||
$$emit$$"MEMBAR-volatile ! (empty encoding)"
|
|
||||||
}
|
|
||||||
%}
|
%}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
__ membar(Assembler::StoreLoad);
|
__ membar(Assembler::StoreLoad);
|
||||||
|
@ -7801,7 +7795,7 @@ instruct xaddB_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDB [$mem],$add" %}
|
format %{ "ADDB [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addb($mem$$Address, $add$$constant);
|
__ addb($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7812,7 +7806,7 @@ instruct xaddB( memory mem, rRegI newval, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDB [$mem],$newval" %}
|
format %{ "XADDB [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddb($mem$$Address, $newval$$Register);
|
__ xaddb($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7824,7 +7818,7 @@ instruct xaddS_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDW [$mem],$add" %}
|
format %{ "ADDW [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addw($mem$$Address, $add$$constant);
|
__ addw($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7835,7 +7829,7 @@ instruct xaddS( memory mem, rRegI newval, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDW [$mem],$newval" %}
|
format %{ "XADDW [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddw($mem$$Address, $newval$$Register);
|
__ xaddw($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7847,7 +7841,7 @@ instruct xaddI_no_res( memory mem, Universe dummy, immI add, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDL [$mem],$add" %}
|
format %{ "ADDL [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addl($mem$$Address, $add$$constant);
|
__ addl($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7858,7 +7852,7 @@ instruct xaddI( memory mem, rRegI newval, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDL [$mem],$newval" %}
|
format %{ "XADDL [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddl($mem$$Address, $newval$$Register);
|
__ xaddl($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7870,7 +7864,7 @@ instruct xaddL_no_res( memory mem, Universe dummy, immL32 add, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "ADDQ [$mem],$add" %}
|
format %{ "ADDQ [$mem],$add" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ addq($mem$$Address, $add$$constant);
|
__ addq($mem$$Address, $add$$constant);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
@ -7881,7 +7875,7 @@ instruct xaddL( memory mem, rRegL newval, rFlagsReg cr) %{
|
||||||
effect(KILL cr);
|
effect(KILL cr);
|
||||||
format %{ "XADDQ [$mem],$newval" %}
|
format %{ "XADDQ [$mem],$newval" %}
|
||||||
ins_encode %{
|
ins_encode %{
|
||||||
if (os::is_MP()) { __ lock(); }
|
__ lock();
|
||||||
__ xaddq($mem$$Address, $newval$$Register);
|
__ xaddq($mem$$Address, $newval$$Register);
|
||||||
%}
|
%}
|
||||||
ins_pipe( pipe_cmpxchg );
|
ins_pipe( pipe_cmpxchg );
|
||||||
|
|
|
@ -137,7 +137,6 @@ julong os::Linux::_physical_memory = 0;
|
||||||
address os::Linux::_initial_thread_stack_bottom = NULL;
|
address os::Linux::_initial_thread_stack_bottom = NULL;
|
||||||
uintptr_t os::Linux::_initial_thread_stack_size = 0;
|
uintptr_t os::Linux::_initial_thread_stack_size = 0;
|
||||||
|
|
||||||
int (*os::Linux::_clock_gettime)(clockid_t, struct timespec *) = NULL;
|
|
||||||
int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = NULL;
|
int (*os::Linux::_pthread_getcpuclockid)(pthread_t, clockid_t *) = NULL;
|
||||||
int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = NULL;
|
int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = NULL;
|
||||||
Mutex* os::Linux::_createThread_lock = NULL;
|
Mutex* os::Linux::_createThread_lock = NULL;
|
||||||
|
@ -268,8 +267,7 @@ pid_t os::Linux::gettid() {
|
||||||
|
|
||||||
// Most versions of linux have a bug where the number of processors are
|
// Most versions of linux have a bug where the number of processors are
|
||||||
// determined by looking at the /proc file system. In a chroot environment,
|
// determined by looking at the /proc file system. In a chroot environment,
|
||||||
// the system call returns 1. This causes the VM to act as if it is
|
// the system call returns 1.
|
||||||
// a single processor and elide locking (see is_MP() call).
|
|
||||||
static bool unsafe_chroot_detected = false;
|
static bool unsafe_chroot_detected = false;
|
||||||
static const char *unstable_chroot_error = "/proc file system not found.\n"
|
static const char *unstable_chroot_error = "/proc file system not found.\n"
|
||||||
"Java may be unstable running multithreaded in a chroot "
|
"Java may be unstable running multithreaded in a chroot "
|
||||||
|
@ -1173,6 +1171,10 @@ void os::Linux::capture_initial_stack(size_t max_size) {
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// time support
|
// time support
|
||||||
|
|
||||||
|
#ifndef SUPPORTS_CLOCK_MONOTONIC
|
||||||
|
#error "Build platform doesn't support clock_gettime and related functionality"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Time since start-up in seconds to a fine granularity.
|
// Time since start-up in seconds to a fine granularity.
|
||||||
// Used by VMSelfDestructTimer and the MemProfiler.
|
// Used by VMSelfDestructTimer and the MemProfiler.
|
||||||
double os::elapsedTime() {
|
double os::elapsedTime() {
|
||||||
|
@ -1218,62 +1220,6 @@ void os::javaTimeSystemUTC(jlong &seconds, jlong &nanos) {
|
||||||
nanos = jlong(time.tv_usec) * 1000;
|
nanos = jlong(time.tv_usec) * 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef CLOCK_MONOTONIC
|
|
||||||
#define CLOCK_MONOTONIC (1)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void os::Linux::clock_init() {
|
|
||||||
// we do dlopen's in this particular order due to bug in linux
|
|
||||||
// dynamical loader (see 6348968) leading to crash on exit
|
|
||||||
void* handle = dlopen("librt.so.1", RTLD_LAZY);
|
|
||||||
if (handle == NULL) {
|
|
||||||
handle = dlopen("librt.so", RTLD_LAZY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handle) {
|
|
||||||
int (*clock_getres_func)(clockid_t, struct timespec*) =
|
|
||||||
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
|
|
||||||
int (*clock_gettime_func)(clockid_t, struct timespec*) =
|
|
||||||
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
|
|
||||||
if (clock_getres_func && clock_gettime_func) {
|
|
||||||
// See if monotonic clock is supported by the kernel. Note that some
|
|
||||||
// early implementations simply return kernel jiffies (updated every
|
|
||||||
// 1/100 or 1/1000 second). It would be bad to use such a low res clock
|
|
||||||
// for nano time (though the monotonic property is still nice to have).
|
|
||||||
// It's fixed in newer kernels, however clock_getres() still returns
|
|
||||||
// 1/HZ. We check if clock_getres() works, but will ignore its reported
|
|
||||||
// resolution for now. Hopefully as people move to new kernels, this
|
|
||||||
// won't be a problem.
|
|
||||||
struct timespec res;
|
|
||||||
struct timespec tp;
|
|
||||||
if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
|
|
||||||
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
|
|
||||||
// yes, monotonic clock is supported
|
|
||||||
_clock_gettime = clock_gettime_func;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// close librt if there is no monotonic clock
|
|
||||||
dlclose(handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
warning("No monotonic clock was available - timed services may " \
|
|
||||||
"be adversely affected if the time-of-day clock changes");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef SYS_clock_getres
|
|
||||||
#if defined(X86) || defined(PPC64) || defined(S390)
|
|
||||||
#define SYS_clock_getres AMD64_ONLY(229) IA32_ONLY(266) PPC64_ONLY(247) S390_ONLY(261)
|
|
||||||
#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
|
|
||||||
#else
|
|
||||||
#warning "SYS_clock_getres not defined for this platform, disabling fast_thread_cpu_time"
|
|
||||||
#define sys_clock_getres(x,y) -1
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void os::Linux::fast_thread_clock_init() {
|
void os::Linux::fast_thread_clock_init() {
|
||||||
if (!UseLinuxPosixThreadCPUClocks) {
|
if (!UseLinuxPosixThreadCPUClocks) {
|
||||||
return;
|
return;
|
||||||
|
@ -1284,17 +1230,17 @@ void os::Linux::fast_thread_clock_init() {
|
||||||
(int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid");
|
(int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid");
|
||||||
|
|
||||||
// Switch to using fast clocks for thread cpu time if
|
// Switch to using fast clocks for thread cpu time if
|
||||||
// the sys_clock_getres() returns 0 error code.
|
// the clock_getres() returns 0 error code.
|
||||||
// Note, that some kernels may support the current thread
|
// Note, that some kernels may support the current thread
|
||||||
// clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks
|
// clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks
|
||||||
// returned by the pthread_getcpuclockid().
|
// returned by the pthread_getcpuclockid().
|
||||||
// If the fast Posix clocks are supported then the sys_clock_getres()
|
// If the fast Posix clocks are supported then the clock_getres()
|
||||||
// must return at least tp.tv_sec == 0 which means a resolution
|
// must return at least tp.tv_sec == 0 which means a resolution
|
||||||
// better than 1 sec. This is extra check for reliability.
|
// better than 1 sec. This is extra check for reliability.
|
||||||
|
|
||||||
if (pthread_getcpuclockid_func &&
|
if (pthread_getcpuclockid_func &&
|
||||||
pthread_getcpuclockid_func(_main_thread, &clockid) == 0 &&
|
pthread_getcpuclockid_func(_main_thread, &clockid) == 0 &&
|
||||||
sys_clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) {
|
os::Posix::clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) {
|
||||||
_supports_fast_thread_cpu_time = true;
|
_supports_fast_thread_cpu_time = true;
|
||||||
_pthread_getcpuclockid = pthread_getcpuclockid_func;
|
_pthread_getcpuclockid = pthread_getcpuclockid_func;
|
||||||
}
|
}
|
||||||
|
@ -1303,7 +1249,7 @@ void os::Linux::fast_thread_clock_init() {
|
||||||
jlong os::javaTimeNanos() {
|
jlong os::javaTimeNanos() {
|
||||||
if (os::supports_monotonic_clock()) {
|
if (os::supports_monotonic_clock()) {
|
||||||
struct timespec tp;
|
struct timespec tp;
|
||||||
int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
|
int status = os::Posix::clock_gettime(CLOCK_MONOTONIC, &tp);
|
||||||
assert(status == 0, "gettime error");
|
assert(status == 0, "gettime error");
|
||||||
jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
|
jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1622,9 +1568,6 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
|
||||||
// This is OK - No Java threads have been created yet, and hence no
|
// This is OK - No Java threads have been created yet, and hence no
|
||||||
// stack guard pages to fix.
|
// stack guard pages to fix.
|
||||||
//
|
//
|
||||||
// This should happen only when you are building JDK7 using a very
|
|
||||||
// old version of JDK6 (e.g., with JPRT) and running test_gamma.
|
|
||||||
//
|
|
||||||
// Dynamic loader will make all stacks executable after
|
// Dynamic loader will make all stacks executable after
|
||||||
// this function returns, and will not do that again.
|
// this function returns, and will not do that again.
|
||||||
assert(Threads::number_of_threads() == 0, "no Java threads should exist yet.");
|
assert(Threads::number_of_threads() == 0, "no Java threads should exist yet.");
|
||||||
|
@ -1877,12 +1820,16 @@ void* os::get_default_process_handle() {
|
||||||
return (void*)::dlopen(NULL, RTLD_LAZY);
|
return (void*)::dlopen(NULL, RTLD_LAZY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool _print_ascii_file(const char* filename, outputStream* st) {
|
static bool _print_ascii_file(const char* filename, outputStream* st, const char* hdr = NULL) {
|
||||||
int fd = ::open(filename, O_RDONLY);
|
int fd = ::open(filename, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hdr != NULL) {
|
||||||
|
st->print_cr("%s", hdr);
|
||||||
|
}
|
||||||
|
|
||||||
char buf[33];
|
char buf[33];
|
||||||
int bytes;
|
int bytes;
|
||||||
buf[32] = '\0';
|
buf[32] = '\0';
|
||||||
|
@ -1975,6 +1922,8 @@ void os::print_os_info(outputStream* st) {
|
||||||
|
|
||||||
os::Linux::print_proc_sys_info(st);
|
os::Linux::print_proc_sys_info(st);
|
||||||
|
|
||||||
|
os::Linux::print_ld_preload_file(st);
|
||||||
|
|
||||||
os::Linux::print_container_info(st);
|
os::Linux::print_container_info(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2133,6 +2082,11 @@ void os::Linux::print_full_memory_info(outputStream* st) {
|
||||||
st->cr();
|
st->cr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void os::Linux::print_ld_preload_file(outputStream* st) {
|
||||||
|
_print_ascii_file("/etc/ld.so.preload", st, "\n/etc/ld.so.preload:");
|
||||||
|
st->cr();
|
||||||
|
}
|
||||||
|
|
||||||
void os::Linux::print_container_info(outputStream* st) {
|
void os::Linux::print_container_info(outputStream* st) {
|
||||||
if (!OSContainer::is_containerized()) {
|
if (!OSContainer::is_containerized()) {
|
||||||
return;
|
return;
|
||||||
|
@ -2471,7 +2425,7 @@ void* os::user_handler() {
|
||||||
static struct timespec create_semaphore_timespec(unsigned int sec, int nsec) {
|
static struct timespec create_semaphore_timespec(unsigned int sec, int nsec) {
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
// Semaphore's are always associated with CLOCK_REALTIME
|
// Semaphore's are always associated with CLOCK_REALTIME
|
||||||
os::Linux::clock_gettime(CLOCK_REALTIME, &ts);
|
os::Posix::clock_gettime(CLOCK_REALTIME, &ts);
|
||||||
// see os_posix.cpp for discussion on overflow checking
|
// see os_posix.cpp for discussion on overflow checking
|
||||||
if (sec >= MAX_SECS) {
|
if (sec >= MAX_SECS) {
|
||||||
ts.tv_sec += MAX_SECS;
|
ts.tv_sec += MAX_SECS;
|
||||||
|
@ -4704,7 +4658,7 @@ void os::Linux::install_signal_handlers() {
|
||||||
|
|
||||||
jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) {
|
jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) {
|
||||||
struct timespec tp;
|
struct timespec tp;
|
||||||
int rc = os::Linux::clock_gettime(clockid, &tp);
|
int rc = os::Posix::clock_gettime(clockid, &tp);
|
||||||
assert(rc == 0, "clock_gettime is expected to return 0 code");
|
assert(rc == 0, "clock_gettime is expected to return 0 code");
|
||||||
|
|
||||||
return (tp.tv_sec * NANOSECS_PER_SEC) + tp.tv_nsec;
|
return (tp.tv_sec * NANOSECS_PER_SEC) + tp.tv_nsec;
|
||||||
|
@ -4976,14 +4930,19 @@ void os::init(void) {
|
||||||
// _main_thread points to the thread that created/loaded the JVM.
|
// _main_thread points to the thread that created/loaded the JVM.
|
||||||
Linux::_main_thread = pthread_self();
|
Linux::_main_thread = pthread_self();
|
||||||
|
|
||||||
Linux::clock_init();
|
|
||||||
initial_time_count = javaTimeNanos();
|
|
||||||
|
|
||||||
// retrieve entry point for pthread_setname_np
|
// retrieve entry point for pthread_setname_np
|
||||||
Linux::_pthread_setname_np =
|
Linux::_pthread_setname_np =
|
||||||
(int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
(int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
||||||
|
|
||||||
os::Posix::init();
|
os::Posix::init();
|
||||||
|
|
||||||
|
initial_time_count = javaTimeNanos();
|
||||||
|
|
||||||
|
// Always warn if no monotonic clock available
|
||||||
|
if (!os::Posix::supports_monotonic_clock()) {
|
||||||
|
warning("No monotonic clock was available - timed services may " \
|
||||||
|
"be adversely affected if the time-of-day clock changes");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// To install functions for atexit system call
|
// To install functions for atexit system call
|
||||||
|
|
|
@ -43,7 +43,6 @@ class Linux {
|
||||||
|
|
||||||
static void check_signal_handler(int sig);
|
static void check_signal_handler(int sig);
|
||||||
|
|
||||||
static int (*_clock_gettime)(clockid_t, struct timespec *);
|
|
||||||
static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
|
static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
|
||||||
static int (*_pthread_setname_np)(pthread_t, const char*);
|
static int (*_pthread_setname_np)(pthread_t, const char*);
|
||||||
|
|
||||||
|
@ -114,6 +113,7 @@ class Linux {
|
||||||
static void print_distro_info(outputStream* st);
|
static void print_distro_info(outputStream* st);
|
||||||
static void print_libversion_info(outputStream* st);
|
static void print_libversion_info(outputStream* st);
|
||||||
static void print_proc_sys_info(outputStream* st);
|
static void print_proc_sys_info(outputStream* st);
|
||||||
|
static void print_ld_preload_file(outputStream* st);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool _stack_is_executable;
|
static bool _stack_is_executable;
|
||||||
|
@ -189,16 +189,9 @@ class Linux {
|
||||||
static bool manually_expand_stack(JavaThread * t, address addr);
|
static bool manually_expand_stack(JavaThread * t, address addr);
|
||||||
static int max_register_window_saves_before_flushing();
|
static int max_register_window_saves_before_flushing();
|
||||||
|
|
||||||
// Real-time clock functions
|
|
||||||
static void clock_init(void);
|
|
||||||
|
|
||||||
// fast POSIX clocks support
|
// fast POSIX clocks support
|
||||||
static void fast_thread_clock_init(void);
|
static void fast_thread_clock_init(void);
|
||||||
|
|
||||||
static int clock_gettime(clockid_t clock_id, struct timespec *tp) {
|
|
||||||
return _clock_gettime ? _clock_gettime(clock_id, tp) : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) {
|
static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) {
|
||||||
return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1;
|
return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ inline struct hostent* os::get_host_by_name(char* name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool os::supports_monotonic_clock() {
|
inline bool os::supports_monotonic_clock() {
|
||||||
return Linux::_clock_gettime != NULL;
|
return os::Posix::supports_monotonic_clock();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void os::exit(int num) {
|
inline void os::exit(int num) {
|
||||||
|
|
|
@ -1609,10 +1609,25 @@ static void pthread_init_common(void) {
|
||||||
// This means we have clockid_t, clock_gettime et al and CLOCK_MONOTONIC
|
// This means we have clockid_t, clock_gettime et al and CLOCK_MONOTONIC
|
||||||
|
|
||||||
static int (*_clock_gettime)(clockid_t, struct timespec *);
|
static int (*_clock_gettime)(clockid_t, struct timespec *);
|
||||||
|
static int (*_clock_getres)(clockid_t, struct timespec *);
|
||||||
static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t);
|
static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t);
|
||||||
|
|
||||||
static bool _use_clock_monotonic_condattr;
|
static bool _use_clock_monotonic_condattr;
|
||||||
|
|
||||||
|
// Exported clock functionality
|
||||||
|
|
||||||
|
int os::Posix::clock_gettime(clockid_t clock_id, struct timespec *tp) {
|
||||||
|
return _clock_gettime != NULL ? _clock_gettime(clock_id, tp) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int os::Posix::clock_getres(clockid_t clock_id, struct timespec *tp) {
|
||||||
|
return _clock_getres != NULL ? _clock_getres(clock_id, tp) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool os::Posix::supports_monotonic_clock() {
|
||||||
|
return _clock_gettime != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine what POSIX API's are present and do appropriate
|
// Determine what POSIX API's are present and do appropriate
|
||||||
// configuration.
|
// configuration.
|
||||||
void os::Posix::init(void) {
|
void os::Posix::init(void) {
|
||||||
|
@ -1620,8 +1635,6 @@ void os::Posix::init(void) {
|
||||||
// NOTE: no logging available when this is called. Put logging
|
// NOTE: no logging available when this is called. Put logging
|
||||||
// statements in init_2().
|
// statements in init_2().
|
||||||
|
|
||||||
// Copied from os::Linux::clock_init(). The duplication is temporary.
|
|
||||||
|
|
||||||
// 1. Check for CLOCK_MONOTONIC support.
|
// 1. Check for CLOCK_MONOTONIC support.
|
||||||
|
|
||||||
void* handle = NULL;
|
void* handle = NULL;
|
||||||
|
@ -1642,6 +1655,7 @@ void os::Posix::init(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_clock_gettime = NULL;
|
_clock_gettime = NULL;
|
||||||
|
_clock_getres = NULL;
|
||||||
|
|
||||||
int (*clock_getres_func)(clockid_t, struct timespec*) =
|
int (*clock_getres_func)(clockid_t, struct timespec*) =
|
||||||
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
|
(int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
|
||||||
|
@ -1656,6 +1670,7 @@ void os::Posix::init(void) {
|
||||||
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
|
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
|
||||||
// Yes, monotonic clock is supported.
|
// Yes, monotonic clock is supported.
|
||||||
_clock_gettime = clock_gettime_func;
|
_clock_gettime = clock_gettime_func;
|
||||||
|
_clock_getres = clock_getres_func;
|
||||||
} else {
|
} else {
|
||||||
#ifdef NEEDS_LIBRT
|
#ifdef NEEDS_LIBRT
|
||||||
// Close librt if there is no monotonic clock.
|
// Close librt if there is no monotonic clock.
|
||||||
|
|
|
@ -116,6 +116,18 @@ public:
|
||||||
// Returns true if either given uid is effective uid and given gid is
|
// Returns true if either given uid is effective uid and given gid is
|
||||||
// effective gid, or if given uid is root.
|
// effective gid, or if given uid is root.
|
||||||
static bool matches_effective_uid_and_gid_or_root(uid_t uid, gid_t gid);
|
static bool matches_effective_uid_and_gid_or_root(uid_t uid, gid_t gid);
|
||||||
|
|
||||||
|
#ifdef SUPPORTS_CLOCK_MONOTONIC
|
||||||
|
|
||||||
|
static bool supports_monotonic_clock();
|
||||||
|
static int clock_gettime(clockid_t clock_id, struct timespec *tp);
|
||||||
|
static int clock_getres(clockid_t clock_id, struct timespec *tp);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static bool supports_monotonic_clock() { return false; }
|
||||||
|
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// On POSIX platforms the signal handler is global so we just do the write.
|
// On POSIX platforms the signal handler is global so we just do the write.
|
||||||
|
|
|
@ -136,7 +136,7 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T exchange_value,
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
// defined in bsd_x86.s
|
// defined in bsd_x86.s
|
||||||
int64_t _Atomic_cmpxchg_long(int64_t, volatile int64_t*, int64_t, bool);
|
int64_t _Atomic_cmpxchg_long(int64_t, volatile int64_t*, int64_t);
|
||||||
void _Atomic_move_long(const volatile int64_t* src, volatile int64_t* dst);
|
void _Atomic_move_long(const volatile int64_t* src, volatile int64_t* dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -635,8 +635,7 @@ mmx_acs_CopyLeft:
|
||||||
|
|
||||||
# Support for int64_t Atomic::cmpxchg(int64_t exchange_value,
|
# Support for int64_t Atomic::cmpxchg(int64_t exchange_value,
|
||||||
# volatile int64_t* dest,
|
# volatile int64_t* dest,
|
||||||
# int64_t compare_value,
|
# int64_t compare_value)
|
||||||
# bool is_MP)
|
|
||||||
#
|
#
|
||||||
.p2align 4,,15
|
.p2align 4,,15
|
||||||
ELF_TYPE(_Atomic_cmpxchg_long,@function)
|
ELF_TYPE(_Atomic_cmpxchg_long,@function)
|
||||||
|
@ -649,10 +648,8 @@ SYMBOL(_Atomic_cmpxchg_long):
|
||||||
movl 24(%esp), %eax # 24(%esp) : compare_value (low)
|
movl 24(%esp), %eax # 24(%esp) : compare_value (low)
|
||||||
movl 28(%esp), %edx # 28(%esp) : compare_value (high)
|
movl 28(%esp), %edx # 28(%esp) : compare_value (high)
|
||||||
movl 20(%esp), %edi # 20(%esp) : dest
|
movl 20(%esp), %edi # 20(%esp) : dest
|
||||||
cmpl $0, 32(%esp) # 32(%esp) : is_MP
|
|
||||||
je 1f
|
|
||||||
lock
|
lock
|
||||||
1: cmpxchg8b (%edi)
|
cmpxchg8b (%edi)
|
||||||
popl %edi
|
popl %edi
|
||||||
popl %ebx
|
popl %ebx
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -50,17 +50,12 @@
|
||||||
//
|
//
|
||||||
// inline void _OrderAccess_dsb() {
|
// inline void _OrderAccess_dsb() {
|
||||||
// volatile intptr_t dummy = 0;
|
// volatile intptr_t dummy = 0;
|
||||||
// if (os::is_MP()) {
|
// __asm__ volatile (
|
||||||
// __asm__ volatile (
|
// "mcr p15, 0, %0, c7, c10, 4"
|
||||||
// "mcr p15, 0, %0, c7, c10, 4"
|
// : : "r" (dummy) : "memory");
|
||||||
// : : "r" (dummy) : "memory");
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
inline static void dmb_sy() {
|
inline static void dmb_sy() {
|
||||||
if (!os::is_MP()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
__asm__ __volatile__ ("dmb sy" : : : "memory");
|
__asm__ __volatile__ ("dmb sy" : : : "memory");
|
||||||
#else
|
#else
|
||||||
|
@ -82,9 +77,6 @@ inline static void dmb_sy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void dmb_st() {
|
inline static void dmb_st() {
|
||||||
if (!os::is_MP()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
__asm__ __volatile__ ("dmb st" : : : "memory");
|
__asm__ __volatile__ ("dmb st" : : : "memory");
|
||||||
#else
|
#else
|
||||||
|
@ -108,9 +100,6 @@ inline static void dmb_st() {
|
||||||
// Load-Load/Store barrier
|
// Load-Load/Store barrier
|
||||||
inline static void dmb_ld() {
|
inline static void dmb_ld() {
|
||||||
#ifdef AARCH64
|
#ifdef AARCH64
|
||||||
if (!os::is_MP()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
__asm__ __volatile__ ("dmb ld" : : : "memory");
|
__asm__ __volatile__ ("dmb ld" : : : "memory");
|
||||||
#else
|
#else
|
||||||
dmb_sy();
|
dmb_sy();
|
||||||
|
|
|
@ -394,11 +394,9 @@ class PatchingStub: public CodeStub {
|
||||||
_id(id)
|
_id(id)
|
||||||
, _info(NULL)
|
, _info(NULL)
|
||||||
, _index(index) {
|
, _index(index) {
|
||||||
if (os::is_MP()) {
|
// force alignment of patch sites so we
|
||||||
// force alignment of patch sites on MP hardware so we
|
// can guarantee atomic writes to the patch site.
|
||||||
// can guarantee atomic writes to the patch site.
|
align_patch_site(masm);
|
||||||
align_patch_site(masm);
|
|
||||||
}
|
|
||||||
_pc_start = masm->pc();
|
_pc_start = masm->pc();
|
||||||
masm->bind(_patch_site_entry);
|
masm->bind(_patch_site_entry);
|
||||||
}
|
}
|
||||||
|
|
|
@ -918,18 +918,16 @@ void InstructionPrinter::do_RuntimeCall(RuntimeCall* x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstructionPrinter::do_MemBar(MemBar* x) {
|
void InstructionPrinter::do_MemBar(MemBar* x) {
|
||||||
if (os::is_MP()) {
|
LIR_Code code = x->code();
|
||||||
LIR_Code code = x->code();
|
switch (code) {
|
||||||
switch (code) {
|
case lir_membar_acquire : output()->print("membar_acquire"); break;
|
||||||
case lir_membar_acquire : output()->print("membar_acquire"); break;
|
case lir_membar_release : output()->print("membar_release"); break;
|
||||||
case lir_membar_release : output()->print("membar_release"); break;
|
case lir_membar : output()->print("membar"); break;
|
||||||
case lir_membar : output()->print("membar"); break;
|
case lir_membar_loadload : output()->print("membar_loadload"); break;
|
||||||
case lir_membar_loadload : output()->print("membar_loadload"); break;
|
case lir_membar_storestore: output()->print("membar_storestore"); break;
|
||||||
case lir_membar_storestore: output()->print("membar_storestore"); break;
|
case lir_membar_loadstore : output()->print("membar_loadstore"); break;
|
||||||
case lir_membar_loadstore : output()->print("membar_loadstore"); break;
|
case lir_membar_storeload : output()->print("membar_storeload"); break;
|
||||||
case lir_membar_storeload : output()->print("membar_storeload"); break;
|
default : ShouldNotReachHere(); break;
|
||||||
default : ShouldNotReachHere(); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -446,10 +446,8 @@ void LIR_Assembler::emit_rtcall(LIR_OpRTCall* op) {
|
||||||
void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
|
void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
|
||||||
verify_oop_map(op->info());
|
verify_oop_map(op->info());
|
||||||
|
|
||||||
if (os::is_MP()) {
|
// must align calls sites, otherwise they can't be updated atomically
|
||||||
// must align calls sites, otherwise they can't be updated atomically on MP hardware
|
align_call(op->code());
|
||||||
align_call(op->code());
|
|
||||||
}
|
|
||||||
|
|
||||||
// emit the static call stub stuff out of line
|
// emit the static call stub stuff out of line
|
||||||
emit_static_call_stub();
|
emit_static_call_stub();
|
||||||
|
|
|
@ -3068,13 +3068,13 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vmIntrinsics::_loadFence :
|
case vmIntrinsics::_loadFence :
|
||||||
if (os::is_MP()) __ membar_acquire();
|
__ membar_acquire();
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_storeFence:
|
case vmIntrinsics::_storeFence:
|
||||||
if (os::is_MP()) __ membar_release();
|
__ membar_release();
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_fullFence :
|
case vmIntrinsics::_fullFence :
|
||||||
if (os::is_MP()) __ membar();
|
__ membar();
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_onSpinWait:
|
case vmIntrinsics::_onSpinWait:
|
||||||
__ on_spin_wait();
|
__ on_spin_wait();
|
||||||
|
@ -3623,18 +3623,16 @@ LIR_Opr LIRGenerator::call_runtime(BasicTypeArray* signature, LIRItemList* args,
|
||||||
}
|
}
|
||||||
|
|
||||||
void LIRGenerator::do_MemBar(MemBar* x) {
|
void LIRGenerator::do_MemBar(MemBar* x) {
|
||||||
if (os::is_MP()) {
|
LIR_Code code = x->code();
|
||||||
LIR_Code code = x->code();
|
switch(code) {
|
||||||
switch(code) {
|
case lir_membar_acquire : __ membar_acquire(); break;
|
||||||
case lir_membar_acquire : __ membar_acquire(); break;
|
case lir_membar_release : __ membar_release(); break;
|
||||||
case lir_membar_release : __ membar_release(); break;
|
case lir_membar : __ membar(); break;
|
||||||
case lir_membar : __ membar(); break;
|
case lir_membar_loadload : __ membar_loadload(); break;
|
||||||
case lir_membar_loadload : __ membar_loadload(); break;
|
case lir_membar_storestore: __ membar_storestore(); break;
|
||||||
case lir_membar_storestore: __ membar_storestore(); break;
|
case lir_membar_loadstore : __ membar_loadstore(); break;
|
||||||
case lir_membar_loadstore : __ membar_loadstore(); break;
|
case lir_membar_storeload : __ membar_storeload(); break;
|
||||||
case lir_membar_storeload : __ membar_storeload(); break;
|
default : ShouldNotReachHere(); break;
|
||||||
default : ShouldNotReachHere(); break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -847,8 +847,32 @@ static Klass* resolve_field_return_klass(const methodHandle& caller, int bci, TR
|
||||||
// call into patch_code and complete the patching process by copying
|
// call into patch_code and complete the patching process by copying
|
||||||
// the patch body back into the main part of the nmethod and resume
|
// the patch body back into the main part of the nmethod and resume
|
||||||
// executing.
|
// executing.
|
||||||
|
|
||||||
|
// NB:
|
||||||
//
|
//
|
||||||
|
// Patchable instruction sequences inherently exhibit race conditions,
|
||||||
|
// where thread A is patching an instruction at the same time thread B
|
||||||
|
// is executing it. The algorithms we use ensure that any observation
|
||||||
|
// that B can make on any intermediate states during A's patching will
|
||||||
|
// always end up with a correct outcome. This is easiest if there are
|
||||||
|
// few or no intermediate states. (Some inline caches have two
|
||||||
|
// related instructions that must be patched in tandem. For those,
|
||||||
|
// intermediate states seem to be unavoidable, but we will get the
|
||||||
|
// right answer from all possible observation orders.)
|
||||||
//
|
//
|
||||||
|
// When patching the entry instruction at the head of a method, or a
|
||||||
|
// linkable call instruction inside of a method, we try very hard to
|
||||||
|
// use a patch sequence which executes as a single memory transaction.
|
||||||
|
// This means, in practice, that when thread A patches an instruction,
|
||||||
|
// it should patch a 32-bit or 64-bit word that somehow overlaps the
|
||||||
|
// instruction or is contained in it. We believe that memory hardware
|
||||||
|
// will never break up such a word write, if it is naturally aligned
|
||||||
|
// for the word being written. We also know that some CPUs work very
|
||||||
|
// hard to create atomic updates even of naturally unaligned words,
|
||||||
|
// but we don't want to bet the farm on this always working.
|
||||||
|
//
|
||||||
|
// Therefore, if there is any chance of a race condition, we try to
|
||||||
|
// patch only naturally aligned words, as single, full-word writes.
|
||||||
|
|
||||||
JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_id ))
|
JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_id ))
|
||||||
NOT_PRODUCT(_patch_code_slowcase_cnt++;)
|
NOT_PRODUCT(_patch_code_slowcase_cnt++;)
|
||||||
|
@ -907,7 +931,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||||
// We need to only cover T_LONG and T_DOUBLE fields, as we can
|
// We need to only cover T_LONG and T_DOUBLE fields, as we can
|
||||||
// break access atomicity only for them.
|
// break access atomicity only for them.
|
||||||
|
|
||||||
// Strictly speaking, the deoptimizaation on 64-bit platforms
|
// Strictly speaking, the deoptimization on 64-bit platforms
|
||||||
// is unnecessary, and T_LONG stores on 32-bit platforms need
|
// is unnecessary, and T_LONG stores on 32-bit platforms need
|
||||||
// to be handled by special patching code when AlwaysAtomicAccesses
|
// to be handled by special patching code when AlwaysAtomicAccesses
|
||||||
// becomes product feature. At this point, we are still going
|
// becomes product feature. At this point, we are still going
|
||||||
|
|
|
@ -399,8 +399,8 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||||
|
|
||||||
// Now we need to check the SystemDictionary
|
// Now we need to check the SystemDictionary
|
||||||
Symbol* sym = name->get_symbol();
|
Symbol* sym = name->get_symbol();
|
||||||
if (sym->byte_at(0) == 'L' &&
|
if (sym->char_at(0) == 'L' &&
|
||||||
sym->byte_at(sym->utf8_length()-1) == ';') {
|
sym->char_at(sym->utf8_length()-1) == ';') {
|
||||||
// This is a name from a signature. Strip off the trimmings.
|
// This is a name from a signature. Strip off the trimmings.
|
||||||
// Call recursive to keep scope of strippedsym.
|
// Call recursive to keep scope of strippedsym.
|
||||||
TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1,
|
TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1,
|
||||||
|
@ -427,7 +427,7 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||||
|
|
||||||
// setup up the proper type to return on OOM
|
// setup up the proper type to return on OOM
|
||||||
ciKlass* fail_type;
|
ciKlass* fail_type;
|
||||||
if (sym->byte_at(0) == '[') {
|
if (sym->char_at(0) == '[') {
|
||||||
fail_type = _unloaded_ciobjarrayklass;
|
fail_type = _unloaded_ciobjarrayklass;
|
||||||
} else {
|
} else {
|
||||||
fail_type = _unloaded_ciinstance_klass;
|
fail_type = _unloaded_ciinstance_klass;
|
||||||
|
@ -453,8 +453,8 @@ ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
|
||||||
// we must build an array type around it. The CI requires array klasses
|
// we must build an array type around it. The CI requires array klasses
|
||||||
// to be loaded if their element klasses are loaded, except when memory
|
// to be loaded if their element klasses are loaded, except when memory
|
||||||
// is exhausted.
|
// is exhausted.
|
||||||
if (sym->byte_at(0) == '[' &&
|
if (sym->char_at(0) == '[' &&
|
||||||
(sym->byte_at(1) == '[' || sym->byte_at(1) == 'L')) {
|
(sym->char_at(1) == '[' || sym->char_at(1) == 'L')) {
|
||||||
// We have an unloaded array.
|
// We have an unloaded array.
|
||||||
// Build it on the fly if the element class exists.
|
// Build it on the fly if the element class exists.
|
||||||
TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1,
|
TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1,
|
||||||
|
|
|
@ -116,7 +116,7 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
|
||||||
jobject loader, jobject protection_domain)
|
jobject loader, jobject protection_domain)
|
||||||
: ciKlass(name, T_OBJECT)
|
: ciKlass(name, T_OBJECT)
|
||||||
{
|
{
|
||||||
assert(name->byte_at(0) != '[', "not an instance klass");
|
assert(name->char_at(0) != '[', "not an instance klass");
|
||||||
_init_state = (InstanceKlass::ClassState)0;
|
_init_state = (InstanceKlass::ClassState)0;
|
||||||
_nonstatic_field_size = -1;
|
_nonstatic_field_size = -1;
|
||||||
_has_nonstatic_fields = false;
|
_has_nonstatic_fields = false;
|
||||||
|
@ -299,7 +299,7 @@ bool ciInstanceKlass::is_in_package_impl(const char* packagename, int len) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Test for trailing '/'
|
// Test for trailing '/'
|
||||||
if ((char) name()->byte_at(len) != '/')
|
if (name()->char_at(len) != '/')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Make sure it's not actually in a subpackage:
|
// Make sure it's not actually in a subpackage:
|
||||||
|
|
|
@ -112,9 +112,9 @@ ciSymbol* ciObjArrayKlass::construct_array_name(ciSymbol* element_name,
|
||||||
Symbol* base_name_sym = element_name->get_symbol();
|
Symbol* base_name_sym = element_name->get_symbol();
|
||||||
char* name;
|
char* name;
|
||||||
|
|
||||||
if (base_name_sym->byte_at(0) == '[' ||
|
if (base_name_sym->char_at(0) == '[' ||
|
||||||
(base_name_sym->byte_at(0) == 'L' && // watch package name 'Lxx'
|
(base_name_sym->char_at(0) == 'L' && // watch package name 'Lxx'
|
||||||
base_name_sym->byte_at(element_len-1) == ';')) {
|
base_name_sym->char_at(element_len-1) == ';')) {
|
||||||
|
|
||||||
int new_len = element_len + dimension + 1; // for the ['s and '\0'
|
int new_len = element_len + dimension + 1; // for the ['s and '\0'
|
||||||
name = CURRENT_THREAD_ENV->name_buffer(new_len);
|
name = CURRENT_THREAD_ENV->name_buffer(new_len);
|
||||||
|
|
|
@ -466,7 +466,7 @@ ciKlass* ciObjectFactory::get_unloaded_klass(ciKlass* accessing_klass,
|
||||||
|
|
||||||
// Two cases: this is an unloaded ObjArrayKlass or an
|
// Two cases: this is an unloaded ObjArrayKlass or an
|
||||||
// unloaded InstanceKlass. Deal with both.
|
// unloaded InstanceKlass. Deal with both.
|
||||||
if (name->byte_at(0) == '[') {
|
if (name->char_at(0) == '[') {
|
||||||
// Decompose the name.'
|
// Decompose the name.'
|
||||||
FieldArrayInfo fd;
|
FieldArrayInfo fd;
|
||||||
BasicType element_type = FieldType::get_array_info(name->get_symbol(),
|
BasicType element_type = FieldType::get_array_info(name->get_symbol(),
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -68,14 +68,14 @@ const char* ciSymbol::as_quoted_ascii() {
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// ciSymbol::base
|
// ciSymbol::base
|
||||||
const jbyte* ciSymbol::base() {
|
const u1* ciSymbol::base() {
|
||||||
GUARDED_VM_ENTRY(return get_symbol()->base();)
|
GUARDED_VM_ENTRY(return get_symbol()->base();)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// ciSymbol::byte_at
|
// ciSymbol::char_at
|
||||||
int ciSymbol::byte_at(int i) {
|
char ciSymbol::char_at(int i) {
|
||||||
GUARDED_VM_ENTRY(return get_symbol()->byte_at(i);)
|
GUARDED_VM_ENTRY(return get_symbol()->char_at(i);)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -61,7 +61,7 @@ private:
|
||||||
void print_impl(outputStream* st);
|
void print_impl(outputStream* st);
|
||||||
|
|
||||||
// This is public in Symbol* but private here, because the base can move:
|
// This is public in Symbol* but private here, because the base can move:
|
||||||
const jbyte* base();
|
const u1* base();
|
||||||
|
|
||||||
// Make a ciSymbol from a C string (implementation).
|
// Make a ciSymbol from a C string (implementation).
|
||||||
static ciSymbol* make_impl(const char* s);
|
static ciSymbol* make_impl(const char* s);
|
||||||
|
@ -77,8 +77,8 @@ public:
|
||||||
// The text of the symbol as ascii with all non-printable characters quoted as \u####
|
// The text of the symbol as ascii with all non-printable characters quoted as \u####
|
||||||
const char* as_quoted_ascii();
|
const char* as_quoted_ascii();
|
||||||
|
|
||||||
// Return the i-th utf8 byte, where i < utf8_length
|
// Return the i-th utf byte as a char, where i < utf8_length
|
||||||
int byte_at(int i);
|
char char_at(int i);
|
||||||
|
|
||||||
// Tests if the symbol starts with the given prefix.
|
// Tests if the symbol starts with the given prefix.
|
||||||
bool starts_with(const char* prefix, int len) const;
|
bool starts_with(const char* prefix, int len) const;
|
||||||
|
|
|
@ -655,7 +655,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
|
||||||
"Illegal zero length constant pool entry at %d in class %s",
|
"Illegal zero length constant pool entry at %d in class %s",
|
||||||
name_index, CHECK);
|
name_index, CHECK);
|
||||||
|
|
||||||
if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) {
|
if (sig->char_at(0) == JVM_SIGNATURE_FUNC) {
|
||||||
// Format check method name and signature
|
// Format check method name and signature
|
||||||
verify_legal_method_name(name, CHECK);
|
verify_legal_method_name(name, CHECK);
|
||||||
verify_legal_method_signature(name, sig, CHECK);
|
verify_legal_method_signature(name, sig, CHECK);
|
||||||
|
@ -682,7 +682,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
|
||||||
// CONSTANT_Dynamic's name and signature are verified above, when iterating NameAndType_info.
|
// CONSTANT_Dynamic's name and signature are verified above, when iterating NameAndType_info.
|
||||||
// Need only to be sure signature is non-zero length and the right type.
|
// Need only to be sure signature is non-zero length and the right type.
|
||||||
if (signature->utf8_length() == 0 ||
|
if (signature->utf8_length() == 0 ||
|
||||||
signature->byte_at(0) == JVM_SIGNATURE_FUNC) {
|
signature->char_at(0) == JVM_SIGNATURE_FUNC) {
|
||||||
throwIllegalSignature("CONSTANT_Dynamic", name, signature, CHECK);
|
throwIllegalSignature("CONSTANT_Dynamic", name, signature, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -707,7 +707,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
|
||||||
// Field name and signature are verified above, when iterating NameAndType_info.
|
// Field name and signature are verified above, when iterating NameAndType_info.
|
||||||
// Need only to be sure signature is non-zero length and the right type.
|
// Need only to be sure signature is non-zero length and the right type.
|
||||||
if (signature->utf8_length() == 0 ||
|
if (signature->utf8_length() == 0 ||
|
||||||
signature->byte_at(0) == JVM_SIGNATURE_FUNC) {
|
signature->char_at(0) == JVM_SIGNATURE_FUNC) {
|
||||||
throwIllegalSignature("Field", name, signature, CHECK);
|
throwIllegalSignature("Field", name, signature, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -716,7 +716,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
|
||||||
// Method name and signature are verified above, when iterating NameAndType_info.
|
// Method name and signature are verified above, when iterating NameAndType_info.
|
||||||
// Need only to be sure signature is non-zero length and the right type.
|
// Need only to be sure signature is non-zero length and the right type.
|
||||||
if (signature->utf8_length() == 0 ||
|
if (signature->utf8_length() == 0 ||
|
||||||
signature->byte_at(0) != JVM_SIGNATURE_FUNC) {
|
signature->char_at(0) != JVM_SIGNATURE_FUNC) {
|
||||||
throwIllegalSignature("Method", name, signature, CHECK);
|
throwIllegalSignature("Method", name, signature, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -724,7 +724,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
|
||||||
const unsigned int name_len = name->utf8_length();
|
const unsigned int name_len = name->utf8_length();
|
||||||
if (tag == JVM_CONSTANT_Methodref &&
|
if (tag == JVM_CONSTANT_Methodref &&
|
||||||
name_len != 0 &&
|
name_len != 0 &&
|
||||||
name->byte_at(0) == '<' &&
|
name->char_at(0) == '<' &&
|
||||||
name != vmSymbols::object_initializer_name()) {
|
name != vmSymbols::object_initializer_name()) {
|
||||||
classfile_parse_error(
|
classfile_parse_error(
|
||||||
"Bad method name at constant pool index %u in class file %s",
|
"Bad method name at constant pool index %u in class file %s",
|
||||||
|
@ -942,7 +942,7 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
|
||||||
|
|
||||||
// Don't need to check legal name because it's checked when parsing constant pool.
|
// Don't need to check legal name because it's checked when parsing constant pool.
|
||||||
// But need to make sure it's not an array type.
|
// But need to make sure it's not an array type.
|
||||||
guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
|
guarantee_property(unresolved_klass->char_at(0) != JVM_SIGNATURE_ARRAY,
|
||||||
"Bad interface name in class file %s", CHECK);
|
"Bad interface name in class file %s", CHECK);
|
||||||
|
|
||||||
// Call resolve_super so classcircularity is checked
|
// Call resolve_super so classcircularity is checked
|
||||||
|
@ -3752,7 +3752,7 @@ const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp,
|
||||||
if (need_verify)
|
if (need_verify)
|
||||||
is_array = super_klass->is_array_klass();
|
is_array = super_klass->is_array_klass();
|
||||||
} else if (need_verify) {
|
} else if (need_verify) {
|
||||||
is_array = (cp->klass_name_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
|
is_array = (cp->klass_name_at(super_class_index)->char_at(0) == JVM_SIGNATURE_ARRAY);
|
||||||
}
|
}
|
||||||
if (need_verify) {
|
if (need_verify) {
|
||||||
guarantee_property(!is_array,
|
guarantee_property(!is_array,
|
||||||
|
@ -5379,7 +5379,7 @@ int ClassFileParser::verify_legal_method_signature(const Symbol* name,
|
||||||
// The first non-signature thing better be a ')'
|
// The first non-signature thing better be a ')'
|
||||||
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
|
if ((length > 0) && (*p++ == JVM_SIGNATURE_ENDFUNC)) {
|
||||||
length--;
|
length--;
|
||||||
if (name->utf8_length() > 0 && name->byte_at(0) == '<') {
|
if (name->utf8_length() > 0 && name->char_at(0) == '<') {
|
||||||
// All internal methods must return void
|
// All internal methods must return void
|
||||||
if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) {
|
if ((length == 1) && (p[0] == JVM_SIGNATURE_VOID)) {
|
||||||
return args_size;
|
return args_size;
|
||||||
|
@ -5796,7 +5796,7 @@ void ClassFileParser::prepend_host_package_name(const InstanceKlass* unsafe_anon
|
||||||
void ClassFileParser::fix_unsafe_anonymous_class_name(TRAPS) {
|
void ClassFileParser::fix_unsafe_anonymous_class_name(TRAPS) {
|
||||||
assert(_unsafe_anonymous_host != NULL, "Expected an unsafe anonymous class");
|
assert(_unsafe_anonymous_host != NULL, "Expected an unsafe anonymous class");
|
||||||
|
|
||||||
const jbyte* anon_last_slash = UTF8::strrchr(_class_name->base(),
|
const jbyte* anon_last_slash = UTF8::strrchr((const jbyte*)_class_name->base(),
|
||||||
_class_name->utf8_length(), '/');
|
_class_name->utf8_length(), '/');
|
||||||
if (anon_last_slash == NULL) { // Unnamed package
|
if (anon_last_slash == NULL) { // Unnamed package
|
||||||
prepend_host_package_name(_unsafe_anonymous_host, CHECK);
|
prepend_host_package_name(_unsafe_anonymous_host, CHECK);
|
||||||
|
@ -6119,7 +6119,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||||
// It has been checked when constant pool is parsed.
|
// It has been checked when constant pool is parsed.
|
||||||
// However, make sure it is not an array type.
|
// However, make sure it is not an array type.
|
||||||
if (_need_verify) {
|
if (_need_verify) {
|
||||||
guarantee_property(_class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
|
guarantee_property(_class_name->char_at(0) != JVM_SIGNATURE_ARRAY,
|
||||||
"Bad class name in class file %s",
|
"Bad class name in class file %s",
|
||||||
CHECK);
|
CHECK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,11 +47,10 @@
|
||||||
// the singleton class the_null_class_loader_data().
|
// the singleton class the_null_class_loader_data().
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/packageEntry.hpp"
|
#include "classfile/packageEntry.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
|
@ -60,9 +59,7 @@
|
||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/metadataFactory.hpp"
|
#include "memory/metadataFactory.hpp"
|
||||||
#include "memory/metaspaceShared.hpp"
|
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "memory/universe.hpp"
|
|
||||||
#include "oops/access.inline.hpp"
|
#include "oops/access.inline.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "oops/oopHandle.inline.hpp"
|
#include "oops/oopHandle.inline.hpp"
|
||||||
|
@ -72,14 +69,10 @@
|
||||||
#include "runtime/mutex.hpp"
|
#include "runtime/mutex.hpp"
|
||||||
#include "runtime/orderAccess.hpp"
|
#include "runtime/orderAccess.hpp"
|
||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
#include "runtime/safepointVerifiers.hpp"
|
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/macros.hpp"
|
#include "utilities/macros.hpp"
|
||||||
#include "utilities/ostream.hpp"
|
#include "utilities/ostream.hpp"
|
||||||
|
|
||||||
volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
|
|
||||||
volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0;
|
|
||||||
|
|
||||||
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
|
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
|
||||||
|
|
||||||
void ClassLoaderData::init_null_class_loader_data() {
|
void ClassLoaderData::init_null_class_loader_data() {
|
||||||
|
@ -345,6 +338,11 @@ void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
|
||||||
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
for (Klass* k = OrderAccess::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||||
// Do not filter ArrayKlass oops here...
|
// Do not filter ArrayKlass oops here...
|
||||||
if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) {
|
if (k->is_array_klass() || (k->is_instance_klass() && InstanceKlass::cast(k)->is_loaded())) {
|
||||||
|
#ifdef ASSERT
|
||||||
|
oop m = k->java_mirror();
|
||||||
|
assert(m != NULL, "NULL mirror");
|
||||||
|
assert(m->is_a(SystemDictionary::Class_klass()), "invalid mirror");
|
||||||
|
#endif
|
||||||
klass_closure->do_klass(k);
|
klass_closure->do_klass(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,13 +442,6 @@ void ClassLoaderData::record_dependency(const Klass* k) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::clear_claimed_marks() {
|
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
|
||||||
cld->clear_claimed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
||||||
{
|
{
|
||||||
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||||
|
@ -478,78 +469,6 @@ void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Class iterator used by the compiler. It gets some number of classes at
|
|
||||||
// a safepoint to decay invocation counters on the methods.
|
|
||||||
class ClassLoaderDataGraphKlassIteratorStatic {
|
|
||||||
ClassLoaderData* _current_loader_data;
|
|
||||||
Klass* _current_class_entry;
|
|
||||||
public:
|
|
||||||
|
|
||||||
ClassLoaderDataGraphKlassIteratorStatic() : _current_loader_data(NULL), _current_class_entry(NULL) {}
|
|
||||||
|
|
||||||
InstanceKlass* try_get_next_class() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
|
||||||
size_t max_classes = ClassLoaderDataGraph::num_instance_classes();
|
|
||||||
assert(max_classes > 0, "should not be called with no instance classes");
|
|
||||||
for (size_t i = 0; i < max_classes; ) {
|
|
||||||
|
|
||||||
if (_current_class_entry != NULL) {
|
|
||||||
Klass* k = _current_class_entry;
|
|
||||||
_current_class_entry = _current_class_entry->next_link();
|
|
||||||
|
|
||||||
if (k->is_instance_klass()) {
|
|
||||||
InstanceKlass* ik = InstanceKlass::cast(k);
|
|
||||||
i++; // count all instance classes found
|
|
||||||
// Not yet loaded classes are counted in max_classes
|
|
||||||
// but only return loaded classes.
|
|
||||||
if (ik->is_loaded()) {
|
|
||||||
return ik;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Go to next CLD
|
|
||||||
if (_current_loader_data != NULL) {
|
|
||||||
_current_loader_data = _current_loader_data->next();
|
|
||||||
}
|
|
||||||
// Start at the beginning
|
|
||||||
if (_current_loader_data == NULL) {
|
|
||||||
_current_loader_data = ClassLoaderDataGraph::_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
_current_class_entry = _current_loader_data->klasses();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Should never be reached unless all instance classes have failed or are not fully loaded.
|
|
||||||
// Caller handles NULL.
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the current class for the static iterator is a class being unloaded or
|
|
||||||
// deallocated, adjust the current class.
|
|
||||||
void adjust_saved_class(ClassLoaderData* cld) {
|
|
||||||
if (_current_loader_data == cld) {
|
|
||||||
_current_loader_data = cld->next();
|
|
||||||
if (_current_loader_data != NULL) {
|
|
||||||
_current_class_entry = _current_loader_data->klasses();
|
|
||||||
} // else try_get_next_class will start at the head
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void adjust_saved_class(Klass* klass) {
|
|
||||||
if (_current_class_entry == klass) {
|
|
||||||
_current_class_entry = klass->next_link();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator;
|
|
||||||
|
|
||||||
InstanceKlass* ClassLoaderDataGraph::try_get_next_class() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
|
||||||
return static_klass_iterator.try_get_next_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ClassLoaderData::initialize_holder(Handle loader_or_mirror) {
|
void ClassLoaderData::initialize_holder(Handle loader_or_mirror) {
|
||||||
if (loader_or_mirror() != NULL) {
|
if (loader_or_mirror() != NULL) {
|
||||||
assert(_holder.is_null(), "never replace holders");
|
assert(_holder.is_null(), "never replace holders");
|
||||||
|
@ -563,7 +482,7 @@ void ClassLoaderData::remove_class(Klass* scratch_class) {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||||
|
|
||||||
// Adjust global class iterator.
|
// Adjust global class iterator.
|
||||||
static_klass_iterator.adjust_saved_class(scratch_class);
|
ClassLoaderDataGraph::adjust_saved_class(scratch_class);
|
||||||
|
|
||||||
Klass* prev = NULL;
|
Klass* prev = NULL;
|
||||||
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
|
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
|
||||||
|
@ -611,7 +530,7 @@ void ClassLoaderData::unload() {
|
||||||
classes_do(InstanceKlass::unload_class);
|
classes_do(InstanceKlass::unload_class);
|
||||||
|
|
||||||
// Clean up global class iterator for compiler
|
// Clean up global class iterator for compiler
|
||||||
static_klass_iterator.adjust_saved_class(this);
|
ClassLoaderDataGraph::adjust_saved_class(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleEntryTable* ClassLoaderData::modules() {
|
ModuleEntryTable* ClassLoaderData::modules() {
|
||||||
|
@ -914,41 +833,6 @@ void ClassLoaderData::free_deallocate_list() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::clean_deallocate_lists(bool walk_previous_versions) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint");
|
|
||||||
uint loaders_processed = 0;
|
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
|
||||||
// is_alive check will be necessary for concurrent class unloading.
|
|
||||||
if (cld->is_alive()) {
|
|
||||||
// clean metaspace
|
|
||||||
if (walk_previous_versions) {
|
|
||||||
cld->classes_do(InstanceKlass::purge_previous_versions);
|
|
||||||
}
|
|
||||||
cld->free_deallocate_list();
|
|
||||||
loaders_processed++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log_debug(class, loader, data)("clean_deallocate_lists: loaders processed %u %s",
|
|
||||||
loaders_processed, walk_previous_versions ? "walk_previous_versions" : "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint");
|
|
||||||
|
|
||||||
_should_clean_deallocate_lists = false; // assume everything gets cleaned
|
|
||||||
|
|
||||||
// Mark metadata seen on the stack so we can delete unreferenced entries.
|
|
||||||
// Walk all metadata, including the expensive code cache walk, only for class redefinition.
|
|
||||||
// The MetadataOnStackMark walk during redefinition saves previous versions if it finds old methods
|
|
||||||
// on the stack or in the code cache, so we only have to repeat the full walk if
|
|
||||||
// they were found at that time.
|
|
||||||
// TODO: have redefinition clean old methods out of the code cache. They still exist in some places.
|
|
||||||
bool walk_all_metadata = InstanceKlass::has_previous_versions_and_reset();
|
|
||||||
|
|
||||||
MetadataOnStackMark md_on_stack(walk_all_metadata);
|
|
||||||
clean_deallocate_lists(walk_all_metadata);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is distinct from free_deallocate_list. For class loader data that are
|
// This is distinct from free_deallocate_list. For class loader data that are
|
||||||
// unloading, this frees the C heap memory for items on the list, and unlinks
|
// unloading, this frees the C heap memory for items on the list, and unlinks
|
||||||
// scratch or error classes so that unloading events aren't triggered for these
|
// scratch or error classes so that unloading events aren't triggered for these
|
||||||
|
@ -1070,523 +954,3 @@ bool ClassLoaderData::contains_klass(Klass* klass) {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// GC root of class loader data created.
|
|
||||||
ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
|
|
||||||
ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
|
|
||||||
ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL;
|
|
||||||
ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
|
|
||||||
|
|
||||||
bool ClassLoaderDataGraph::_should_purge = false;
|
|
||||||
bool ClassLoaderDataGraph::_should_clean_deallocate_lists = false;
|
|
||||||
bool ClassLoaderDataGraph::_safepoint_cleanup_needed = false;
|
|
||||||
bool ClassLoaderDataGraph::_metaspace_oom = false;
|
|
||||||
|
|
||||||
// Add a new class loader data node to the list. Assign the newly created
|
|
||||||
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
|
|
||||||
ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) {
|
|
||||||
|
|
||||||
assert_lock_strong(ClassLoaderDataGraph_lock);
|
|
||||||
|
|
||||||
ClassLoaderData* cld;
|
|
||||||
|
|
||||||
// First check if another thread beat us to creating the CLD and installing
|
|
||||||
// it into the loader while we were waiting for the lock.
|
|
||||||
if (!is_unsafe_anonymous && loader.not_null()) {
|
|
||||||
cld = java_lang_ClassLoader::loader_data_acquire(loader());
|
|
||||||
if (cld != NULL) {
|
|
||||||
return cld;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We mustn't GC until we've installed the ClassLoaderData in the Graph since the CLD
|
|
||||||
// contains oops in _handles that must be walked. GC doesn't walk CLD from the
|
|
||||||
// loader oop in all collections, particularly young collections.
|
|
||||||
NoSafepointVerifier no_safepoints;
|
|
||||||
|
|
||||||
cld = new ClassLoaderData(loader, is_unsafe_anonymous);
|
|
||||||
|
|
||||||
// First install the new CLD to the Graph.
|
|
||||||
cld->set_next(_head);
|
|
||||||
_head = cld;
|
|
||||||
|
|
||||||
// Next associate with the class_loader.
|
|
||||||
if (!is_unsafe_anonymous) {
|
|
||||||
// Use OrderAccess, since readers need to get the loader_data only after
|
|
||||||
// it's added to the Graph
|
|
||||||
java_lang_ClassLoader::release_set_loader_data(loader(), cld);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lastly log, if requested
|
|
||||||
LogTarget(Trace, class, loader, data) lt;
|
|
||||||
if (lt.is_enabled()) {
|
|
||||||
ResourceMark rm;
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print("create ");
|
|
||||||
cld->print_value_on(&ls);
|
|
||||||
ls.cr();
|
|
||||||
}
|
|
||||||
return cld;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) {
|
|
||||||
MutexLocker ml(ClassLoaderDataGraph_lock);
|
|
||||||
ClassLoaderData* loader_data = add_to_graph(loader, is_unsafe_anonymous);
|
|
||||||
return loader_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::cld_do(CLDClosure* cl) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
|
|
||||||
cl->do_cld(cld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
// 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");
|
|
||||||
cl->do_cld(cld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
|
|
||||||
CLDClosure* closure = cld->keep_alive() ? strong : weak;
|
|
||||||
if (closure != NULL) {
|
|
||||||
closure->do_cld(cld);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
if (ClassUnloading) {
|
|
||||||
roots_cld_do(cl, NULL);
|
|
||||||
} else {
|
|
||||||
cld_do(cl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Closure for locking and iterating through classes.
|
|
||||||
LockedClassesDo::LockedClassesDo(classes_do_func_t f) : _function(f) {
|
|
||||||
ClassLoaderDataGraph_lock->lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
LockedClassesDo::LockedClassesDo() : _function(NULL) {
|
|
||||||
// callers provide their own do_klass
|
|
||||||
ClassLoaderDataGraph_lock->lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
LockedClassesDo::~LockedClassesDo() { ClassLoaderDataGraph_lock->unlock(); }
|
|
||||||
|
|
||||||
|
|
||||||
// Iterating over the CLDG needs to be locked because
|
|
||||||
// unloading can remove entries concurrently soon.
|
|
||||||
class ClassLoaderDataGraphIterator : public StackObj {
|
|
||||||
ClassLoaderData* _next;
|
|
||||||
HandleMark _hm; // clean up handles when this is done.
|
|
||||||
Handle _holder;
|
|
||||||
Thread* _thread;
|
|
||||||
|
|
||||||
void hold_next() {
|
|
||||||
if (_next != NULL) {
|
|
||||||
_holder = Handle(_thread, _next->holder_phantom());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head) {
|
|
||||||
_thread = Thread::current();
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
hold_next();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool repeat() const {
|
|
||||||
return _next != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoaderData* get_next() {
|
|
||||||
ClassLoaderData* next = _next;
|
|
||||||
if (_next != NULL) {
|
|
||||||
_next = _next->next();
|
|
||||||
hold_next();
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// These functions assume that the caller has locked the ClassLoaderDataGraph_lock
|
|
||||||
// if they are not calling the function from a safepoint.
|
|
||||||
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->classes_do(klass_closure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->classes_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::methods_do(void f(Method*)) {
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->methods_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
|
|
||||||
assert_locked_or_safepoint(Module_lock);
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->modules_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
// 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);
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->packages_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
// 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) {
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->loaded_classes_do(klass_closure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This case can block but cannot do unloading (called from CDS)
|
|
||||||
void ClassLoaderDataGraph::unlocked_loaded_classes_do(KlassClosure* klass_closure) {
|
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
|
||||||
cld->loaded_classes_do(klass_closure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \
|
|
||||||
ClassLoaderData* X; \
|
|
||||||
while ((X = iter.get_next()) != NULL) \
|
|
||||||
if (X->dictionary() != NULL)
|
|
||||||
|
|
||||||
// Walk classes in the loaded class dictionaries in various forms.
|
|
||||||
// Only walks the classes defined in this class loader.
|
|
||||||
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
|
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
|
||||||
cld->dictionary()->classes_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only walks the classes defined in this class loader.
|
|
||||||
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
|
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
|
||||||
cld->dictionary()->classes_do(f, CHECK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::verify_dictionary() {
|
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
|
||||||
cld->dictionary()->verify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
|
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
|
||||||
st->print("Dictionary for ");
|
|
||||||
cld->print_value_on(st);
|
|
||||||
st->cr();
|
|
||||||
cld->dictionary()->print_on(st);
|
|
||||||
st->cr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) {
|
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
|
||||||
ResourceMark rm;
|
|
||||||
stringStream tempst;
|
|
||||||
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
|
|
||||||
cld->dictionary()->print_table_statistics(st, tempst.as_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
|
|
||||||
|
|
||||||
GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
|
|
||||||
|
|
||||||
// The CLDs in [_head, _saved_head] were all added during last call to remember_new_clds(true);
|
|
||||||
ClassLoaderData* curr = _head;
|
|
||||||
while (curr != _saved_head) {
|
|
||||||
if (!curr->claimed()) {
|
|
||||||
array->push(curr);
|
|
||||||
LogTarget(Debug, class, loader, data) lt;
|
|
||||||
if (lt.is_enabled()) {
|
|
||||||
LogStream ls(lt);
|
|
||||||
ls.print("found new CLD: ");
|
|
||||||
curr->print_value_on(&ls);
|
|
||||||
ls.cr();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
curr = curr->_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
|
|
||||||
if (loader_data == data) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif // PRODUCT
|
|
||||||
|
|
||||||
// Move class loader data from main list to the unloaded list for unloading
|
|
||||||
// and deallocation later.
|
|
||||||
bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
|
|
||||||
// Indicate whether safepoint cleanup is needed.
|
|
||||||
_safepoint_cleanup_needed |= do_cleaning;
|
|
||||||
|
|
||||||
ClassLoaderData* data = _head;
|
|
||||||
ClassLoaderData* prev = NULL;
|
|
||||||
bool seen_dead_loader = false;
|
|
||||||
uint loaders_processed = 0;
|
|
||||||
uint loaders_removed = 0;
|
|
||||||
|
|
||||||
// Save previous _unloading pointer for CMS which may add to unloading list before
|
|
||||||
// purging and we don't want to rewalk the previously unloaded class loader data.
|
|
||||||
_saved_unloading = _unloading;
|
|
||||||
|
|
||||||
data = _head;
|
|
||||||
while (data != NULL) {
|
|
||||||
if (data->is_alive()) {
|
|
||||||
prev = data;
|
|
||||||
data = data->next();
|
|
||||||
loaders_processed++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
seen_dead_loader = true;
|
|
||||||
loaders_removed++;
|
|
||||||
ClassLoaderData* dead = data;
|
|
||||||
dead->unload();
|
|
||||||
data = data->next();
|
|
||||||
// Remove from loader list.
|
|
||||||
// This class loader data will no longer be found
|
|
||||||
// in the ClassLoaderDataGraph.
|
|
||||||
if (prev != NULL) {
|
|
||||||
prev->set_next(data);
|
|
||||||
} else {
|
|
||||||
assert(dead == _head, "sanity check");
|
|
||||||
_head = data;
|
|
||||||
}
|
|
||||||
dead->set_next(_unloading);
|
|
||||||
_unloading = dead;
|
|
||||||
}
|
|
||||||
|
|
||||||
log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
|
|
||||||
|
|
||||||
return seen_dead_loader;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's at least one dead class loader. Purge refererences of healthy module
|
|
||||||
// reads lists and package export lists to modules belonging to dead loaders.
|
|
||||||
void ClassLoaderDataGraph::clean_module_and_package_info() {
|
|
||||||
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
|
||||||
|
|
||||||
ClassLoaderData* data = _head;
|
|
||||||
while (data != NULL) {
|
|
||||||
// Remove entries in the dictionary of live class loader that have
|
|
||||||
// initiated loading classes in a dead class loader.
|
|
||||||
if (data->dictionary() != NULL) {
|
|
||||||
data->dictionary()->do_unloading();
|
|
||||||
}
|
|
||||||
// Walk a ModuleEntry's reads, and a PackageEntry's exports
|
|
||||||
// lists to determine if there are modules on those lists that are now
|
|
||||||
// dead and should be removed. A module's life cycle is equivalent
|
|
||||||
// to its defining class loader's life cycle. Since a module is
|
|
||||||
// considered dead if its class loader is dead, these walks must
|
|
||||||
// occur after each class loader's aliveness is determined.
|
|
||||||
if (data->packages() != NULL) {
|
|
||||||
data->packages()->purge_all_package_exports();
|
|
||||||
}
|
|
||||||
if (data->modules_defined()) {
|
|
||||||
data->modules()->purge_all_module_reads();
|
|
||||||
}
|
|
||||||
data = data->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::purge() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
|
||||||
ClassLoaderData* list = _unloading;
|
|
||||||
_unloading = NULL;
|
|
||||||
ClassLoaderData* next = list;
|
|
||||||
bool classes_unloaded = false;
|
|
||||||
while (next != NULL) {
|
|
||||||
ClassLoaderData* purge_me = next;
|
|
||||||
next = purge_me->next();
|
|
||||||
delete purge_me;
|
|
||||||
classes_unloaded = true;
|
|
||||||
}
|
|
||||||
if (classes_unloaded) {
|
|
||||||
Metaspace::purge();
|
|
||||||
set_metaspace_oom(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ClassLoaderDataGraph::resize_if_needed() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
|
||||||
int resized = 0;
|
|
||||||
if (Dictionary::does_any_dictionary_needs_resizing()) {
|
|
||||||
FOR_ALL_DICTIONARY(cld) {
|
|
||||||
if (cld->dictionary()->resize_if_needed()) {
|
|
||||||
resized++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resized;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
|
|
||||||
: _next_klass(NULL) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
|
||||||
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
|
|
||||||
Klass* klass = NULL;
|
|
||||||
|
|
||||||
// Find the first klass in the CLDG.
|
|
||||||
while (cld != NULL) {
|
|
||||||
assert_locked_or_safepoint(cld->metaspace_lock());
|
|
||||||
klass = cld->_klasses;
|
|
||||||
if (klass != NULL) {
|
|
||||||
_next_klass = klass;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cld = cld->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) {
|
|
||||||
Klass* next = klass->next_link();
|
|
||||||
if (next != NULL) {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No more klasses in the current CLD. Time to find a new CLD.
|
|
||||||
ClassLoaderData* cld = klass->class_loader_data();
|
|
||||||
assert_locked_or_safepoint(cld->metaspace_lock());
|
|
||||||
while (next == NULL) {
|
|
||||||
cld = cld->next();
|
|
||||||
if (cld == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next = cld->_klasses;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
|
|
||||||
Klass* head = _next_klass;
|
|
||||||
|
|
||||||
while (head != NULL) {
|
|
||||||
Klass* next = next_klass_in_cldg(head);
|
|
||||||
|
|
||||||
Klass* old_head = Atomic::cmpxchg(next, &_next_klass, head);
|
|
||||||
|
|
||||||
if (old_head == head) {
|
|
||||||
return head; // Won the CAS.
|
|
||||||
}
|
|
||||||
|
|
||||||
head = old_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nothing more for the iterator to hand out.
|
|
||||||
assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
|
||||||
_data = ClassLoaderDataGraph::_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassLoaderDataGraphMetaspaceIterator::~ClassLoaderDataGraphMetaspaceIterator() {}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
// callable from debugger
|
|
||||||
extern "C" int print_loader_data_graph() {
|
|
||||||
ResourceMark rm;
|
|
||||||
ClassLoaderDataGraph::print_on(tty);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::verify() {
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->verify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::print_on(outputStream * const out) {
|
|
||||||
ClassLoaderDataGraphIterator iter;
|
|
||||||
while (iter.repeat()) {
|
|
||||||
ClassLoaderData* cld = iter.get_next();
|
|
||||||
cld->print_on(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif // PRODUCT
|
|
||||||
|
|
|
@ -53,9 +53,8 @@
|
||||||
// ClassLoaderData are stored in the runtime representation of classes,
|
// ClassLoaderData are stored in the runtime representation of classes,
|
||||||
// and provides iterators for root tracing and other GC operations.
|
// and provides iterators for root tracing and other GC operations.
|
||||||
|
|
||||||
class ClassLoaderData;
|
class ClassLoaderDataGraph;
|
||||||
class JNIMethodBlock;
|
class JNIMethodBlock;
|
||||||
class Metadebug;
|
|
||||||
class ModuleEntry;
|
class ModuleEntry;
|
||||||
class PackageEntry;
|
class PackageEntry;
|
||||||
class ModuleEntryTable;
|
class ModuleEntryTable;
|
||||||
|
@ -63,136 +62,6 @@ class PackageEntryTable;
|
||||||
class DictionaryEntry;
|
class DictionaryEntry;
|
||||||
class Dictionary;
|
class Dictionary;
|
||||||
|
|
||||||
// GC root for walking class loader data created
|
|
||||||
|
|
||||||
class ClassLoaderDataGraph : public AllStatic {
|
|
||||||
friend class ClassLoaderData;
|
|
||||||
friend class ClassLoaderDataGraphMetaspaceIterator;
|
|
||||||
friend class ClassLoaderDataGraphKlassIteratorAtomic;
|
|
||||||
friend class ClassLoaderDataGraphKlassIteratorStatic;
|
|
||||||
friend class ClassLoaderDataGraphIterator;
|
|
||||||
friend class VMStructs;
|
|
||||||
private:
|
|
||||||
// All CLDs (except the null CLD) can be reached by walking _head->_next->...
|
|
||||||
static ClassLoaderData* _head;
|
|
||||||
static ClassLoaderData* _unloading;
|
|
||||||
// CMS support.
|
|
||||||
static ClassLoaderData* _saved_head;
|
|
||||||
static ClassLoaderData* _saved_unloading;
|
|
||||||
static bool _should_purge;
|
|
||||||
|
|
||||||
// Set if there's anything to purge in the deallocate lists or previous versions
|
|
||||||
// during a safepoint after class unloading in a full GC.
|
|
||||||
static bool _should_clean_deallocate_lists;
|
|
||||||
static bool _safepoint_cleanup_needed;
|
|
||||||
|
|
||||||
// OOM has been seen in metaspace allocation. Used to prevent some
|
|
||||||
// allocations until class unloading
|
|
||||||
static bool _metaspace_oom;
|
|
||||||
|
|
||||||
static volatile size_t _num_instance_classes;
|
|
||||||
static volatile size_t _num_array_classes;
|
|
||||||
|
|
||||||
static ClassLoaderData* add_to_graph(Handle class_loader, bool is_unsafe_anonymous);
|
|
||||||
static ClassLoaderData* add(Handle class_loader, bool is_unsafe_anonymous);
|
|
||||||
|
|
||||||
public:
|
|
||||||
static ClassLoaderData* find_or_create(Handle class_loader);
|
|
||||||
static void clean_module_and_package_info();
|
|
||||||
static void purge();
|
|
||||||
static void clear_claimed_marks();
|
|
||||||
// Iteration through CLDG inside a safepoint; GC support
|
|
||||||
static void cld_do(CLDClosure* cl);
|
|
||||||
static void cld_unloading_do(CLDClosure* cl);
|
|
||||||
static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
|
|
||||||
static void always_strong_cld_do(CLDClosure* cl);
|
|
||||||
// klass do
|
|
||||||
// Walking classes through the ClassLoaderDataGraph include array classes. It also includes
|
|
||||||
// classes that are allocated but not loaded, classes that have errors, and scratch classes
|
|
||||||
// for redefinition. These classes are removed during the next class unloading.
|
|
||||||
// Walking the ClassLoaderDataGraph also includes unsafe anonymous classes.
|
|
||||||
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 unlocked_loaded_classes_do(KlassClosure* klass_closure);
|
|
||||||
static void classes_unloading_do(void f(Klass* const));
|
|
||||||
static bool do_unloading(bool do_cleaning);
|
|
||||||
|
|
||||||
// Expose state to avoid logging overhead in safepoint cleanup tasks.
|
|
||||||
static inline bool should_clean_metaspaces_and_reset();
|
|
||||||
static void set_should_clean_deallocate_lists() { _should_clean_deallocate_lists = true; }
|
|
||||||
static void clean_deallocate_lists(bool purge_previous_versions);
|
|
||||||
static void walk_metadata_and_clean_metaspaces();
|
|
||||||
|
|
||||||
// dictionary do
|
|
||||||
// Iterate over all klasses in dictionary, but
|
|
||||||
// just the classes from defining class loaders.
|
|
||||||
static void dictionary_classes_do(void f(InstanceKlass*));
|
|
||||||
// Added for initialize_itable_for_klass to handle exceptions.
|
|
||||||
static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
|
|
||||||
|
|
||||||
// VM_CounterDecay iteration support
|
|
||||||
static InstanceKlass* try_get_next_class();
|
|
||||||
|
|
||||||
static void verify_dictionary();
|
|
||||||
static void print_dictionary(outputStream* st);
|
|
||||||
static void print_dictionary_statistics(outputStream* st);
|
|
||||||
|
|
||||||
// CMS support.
|
|
||||||
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
|
|
||||||
static GrowableArray<ClassLoaderData*>* new_clds();
|
|
||||||
|
|
||||||
static void set_should_purge(bool b) { _should_purge = b; }
|
|
||||||
static void purge_if_needed() {
|
|
||||||
// Only purge the CLDG for CMS if concurrent sweep is complete.
|
|
||||||
if (_should_purge) {
|
|
||||||
purge();
|
|
||||||
// reset for next time.
|
|
||||||
set_should_purge(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int resize_if_needed();
|
|
||||||
|
|
||||||
static bool has_metaspace_oom() { return _metaspace_oom; }
|
|
||||||
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
|
|
||||||
|
|
||||||
static void print_on(outputStream * const out) PRODUCT_RETURN;
|
|
||||||
static void print() { print_on(tty); }
|
|
||||||
static void verify();
|
|
||||||
|
|
||||||
// instance and array class counters
|
|
||||||
static inline size_t num_instance_classes();
|
|
||||||
static inline size_t num_array_classes();
|
|
||||||
static inline void inc_instance_classes(size_t count);
|
|
||||||
static inline void dec_instance_classes(size_t count);
|
|
||||||
static inline void inc_array_classes(size_t count);
|
|
||||||
static inline void dec_array_classes(size_t count);
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
static bool contains_loader_data(ClassLoaderData* loader_data);
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
class LockedClassesDo : public KlassClosure {
|
|
||||||
typedef void (*classes_do_func_t)(Klass*);
|
|
||||||
classes_do_func_t _function;
|
|
||||||
public:
|
|
||||||
LockedClassesDo(); // For callers who provide their own do_klass
|
|
||||||
LockedClassesDo(classes_do_func_t function);
|
|
||||||
~LockedClassesDo();
|
|
||||||
|
|
||||||
void do_klass(Klass* k) {
|
|
||||||
(*_function)(k);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ClassLoaderData class
|
// ClassLoaderData class
|
||||||
|
|
||||||
class ClassLoaderData : public CHeapObj<mtClass> {
|
class ClassLoaderData : public CHeapObj<mtClass> {
|
||||||
|
@ -314,7 +183,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||||
bool keep_alive() const { return _keep_alive > 0; }
|
bool keep_alive() const { return _keep_alive > 0; }
|
||||||
|
|
||||||
oop holder_phantom() const;
|
oop holder_phantom() const;
|
||||||
void classes_do(void f(Klass*));
|
void classes_do(void f(Klass* const));
|
||||||
void loaded_classes_do(KlassClosure* klass_closure);
|
void loaded_classes_do(KlassClosure* klass_closure);
|
||||||
void classes_do(void f(InstanceKlass*));
|
void classes_do(void f(InstanceKlass*));
|
||||||
void methods_do(void f(Method*));
|
void methods_do(void f(Method*));
|
||||||
|
@ -448,31 +317,4 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||||
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
JFR_ONLY(DEFINE_TRACE_ID_METHODS;)
|
||||||
};
|
};
|
||||||
|
|
||||||
// An iterator that distributes Klasses to parallel worker threads.
|
|
||||||
class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj {
|
|
||||||
Klass* volatile _next_klass;
|
|
||||||
public:
|
|
||||||
ClassLoaderDataGraphKlassIteratorAtomic();
|
|
||||||
Klass* next_klass();
|
|
||||||
private:
|
|
||||||
static Klass* next_klass_in_cldg(Klass* klass);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ClassLoaderDataGraphMetaspaceIterator : public StackObj {
|
|
||||||
ClassLoaderData* _data;
|
|
||||||
public:
|
|
||||||
ClassLoaderDataGraphMetaspaceIterator();
|
|
||||||
~ClassLoaderDataGraphMetaspaceIterator();
|
|
||||||
bool repeat() { return _data != NULL; }
|
|
||||||
ClassLoaderMetaspace* get_next() {
|
|
||||||
assert(_data != NULL, "Should not be NULL in call to the iterator");
|
|
||||||
ClassLoaderMetaspace* result = _data->metaspace_or_null();
|
|
||||||
_data = _data->next();
|
|
||||||
// This result might be NULL for class loaders without metaspace
|
|
||||||
// yet. It would be nice to return only non-null results but
|
|
||||||
// there is no guarantee that there will be a non-null result
|
|
||||||
// down the list so the caller is going to have to check.
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_HPP
|
||||||
|
|
|
@ -55,54 +55,4 @@ inline ClassLoaderData* ClassLoaderData::class_loader_data(oop loader) {
|
||||||
return loader_data;
|
return loader_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) {
|
|
||||||
guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop");
|
|
||||||
// Gets the class loader data out of the java/lang/ClassLoader object, if non-null
|
|
||||||
// it's already in the loader_data, so no need to add
|
|
||||||
ClassLoaderData* loader_data= java_lang_ClassLoader::loader_data_acquire(loader());
|
|
||||||
if (loader_data) {
|
|
||||||
return loader_data;
|
|
||||||
}
|
|
||||||
return ClassLoaderDataGraph::add(loader, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ClassLoaderDataGraph::num_instance_classes() {
|
|
||||||
return _num_instance_classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ClassLoaderDataGraph::num_array_classes() {
|
|
||||||
return _num_array_classes;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::inc_instance_classes(size_t count) {
|
|
||||||
Atomic::add(count, &_num_instance_classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::dec_instance_classes(size_t count) {
|
|
||||||
assert(count <= _num_instance_classes, "Sanity");
|
|
||||||
Atomic::sub(count, &_num_instance_classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::inc_array_classes(size_t count) {
|
|
||||||
Atomic::add(count, &_num_array_classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ClassLoaderDataGraph::dec_array_classes(size_t count) {
|
|
||||||
assert(count <= _num_array_classes, "Sanity");
|
|
||||||
Atomic::sub(count, &_num_array_classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ClassLoaderDataGraph::should_clean_metaspaces_and_reset() {
|
|
||||||
// Only clean metaspaces after full GC.
|
|
||||||
bool do_cleaning = _safepoint_cleanup_needed;
|
|
||||||
#if INCLUDE_JVMTI
|
|
||||||
do_cleaning = do_cleaning && (_should_clean_deallocate_lists || InstanceKlass::has_previous_versions());
|
|
||||||
#else
|
|
||||||
do_cleaning = do_cleaning && _should_clean_deallocate_lists;
|
|
||||||
#endif
|
|
||||||
_safepoint_cleanup_needed = false; // reset
|
|
||||||
return do_cleaning;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_INLINE_HPP
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATA_INLINE_HPP
|
||||||
|
|
697
src/hotspot/share/classfile/classLoaderDataGraph.cpp
Normal file
697
src/hotspot/share/classfile/classLoaderDataGraph.cpp
Normal file
|
@ -0,0 +1,697 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please 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/classLoaderDataGraph.inline.hpp"
|
||||||
|
#include "classfile/dictionary.hpp"
|
||||||
|
#include "classfile/javaClasses.hpp"
|
||||||
|
#include "classfile/metadataOnStackMark.hpp"
|
||||||
|
#include "classfile/moduleEntry.hpp"
|
||||||
|
#include "classfile/packageEntry.hpp"
|
||||||
|
#include "logging/log.hpp"
|
||||||
|
#include "logging/logStream.hpp"
|
||||||
|
#include "memory/allocation.inline.hpp"
|
||||||
|
#include "memory/metaspace.hpp"
|
||||||
|
#include "memory/resourceArea.hpp"
|
||||||
|
#include "runtime/atomic.hpp"
|
||||||
|
#include "runtime/handles.inline.hpp"
|
||||||
|
#include "runtime/mutex.hpp"
|
||||||
|
#include "runtime/safepoint.hpp"
|
||||||
|
#include "runtime/safepointVerifiers.hpp"
|
||||||
|
#include "utilities/growableArray.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
|
#include "utilities/ostream.hpp"
|
||||||
|
|
||||||
|
volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
|
||||||
|
volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0;
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::clear_claimed_marks() {
|
||||||
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
cld->clear_claimed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Class iterator used by the compiler. It gets some number of classes at
|
||||||
|
// a safepoint to decay invocation counters on the methods.
|
||||||
|
class ClassLoaderDataGraphKlassIteratorStatic {
|
||||||
|
ClassLoaderData* _current_loader_data;
|
||||||
|
Klass* _current_class_entry;
|
||||||
|
public:
|
||||||
|
|
||||||
|
ClassLoaderDataGraphKlassIteratorStatic() : _current_loader_data(NULL), _current_class_entry(NULL) {}
|
||||||
|
|
||||||
|
InstanceKlass* try_get_next_class() {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||||
|
size_t max_classes = ClassLoaderDataGraph::num_instance_classes();
|
||||||
|
assert(max_classes > 0, "should not be called with no instance classes");
|
||||||
|
for (size_t i = 0; i < max_classes; ) {
|
||||||
|
|
||||||
|
if (_current_class_entry != NULL) {
|
||||||
|
Klass* k = _current_class_entry;
|
||||||
|
_current_class_entry = _current_class_entry->next_link();
|
||||||
|
|
||||||
|
if (k->is_instance_klass()) {
|
||||||
|
InstanceKlass* ik = InstanceKlass::cast(k);
|
||||||
|
i++; // count all instance classes found
|
||||||
|
// Not yet loaded classes are counted in max_classes
|
||||||
|
// but only return loaded classes.
|
||||||
|
if (ik->is_loaded()) {
|
||||||
|
return ik;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Go to next CLD
|
||||||
|
if (_current_loader_data != NULL) {
|
||||||
|
_current_loader_data = _current_loader_data->next();
|
||||||
|
}
|
||||||
|
// Start at the beginning
|
||||||
|
if (_current_loader_data == NULL) {
|
||||||
|
_current_loader_data = ClassLoaderDataGraph::_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
_current_class_entry = _current_loader_data->klasses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Should never be reached unless all instance classes have failed or are not fully loaded.
|
||||||
|
// Caller handles NULL.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the current class for the static iterator is a class being unloaded or
|
||||||
|
// deallocated, adjust the current class.
|
||||||
|
void adjust_saved_class(ClassLoaderData* cld) {
|
||||||
|
if (_current_loader_data == cld) {
|
||||||
|
_current_loader_data = cld->next();
|
||||||
|
if (_current_loader_data != NULL) {
|
||||||
|
_current_class_entry = _current_loader_data->klasses();
|
||||||
|
} // else try_get_next_class will start at the head
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void adjust_saved_class(Klass* klass) {
|
||||||
|
if (_current_class_entry == klass) {
|
||||||
|
_current_class_entry = klass->next_link();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static ClassLoaderDataGraphKlassIteratorStatic static_klass_iterator;
|
||||||
|
|
||||||
|
InstanceKlass* ClassLoaderDataGraph::try_get_next_class() {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||||
|
return static_klass_iterator.try_get_next_class();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::adjust_saved_class(ClassLoaderData* cld) {
|
||||||
|
return static_klass_iterator.adjust_saved_class(cld);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::adjust_saved_class(Klass* klass) {
|
||||||
|
return static_klass_iterator.adjust_saved_class(klass);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::clean_deallocate_lists(bool walk_previous_versions) {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint");
|
||||||
|
uint loaders_processed = 0;
|
||||||
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
// is_alive check will be necessary for concurrent class unloading.
|
||||||
|
if (cld->is_alive()) {
|
||||||
|
// clean metaspace
|
||||||
|
if (walk_previous_versions) {
|
||||||
|
cld->classes_do(InstanceKlass::purge_previous_versions);
|
||||||
|
}
|
||||||
|
cld->free_deallocate_list();
|
||||||
|
loaders_processed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_debug(class, loader, data)("clean_deallocate_lists: loaders processed %u %s",
|
||||||
|
loaders_processed, walk_previous_versions ? "walk_previous_versions" : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces() {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must only be called at safepoint");
|
||||||
|
|
||||||
|
_should_clean_deallocate_lists = false; // assume everything gets cleaned
|
||||||
|
|
||||||
|
// Mark metadata seen on the stack so we can delete unreferenced entries.
|
||||||
|
// Walk all metadata, including the expensive code cache walk, only for class redefinition.
|
||||||
|
// The MetadataOnStackMark walk during redefinition saves previous versions if it finds old methods
|
||||||
|
// on the stack or in the code cache, so we only have to repeat the full walk if
|
||||||
|
// they were found at that time.
|
||||||
|
// TODO: have redefinition clean old methods out of the code cache. They still exist in some places.
|
||||||
|
bool walk_all_metadata = InstanceKlass::has_previous_versions_and_reset();
|
||||||
|
|
||||||
|
MetadataOnStackMark md_on_stack(walk_all_metadata);
|
||||||
|
clean_deallocate_lists(walk_all_metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// GC root of class loader data created.
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::_saved_unloading = NULL;
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
|
||||||
|
|
||||||
|
bool ClassLoaderDataGraph::_should_purge = false;
|
||||||
|
bool ClassLoaderDataGraph::_should_clean_deallocate_lists = false;
|
||||||
|
bool ClassLoaderDataGraph::_safepoint_cleanup_needed = false;
|
||||||
|
bool ClassLoaderDataGraph::_metaspace_oom = false;
|
||||||
|
|
||||||
|
// Add a new class loader data node to the list. Assign the newly created
|
||||||
|
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_unsafe_anonymous) {
|
||||||
|
|
||||||
|
assert_lock_strong(ClassLoaderDataGraph_lock);
|
||||||
|
|
||||||
|
ClassLoaderData* cld;
|
||||||
|
|
||||||
|
// First check if another thread beat us to creating the CLD and installing
|
||||||
|
// it into the loader while we were waiting for the lock.
|
||||||
|
if (!is_unsafe_anonymous && loader.not_null()) {
|
||||||
|
cld = java_lang_ClassLoader::loader_data_acquire(loader());
|
||||||
|
if (cld != NULL) {
|
||||||
|
return cld;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We mustn't GC until we've installed the ClassLoaderData in the Graph since the CLD
|
||||||
|
// contains oops in _handles that must be walked. GC doesn't walk CLD from the
|
||||||
|
// loader oop in all collections, particularly young collections.
|
||||||
|
NoSafepointVerifier no_safepoints;
|
||||||
|
|
||||||
|
cld = new ClassLoaderData(loader, is_unsafe_anonymous);
|
||||||
|
|
||||||
|
// First install the new CLD to the Graph.
|
||||||
|
cld->set_next(_head);
|
||||||
|
_head = cld;
|
||||||
|
|
||||||
|
// Next associate with the class_loader.
|
||||||
|
if (!is_unsafe_anonymous) {
|
||||||
|
// Use OrderAccess, since readers need to get the loader_data only after
|
||||||
|
// it's added to the Graph
|
||||||
|
java_lang_ClassLoader::release_set_loader_data(loader(), cld);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lastly log, if requested
|
||||||
|
LogTarget(Trace, class, loader, data) lt;
|
||||||
|
if (lt.is_enabled()) {
|
||||||
|
ResourceMark rm;
|
||||||
|
LogStream ls(lt);
|
||||||
|
ls.print("create ");
|
||||||
|
cld->print_value_on(&ls);
|
||||||
|
ls.cr();
|
||||||
|
}
|
||||||
|
return cld;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_unsafe_anonymous) {
|
||||||
|
MutexLocker ml(ClassLoaderDataGraph_lock);
|
||||||
|
ClassLoaderData* loader_data = add_to_graph(loader, is_unsafe_anonymous);
|
||||||
|
return loader_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::cld_do(CLDClosure* cl) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
|
||||||
|
cl->do_cld(cld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::cld_unloading_do(CLDClosure* cl) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
// 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");
|
||||||
|
cl->do_cld(cld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::roots_cld_do(CLDClosure* strong, CLDClosure* weak) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->_next) {
|
||||||
|
CLDClosure* closure = cld->keep_alive() ? strong : weak;
|
||||||
|
if (closure != NULL) {
|
||||||
|
closure->do_cld(cld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::always_strong_cld_do(CLDClosure* cl) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
if (ClassUnloading) {
|
||||||
|
roots_cld_do(cl, NULL);
|
||||||
|
} else {
|
||||||
|
cld_do(cl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Closure for locking and iterating through classes.
|
||||||
|
LockedClassesDo::LockedClassesDo(classes_do_func_t f) : _function(f) {
|
||||||
|
ClassLoaderDataGraph_lock->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedClassesDo::LockedClassesDo() : _function(NULL) {
|
||||||
|
// callers provide their own do_klass
|
||||||
|
ClassLoaderDataGraph_lock->lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedClassesDo::~LockedClassesDo() { ClassLoaderDataGraph_lock->unlock(); }
|
||||||
|
|
||||||
|
|
||||||
|
// Iterating over the CLDG needs to be locked because
|
||||||
|
// unloading can remove entries concurrently soon.
|
||||||
|
class ClassLoaderDataGraphIterator : public StackObj {
|
||||||
|
ClassLoaderData* _next;
|
||||||
|
HandleMark _hm; // clean up handles when this is done.
|
||||||
|
Handle _holder;
|
||||||
|
Thread* _thread;
|
||||||
|
|
||||||
|
void hold_next() {
|
||||||
|
if (_next != NULL) {
|
||||||
|
_holder = Handle(_thread, _next->holder_phantom());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
ClassLoaderDataGraphIterator() : _next(ClassLoaderDataGraph::_head) {
|
||||||
|
_thread = Thread::current();
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
hold_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool repeat() const {
|
||||||
|
return _next != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoaderData* get_next() {
|
||||||
|
ClassLoaderData* next = _next;
|
||||||
|
if (_next != NULL) {
|
||||||
|
_next = _next->next();
|
||||||
|
hold_next();
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// These functions assume that the caller has locked the ClassLoaderDataGraph_lock
|
||||||
|
// if they are not calling the function from a safepoint.
|
||||||
|
void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->classes_do(klass_closure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->classes_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::methods_do(void f(Method*)) {
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->methods_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::modules_do(void f(ModuleEntry*)) {
|
||||||
|
assert_locked_or_safepoint(Module_lock);
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->modules_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::modules_unloading_do(void f(ModuleEntry*)) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
// 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);
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->packages_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::packages_unloading_do(void f(PackageEntry*)) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
// 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) {
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->loaded_classes_do(klass_closure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This case can block but cannot do unloading (called from CDS)
|
||||||
|
void ClassLoaderDataGraph::unlocked_loaded_classes_do(KlassClosure* klass_closure) {
|
||||||
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
cld->loaded_classes_do(klass_closure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::classes_unloading_do(void f(Klass* const)) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FOR_ALL_DICTIONARY(X) ClassLoaderDataGraphIterator iter; \
|
||||||
|
ClassLoaderData* X; \
|
||||||
|
while ((X = iter.get_next()) != NULL) \
|
||||||
|
if (X->dictionary() != NULL)
|
||||||
|
|
||||||
|
// Walk classes in the loaded class dictionaries in various forms.
|
||||||
|
// Only walks the classes defined in this class loader.
|
||||||
|
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*)) {
|
||||||
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
cld->dictionary()->classes_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only walks the classes defined in this class loader.
|
||||||
|
void ClassLoaderDataGraph::dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS) {
|
||||||
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
cld->dictionary()->classes_do(f, CHECK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::verify_dictionary() {
|
||||||
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
cld->dictionary()->verify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::print_dictionary(outputStream* st) {
|
||||||
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
st->print("Dictionary for ");
|
||||||
|
cld->print_value_on(st);
|
||||||
|
st->cr();
|
||||||
|
cld->dictionary()->print_on(st);
|
||||||
|
st->cr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::print_dictionary_statistics(outputStream* st) {
|
||||||
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
ResourceMark rm;
|
||||||
|
stringStream tempst;
|
||||||
|
tempst.print("System Dictionary for %s class loader", cld->loader_name_and_id());
|
||||||
|
cld->dictionary()->print_table_statistics(st, tempst.as_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GrowableArray<ClassLoaderData*>* ClassLoaderDataGraph::new_clds() {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
assert(_head == NULL || _saved_head != NULL, "remember_new_clds(true) not called?");
|
||||||
|
|
||||||
|
GrowableArray<ClassLoaderData*>* array = new GrowableArray<ClassLoaderData*>();
|
||||||
|
|
||||||
|
// The CLDs in [_head, _saved_head] were all added during last call to remember_new_clds(true);
|
||||||
|
ClassLoaderData* curr = _head;
|
||||||
|
while (curr != _saved_head) {
|
||||||
|
if (!curr->claimed()) {
|
||||||
|
array->push(curr);
|
||||||
|
LogTarget(Debug, class, loader, data) lt;
|
||||||
|
if (lt.is_enabled()) {
|
||||||
|
LogStream ls(lt);
|
||||||
|
ls.print("found new CLD: ");
|
||||||
|
curr->print_value_on(&ls);
|
||||||
|
ls.cr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curr = curr->_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
for (ClassLoaderData* data = _head; data != NULL; data = data->next()) {
|
||||||
|
if (loader_data == data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // PRODUCT
|
||||||
|
|
||||||
|
// Move class loader data from main list to the unloaded list for unloading
|
||||||
|
// and deallocation later.
|
||||||
|
bool ClassLoaderDataGraph::do_unloading(bool do_cleaning) {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
|
||||||
|
// Indicate whether safepoint cleanup is needed.
|
||||||
|
_safepoint_cleanup_needed |= do_cleaning;
|
||||||
|
|
||||||
|
ClassLoaderData* data = _head;
|
||||||
|
ClassLoaderData* prev = NULL;
|
||||||
|
bool seen_dead_loader = false;
|
||||||
|
uint loaders_processed = 0;
|
||||||
|
uint loaders_removed = 0;
|
||||||
|
|
||||||
|
// Save previous _unloading pointer for CMS which may add to unloading list before
|
||||||
|
// purging and we don't want to rewalk the previously unloaded class loader data.
|
||||||
|
_saved_unloading = _unloading;
|
||||||
|
|
||||||
|
data = _head;
|
||||||
|
while (data != NULL) {
|
||||||
|
if (data->is_alive()) {
|
||||||
|
prev = data;
|
||||||
|
data = data->next();
|
||||||
|
loaders_processed++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen_dead_loader = true;
|
||||||
|
loaders_removed++;
|
||||||
|
ClassLoaderData* dead = data;
|
||||||
|
dead->unload();
|
||||||
|
data = data->next();
|
||||||
|
// Remove from loader list.
|
||||||
|
// This class loader data will no longer be found
|
||||||
|
// in the ClassLoaderDataGraph.
|
||||||
|
if (prev != NULL) {
|
||||||
|
prev->set_next(data);
|
||||||
|
} else {
|
||||||
|
assert(dead == _head, "sanity check");
|
||||||
|
_head = data;
|
||||||
|
}
|
||||||
|
dead->set_next(_unloading);
|
||||||
|
_unloading = dead;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
|
||||||
|
|
||||||
|
return seen_dead_loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There's at least one dead class loader. Purge refererences of healthy module
|
||||||
|
// reads lists and package export lists to modules belonging to dead loaders.
|
||||||
|
void ClassLoaderDataGraph::clean_module_and_package_info() {
|
||||||
|
assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
|
||||||
|
|
||||||
|
ClassLoaderData* data = _head;
|
||||||
|
while (data != NULL) {
|
||||||
|
// Remove entries in the dictionary of live class loader that have
|
||||||
|
// initiated loading classes in a dead class loader.
|
||||||
|
if (data->dictionary() != NULL) {
|
||||||
|
data->dictionary()->do_unloading();
|
||||||
|
}
|
||||||
|
// Walk a ModuleEntry's reads, and a PackageEntry's exports
|
||||||
|
// lists to determine if there are modules on those lists that are now
|
||||||
|
// dead and should be removed. A module's life cycle is equivalent
|
||||||
|
// to its defining class loader's life cycle. Since a module is
|
||||||
|
// considered dead if its class loader is dead, these walks must
|
||||||
|
// occur after each class loader's aliveness is determined.
|
||||||
|
if (data->packages() != NULL) {
|
||||||
|
data->packages()->purge_all_package_exports();
|
||||||
|
}
|
||||||
|
if (data->modules_defined()) {
|
||||||
|
data->modules()->purge_all_module_reads();
|
||||||
|
}
|
||||||
|
data = data->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::purge() {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||||
|
ClassLoaderData* list = _unloading;
|
||||||
|
_unloading = NULL;
|
||||||
|
ClassLoaderData* next = list;
|
||||||
|
bool classes_unloaded = false;
|
||||||
|
while (next != NULL) {
|
||||||
|
ClassLoaderData* purge_me = next;
|
||||||
|
next = purge_me->next();
|
||||||
|
delete purge_me;
|
||||||
|
classes_unloaded = true;
|
||||||
|
}
|
||||||
|
if (classes_unloaded) {
|
||||||
|
Metaspace::purge();
|
||||||
|
set_metaspace_oom(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ClassLoaderDataGraph::resize_if_needed() {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||||
|
int resized = 0;
|
||||||
|
if (Dictionary::does_any_dictionary_needs_resizing()) {
|
||||||
|
FOR_ALL_DICTIONARY(cld) {
|
||||||
|
if (cld->dictionary()->resize_if_needed()) {
|
||||||
|
resized++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resized;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoaderDataGraphKlassIteratorAtomic::ClassLoaderDataGraphKlassIteratorAtomic()
|
||||||
|
: _next_klass(NULL) {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||||
|
ClassLoaderData* cld = ClassLoaderDataGraph::_head;
|
||||||
|
Klass* klass = NULL;
|
||||||
|
|
||||||
|
// Find the first klass in the CLDG.
|
||||||
|
while (cld != NULL) {
|
||||||
|
assert_locked_or_safepoint(cld->metaspace_lock());
|
||||||
|
klass = cld->_klasses;
|
||||||
|
if (klass != NULL) {
|
||||||
|
_next_klass = klass;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cld = cld->next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass_in_cldg(Klass* klass) {
|
||||||
|
Klass* next = klass->next_link();
|
||||||
|
if (next != NULL) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No more klasses in the current CLD. Time to find a new CLD.
|
||||||
|
ClassLoaderData* cld = klass->class_loader_data();
|
||||||
|
assert_locked_or_safepoint(cld->metaspace_lock());
|
||||||
|
while (next == NULL) {
|
||||||
|
cld = cld->next();
|
||||||
|
if (cld == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next = cld->_klasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Klass* ClassLoaderDataGraphKlassIteratorAtomic::next_klass() {
|
||||||
|
Klass* head = _next_klass;
|
||||||
|
|
||||||
|
while (head != NULL) {
|
||||||
|
Klass* next = next_klass_in_cldg(head);
|
||||||
|
|
||||||
|
Klass* old_head = Atomic::cmpxchg(next, &_next_klass, head);
|
||||||
|
|
||||||
|
if (old_head == head) {
|
||||||
|
return head; // Won the CAS.
|
||||||
|
}
|
||||||
|
|
||||||
|
head = old_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing more for the iterator to hand out.
|
||||||
|
assert(head == NULL, "head is " PTR_FORMAT ", expected not null:", p2i(head));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoaderDataGraphMetaspaceIterator::ClassLoaderDataGraphMetaspaceIterator() {
|
||||||
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint!");
|
||||||
|
_data = ClassLoaderDataGraph::_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassLoaderDataGraphMetaspaceIterator::~ClassLoaderDataGraphMetaspaceIterator() {}
|
||||||
|
|
||||||
|
ClassLoaderMetaspace* ClassLoaderDataGraphMetaspaceIterator::get_next() {
|
||||||
|
assert(_data != NULL, "Should not be NULL in call to the iterator");
|
||||||
|
ClassLoaderMetaspace* result = _data->metaspace_or_null();
|
||||||
|
_data = _data->next();
|
||||||
|
// This result might be NULL for class loaders without metaspace
|
||||||
|
// yet. It would be nice to return only non-null results but
|
||||||
|
// there is no guarantee that there will be a non-null result
|
||||||
|
// down the list so the caller is going to have to check.
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
// callable from debugger
|
||||||
|
extern "C" int print_loader_data_graph() {
|
||||||
|
ResourceMark rm;
|
||||||
|
ClassLoaderDataGraph::print_on(tty);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::verify() {
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->verify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::print_on(outputStream * const out) {
|
||||||
|
ClassLoaderDataGraphIterator iter;
|
||||||
|
while (iter.repeat()) {
|
||||||
|
ClassLoaderData* cld = iter.get_next();
|
||||||
|
cld->print_on(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // PRODUCT
|
182
src/hotspot/share/classfile/classLoaderDataGraph.hpp
Normal file
182
src/hotspot/share/classfile/classLoaderDataGraph.hpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please 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_CLASSLOADERDATAGRAPH_HPP
|
||||||
|
#define SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_HPP
|
||||||
|
|
||||||
|
#include "classfile/classLoaderData.hpp"
|
||||||
|
#include "memory/allocation.hpp"
|
||||||
|
#include "utilities/growableArray.hpp"
|
||||||
|
#include "utilities/macros.hpp"
|
||||||
|
|
||||||
|
// GC root for walking class loader data created
|
||||||
|
|
||||||
|
class ClassLoaderDataGraph : public AllStatic {
|
||||||
|
friend class ClassLoaderData;
|
||||||
|
friend class ClassLoaderDataGraphMetaspaceIterator;
|
||||||
|
friend class ClassLoaderDataGraphKlassIteratorAtomic;
|
||||||
|
friend class ClassLoaderDataGraphKlassIteratorStatic;
|
||||||
|
friend class ClassLoaderDataGraphIterator;
|
||||||
|
friend class VMStructs;
|
||||||
|
private:
|
||||||
|
// All CLDs (except the null CLD) can be reached by walking _head->_next->...
|
||||||
|
static ClassLoaderData* _head;
|
||||||
|
static ClassLoaderData* _unloading;
|
||||||
|
// CMS support.
|
||||||
|
static ClassLoaderData* _saved_head;
|
||||||
|
static ClassLoaderData* _saved_unloading;
|
||||||
|
static bool _should_purge;
|
||||||
|
|
||||||
|
// Set if there's anything to purge in the deallocate lists or previous versions
|
||||||
|
// during a safepoint after class unloading in a full GC.
|
||||||
|
static bool _should_clean_deallocate_lists;
|
||||||
|
static bool _safepoint_cleanup_needed;
|
||||||
|
|
||||||
|
// OOM has been seen in metaspace allocation. Used to prevent some
|
||||||
|
// allocations until class unloading
|
||||||
|
static bool _metaspace_oom;
|
||||||
|
|
||||||
|
static volatile size_t _num_instance_classes;
|
||||||
|
static volatile size_t _num_array_classes;
|
||||||
|
|
||||||
|
static ClassLoaderData* add_to_graph(Handle class_loader, bool is_unsafe_anonymous);
|
||||||
|
static ClassLoaderData* add(Handle class_loader, bool is_unsafe_anonymous);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ClassLoaderData* find_or_create(Handle class_loader);
|
||||||
|
static void clean_module_and_package_info();
|
||||||
|
static void purge();
|
||||||
|
static void clear_claimed_marks();
|
||||||
|
// Iteration through CLDG inside a safepoint; GC support
|
||||||
|
static void cld_do(CLDClosure* cl);
|
||||||
|
static void cld_unloading_do(CLDClosure* cl);
|
||||||
|
static void roots_cld_do(CLDClosure* strong, CLDClosure* weak);
|
||||||
|
static void always_strong_cld_do(CLDClosure* cl);
|
||||||
|
// klass do
|
||||||
|
// Walking classes through the ClassLoaderDataGraph include array classes. It also includes
|
||||||
|
// classes that are allocated but not loaded, classes that have errors, and scratch classes
|
||||||
|
// for redefinition. These classes are removed during the next class unloading.
|
||||||
|
// Walking the ClassLoaderDataGraph also includes unsafe anonymous classes.
|
||||||
|
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 unlocked_loaded_classes_do(KlassClosure* klass_closure);
|
||||||
|
static void classes_unloading_do(void f(Klass* const));
|
||||||
|
static bool do_unloading(bool do_cleaning);
|
||||||
|
|
||||||
|
// Expose state to avoid logging overhead in safepoint cleanup tasks.
|
||||||
|
static inline bool should_clean_metaspaces_and_reset();
|
||||||
|
static void set_should_clean_deallocate_lists() { _should_clean_deallocate_lists = true; }
|
||||||
|
static void clean_deallocate_lists(bool purge_previous_versions);
|
||||||
|
static void walk_metadata_and_clean_metaspaces();
|
||||||
|
|
||||||
|
// dictionary do
|
||||||
|
// Iterate over all klasses in dictionary, but
|
||||||
|
// just the classes from defining class loaders.
|
||||||
|
static void dictionary_classes_do(void f(InstanceKlass*));
|
||||||
|
// Added for initialize_itable_for_klass to handle exceptions.
|
||||||
|
static void dictionary_classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
|
||||||
|
|
||||||
|
// VM_CounterDecay iteration support
|
||||||
|
static InstanceKlass* try_get_next_class();
|
||||||
|
static void adjust_saved_class(ClassLoaderData* cld);
|
||||||
|
static void adjust_saved_class(Klass* klass);
|
||||||
|
|
||||||
|
static void verify_dictionary();
|
||||||
|
static void print_dictionary(outputStream* st);
|
||||||
|
static void print_dictionary_statistics(outputStream* st);
|
||||||
|
|
||||||
|
// CMS support.
|
||||||
|
static void remember_new_clds(bool remember) { _saved_head = (remember ? _head : NULL); }
|
||||||
|
static GrowableArray<ClassLoaderData*>* new_clds();
|
||||||
|
|
||||||
|
static void set_should_purge(bool b) { _should_purge = b; }
|
||||||
|
static void purge_if_needed() {
|
||||||
|
// Only purge the CLDG for CMS if concurrent sweep is complete.
|
||||||
|
if (_should_purge) {
|
||||||
|
purge();
|
||||||
|
// reset for next time.
|
||||||
|
set_should_purge(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resize_if_needed();
|
||||||
|
|
||||||
|
static bool has_metaspace_oom() { return _metaspace_oom; }
|
||||||
|
static void set_metaspace_oom(bool value) { _metaspace_oom = value; }
|
||||||
|
|
||||||
|
static void print_on(outputStream * const out) PRODUCT_RETURN;
|
||||||
|
static void print() { print_on(tty); }
|
||||||
|
static void verify();
|
||||||
|
|
||||||
|
// instance and array class counters
|
||||||
|
static inline size_t num_instance_classes();
|
||||||
|
static inline size_t num_array_classes();
|
||||||
|
static inline void inc_instance_classes(size_t count);
|
||||||
|
static inline void dec_instance_classes(size_t count);
|
||||||
|
static inline void inc_array_classes(size_t count);
|
||||||
|
static inline void dec_array_classes(size_t count);
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
static bool contains_loader_data(ClassLoaderData* loader_data);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
class LockedClassesDo : public KlassClosure {
|
||||||
|
typedef void (*classes_do_func_t)(Klass*);
|
||||||
|
classes_do_func_t _function;
|
||||||
|
public:
|
||||||
|
LockedClassesDo(); // For callers who provide their own do_klass
|
||||||
|
LockedClassesDo(classes_do_func_t function);
|
||||||
|
~LockedClassesDo();
|
||||||
|
|
||||||
|
void do_klass(Klass* k) {
|
||||||
|
(*_function)(k);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// An iterator that distributes Klasses to parallel worker threads.
|
||||||
|
class ClassLoaderDataGraphKlassIteratorAtomic : public StackObj {
|
||||||
|
Klass* volatile _next_klass;
|
||||||
|
public:
|
||||||
|
ClassLoaderDataGraphKlassIteratorAtomic();
|
||||||
|
Klass* next_klass();
|
||||||
|
private:
|
||||||
|
static Klass* next_klass_in_cldg(Klass* klass);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClassLoaderDataGraphMetaspaceIterator : public StackObj {
|
||||||
|
ClassLoaderData* _data;
|
||||||
|
public:
|
||||||
|
ClassLoaderDataGraphMetaspaceIterator();
|
||||||
|
~ClassLoaderDataGraphMetaspaceIterator();
|
||||||
|
bool repeat() { return _data != NULL; }
|
||||||
|
ClassLoaderMetaspace* get_next();
|
||||||
|
};
|
||||||
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_HPP
|
82
src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp
Normal file
82
src/hotspot/share/classfile/classLoaderDataGraph.inline.hpp
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please 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_CLASSLOADERDATAGRAPH_INLINE_HPP
|
||||||
|
#define SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_INLINE_HPP
|
||||||
|
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
|
#include "classfile/javaClasses.hpp"
|
||||||
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "runtime/atomic.hpp"
|
||||||
|
|
||||||
|
inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) {
|
||||||
|
guarantee(loader() != NULL && oopDesc::is_oop(loader()), "Loader must be oop");
|
||||||
|
// Gets the class loader data out of the java/lang/ClassLoader object, if non-null
|
||||||
|
// it's already in the loader_data, so no need to add
|
||||||
|
ClassLoaderData* loader_data = java_lang_ClassLoader::loader_data_acquire(loader());
|
||||||
|
if (loader_data) {
|
||||||
|
return loader_data;
|
||||||
|
}
|
||||||
|
return ClassLoaderDataGraph::add(loader, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ClassLoaderDataGraph::num_instance_classes() {
|
||||||
|
return _num_instance_classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ClassLoaderDataGraph::num_array_classes() {
|
||||||
|
return _num_array_classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::inc_instance_classes(size_t count) {
|
||||||
|
Atomic::add(count, &_num_instance_classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::dec_instance_classes(size_t count) {
|
||||||
|
assert(count <= _num_instance_classes, "Sanity");
|
||||||
|
Atomic::sub(count, &_num_instance_classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::inc_array_classes(size_t count) {
|
||||||
|
Atomic::add(count, &_num_array_classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::dec_array_classes(size_t count) {
|
||||||
|
assert(count <= _num_array_classes, "Sanity");
|
||||||
|
Atomic::sub(count, &_num_array_classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClassLoaderDataGraph::should_clean_metaspaces_and_reset() {
|
||||||
|
// Only clean metaspaces after full GC.
|
||||||
|
bool do_cleaning = _safepoint_cleanup_needed;
|
||||||
|
#if INCLUDE_JVMTI
|
||||||
|
do_cleaning = do_cleaning && (_should_clean_deallocate_lists || InstanceKlass::has_previous_versions());
|
||||||
|
#else
|
||||||
|
do_cleaning = do_cleaning && _should_clean_deallocate_lists;
|
||||||
|
#endif
|
||||||
|
_safepoint_cleanup_needed = false; // reset
|
||||||
|
return do_cleaning;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SHARE_VM_CLASSFILE_CLASSLOADERDATAGRAPH_INLINE_HPP
|
|
@ -26,6 +26,7 @@
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classLoaderHierarchyDCmd.hpp"
|
#include "classfile/classLoaderHierarchyDCmd.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/classLoaderStats.hpp"
|
#include "classfile/classLoaderStats.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
|
@ -23,8 +23,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/loaderConstraints.hpp"
|
#include "classfile/loaderConstraints.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
|
|
@ -478,8 +478,8 @@ private:
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
assert(sym->utf8_length() == _len, "%s [%d,%d]", where, sym->utf8_length(), _len);
|
assert(sym->utf8_length() == _len, "%s [%d,%d]", where, sym->utf8_length(), _len);
|
||||||
for (int i = 0; i < _len; i++) {
|
for (int i = 0; i < _len; i++) {
|
||||||
assert(sym->byte_at(i) == (jbyte) _name[i],
|
assert(sym->char_at(i) == _name[i],
|
||||||
"%s [%d,%d,%d]", where, i, sym->byte_at(i), _name[i]);
|
"%s [%d,%d,%d]", where, i, sym->char_at(i), _name[i]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "classfile/classFileStream.hpp"
|
#include "classfile/classFileStream.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
#include "classfile/classLoaderData.inline.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.inline.hpp"
|
||||||
#include "classfile/classLoaderExt.hpp"
|
#include "classfile/classLoaderExt.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
|
@ -2600,7 +2601,7 @@ Handle SystemDictionary::find_java_mirror_for_type(Symbol* signature,
|
||||||
if (type->utf8_length() == 1) {
|
if (type->utf8_length() == 1) {
|
||||||
|
|
||||||
// It's a primitive. (Void has a primitive mirror too.)
|
// It's a primitive. (Void has a primitive mirror too.)
|
||||||
char ch = (char) type->byte_at(0);
|
char ch = type->char_at(0);
|
||||||
assert(is_java_primitive(char2type(ch)) || ch == 'V', "");
|
assert(is_java_primitive(char2type(ch)) || ch == 'V', "");
|
||||||
return Handle(THREAD, find_java_mirror_for_type(ch));
|
return Handle(THREAD, find_java_mirror_for_type(ch));
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ bool VerificationType::is_reference_assignable_from(
|
||||||
VerificationType VerificationType::get_component(ClassVerifier *context, TRAPS) const {
|
VerificationType VerificationType::get_component(ClassVerifier *context, TRAPS) const {
|
||||||
assert(is_array() && name()->utf8_length() >= 2, "Must be a valid array");
|
assert(is_array() && name()->utf8_length() >= 2, "Must be a valid array");
|
||||||
Symbol* component;
|
Symbol* component;
|
||||||
switch (name()->byte_at(1)) {
|
switch (name()->char_at(1)) {
|
||||||
case 'Z': return VerificationType(Boolean);
|
case 'Z': return VerificationType(Boolean);
|
||||||
case 'B': return VerificationType(Byte);
|
case 'B': return VerificationType(Byte);
|
||||||
case 'C': return VerificationType(Char);
|
case 'C': return VerificationType(Char);
|
||||||
|
|
|
@ -207,7 +207,7 @@ class VerificationType {
|
||||||
bool is_check() const { return (_u._data & TypeQuery) == TypeQuery; }
|
bool is_check() const { return (_u._data & TypeQuery) == TypeQuery; }
|
||||||
|
|
||||||
bool is_x_array(char sig) const {
|
bool is_x_array(char sig) const {
|
||||||
return is_null() || (is_array() && (name()->byte_at(1) == sig));
|
return is_null() || (is_array() && (name()->char_at(1) == sig));
|
||||||
}
|
}
|
||||||
bool is_int_array() const { return is_x_array('I'); }
|
bool is_int_array() const { return is_x_array('I'); }
|
||||||
bool is_byte_array() const { return is_x_array('B'); }
|
bool is_byte_array() const { return is_x_array('B'); }
|
||||||
|
@ -223,10 +223,10 @@ class VerificationType {
|
||||||
{ return is_object_array() || is_array_array(); }
|
{ return is_object_array() || is_array_array(); }
|
||||||
bool is_object() const
|
bool is_object() const
|
||||||
{ return (is_reference() && !is_null() && name()->utf8_length() >= 1 &&
|
{ return (is_reference() && !is_null() && name()->utf8_length() >= 1 &&
|
||||||
name()->byte_at(0) != '['); }
|
name()->char_at(0) != '['); }
|
||||||
bool is_array() const
|
bool is_array() const
|
||||||
{ return (is_reference() && !is_null() && name()->utf8_length() >= 2 &&
|
{ return (is_reference() && !is_null() && name()->utf8_length() >= 2 &&
|
||||||
name()->byte_at(0) == '['); }
|
name()->char_at(0) == '['); }
|
||||||
bool is_uninitialized() const
|
bool is_uninitialized() const
|
||||||
{ return ((_u._data & Uninitialized) == Uninitialized); }
|
{ return ((_u._data & Uninitialized) == Uninitialized); }
|
||||||
bool is_uninitialized_this() const
|
bool is_uninitialized_this() const
|
||||||
|
@ -322,7 +322,7 @@ class VerificationType {
|
||||||
int dimensions() const {
|
int dimensions() const {
|
||||||
assert(is_array(), "Must be an array");
|
assert(is_array(), "Must be an array");
|
||||||
int index = 0;
|
int index = 0;
|
||||||
while (name()->byte_at(index) == '[') index++;
|
while (name()->char_at(index) == '[') index++;
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2809,7 +2809,7 @@ void ClassVerifier::verify_invoke_instructions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method_name->byte_at(0) == '<') {
|
if (method_name->char_at(0) == '<') {
|
||||||
// Make sure <init> can only be invoked by invokespecial
|
// Make sure <init> can only be invoked by invokespecial
|
||||||
if (opcode != Bytecodes::_invokespecial ||
|
if (opcode != Bytecodes::_invokespecial ||
|
||||||
method_name != vmSymbols::object_initializer_name()) {
|
method_name != vmSymbols::object_initializer_name()) {
|
||||||
|
|
|
@ -212,7 +212,7 @@ void vmSymbols::serialize(SerializeClosure* soc) {
|
||||||
BasicType vmSymbols::signature_type(const Symbol* s) {
|
BasicType vmSymbols::signature_type(const Symbol* s) {
|
||||||
assert(s != NULL, "checking");
|
assert(s != NULL, "checking");
|
||||||
if (s->utf8_length() == 1) {
|
if (s->utf8_length() == 1) {
|
||||||
BasicType result = char2type(s->byte_at(0));
|
BasicType result = char2type(s->char_at(0));
|
||||||
if (is_java_primitive(result) || result == T_VOID) {
|
if (is_java_primitive(result) || result == T_VOID) {
|
||||||
assert(s == _type_signatures[result], "");
|
assert(s == _type_signatures[result], "");
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -2748,9 +2748,7 @@ public:
|
||||||
virtual void verify() const {
|
virtual void verify() const {
|
||||||
// make sure code pattern is actually a call imm32 instruction
|
// make sure code pattern is actually a call imm32 instruction
|
||||||
_call->verify();
|
_call->verify();
|
||||||
if (os::is_MP()) {
|
_call->verify_alignment();
|
||||||
_call->verify_alignment();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void verify_resolve_call(address dest) const {
|
virtual void verify_resolve_call(address dest) const {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "classfile/symbolTable.hpp"
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
|
|
|
@ -136,7 +136,6 @@ static JVMFlag::Error CMSReservedAreaConstraintFunc(const char* name, size_t val
|
||||||
return JVMFlag::VIOLATES_CONSTRAINT;
|
return JVMFlag::VIOLATES_CONSTRAINT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return JVMFlag::SUCCESS;
|
return JVMFlag::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,12 +150,11 @@ JVMFlag::Error CMSRescanMultipleConstraintFunc(size_t value, bool verbose) {
|
||||||
if (value % HeapWordSize != 0) {
|
if (value % HeapWordSize != 0) {
|
||||||
JVMFlag::printError(verbose,
|
JVMFlag::printError(verbose,
|
||||||
"CMSRescanMultiple (" SIZE_FORMAT ") must be "
|
"CMSRescanMultiple (" SIZE_FORMAT ") must be "
|
||||||
"a multiple of " SIZE_FORMAT "\n",
|
"a multiple of %d\n",
|
||||||
value, HeapWordSize);
|
value, HeapWordSize);
|
||||||
status = JVMFlag::VIOLATES_CONSTRAINT;
|
status = JVMFlag::VIOLATES_CONSTRAINT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/metadataOnStackMark.hpp"
|
||||||
#include "classfile/stringTable.hpp"
|
#include "classfile/stringTable.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
|
@ -1048,6 +1049,9 @@ void G1CollectedHeap::prepare_heap_for_mutators() {
|
||||||
// Rebuild the strong code root lists for each region
|
// Rebuild the strong code root lists for each region
|
||||||
rebuild_strong_code_roots();
|
rebuild_strong_code_roots();
|
||||||
|
|
||||||
|
// Purge code root memory
|
||||||
|
purge_code_root_memory();
|
||||||
|
|
||||||
// Start a new incremental collection set for the next pause
|
// Start a new incremental collection set for the next pause
|
||||||
start_new_collection_set();
|
start_new_collection_set();
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "code/codeCache.hpp"
|
#include "code/codeCache.hpp"
|
||||||
#include "gc/g1/g1BarrierSet.hpp"
|
#include "gc/g1/g1BarrierSet.hpp"
|
||||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderDataGraph.hpp"
|
||||||
#include "gc/g1/g1Analytics.hpp"
|
#include "gc/g1/g1Analytics.hpp"
|
||||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||||
#include "gc/g1/g1ConcurrentMark.inline.hpp"
|
#include "gc/g1/g1ConcurrentMark.inline.hpp"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue