# HG changeset patch
# User sspitsyn
# Date 1507532933 0
# Node ID f5f98c9f188467fd743c683197be22fa43362b40
# Parent d4380ee1cbe96f7ba523a58d3e44b3d25a489f37# Parent 5c8607bb3d2de969b2660534b4df978e36faac23
Merge
diff -r d4380ee1cbe9 -r f5f98c9f1884 .hgtags
--- a/.hgtags Sat Oct 07 22:45:12 2017 +0900
+++ b/.hgtags Mon Oct 09 07:08:53 2017 +0000
@@ -449,3 +449,4 @@
e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
+8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25
diff -r d4380ee1cbe9 -r f5f98c9f1884 bin/jib.sh
--- a/bin/jib.sh Sat Oct 07 22:45:12 2017 +0900
+++ b/bin/jib.sh Mon Oct 09 07:08:53 2017 +0000
@@ -28,8 +28,8 @@
mydir="$(dirname "${BASH_SOURCE[0]}")"
myname="$(basename "${BASH_SOURCE[0]}")"
-installed_jib_script=${mydir}/../../.jib/jib
-install_data=${mydir}/../../.jib/.data
+installed_jib_script=${mydir}/../.jib/jib
+install_data=${mydir}/../.jib/.data
setup_url() {
if [ -f ~/.config/jib/jib.conf ]; then
@@ -42,7 +42,7 @@
jib_revision="2.0-SNAPSHOT"
jib_ext="jib.sh.gz"
- closed_script="${mydir}/../../../closed/conf/jib-install.conf"
+ closed_script="${mydir}/../../closed/make/conf/jib-install.conf"
if [ -f "${closed_script}" ]; then
source "${closed_script}"
fi
diff -r d4380ee1cbe9 -r f5f98c9f1884 doc/nashorn/JavaScriptingProgrammersGuide.html
--- a/doc/nashorn/JavaScriptingProgrammersGuide.html Sat Oct 07 22:45:12 2017 +0900
+++ b/doc/nashorn/JavaScriptingProgrammersGuide.html Mon Oct 09 07:08:53 2017 +0000
@@ -127,7 +127,7 @@
Scripting Package
-The Java Scripting functionality is in the javax.script
+The Java Scripting functionality is in the javax.script
package. This is a relatively small, simple API. The starting point
of the scripting API is the ScriptEngineManager
class.
A ScriptEngineManager object can discover script engines through
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/BuildNashorn.gmk
--- a/make/BuildNashorn.gmk Sat Oct 07 22:45:12 2017 +0900
+++ b/make/BuildNashorn.gmk Mon Oct 09 07:08:53 2017 +0000
@@ -41,7 +41,7 @@
$(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \
JVM := $(JAVA_JAVAC), \
JAVAC := $(NEW_JAVAC), \
- FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
+ FLAGS := -g -source 10 -target 10 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
--system none --module-source-path $(call GetModuleSrcPath), \
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/InitSupport.gmk
--- a/make/InitSupport.gmk Sat Oct 07 22:45:12 2017 +0900
+++ b/make/InitSupport.gmk Mon Oct 09 07:08:53 2017 +0000
@@ -36,7 +36,7 @@
# Include the corresponding closed file, if present.
# Normal hook mechanism cannot be used since we have no SPEC.
- -include $(topdir)/closed/make/InitSupport.gmk
+ -include $(topdir)/../closed/make/InitSupport.gmk
##############################################################################
# Helper functions for the initial part of Init.gmk, before the spec file is
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/autoconf/flags.m4
--- a/make/autoconf/flags.m4 Sat Oct 07 22:45:12 2017 +0900
+++ b/make/autoconf/flags.m4 Mon Oct 09 07:08:53 2017 +0000
@@ -1311,6 +1311,7 @@
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}"
$2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+ $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
$2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -1388,6 +1389,7 @@
AC_SUBST($2JDKEXE_LIBS)
AC_SUBST($2LDFLAGS_CXX_JDK)
AC_SUBST($2LDFLAGS_HASH_STYLE)
+ AC_SUBST($2LDFLAGS_NO_EXEC_STACK)
AC_SUBST($2JVM_CFLAGS)
AC_SUBST($2JVM_LDFLAGS)
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/autoconf/generated-configure.sh
--- a/make/autoconf/generated-configure.sh Sat Oct 07 22:45:12 2017 +0900
+++ b/make/autoconf/generated-configure.sh Mon Oct 09 07:08:53 2017 +0000
@@ -723,6 +723,7 @@
OPENJDK_BUILD_JVM_ASFLAGS
OPENJDK_BUILD_JVM_LDFLAGS
OPENJDK_BUILD_JVM_CFLAGS
+OPENJDK_BUILD_LDFLAGS_NO_EXEC_STACK
OPENJDK_BUILD_LDFLAGS_HASH_STYLE
OPENJDK_BUILD_LDFLAGS_CXX_JDK
OPENJDK_BUILD_JDKEXE_LIBS
@@ -738,6 +739,7 @@
JVM_ASFLAGS
JVM_LDFLAGS
JVM_CFLAGS
+LDFLAGS_NO_EXEC_STACK
LDFLAGS_HASH_STYLE
LDFLAGS_CXX_JDK
JDKEXE_LIBS
@@ -5115,7 +5117,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1506333008
+DATE_WHEN_GENERATED=1506397140
###############################################################################
#
@@ -52024,6 +52026,7 @@
LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+ LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -52109,6 +52112,7 @@
+
# Special extras...
if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then
@@ -52903,6 +52907,7 @@
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}"
OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+ OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
-libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -52988,6 +52993,7 @@
+
# Tests are only ever compiled for TARGET
# Flags for compiling test libraries
CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/autoconf/spec.gmk.in
--- a/make/autoconf/spec.gmk.in Sat Oct 07 22:45:12 2017 +0900
+++ b/make/autoconf/spec.gmk.in Mon Oct 09 07:08:53 2017 +0000
@@ -387,6 +387,7 @@
CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
+LDFLAGS_NO_EXEC_STACK := @LDFLAGS_NO_EXEC_STACK@
JVM_CFLAGS := @JVM_CFLAGS@
JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/common/Modules.gmk
--- a/make/common/Modules.gmk Sat Oct 07 22:45:12 2017 +0900
+++ b/make/common/Modules.gmk Mon Oct 09 07:08:53 2017 +0000
@@ -58,7 +58,6 @@
java.rmi \
java.security.sasl \
java.xml \
- jdk.httpserver \
jdk.internal.vm.ci \
jdk.management \
jdk.management.agent \
@@ -112,6 +111,7 @@
jdk.crypto.cryptoki \
jdk.crypto.ec \
jdk.dynalink \
+ jdk.httpserver \
jdk.incubator.httpclient \
jdk.internal.vm.compiler.management \
jdk.jsobject \
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/conf/jib-profiles.js
--- a/make/conf/jib-profiles.js Sat Oct 07 22:45:12 2017 +0900
+++ b/make/conf/jib-profiles.js Mon Oct 09 07:08:53 2017 +0000
@@ -900,6 +900,45 @@
}
},
+ "windows-x64-open": {
+ artifacts: {
+ jdk: {
+ local: "bundles/\\(jdk.*bin.tar.gz\\)",
+ remote: [
+ "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ + "_windows-x64_bin.tar.gz",
+ "bundles/openjdk/GPL/windows-x64/\\1"
+ ],
+ subdir: "jdk-" + data.version
+ },
+ jre: {
+ local: "bundles/\\(jre.*bin.tar.gz\\)",
+ remote: "bundles/openjdk/GPL/windows-x64/\\1"
+ },
+ test: {
+ local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
+ remote: [
+ "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ + "_windows-x64_bin-tests.tar.gz",
+ "bundles/openjdk/GPL/windows-x64/\\1"
+ ]
+ },
+ jdk_symbols: {
+ local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
+ remote: [
+ "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+ + "_windows-x64_bin-symbols.tar.gz",
+ "bundles/openjdk/GPL/windows-x64/\\1"
+ ],
+ subdir: "jdk-" + data.version
+ },
+ jre_symbols: {
+ local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
+ remote: "bundles/openjdk/GPL/windows-x64/\\1",
+ }
+ }
+ },
+
"linux-x86-open-debug": {
artifacts: {
jdk: {
@@ -929,9 +968,10 @@
profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
+ profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]);
// Generate artifacts for ri profiles
- [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri" ]
+ [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri", "windows-x64-ri" ]
.forEach(function (name) {
// Rewrite all remote dirs to "bundles/openjdk/BCL/..."
for (artifactName in profiles[name].artifacts) {
@@ -947,6 +987,11 @@
configure_args: "--with-freetype-license="
+ input.get("freetype", "install_path")
+ "/freetype-2.7.1-v120-x86/freetype.md"
+ },
+ "windows-x64-ri": {
+ configure_args: "--with-freetype-license="
+ + input.get("freetype", "install_path")
+ + "/freetype-2.7.1-v120-x64/freetype.md"
}
};
profiles = concatObjects(profiles, profilesRiFreetype);
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/hotspot/lib/CompileLibjsig.gmk
--- a/make/hotspot/lib/CompileLibjsig.gmk Sat Oct 07 22:45:12 2017 +0900
+++ b/make/hotspot/lib/CompileLibjsig.gmk Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
ifeq ($(STATIC_BUILD), false)
ifeq ($(OPENJDK_TARGET_OS), linux)
LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS)
- LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS)
+ LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) ${LDFLAGS_NO_EXEC_STACK} $(EXTRA_CFLAGS)
LIBJSIG_LIBS := $(LIBDL)
# NOTE: The old build compiled this library without -soname.
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java
--- a/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java Sat Oct 07 22:45:12 2017 +0900
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java Mon Oct 09 07:08:53 2017 +0000
@@ -57,8 +57,8 @@
}
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
- List options = Arrays.asList("-source", "9",
- "-target", "9",
+ List options = Arrays.asList("-source", "10",
+ "-target", "10",
"-proc:only",
"--system", "none",
"--module-source-path", args[0],
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/nashorn/build.xml
--- a/make/nashorn/build.xml Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/build.xml Mon Oct 09 07:08:53 2017 +0000
@@ -174,8 +174,6 @@
@@ -190,8 +188,6 @@
@@ -207,8 +203,6 @@
@@ -342,8 +336,6 @@
@@ -351,7 +343,7 @@
-
+
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/nashorn/buildtools/nasgen/project.properties
--- a/make/nashorn/buildtools/nasgen/project.properties Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/buildtools/nasgen/project.properties Mon Oct 09 07:08:53 2017 +0000
@@ -24,8 +24,6 @@
# source and target levels
build.compiler=modern
-javac.source=1.7
-javac.target=1.7
# This directory is removed when the project is cleaned:
nasgen.build.dir=../../../../build/nashorn/nasgen
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/nashorn/buildtools/nashorntask/project.properties
--- a/make/nashorn/buildtools/nashorntask/project.properties Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/buildtools/nashorntask/project.properties Mon Oct 09 07:08:53 2017 +0000
@@ -24,8 +24,6 @@
# source and target levels
build.compiler=modern
-javac.source=1.8
-javac.target=1.8
# This directory is removed when the project is cleaned:
nashorntask.build.dir=../../../../build/nashorn/nashorntask
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/nashorn/project.properties
--- a/make/nashorn/project.properties Sat Oct 07 22:45:12 2017 +0900
+++ b/make/nashorn/project.properties Mon Oct 09 07:08:53 2017 +0000
@@ -32,8 +32,6 @@
# source and target levels
build.compiler=modern
-javac.source=1.9
-javac.target=1.9
javadoc.option=\
-tag "implSpec:a:Implementation Requirements:" \
@@ -146,7 +144,7 @@
${file.reference.bsh.jar}${path.separator}\
${file.reference.snakeyaml.jar}
-test.module.imports=\
+test.module.imports.compile.time=\
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.ir=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.codegen=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.parser=ALL-UNNAMED \
@@ -159,7 +157,10 @@
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \
--add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \
- --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
+ --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
+
+test.module.imports.runtime=\
+ ${test.module.imports.compile.time} \
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \
--add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED
@@ -359,7 +360,7 @@
run.test.jvmargs.common=\
-server \
- ${test.module.imports} \
+ ${test.module.imports.runtime} \
${run.test.jvmargs.external} \
--add-modules jdk.scripting.nashorn.shell \
${nashorn.override.option} \
diff -r d4380ee1cbe9 -r f5f98c9f1884 make/test/JtregNativeHotspot.gmk
--- a/make/test/JtregNativeHotspot.gmk Sat Oct 07 22:45:12 2017 +0900
+++ b/make/test/JtregNativeHotspot.gmk Mon Oct 09 07:08:53 2017 +0000
@@ -59,6 +59,7 @@
$(TOPDIR)/test/hotspot/jtreg/runtime/SameObject \
$(TOPDIR)/test/hotspot/jtreg/runtime/BoolReturn \
$(TOPDIR)/test/hotspot/jtreg/runtime/noClassDefFoundMsg \
+ $(TOPDIR)/test/hotspot/jtreg/runtime/RedefineTests \
$(TOPDIR)/test/hotspot/jtreg/compiler/floatingpoint/ \
$(TOPDIR)/test/hotspot/jtreg/compiler/calls \
$(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorInfo \
@@ -103,6 +104,7 @@
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAClassLoadPrepare := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libMAAThreadStart := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libAllowedFunctions := -lc
+ BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libRedefineDoubleDelete := -lc
endif
ifeq ($(OPENJDK_TARGET_OS), linux)
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2840,6 +2840,44 @@
bind(L_done);
}
+// Code for BigInteger::mulAdd instrinsic
+// out = r0
+// in = r1
+// offset = r2 (already out.length-offset)
+// len = r3
+// k = r4
+//
+// pseudo code from java implementation:
+// carry = 0;
+// offset = out.length-offset - 1;
+// for (int j=len-1; j >= 0; j--) {
+// product = (in[j] & LONG_MASK) * kLong + (out[offset] & LONG_MASK) + carry;
+// out[offset--] = (int)product;
+// carry = product >>> 32;
+// }
+// return (int)carry;
+void MacroAssembler::mul_add(Register out, Register in, Register offset,
+ Register len, Register k) {
+ Label LOOP, END;
+ // pre-loop
+ cmp(len, zr); // cmp, not cbz/cbnz: to use condition twice => less branches
+ csel(out, zr, out, Assembler::EQ);
+ br(Assembler::EQ, END);
+ add(in, in, len, LSL, 2); // in[j+1] address
+ add(offset, out, offset, LSL, 2); // out[offset + 1] address
+ mov(out, zr); // used to keep carry now
+ BIND(LOOP);
+ ldrw(rscratch1, Address(pre(in, -4)));
+ madd(rscratch1, rscratch1, k, out);
+ ldrw(rscratch2, Address(pre(offset, -4)));
+ add(rscratch1, rscratch1, rscratch2);
+ strw(rscratch1, Address(offset));
+ lsr(out, rscratch1, 32);
+ subs(len, len, 1);
+ br(Assembler::NE, LOOP);
+ BIND(END);
+}
+
/**
* Emits code to update CRC-32 with a byte value according to constants in table
*
@@ -3291,6 +3329,7 @@
ldr(dst, Address(dst, ConstMethod::constants_offset()));
ldr(dst, Address(dst, ConstantPool::pool_holder_offset_in_bytes()));
ldr(dst, Address(dst, mirror_offset));
+ resolve_oop_handle(dst);
}
void MacroAssembler::cmp_klass(Register oop, Register trial_klass, Register tmp) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1265,6 +1265,7 @@
void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z,
Register zlen, Register tmp1, Register tmp2, Register tmp3,
Register tmp4, Register tmp5, Register tmp6, Register tmp7);
+ void mul_add(Register out, Register in, Register offs, Register len, Register k);
// ISB may be needed because of a safepoint
void maybe_isb() { isb(); }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3607,6 +3607,63 @@
return start;
}
+ address generate_squareToLen() {
+ // squareToLen algorithm for sizes 1..127 described in java code works
+ // faster than multiply_to_len on some CPUs and slower on others, but
+ // multiply_to_len shows a bit better overall results
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "squareToLen");
+ address start = __ pc();
+
+ const Register x = r0;
+ const Register xlen = r1;
+ const Register z = r2;
+ const Register zlen = r3;
+ const Register y = r4; // == x
+ const Register ylen = r5; // == xlen
+
+ const Register tmp1 = r10;
+ const Register tmp2 = r11;
+ const Register tmp3 = r12;
+ const Register tmp4 = r13;
+ const Register tmp5 = r14;
+ const Register tmp6 = r15;
+ const Register tmp7 = r16;
+
+ RegSet spilled_regs = RegSet::of(y, ylen);
+ BLOCK_COMMENT("Entry:");
+ __ enter();
+ __ push(spilled_regs, sp);
+ __ mov(y, x);
+ __ mov(ylen, xlen);
+ __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+ __ pop(spilled_regs, sp);
+ __ leave();
+ __ ret(lr);
+ return start;
+ }
+
+ address generate_mulAdd() {
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "mulAdd");
+
+ address start = __ pc();
+
+ const Register out = r0;
+ const Register in = r1;
+ const Register offset = r2;
+ const Register len = r3;
+ const Register k = r4;
+
+ BLOCK_COMMENT("Entry:");
+ __ enter();
+ __ mul_add(out, in, offset, len, k);
+ __ leave();
+ __ ret(lr);
+
+ return start;
+ }
+
void ghash_multiply(FloatRegister result_lo, FloatRegister result_hi,
FloatRegister a, FloatRegister b, FloatRegister a1_xor_a0,
FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3, FloatRegister tmp4) {
@@ -4913,6 +4970,14 @@
StubRoutines::_multiplyToLen = generate_multiplyToLen();
}
+ if (UseSquareToLenIntrinsic) {
+ StubRoutines::_squareToLen = generate_squareToLen();
+ }
+
+ if (UseMulAddIntrinsic) {
+ StubRoutines::_mulAdd = generate_mulAdd();
+ }
+
if (UseMontgomeryMultiplyIntrinsic) {
StubCodeMark mark(this, "StubRoutines", "montgomeryMultiply");
MontgomeryMultiplyGenerator g(_masm, /*squaring*/false);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2297,6 +2297,7 @@
ConstantPoolCacheEntry::f1_offset())));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ ldr(obj, Address(obj, mirror_offset));
+ __ resolve_oop_handle(obj);
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/aarch64/vm_version_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -340,6 +340,14 @@
UseMultiplyToLenIntrinsic = true;
}
+ if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
+ UseSquareToLenIntrinsic = true;
+ }
+
+ if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
+ UseMulAddIntrinsic = true;
+ }
+
if (FLAG_IS_DEFAULT(UseBarriersForVolatile)) {
UseBarriersForVolatile = (_features & CPU_DMB_ATOMICS) != 0;
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/arm/macroAssembler_arm.cpp
--- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2899,6 +2899,7 @@
ldr(tmp, Address(tmp, ConstMethod::constants_offset()));
ldr(tmp, Address(tmp, ConstantPool::pool_holder_offset_in_bytes()));
ldr(mirror, Address(tmp, mirror_offset));
+ resolve_oop_handle(mirror);
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/arm/templateTable_arm.cpp
--- a/src/hotspot/cpu/arm/templateTable_arm.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/arm/templateTable_arm.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2963,6 +2963,7 @@
cp_base_offset + ConstantPoolCacheEntry::f1_offset()));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ ldr(Robj, Address(Robj, mirror_offset));
+ __ resolve_oop_handle(Robj);
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/assembler_ppc.hpp
--- a/src/hotspot/cpu/ppc/assembler_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -517,6 +517,9 @@
XXPERMDI_OPCODE= (60u << OPCODE_SHIFT | 10u << 3),
XXMRGHW_OPCODE = (60u << OPCODE_SHIFT | 18u << 3),
XXMRGLW_OPCODE = (60u << OPCODE_SHIFT | 50u << 3),
+ XXSPLTW_OPCODE = (60u << OPCODE_SHIFT | 164u << 2),
+ XXLXOR_OPCODE = (60u << OPCODE_SHIFT | 154u << 3),
+ XXLEQV_OPCODE = (60u << OPCODE_SHIFT | 186u << 3),
// Vector Permute and Formatting
VPKPX_OPCODE = (4u << OPCODE_SHIFT | 782u ),
@@ -1125,6 +1128,7 @@
static int vsplti_sim(int x) { return opp_u_field(x, 15, 11); } // for vsplti* instructions
static int vsldoi_shb(int x) { return opp_u_field(x, 25, 22); } // for vsldoi instruction
static int vcmp_rc( int x) { return opp_u_field(x, 21, 21); } // for vcmp* instructions
+ static int xxsplt_uim(int x) { return opp_u_field(x, 15, 14); } // for xxsplt* instructions
//static int xo1( int x) { return opp_u_field(x, 29, 21); }// is contained in our opcodes
//static int xo2( int x) { return opp_u_field(x, 30, 21); }// is contained in our opcodes
@@ -2155,6 +2159,11 @@
inline void xxpermdi( VectorSRegister d, VectorSRegister a, VectorSRegister b, int dm);
inline void xxmrghw( VectorSRegister d, VectorSRegister a, VectorSRegister b);
inline void xxmrglw( VectorSRegister d, VectorSRegister a, VectorSRegister b);
+ inline void mtvsrd( VectorSRegister d, Register a);
+ inline void mtvsrwz( VectorSRegister d, Register a);
+ inline void xxspltw( VectorSRegister d, VectorSRegister b, int ui2);
+ inline void xxlxor( VectorSRegister d, VectorSRegister a, VectorSRegister b);
+ inline void xxleqv( VectorSRegister d, VectorSRegister a, VectorSRegister b);
// VSX Extended Mnemonics
inline void xxspltd( VectorSRegister d, VectorSRegister a, int x);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/assembler_ppc.inline.hpp
--- a/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/assembler_ppc.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -761,9 +761,14 @@
// Vector-Scalar (VSX) instructions.
inline void Assembler::lxvd2x( VectorSRegister d, Register s1) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); }
inline void Assembler::lxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( LXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); }
-inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra(0) | rb(s1)); }
-inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrt(d) | ra0mem(s1) | rb(s2)); }
-inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
+inline void Assembler::stxvd2x( VectorSRegister d, Register s1) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra(0) | rb(s1)); }
+inline void Assembler::stxvd2x( VectorSRegister d, Register s1, Register s2) { emit_int32( STXVD2X_OPCODE | vsrs(d) | ra0mem(s1) | rb(s2)); }
+inline void Assembler::mtvsrd( VectorSRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d) | ra(a)); }
+inline void Assembler::mtvsrwz( VectorSRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d) | ra(a)); }
+inline void Assembler::xxspltw( VectorSRegister d, VectorSRegister b, int ui2) { emit_int32( XXSPLTW_OPCODE | vsrt(d) | vsrb(b) | xxsplt_uim(uimm(ui2,2))); }
+inline void Assembler::xxlxor( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXLXOR_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
+inline void Assembler::xxleqv( VectorSRegister d, VectorSRegister a, VectorSRegister b) { emit_int32( XXLEQV_OPCODE | vsrt(d) | vsra(a) | vsrb(b)); }
+inline void Assembler::mtvrd( VectorRegister d, Register a) { emit_int32( MTVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mfvrd( Register a, VectorRegister d) { emit_int32( MFVSRD_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mtvrwz( VectorRegister d, Register a) { emit_int32( MTVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
inline void Assembler::mfvrwz( Register a, VectorRegister d) { emit_int32( MFVSRWZ_OPCODE | vsrt(d->to_vsr()) | ra(a)); }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/globals_ppc.hpp
--- a/src/hotspot/cpu/ppc/globals_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/globals_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -32,7 +32,7 @@
// Sets the default values for platform dependent flags used by the runtime system.
// (see globals.hpp)
-define_pd_global(bool, ShareVtableStubs, false); // Improves performance markedly for mtrt and compress.
+define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this.
@@ -103,6 +103,9 @@
"CPU Version: x for PowerX. Currently recognizes Power5 to " \
"Power8. Default is 0. Newer CPUs will be recognized as Power8.") \
\
+ product(bool, SuperwordUseVSX, false, \
+ "Use Power8 VSX instructions for superword optimization.") \
+ \
/* Reoptimize code-sequences of calls at runtime, e.g. replace an */ \
/* indirect call by a direct call. */ \
product(bool, ReoptimizeCallSequences, true, \
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3382,6 +3382,7 @@
ld(mirror, in_bytes(ConstMethod::constants_offset()), const_method);
ld(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror);
ld(mirror, in_bytes(Klass::java_mirror_offset()), mirror);
+ resolve_oop_handle(mirror);
}
// Clear Array
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/ppc.ad
--- a/src/hotspot/cpu/ppc/ppc.ad Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/ppc.ad Mon Oct 09 07:08:53 2017 +0000
@@ -254,6 +254,73 @@
reg_def SR_SPEFSCR(SOC, SOC, Op_RegP, 4, SR_SPEFSCR->as_VMReg()); // v
reg_def SR_PPR( SOC, SOC, Op_RegP, 5, SR_PPR->as_VMReg()); // v
+// ----------------------------
+// Vector-Scalar Registers
+// ----------------------------
+ reg_def VSR0 ( SOC, SOC, Op_VecX, 0, NULL);
+ reg_def VSR1 ( SOC, SOC, Op_VecX, 1, NULL);
+ reg_def VSR2 ( SOC, SOC, Op_VecX, 2, NULL);
+ reg_def VSR3 ( SOC, SOC, Op_VecX, 3, NULL);
+ reg_def VSR4 ( SOC, SOC, Op_VecX, 4, NULL);
+ reg_def VSR5 ( SOC, SOC, Op_VecX, 5, NULL);
+ reg_def VSR6 ( SOC, SOC, Op_VecX, 6, NULL);
+ reg_def VSR7 ( SOC, SOC, Op_VecX, 7, NULL);
+ reg_def VSR8 ( SOC, SOC, Op_VecX, 8, NULL);
+ reg_def VSR9 ( SOC, SOC, Op_VecX, 9, NULL);
+ reg_def VSR10 ( SOC, SOC, Op_VecX, 10, NULL);
+ reg_def VSR11 ( SOC, SOC, Op_VecX, 11, NULL);
+ reg_def VSR12 ( SOC, SOC, Op_VecX, 12, NULL);
+ reg_def VSR13 ( SOC, SOC, Op_VecX, 13, NULL);
+ reg_def VSR14 ( SOC, SOC, Op_VecX, 14, NULL);
+ reg_def VSR15 ( SOC, SOC, Op_VecX, 15, NULL);
+ reg_def VSR16 ( SOC, SOC, Op_VecX, 16, NULL);
+ reg_def VSR17 ( SOC, SOC, Op_VecX, 17, NULL);
+ reg_def VSR18 ( SOC, SOC, Op_VecX, 18, NULL);
+ reg_def VSR19 ( SOC, SOC, Op_VecX, 19, NULL);
+ reg_def VSR20 ( SOC, SOC, Op_VecX, 20, NULL);
+ reg_def VSR21 ( SOC, SOC, Op_VecX, 21, NULL);
+ reg_def VSR22 ( SOC, SOC, Op_VecX, 22, NULL);
+ reg_def VSR23 ( SOC, SOC, Op_VecX, 23, NULL);
+ reg_def VSR24 ( SOC, SOC, Op_VecX, 24, NULL);
+ reg_def VSR25 ( SOC, SOC, Op_VecX, 25, NULL);
+ reg_def VSR26 ( SOC, SOC, Op_VecX, 26, NULL);
+ reg_def VSR27 ( SOC, SOC, Op_VecX, 27, NULL);
+ reg_def VSR28 ( SOC, SOC, Op_VecX, 28, NULL);
+ reg_def VSR29 ( SOC, SOC, Op_VecX, 29, NULL);
+ reg_def VSR30 ( SOC, SOC, Op_VecX, 30, NULL);
+ reg_def VSR31 ( SOC, SOC, Op_VecX, 31, NULL);
+ reg_def VSR32 ( SOC, SOC, Op_VecX, 32, NULL);
+ reg_def VSR33 ( SOC, SOC, Op_VecX, 33, NULL);
+ reg_def VSR34 ( SOC, SOC, Op_VecX, 34, NULL);
+ reg_def VSR35 ( SOC, SOC, Op_VecX, 35, NULL);
+ reg_def VSR36 ( SOC, SOC, Op_VecX, 36, NULL);
+ reg_def VSR37 ( SOC, SOC, Op_VecX, 37, NULL);
+ reg_def VSR38 ( SOC, SOC, Op_VecX, 38, NULL);
+ reg_def VSR39 ( SOC, SOC, Op_VecX, 39, NULL);
+ reg_def VSR40 ( SOC, SOC, Op_VecX, 40, NULL);
+ reg_def VSR41 ( SOC, SOC, Op_VecX, 41, NULL);
+ reg_def VSR42 ( SOC, SOC, Op_VecX, 42, NULL);
+ reg_def VSR43 ( SOC, SOC, Op_VecX, 43, NULL);
+ reg_def VSR44 ( SOC, SOC, Op_VecX, 44, NULL);
+ reg_def VSR45 ( SOC, SOC, Op_VecX, 45, NULL);
+ reg_def VSR46 ( SOC, SOC, Op_VecX, 46, NULL);
+ reg_def VSR47 ( SOC, SOC, Op_VecX, 47, NULL);
+ reg_def VSR48 ( SOC, SOC, Op_VecX, 48, NULL);
+ reg_def VSR49 ( SOC, SOC, Op_VecX, 49, NULL);
+ reg_def VSR50 ( SOC, SOC, Op_VecX, 50, NULL);
+ reg_def VSR51 ( SOC, SOC, Op_VecX, 51, NULL);
+ reg_def VSR52 ( SOC, SOC, Op_VecX, 52, NULL);
+ reg_def VSR53 ( SOC, SOC, Op_VecX, 53, NULL);
+ reg_def VSR54 ( SOC, SOC, Op_VecX, 54, NULL);
+ reg_def VSR55 ( SOC, SOC, Op_VecX, 55, NULL);
+ reg_def VSR56 ( SOC, SOC, Op_VecX, 56, NULL);
+ reg_def VSR57 ( SOC, SOC, Op_VecX, 57, NULL);
+ reg_def VSR58 ( SOC, SOC, Op_VecX, 58, NULL);
+ reg_def VSR59 ( SOC, SOC, Op_VecX, 59, NULL);
+ reg_def VSR60 ( SOC, SOC, Op_VecX, 60, NULL);
+ reg_def VSR61 ( SOC, SOC, Op_VecX, 61, NULL);
+ reg_def VSR62 ( SOC, SOC, Op_VecX, 62, NULL);
+ reg_def VSR63 ( SOC, SOC, Op_VecX, 63, NULL);
// ----------------------------
// Specify priority of register selection within phases of register
@@ -385,6 +452,73 @@
);
alloc_class chunk3 (
+ VSR0,
+ VSR1,
+ VSR2,
+ VSR3,
+ VSR4,
+ VSR5,
+ VSR6,
+ VSR7,
+ VSR8,
+ VSR9,
+ VSR10,
+ VSR11,
+ VSR12,
+ VSR13,
+ VSR14,
+ VSR15,
+ VSR16,
+ VSR17,
+ VSR18,
+ VSR19,
+ VSR20,
+ VSR21,
+ VSR22,
+ VSR23,
+ VSR24,
+ VSR25,
+ VSR26,
+ VSR27,
+ VSR28,
+ VSR29,
+ VSR30,
+ VSR31,
+ VSR32,
+ VSR33,
+ VSR34,
+ VSR35,
+ VSR36,
+ VSR37,
+ VSR38,
+ VSR39,
+ VSR40,
+ VSR41,
+ VSR42,
+ VSR43,
+ VSR44,
+ VSR45,
+ VSR46,
+ VSR47,
+ VSR48,
+ VSR49,
+ VSR50,
+ VSR51,
+ VSR52,
+ VSR53,
+ VSR54,
+ VSR55,
+ VSR56,
+ VSR57,
+ VSR58,
+ VSR59,
+ VSR60,
+ VSR61,
+ VSR62,
+ VSR63
+);
+
+alloc_class chunk4 (
// special registers
// These registers are not allocated, but used for nodes generated by postalloc expand.
SR_XER,
@@ -769,6 +903,45 @@
F31, F31_H // nv!
);
+// ----------------------------
+// Vector-Scalar Register Class
+// ----------------------------
+
+reg_class vs_reg(
+ VSR32,
+ VSR33,
+ VSR34,
+ VSR35,
+ VSR36,
+ VSR37,
+ VSR38,
+ VSR39,
+ VSR40,
+ VSR41,
+ VSR42,
+ VSR43,
+ VSR44,
+ VSR45,
+ VSR46,
+ VSR47,
+ VSR48,
+ VSR49,
+ VSR50,
+ VSR51
+// VSR52, // nv!
+// VSR53, // nv!
+// VSR54, // nv!
+// VSR55, // nv!
+// VSR56, // nv!
+// VSR57, // nv!
+// VSR58, // nv!
+// VSR59, // nv!
+// VSR60, // nv!
+// VSR61, // nv!
+// VSR62, // nv!
+// VSR63 // nv!
+);
+
%}
//----------DEFINITION BLOCK---------------------------------------------------
@@ -1502,7 +1675,7 @@
if (reg < 64+64) return rc_float;
// Between float regs & stack are the flags regs.
- assert(OptoReg::is_stack(reg), "blow up if spilling flags");
+ assert(OptoReg::is_stack(reg) || reg < 64+64+64, "blow up if spilling flags");
return rc_stack;
}
@@ -2048,14 +2221,24 @@
// Vector width in bytes.
const int Matcher::vector_width_in_bytes(BasicType bt) {
- assert(MaxVectorSize == 8, "");
- return 8;
+ if (SuperwordUseVSX) {
+ assert(MaxVectorSize == 16, "");
+ return 16;
+ } else {
+ assert(MaxVectorSize == 8, "");
+ return 8;
+ }
}
// Vector ideal reg.
const uint Matcher::vector_ideal_reg(int size) {
- assert(MaxVectorSize == 8 && size == 8, "");
- return Op_RegL;
+ if (SuperwordUseVSX) {
+ assert(MaxVectorSize == 16 && size == 16, "");
+ return Op_VecX;
+ } else {
+ assert(MaxVectorSize == 8 && size == 8, "");
+ return Op_RegL;
+ }
}
const uint Matcher::vector_shift_count_ideal_reg(int size) {
@@ -2075,7 +2258,7 @@
// PPC doesn't support misaligned vectors store/load.
const bool Matcher::misaligned_vectors_ok() {
- return false;
+ return !AlignVector; // can be changed by flag
}
// PPC AES support not yet implemented
@@ -2217,10 +2400,31 @@
F13_num
};
+const MachRegisterNumbers vsarg_reg[64] = {
+ VSR0_num, VSR1_num, VSR2_num, VSR3_num,
+ VSR4_num, VSR5_num, VSR6_num, VSR7_num,
+ VSR8_num, VSR9_num, VSR10_num, VSR11_num,
+ VSR12_num, VSR13_num, VSR14_num, VSR15_num,
+ VSR16_num, VSR17_num, VSR18_num, VSR19_num,
+ VSR20_num, VSR21_num, VSR22_num, VSR23_num,
+ VSR24_num, VSR23_num, VSR24_num, VSR25_num,
+ VSR28_num, VSR29_num, VSR30_num, VSR31_num,
+ VSR32_num, VSR33_num, VSR34_num, VSR35_num,
+ VSR36_num, VSR37_num, VSR38_num, VSR39_num,
+ VSR40_num, VSR41_num, VSR42_num, VSR43_num,
+ VSR44_num, VSR45_num, VSR46_num, VSR47_num,
+ VSR48_num, VSR49_num, VSR50_num, VSR51_num,
+ VSR52_num, VSR53_num, VSR54_num, VSR55_num,
+ VSR56_num, VSR57_num, VSR58_num, VSR59_num,
+ VSR60_num, VSR61_num, VSR62_num, VSR63_num
+};
+
const int num_iarg_registers = sizeof(iarg_reg) / sizeof(iarg_reg[0]);
const int num_farg_registers = sizeof(farg_reg) / sizeof(farg_reg[0]);
+const int num_vsarg_registers = sizeof(vsarg_reg) / sizeof(vsarg_reg[0]);
+
// Return whether or not this register is ever used as an argument. This
// function is used on startup to build the trampoline stubs in generateOptoStub.
// Registers not mentioned will be killed by the VM call in the trampoline, and
@@ -2552,6 +2756,115 @@
return nodes;
}
+typedef struct {
+ loadConL_hiNode *_large_hi;
+ loadConL_loNode *_large_lo;
+ mtvsrdNode *_moved;
+ xxspltdNode *_replicated;
+ loadConLNode *_small;
+ MachNode *_last;
+} loadConLReplicatedNodesTuple;
+
+loadConLReplicatedNodesTuple loadConLReplicatedNodesTuple_create(Compile *C, PhaseRegAlloc *ra_, Node *toc, immLOper *immSrc,
+ vecXOper *dst, immI_0Oper *zero,
+ OptoReg::Name reg_second, OptoReg::Name reg_first,
+ OptoReg::Name reg_vec_second, OptoReg::Name reg_vec_first) {
+ loadConLReplicatedNodesTuple nodes;
+
+ const bool large_constant_pool = true; // TODO: PPC port C->cfg()->_consts_size > 4000;
+ if (large_constant_pool) {
+ // Create new nodes.
+ loadConL_hiNode *m1 = new loadConL_hiNode();
+ loadConL_loNode *m2 = new loadConL_loNode();
+ mtvsrdNode *m3 = new mtvsrdNode();
+ xxspltdNode *m4 = new xxspltdNode();
+
+ // inputs for new nodes
+ m1->add_req(NULL, toc);
+ m2->add_req(NULL, m1);
+ m3->add_req(NULL, m2);
+ m4->add_req(NULL, m3);
+
+ // operands for new nodes
+ m1->_opnds[0] = new iRegLdstOper(); // dst
+ m1->_opnds[1] = immSrc; // src
+ m1->_opnds[2] = new iRegPdstOper(); // toc
+
+ m2->_opnds[0] = new iRegLdstOper(); // dst
+ m2->_opnds[1] = immSrc; // src
+ m2->_opnds[2] = new iRegLdstOper(); // base
+
+ m3->_opnds[0] = new vecXOper(); // dst
+ m3->_opnds[1] = new iRegLdstOper(); // src
+
+ m4->_opnds[0] = new vecXOper(); // dst
+ m4->_opnds[1] = new vecXOper(); // src
+ m4->_opnds[2] = zero;
+
+ // Initialize ins_attrib TOC fields.
+ m1->_const_toc_offset = -1;
+ m2->_const_toc_offset_hi_node = m1;
+
+ // Initialize ins_attrib instruction offset.
+ m1->_cbuf_insts_offset = -1;
+
+ // register allocation for new nodes
+ ra_->set_pair(m1->_idx, reg_second, reg_first);
+ ra_->set_pair(m2->_idx, reg_second, reg_first);
+ ra_->set1(m3->_idx, reg_second);
+ ra_->set2(m3->_idx, reg_vec_first);
+ ra_->set_pair(m4->_idx, reg_vec_second, reg_vec_first);
+
+ // Create result.
+ nodes._large_hi = m1;
+ nodes._large_lo = m2;
+ nodes._moved = m3;
+ nodes._replicated = m4;
+ nodes._small = NULL;
+ nodes._last = nodes._replicated;
+ assert(m2->bottom_type()->isa_long(), "must be long");
+ } else {
+ loadConLNode *m2 = new loadConLNode();
+ mtvsrdNode *m3 = new mtvsrdNode();
+ xxspltdNode *m4 = new xxspltdNode();
+
+ // inputs for new nodes
+ m2->add_req(NULL, toc);
+
+ // operands for new nodes
+ m2->_opnds[0] = new iRegLdstOper(); // dst
+ m2->_opnds[1] = immSrc; // src
+ m2->_opnds[2] = new iRegPdstOper(); // toc
+
+ m3->_opnds[0] = new vecXOper(); // dst
+ m3->_opnds[1] = new iRegLdstOper(); // src
+
+ m4->_opnds[0] = new vecXOper(); // dst
+ m4->_opnds[1] = new vecXOper(); // src
+ m4->_opnds[2] = zero;
+
+ // Initialize ins_attrib instruction offset.
+ m2->_cbuf_insts_offset = -1;
+ ra_->set1(m3->_idx, reg_second);
+ ra_->set2(m3->_idx, reg_vec_first);
+ ra_->set_pair(m4->_idx, reg_vec_second, reg_vec_first);
+
+ // register allocation for new nodes
+ ra_->set_pair(m2->_idx, reg_second, reg_first);
+
+ // Create result.
+ nodes._large_hi = NULL;
+ nodes._large_lo = NULL;
+ nodes._small = m2;
+ nodes._moved = m3;
+ nodes._replicated = m4;
+ nodes._last = nodes._replicated;
+ assert(m2->bottom_type()->isa_long(), "must be long");
+ }
+
+ return nodes;
+}
+
%} // source
encode %{
@@ -3212,6 +3525,27 @@
assert(loadConLNodes._last->bottom_type()->isa_long(), "must be long");
%}
+ enc_class postalloc_expand_load_replF_constant_vsx(vecX dst, immF src, iRegLdst toc) %{
+ // Create new nodes.
+
+ // Make an operand with the bit pattern to load as float.
+ immLOper *op_repl = new immLOper((jlong)replicate_immF(op_src->constantF()));
+ immI_0Oper *op_zero = new immI_0Oper(0);
+
+ loadConLReplicatedNodesTuple loadConLNodes =
+ loadConLReplicatedNodesTuple_create(C, ra_, n_toc, op_repl, op_dst, op_zero,
+ OptoReg::Name(R20_H_num), OptoReg::Name(R20_num),
+ OptoReg::Name(VSR11_num), OptoReg::Name(VSR10_num));
+
+ // Push new nodes.
+ if (loadConLNodes._large_hi) { nodes->push(loadConLNodes._large_hi); }
+ if (loadConLNodes._large_lo) { nodes->push(loadConLNodes._large_lo); }
+ if (loadConLNodes._moved) { nodes->push(loadConLNodes._moved); }
+ if (loadConLNodes._last) { nodes->push(loadConLNodes._last); }
+
+ assert(nodes->length() >= 1, "must have created at least 1 node");
+ %}
+
// This enc_class is needed so that scheduler gets proper
// input mapping for latency computation.
enc_class enc_poll(immI dst, iRegLdst poll) %{
@@ -3840,6 +4174,14 @@
//
// Formats are generated automatically for constants and base registers.
+operand vecX() %{
+ constraint(ALLOC_IN_RC(vs_reg));
+ match(VecX);
+
+ format %{ %}
+ interface(REG_INTER);
+%}
+
//----------Simple Operands----------------------------------------------------
// Immediate Operands
@@ -5372,6 +5714,20 @@
ins_pipe(pipe_class_memory);
%}
+// Load Aligned Packed Byte
+instruct loadV16(vecX dst, indirect mem) %{
+ predicate(n->as_LoadVector()->memory_size() == 16);
+ match(Set dst (LoadVector mem));
+ ins_cost(MEMORY_REF_COST);
+
+ format %{ "LXVD2X $dst, $mem \t// load 16-byte Vector" %}
+ size(4);
+ ins_encode %{
+ __ lxvd2x($dst$$VectorSRegister, $mem$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Load Range, range = array length (=jint)
instruct loadRange(iRegIdst dst, memory mem) %{
match(Set dst (LoadRange mem));
@@ -6368,6 +6724,20 @@
ins_pipe(pipe_class_memory);
%}
+// Store Packed Byte long register to memory
+instruct storeV16(indirect mem, vecX src) %{
+ predicate(n->as_StoreVector()->memory_size() == 16);
+ match(Set mem (StoreVector mem src));
+ ins_cost(MEMORY_REF_COST);
+
+ format %{ "STXVD2X $mem, $src \t// store 16-byte Vector" %}
+ size(4);
+ ins_encode %{
+ __ stxvd2x($src$$VectorSRegister, $mem$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Store Compressed Oop
instruct storeN(memory dst, iRegN_P2N src) %{
match(Set dst (StoreN dst src));
@@ -13239,6 +13609,26 @@
ins_pipe(pipe_class_default);
%}
+instruct mtvsrwz(vecX temp1, iRegIsrc src) %{
+ effect(DEF temp1, USE src);
+
+ size(4);
+ ins_encode %{
+ __ mtvsrwz($temp1$$VectorSRegister, $src$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct xxspltw(vecX dst, vecX src, immI8 imm1) %{
+ effect(DEF dst, USE src, USE imm1);
+
+ size(4);
+ ins_encode %{
+ __ xxspltw($dst$$VectorSRegister, $src$$VectorSRegister, $imm1$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
//---------- Replicate Vector Instructions ------------------------------------
// Insrdi does replicate if src == dst.
@@ -13318,6 +13708,46 @@
ins_pipe(pipe_class_default);
%}
+instruct repl16B_reg_Ex(vecX dst, iRegIsrc src) %{
+ match(Set dst (ReplicateB src));
+ predicate(n->as_Vector()->length() == 16);
+
+ expand %{
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 imm1 %{ (int) 1 %}
+ moveReg(tmpL, src);
+ repl56(tmpL);
+ repl48(tmpL);
+ mtvsrwz(tmpV, tmpL);
+ xxspltw(dst, tmpV, imm1);
+ %}
+%}
+
+instruct repl16B_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateB zero));
+ predicate(n->as_Vector()->length() == 16);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl16B_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateB src));
+ predicate(n->as_Vector()->length() == 16);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct repl4S_reg_Ex(iRegLdst dst, iRegIsrc src) %{
match(Set dst (ReplicateS src));
predicate(n->as_Vector()->length() == 4);
@@ -13352,6 +13782,46 @@
ins_pipe(pipe_class_default);
%}
+instruct repl8S_reg_Ex(vecX dst, iRegIsrc src) %{
+ match(Set dst (ReplicateS src));
+ predicate(n->as_Vector()->length() == 8);
+
+ expand %{
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ moveReg(tmpL, src);
+ repl48(tmpL);
+ repl32(tmpL);
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl8S_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateS zero));
+ predicate(n->as_Vector()->length() == 8);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate8S" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl8S_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateS src));
+ predicate(n->as_Vector()->length() == 8);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
instruct repl2I_reg_Ex(iRegLdst dst, iRegIsrc src) %{
match(Set dst (ReplicateI src));
predicate(n->as_Vector()->length() == 2);
@@ -13386,6 +13856,46 @@
ins_pipe(pipe_class_default);
%}
+instruct repl4I_reg_Ex(vecX dst, iRegIsrc src) %{
+ match(Set dst (ReplicateI src));
+ predicate(n->as_Vector()->length() == 4);
+ ins_cost(2 * DEFAULT_COST);
+
+ expand %{
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ moveReg(tmpL, src);
+ repl32(tmpL);
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl4I_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateI zero));
+ predicate(n->as_Vector()->length() == 4);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate4I" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl4I_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateI src));
+ predicate(n->as_Vector()->length() == 4);
+
+ format %{ "XXLEQV $dst, $dst, $dst \t// replicate4I" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// Move float to int register via stack, replicate.
instruct repl2F_reg_Ex(iRegLdst dst, regF src) %{
match(Set dst (ReplicateF src));
@@ -13484,6 +13994,154 @@
%}
+instruct repl4F_reg_Ex(vecX dst, regF src) %{
+ match(Set dst (ReplicateF src));
+ predicate(n->as_Vector()->length() == 4);
+ ins_cost(2 * MEMORY_REF_COST + DEFAULT_COST);
+ expand %{
+ stackSlotL tmpS;
+ iRegIdst tmpI;
+ iRegLdst tmpL;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+
+ moveF2I_reg_stack(tmpS, src); // Move float to stack.
+ moveF2I_stack_reg(tmpI, tmpS); // Move stack to int reg.
+ moveReg(tmpL, tmpI); // Move int to long reg.
+ repl32(tmpL); // Replicate bitpattern.
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl4F_immF_Ex(vecX dst, immF src) %{
+ match(Set dst (ReplicateF src));
+ predicate(n->as_Vector()->length() == 4);
+ ins_cost(10 * DEFAULT_COST);
+
+ postalloc_expand( postalloc_expand_load_replF_constant_vsx(dst, src, constanttablebase) );
+%}
+
+instruct repl4F_immF0(vecX dst, immF_0 zero) %{
+ match(Set dst (ReplicateF zero));
+ predicate(n->as_Vector()->length() == 4);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate4F" %}
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2D_reg_Ex(vecX dst, regD src) %{
+ match(Set dst (ReplicateD src));
+ predicate(n->as_Vector()->length() == 2);
+ expand %{
+ stackSlotL tmpS;
+ iRegLdst tmpL;
+ iRegLdst tmp;
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ moveD2L_reg_stack(tmpS, src);
+ moveD2L_stack_reg(tmpL, tmpS);
+ mtvsrd(tmpV, tmpL);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl2D_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateD zero));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate2D" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2D_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateD src));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct mtvsrd(vecX dst, iRegLsrc src) %{
+ predicate(false);
+ effect(DEF dst, USE src);
+
+ format %{ "MTVSRD $dst, $src \t// Move to 16-byte register"%}
+ size(4);
+ ins_encode %{
+ __ mtvsrd($dst$$VectorSRegister, $src$$Register);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct xxspltd(vecX dst, vecX src, immI8 zero) %{
+ effect(DEF dst, USE src, USE zero);
+
+ format %{ "XXSPLATD $dst, $src, $zero \t// Permute 16-byte register"%}
+ size(4);
+ ins_encode %{
+ __ xxpermdi($dst$$VectorSRegister, $src$$VectorSRegister, $src$$VectorSRegister, $zero$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct xxpermdi(vecX dst, vecX src1, vecX src2, immI8 zero) %{
+ effect(DEF dst, USE src1, USE src2, USE zero);
+
+ format %{ "XXPERMDI $dst, $src1, $src2, $zero \t// Permute 16-byte register"%}
+ size(4);
+ ins_encode %{
+ __ xxpermdi($dst$$VectorSRegister, $src1$$VectorSRegister, $src2$$VectorSRegister, $zero$$constant);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2L_reg_Ex(vecX dst, iRegLsrc src) %{
+ match(Set dst (ReplicateL src));
+ predicate(n->as_Vector()->length() == 2);
+ expand %{
+ vecX tmpV;
+ immI8 zero %{ (int) 0 %}
+ mtvsrd(tmpV, src);
+ xxpermdi(dst, tmpV, tmpV, zero);
+ %}
+%}
+
+instruct repl2L_immI0(vecX dst, immI_0 zero) %{
+ match(Set dst (ReplicateL zero));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLXOR $dst, $zero \t// replicate2L" %}
+ size(4);
+ ins_encode %{
+ __ xxlxor($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
+instruct repl2L_immIminus1(vecX dst, immI_minus1 src) %{
+ match(Set dst (ReplicateL src));
+ predicate(n->as_Vector()->length() == 2);
+
+ format %{ "XXLEQV $dst, $src \t// replicate16B" %}
+ size(4);
+ ins_encode %{
+ __ xxleqv($dst$$VectorSRegister, $dst$$VectorSRegister, $dst$$VectorSRegister);
+ %}
+ ins_pipe(pipe_class_default);
+%}
+
// ============================================================================
// Safepoint Instruction
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/register_definitions_ppc.cpp
--- a/src/hotspot/cpu/ppc/register_definitions_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/register_definitions_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -31,3 +31,5 @@
REGISTER_DEFINITION(Register, noreg);
REGISTER_DEFINITION(FloatRegister, fnoreg);
+
+REGISTER_DEFINITION(VectorSRegister, vsnoreg);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/register_ppc.hpp
--- a/src/hotspot/cpu/ppc/register_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/register_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -677,7 +677,7 @@
* 2 // register halves
+ ConditionRegisterImpl::number_of_registers // condition code registers
+ SpecialRegisterImpl::number_of_registers // special registers
- + VectorRegisterImpl::number_of_registers // VSX registers
+ + VectorSRegisterImpl::number_of_registers // VSX registers
};
static const int max_gpr;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -479,8 +479,8 @@
// Is vector's size (in bytes) bigger than a size saved by default?
bool SharedRuntime::is_wide_vector(int size) {
- // Note, MaxVectorSize == 8 on PPC64.
- assert(size <= 8, "%d bytes vectors are not supported", size);
+ // Note, MaxVectorSize == 8/16 on PPC64.
+ assert(size <= (SuperwordUseVSX ? 16 : 8), "%d bytes vectors are not supported", size);
return size > 8;
}
@@ -2234,9 +2234,6 @@
__ release();
// TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
__ stw(R0, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
// The JNI call
@@ -2393,9 +2390,6 @@
__ release();
// TODO: PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
__ stw(R0, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
__ bind(after_transition);
// Reguard any pages if necessary.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
--- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1470,10 +1470,6 @@
// TODO PPC port assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
__ stw(R0, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
-
//=============================================================================
// Call the native method. Argument registers must not have been
// overwritten since "__ call_stub(signature_handler);" (except for
@@ -1594,9 +1590,6 @@
__ li(R0/*thread_state*/, _thread_in_Java);
__ release();
__ stw(R0/*thread_state*/, thread_(thread_state));
- if (UseMembar) {
- __ fence();
- }
if (CheckJNICalls) {
// clear_pending_jni_exception_check
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/templateTable_ppc_64.cpp
--- a/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/templateTable_ppc_64.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2224,6 +2224,7 @@
if (is_static) {
__ ld(Robj, in_bytes(cp_base_offset) + in_bytes(ConstantPoolCacheEntry::f1_offset()), Rcache);
__ ld(Robj, in_bytes(Klass::java_mirror_offset()), Robj);
+ __ resolve_oop_handle(Robj);
// Acquire not needed here. Following access has an address dependency on this value.
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/ppc/vm_version_ppc.cpp
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -107,7 +107,17 @@
// TODO: PPC port PdScheduling::power6SectorSize = 0x20;
}
- MaxVectorSize = 8;
+ if (PowerArchitecturePPC64 >= 8) {
+ if (FLAG_IS_DEFAULT(SuperwordUseVSX)) {
+ FLAG_SET_ERGO(bool, SuperwordUseVSX, true);
+ }
+ } else {
+ if (SuperwordUseVSX) {
+ warning("SuperwordUseVSX specified, but needs at least Power8.");
+ FLAG_SET_DEFAULT(SuperwordUseVSX, false);
+ }
+ }
+ MaxVectorSize = SuperwordUseVSX ? 16 : 8;
#endif
// Create and print feature-string.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/s390/assembler_s390.hpp
--- a/src/hotspot/cpu/s390/assembler_s390.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/assembler_s390.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1276,6 +1276,13 @@
// Test under Mask
#define VTM_ZOPC (unsigned long)(0xe7L << 40 | 0xd8L << 0) // Like TM, set CC according to state of selected bits.
+//---< Vector String Instructions >---
+#define VFAE_ZOPC (unsigned long)(0xe7L << 40 | 0x82L << 0) // Find any element
+#define VFEE_ZOPC (unsigned long)(0xe7L << 40 | 0x80L << 0) // Find element equal
+#define VFENE_ZOPC (unsigned long)(0xe7L << 40 | 0x81L << 0) // Find element not equal
+#define VSTRC_ZOPC (unsigned long)(0xe7L << 40 | 0x8aL << 0) // String range compare
+#define VISTR_ZOPC (unsigned long)(0xe7L << 40 | 0x5cL << 0) // Isolate String
+
//--------------------------------
//-- Miscellaneous Operations --
@@ -1475,10 +1482,18 @@
VRET_QW = 4
};
- // Vector Operation Condition Code Control.
- enum VOpCCC {
- VOP_CCIGN = 0, // ignore, don't set CC
- VOP_CCSET = 1 // set the CC
+ // Vector Operation Result Control.
+ // This is a set of flags used in some vector instructions to control
+ // the result (side) effects of instruction execution.
+ enum VOpRC {
+ VOPRC_CCSET = 0b0001, // set the CC.
+ VOPRC_CCIGN = 0b0000, // ignore, don't set CC.
+ VOPRC_ZS = 0b0010, // Zero Search. Additional, elementwise, comparison against zero.
+ VOPRC_NOZS = 0b0000, // No Zero Search.
+ VOPRC_RTBYTEIX = 0b0100, // generate byte index to lowest element with true comparison.
+ VOPRC_RTBITVEC = 0b0000, // generate bit vector, all 1s for true, all 0s for false element comparisons.
+ VOPRC_INVERT = 0b1000, // invert comparison results.
+ VOPRC_NOINVERT = 0b0000 // use comparison results as is, do not invert.
};
// Inverse condition code, i.e. determine "15 - cc" for a given condition code cc.
@@ -1625,10 +1640,15 @@
return uimm4(ix, pos, 48);
}
- // Vector Operation Condition Code Control. 4-bit field, one bit of which indicates if the condition code is to be set by the operation.
- static int64_t vccc_mask(int64_t flag, int pos) {
- assert((flag == VOP_CCIGN) || (flag == VOP_CCSET), "VCCC flag value out of range");
- return uimm4(flag, pos, 48);
+ // Vector Operation Result Control. 4-bit field.
+ static int64_t voprc_any(int64_t flags, int pos, int64_t allowed_flags = 0b1111) {
+ assert((flags & allowed_flags) == flags, "Invalid VOPRC_* flag combination: %d", (int)flags);
+ return uimm4(flags, pos, 48);
+ }
+
+ // Vector Operation Result Control. Condition code setting.
+ static int64_t voprc_ccmask(int64_t flags, int pos) {
+ return voprc_any(flags, pos, VOPRC_CCIGN | VOPRC_CCSET);
}
public:
@@ -2772,6 +2792,31 @@
// Test under Mask
inline void z_vtm( VectorRegister v1, VectorRegister v2);
+ //---< Vector String Instructions >---
+ inline void z_vfae( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find any element
+ inline void z_vfaeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfaeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfaef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfee( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find element equal
+ inline void z_vfeeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfeeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfeef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfene( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5); // Find element not equal
+ inline void z_vfeneb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfeneh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vfenef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5);
+ inline void z_vstrc( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t imm5, int64_t cc6); // String range compare
+ inline void z_vstrcb( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6);
+ inline void z_vstrch( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6);
+ inline void z_vstrcf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6);
+ inline void z_vistr( VectorRegister v1, VectorRegister v2, int64_t imm3, int64_t cc5); // Isolate String
+ inline void z_vistrb( VectorRegister v1, VectorRegister v2, int64_t cc5);
+ inline void z_vistrh( VectorRegister v1, VectorRegister v2, int64_t cc5);
+ inline void z_vistrf( VectorRegister v1, VectorRegister v2, int64_t cc5);
+ inline void z_vistrbs(VectorRegister v1, VectorRegister v2);
+ inline void z_vistrhs(VectorRegister v1, VectorRegister v2);
+ inline void z_vistrfs(VectorRegister v1, VectorRegister v2);
+
// Floatingpoint instructions
// ==========================
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/s390/assembler_s390.inline.hpp
--- a/src/hotspot/cpu/s390/assembler_s390.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/assembler_s390.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -762,21 +762,21 @@
inline void Assembler::z_vpkf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_FW); } // vector element type 'F'
inline void Assembler::z_vpkg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpk(v1, v2, v3, VRET_DW); } // vector element type 'G'
-inline void Assembler::z_vpks( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vpksh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vpksf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vpksg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vpkshs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', set CC
-inline void Assembler::z_vpksfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', set CC
-inline void Assembler::z_vpksgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', set CC
+inline void Assembler::z_vpks( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vpksh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vpksf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vpksg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vpkshs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', set CC
+inline void Assembler::z_vpksfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', set CC
+inline void Assembler::z_vpksgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpks(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', set CC
-inline void Assembler::z_vpkls( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKLS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vpklsh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vpklsf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vpklsg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vpklshs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', set CC
-inline void Assembler::z_vpklsfs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', set CC
-inline void Assembler::z_vpklsgs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', set CC
+inline void Assembler::z_vpkls( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VPKLS_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_HW, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vpklsh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vpklsf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vpklsg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vpklshs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', set CC
+inline void Assembler::z_vpklsfs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', set CC
+inline void Assembler::z_vpklsgs(VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vpkls(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', set CC
// vector register unpack (sign-extended)
inline void Assembler::z_vuph( VectorRegister v1, VectorRegister v2, int64_t m3) {emit_48(VUPH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(m3, VRET_BYTE, VRET_FW, 32)); }
@@ -967,33 +967,33 @@
inline void Assembler::z_vo( VectorRegister v1, VectorRegister v2, VectorRegister v3) {emit_48(VO_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16)); }
// Comparison (element-wise)
-inline void Assembler::z_vceq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCEQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vceqb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOP_CCIGN); } // vector element type 'B', don't set CC
-inline void Assembler::z_vceqh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vceqf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vceqg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vceqbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOP_CCSET); } // vector element type 'B', don't set CC
-inline void Assembler::z_vceqhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', don't set CC
-inline void Assembler::z_vceqfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', don't set CC
-inline void Assembler::z_vceqgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', don't set CC
-inline void Assembler::z_vch( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vchb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOP_CCIGN); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vchbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOP_CCSET); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', don't set CC
-inline void Assembler::z_vchl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCHL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | vccc_mask(cc5, 24)); }
-inline void Assembler::z_vchlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOP_CCIGN); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOP_CCIGN); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOP_CCIGN); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOP_CCIGN); } // vector element type 'G', don't set CC
-inline void Assembler::z_vchlbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOP_CCSET); } // vector element type 'B', don't set CC
-inline void Assembler::z_vchlhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOP_CCSET); } // vector element type 'H', don't set CC
-inline void Assembler::z_vchlfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOP_CCSET); } // vector element type 'F', don't set CC
-inline void Assembler::z_vchlgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOP_CCSET); } // vector element type 'G', don't set CC
+inline void Assembler::z_vceq( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCEQ_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vceqb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC
+inline void Assembler::z_vceqh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vceqf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vceqg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vceqbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC
+inline void Assembler::z_vceqhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC
+inline void Assembler::z_vceqfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC
+inline void Assembler::z_vceqgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vceq(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC
+inline void Assembler::z_vch( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCH_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vchb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vchbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vch(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC
+inline void Assembler::z_vchl( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4, int64_t cc5) {emit_48(VCHL_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32) | voprc_ccmask(cc5, 24)); }
+inline void Assembler::z_vchlb( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOPRC_CCIGN); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchlh( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOPRC_CCIGN); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchlf( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOPRC_CCIGN); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchlg( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOPRC_CCIGN); } // vector element type 'G', don't set CC
+inline void Assembler::z_vchlbs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_BYTE, VOPRC_CCSET); } // vector element type 'B', don't set CC
+inline void Assembler::z_vchlhs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_HW, VOPRC_CCSET); } // vector element type 'H', don't set CC
+inline void Assembler::z_vchlfs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_FW, VOPRC_CCSET); } // vector element type 'F', don't set CC
+inline void Assembler::z_vchlgs( VectorRegister v1, VectorRegister v2, VectorRegister v3) {z_vchl(v1, v2, v3, VRET_DW, VOPRC_CCSET); } // vector element type 'G', don't set CC
// Max/Min (element-wise)
inline void Assembler::z_vmx( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t m4) {emit_48(VMX_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(m4, VRET_BYTE, VRET_DW, 32)); }
@@ -1091,6 +1091,31 @@
// Test under Mask
inline void Assembler::z_vtm( VectorRegister v1, VectorRegister v2) {emit_48(VTM_ZOPC | vreg(v1, 8) | vreg(v2, 12)); }
+//---< Vector String Instructions >---
+inline void Assembler::z_vfae( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFAE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find any element
+inline void Assembler::z_vfaeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_BYTE, cc5); }
+inline void Assembler::z_vfaeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_HW, cc5); }
+inline void Assembler::z_vfaef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfae(v1, v2, v3, VRET_FW, cc5); }
+inline void Assembler::z_vfee( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFEE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find element equal
+inline void Assembler::z_vfeeb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_BYTE, cc5); }
+inline void Assembler::z_vfeeh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_HW, cc5); }
+inline void Assembler::z_vfeef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfee(v1, v2, v3, VRET_FW, cc5); }
+inline void Assembler::z_vfene( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t imm4, int64_t cc5) {emit_48(VFENE_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vesc_mask(imm4, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // Find element not equal
+inline void Assembler::z_vfeneb( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_BYTE, cc5); }
+inline void Assembler::z_vfeneh( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_HW, cc5); }
+inline void Assembler::z_vfenef( VectorRegister v1, VectorRegister v2, VectorRegister v3, int64_t cc5) {z_vfene(v1, v2, v3, VRET_FW, cc5); }
+inline void Assembler::z_vstrc( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t imm5, int64_t cc6) {emit_48(VSTRC_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vreg(v3, 16) | vreg(v4, 32) | vesc_mask(imm5, VRET_BYTE, VRET_FW, 20) | voprc_any(cc6, 24) ); } // String range compare
+inline void Assembler::z_vstrcb( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_BYTE, cc6); }
+inline void Assembler::z_vstrch( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_HW, cc6); }
+inline void Assembler::z_vstrcf( VectorRegister v1, VectorRegister v2, VectorRegister v3, VectorRegister v4, int64_t cc6) {z_vstrc(v1, v2, v3, v4, VRET_FW, cc6); }
+inline void Assembler::z_vistr( VectorRegister v1, VectorRegister v2, int64_t imm3, int64_t cc5) {emit_48(VISTR_ZOPC | vreg(v1, 8) | vreg(v2, 12) | vesc_mask(imm3, VRET_BYTE, VRET_FW, 32) | voprc_any(cc5, 24) ); } // isolate string
+inline void Assembler::z_vistrb( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_BYTE, cc5); }
+inline void Assembler::z_vistrh( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_HW, cc5); }
+inline void Assembler::z_vistrf( VectorRegister v1, VectorRegister v2, int64_t cc5) {z_vistr(v1, v2, VRET_FW, cc5); }
+inline void Assembler::z_vistrbs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_BYTE, VOPRC_CCSET); }
+inline void Assembler::z_vistrhs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_HW, VOPRC_CCSET); }
+inline void Assembler::z_vistrfs(VectorRegister v1, VectorRegister v2) {z_vistr(v1, v2, VRET_FW, VOPRC_CCSET); }
+
//-------------------------------
// FLOAT INSTRUCTIONS
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/s390/globals_s390.hpp
--- a/src/hotspot/cpu/s390/globals_s390.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/globals_s390.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
// Sorted according to sparc.
// z/Architecture remembers branch targets, so don't share vtables.
-define_pd_global(bool, ShareVtableStubs, false);
+define_pd_global(bool, ShareVtableStubs, true);
define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this.
define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/s390/macroAssembler_s390.cpp
--- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -4671,6 +4671,7 @@
mem2reg_opt(mirror, Address(mirror, ConstMethod::constants_offset()));
mem2reg_opt(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes()));
mem2reg_opt(mirror, Address(mirror, Klass::java_mirror_offset()));
+ resolve_oop_handle(mirror);
}
//---------------------------------------------------------------
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/s390/templateTable_s390.cpp
--- a/src/hotspot/cpu/s390/templateTable_s390.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/s390/templateTable_s390.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2382,6 +2382,7 @@
if (is_static) {
__ mem2reg_opt(obj, Address(cache, index, cp_base_offset + ConstantPoolCacheEntry::f1_offset()));
__ mem2reg_opt(obj, Address(obj, Klass::java_mirror_offset()));
+ __ resolve_oop_handle(obj);
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3844,6 +3844,7 @@
ld_ptr(mirror, in_bytes(ConstMethod::constants_offset()), mirror);
ld_ptr(mirror, ConstantPool::pool_holder_offset_in_bytes(), mirror);
ld_ptr(mirror, mirror_offset, mirror);
+ resolve_oop_handle(mirror);
}
void MacroAssembler::load_klass(Register src_oop, Register klass) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/sparc/templateTable_sparc.cpp
--- a/src/hotspot/cpu/sparc/templateTable_sparc.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/sparc/templateTable_sparc.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2049,6 +2049,7 @@
__ ld_ptr(Rcache, cp_base_offset + ConstantPoolCacheEntry::f1_offset(), Robj);
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ ld_ptr( Robj, mirror_offset, Robj);
+ __ resolve_oop_handle(Robj);
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/x86/macroAssembler_x86.cpp
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -6617,6 +6617,7 @@
movptr(mirror, Address(mirror, ConstMethod::constants_offset()));
movptr(mirror, Address(mirror, ConstantPool::pool_holder_offset_in_bytes()));
movptr(mirror, Address(mirror, mirror_offset));
+ resolve_oop_handle(mirror);
}
void MacroAssembler::load_klass(Register dst, Register src) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/x86/templateTable_x86.cpp
--- a/src/hotspot/cpu/x86/templateTable_x86.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/templateTable_x86.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2665,6 +2665,7 @@
ConstantPoolCacheEntry::f1_offset())));
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
__ movptr(obj, Address(obj, mirror_offset));
+ __ resolve_oop_handle(obj);
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/x86/vm_version_x86.cpp
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -46,7 +46,7 @@
address VM_Version::_cpuinfo_cont_addr = 0;
static BufferBlob* stub_blob;
-static const int stub_size = 1000;
+static const int stub_size = 1100;
extern "C" {
typedef void (*get_cpu_info_stub_t)(void*);
@@ -70,7 +70,7 @@
bool use_evex = FLAG_IS_DEFAULT(UseAVX) || (UseAVX > 2);
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
- Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done, wrapup;
+ Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, ext_cpuid8, done, wrapup;
Label legacy_setup, save_restore_except, legacy_save_restore, start_simd_check;
StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub");
@@ -267,14 +267,30 @@
__ cmpl(rax, 0x80000000); // Is cpuid(0x80000001) supported?
__ jcc(Assembler::belowEqual, done);
__ cmpl(rax, 0x80000004); // Is cpuid(0x80000005) supported?
- __ jccb(Assembler::belowEqual, ext_cpuid1);
+ __ jcc(Assembler::belowEqual, ext_cpuid1);
__ cmpl(rax, 0x80000006); // Is cpuid(0x80000007) supported?
__ jccb(Assembler::belowEqual, ext_cpuid5);
__ cmpl(rax, 0x80000007); // Is cpuid(0x80000008) supported?
__ jccb(Assembler::belowEqual, ext_cpuid7);
+ __ cmpl(rax, 0x80000008); // Is cpuid(0x80000009 and above) supported?
+ __ jccb(Assembler::belowEqual, ext_cpuid8);
+ __ cmpl(rax, 0x8000001E); // Is cpuid(0x8000001E) supported?
+ __ jccb(Assembler::below, ext_cpuid8);
+ //
+ // Extended cpuid(0x8000001E)
+ //
+ __ movl(rax, 0x8000001E);
+ __ cpuid();
+ __ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid1E_offset())));
+ __ movl(Address(rsi, 0), rax);
+ __ movl(Address(rsi, 4), rbx);
+ __ movl(Address(rsi, 8), rcx);
+ __ movl(Address(rsi,12), rdx);
+
//
// Extended cpuid(0x80000008)
//
+ __ bind(ext_cpuid8);
__ movl(rax, 0x80000008);
__ cpuid();
__ lea(rsi, Address(rbp, in_bytes(VM_Version::ext_cpuid8_offset())));
@@ -1109,11 +1125,27 @@
}
#ifdef COMPILER2
- if (MaxVectorSize > 16) {
- // Limit vectors size to 16 bytes on current AMD cpus.
+ if (cpu_family() < 0x17 && MaxVectorSize > 16) {
+ // Limit vectors size to 16 bytes on AMD cpus < 17h.
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
#endif // COMPILER2
+
+ // Some defaults for AMD family 17h
+ if ( cpu_family() == 0x17 ) {
+ // On family 17h processors use XMM and UnalignedLoadStores for Array Copy
+ if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) {
+ FLAG_SET_DEFAULT(UseXMMForArrayCopy, true);
+ }
+ if (supports_sse2() && FLAG_IS_DEFAULT(UseUnalignedLoadStores)) {
+ FLAG_SET_DEFAULT(UseUnalignedLoadStores, true);
+ }
+#ifdef COMPILER2
+ if (supports_sse4_2() && FLAG_IS_DEFAULT(UseFPUForSpilling)) {
+ FLAG_SET_DEFAULT(UseFPUForSpilling, true);
+ }
+#endif
+ }
}
if( is_intel() ) { // Intel cpus specific settings
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/cpu/x86/vm_version_x86.hpp
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -228,6 +228,15 @@
} bits;
};
+ union ExtCpuid1EEbx {
+ uint32_t value;
+ struct {
+ uint32_t : 8,
+ threads_per_core : 8,
+ : 16;
+ } bits;
+ };
+
union XemXcr0Eax {
uint32_t value;
struct {
@@ -398,6 +407,12 @@
ExtCpuid8Ecx ext_cpuid8_ecx;
uint32_t ext_cpuid8_edx; // reserved
+ // cpuid function 0x8000001E // AMD 17h
+ uint32_t ext_cpuid1E_eax;
+ ExtCpuid1EEbx ext_cpuid1E_ebx; // threads per core (AMD17h)
+ uint32_t ext_cpuid1E_ecx;
+ uint32_t ext_cpuid1E_edx; // unused currently
+
// extended control register XCR0 (the XFEATURE_ENABLED_MASK register)
XemXcr0Eax xem_xcr0_eax;
uint32_t xem_xcr0_edx; // reserved
@@ -505,6 +520,14 @@
result |= CPU_CLMUL;
if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0)
result |= CPU_RTM;
+ if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0)
+ result |= CPU_ADX;
+ if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
+ result |= CPU_BMI2;
+ if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0)
+ result |= CPU_SHA;
+ if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0)
+ result |= CPU_FMA;
// AMD features.
if (is_amd()) {
@@ -518,16 +541,8 @@
}
// Intel features.
if(is_intel()) {
- if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0)
- result |= CPU_ADX;
- if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
- result |= CPU_BMI2;
- if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0)
- result |= CPU_SHA;
if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
result |= CPU_LZCNT;
- if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0)
- result |= CPU_FMA;
// for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw
if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) {
result |= CPU_3DNOW_PREFETCH;
@@ -590,6 +605,7 @@
static ByteSize ext_cpuid5_offset() { return byte_offset_of(CpuidInfo, ext_cpuid5_eax); }
static ByteSize ext_cpuid7_offset() { return byte_offset_of(CpuidInfo, ext_cpuid7_eax); }
static ByteSize ext_cpuid8_offset() { return byte_offset_of(CpuidInfo, ext_cpuid8_eax); }
+ static ByteSize ext_cpuid1E_offset() { return byte_offset_of(CpuidInfo, ext_cpuid1E_eax); }
static ByteSize tpl_cpuidB0_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB0_eax); }
static ByteSize tpl_cpuidB1_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB1_eax); }
static ByteSize tpl_cpuidB2_offset() { return byte_offset_of(CpuidInfo, tpl_cpuidB2_eax); }
@@ -673,8 +689,12 @@
if (is_intel() && supports_processor_topology()) {
result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus;
} else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) {
- result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
- cores_per_cpu();
+ if (cpu_family() >= 0x17) {
+ result = _cpuid_info.ext_cpuid1E_ebx.bits.threads_per_core + 1;
+ } else {
+ result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
+ cores_per_cpu();
+ }
}
return (result == 0 ? 1 : result);
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp
--- a/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/aix_ppc/atomic_aix_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -34,22 +34,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
//
// machine barrier instructions:
//
@@ -148,13 +132,15 @@
return result;
}
-
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
-
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- unsigned int old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -182,15 +168,18 @@
"memory"
);
- return (jint) old_value;
+ return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
-
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- long old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -218,11 +207,7 @@
"memory"
);
- return (intptr_t) old_value;
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+ return old_value;
}
inline void cmpxchg_pre_membar(cmpxchg_memory_order order) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp
--- a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,19 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-
template
struct Atomic::PlatformAdd
: Atomic::FetchAndAdd >
@@ -61,7 +48,11 @@
return old_value;
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
__asm__ volatile ( "xchgl (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -69,10 +60,6 @@
return exchange_value;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
-
template<>
template
inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
@@ -102,9 +89,6 @@
}
#ifdef AMD64
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-
template<>
template
inline D Atomic::PlatformAdd<8>::fetch_and_add(I add_value, D volatile* dest) const {
@@ -118,7 +102,11 @@
return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
__asm__ __volatile__ ("xchgq (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -140,14 +128,8 @@
return exchange_value;
}
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#else // !AMD64
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
extern "C" {
// defined in bsd_x86.s
jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong, bool);
@@ -164,18 +146,21 @@
return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- _Atomic_move_long(src, &dest);
- return dest;
+ _Atomic_move_long(reinterpret_cast(src), reinterpret_cast(&dest));
+ return PrimitiveConversions::cast(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, dest);
+template<>
+template
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ _Atomic_move_long(reinterpret_cast(&store_value), reinterpret_cast(dest));
}
#endif // AMD64
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp
--- a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -87,7 +87,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int m68k_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until success.
int prev = *ptr;
@@ -148,7 +148,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int arm_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int arm_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until a __kernel_cmpxchg succeeds.
int prev = *ptr;
@@ -159,20 +159,6 @@
}
#endif // ARM
-inline void Atomic::store(jint store_value, volatile jint* dest) {
-#if !defined(ARM) && !defined(M68K)
- __sync_synchronize();
-#endif
- *dest = store_value;
-}
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) {
-#if !defined(ARM) && !defined(M68K)
- __sync_synchronize();
-#endif
- *dest = store_value;
-}
-
template
struct Atomic::PlatformAdd
: Atomic::AddAndFetch >
@@ -207,18 +193,22 @@
return __sync_add_and_fetch(dest, add_value);
}
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper(arm_lock_test_and_set, exchange_value, dest);
#else
#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper(m68k_lock_test_and_set, exchange_value, dest);
#else
// __sync_lock_test_and_set is a bizarrely named atomic exchange
// operation. Note that some platforms only support this with the
// limitation that the only valid value to store is the immediate
// constant 1. There is a test for this in JNI_CreateJavaVM().
- jint result = __sync_lock_test_and_set (dest, exchange_value);
+ T result = __sync_lock_test_and_set (dest, exchange_value);
// All atomic operations are expected to be full memory barriers
// (see atomic.hpp). However, __sync_lock_test_and_set is not
// a full memory barrier, but an acquire barrier. Hence, this added
@@ -229,24 +219,14 @@
#endif // ARM
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value,
- volatile intptr_t* dest) {
-#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
-#else
-#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
-#else
- intptr_t result = __sync_lock_test_and_set (dest, exchange_value);
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result = __sync_lock_test_and_set (dest, exchange_value);
__sync_synchronize();
return result;
-#endif // M68K
-#endif // ARM
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void *) xchg_ptr((intptr_t) exchange_value,
- (volatile intptr_t*) dest);
}
// No direct support for cmpxchg of bytes; emulate using int.
@@ -281,18 +261,21 @@
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- os::atomic_copy64(src, &dest);
- return dest;
+ os::atomic_copy64(reinterpret_cast(src), reinterpret_cast(&dest));
+ return PrimitiveConversions::cast(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, dest);
+template<>
+template
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ os::atomic_copy64(reinterpret_cast(&store_value), reinterpret_cast(dest));
}
#endif // OS_CPU_BSD_ZERO_VM_ATOMIC_BSD_ZERO_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp
--- a/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_aarch64/atomic_linux_aarch64.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -34,19 +34,6 @@
#define READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE);
#define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE);
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-
template
struct Atomic::PlatformAdd
: Atomic::AddAndFetch >
@@ -57,19 +44,16 @@
}
};
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest)
-{
- jint res = __sync_lock_test_and_set (dest, exchange_value);
+template
+template
+inline T Atomic::PlatformXchg::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(byte_size == sizeof(T));
+ T res = __sync_lock_test_and_set(dest, exchange_value);
FULL_MEM_BARRIER;
return res;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest)
-{
- return (void *) xchg_ptr((intptr_t) exchange_value,
- (volatile intptr_t*) dest);
-}
-
template
template
inline T Atomic::PlatformCmpxchg::operator()(T exchange_value,
@@ -87,16 +71,4 @@
}
}
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest)
-{
- intptr_t res = __sync_lock_test_and_set (dest, exchange_value);
- FULL_MEM_BARRIER;
- return res;
-}
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#endif // OS_CPU_LINUX_AARCH64_VM_ATOMIC_LINUX_AARCH64_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp
--- a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -44,39 +44,24 @@
* kernel source or kernel_user_helpers.txt in Linux Doc.
*/
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load (const volatile jlong* src) {
- assert(((intx)src & (sizeof(jlong)-1)) == 0, "Atomic load jlong mis-aligned");
-#ifdef AARCH64
- return *src;
-#else
- return (*os::atomic_load_long_func)(src);
-#endif
+#ifndef AARCH64
+template<>
+template
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ return PrimitiveConversions::cast(
+ (*os::atomic_load_long_func)(reinterpret_cast(src)));
}
-inline void Atomic::store (jlong value, volatile jlong* dest) {
- assert(((intx)dest & (sizeof(jlong)-1)) == 0, "Atomic store jlong mis-aligned");
-#ifdef AARCH64
- *dest = value;
-#else
- (*os::atomic_store_long_func)(value, dest);
+template<>
+template
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ (*os::atomic_store_long_func)(
+ PrimitiveConversions::cast(store_value), reinterpret_cast(dest));
+}
#endif
-}
-
-inline void Atomic::store (jlong value, jlong* dest) {
- store(value, (volatile jlong*)dest);
-}
// As per atomic.hpp all read-modify-write operations have to provide two-way
// barriers semantics. For AARCH64 we are using load-acquire-with-reservation and
@@ -141,11 +126,15 @@
: "memory");
return val;
}
-#endif // AARCH64
+#endif
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef AARCH64
- jint old_val;
+ T old_val;
int tmp;
__asm__ volatile(
"1:\n\t"
@@ -157,13 +146,17 @@
: "memory");
return old_val;
#else
- return (*os::atomic_xchg_func)(exchange_value, dest);
+ return xchg_using_helper(os::atomic_xchg_func, exchange_value, dest);
#endif
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
#ifdef AARCH64
- intptr_t old_val;
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_val;
int tmp;
__asm__ volatile(
"1:\n\t"
@@ -174,14 +167,8 @@
: [new_val] "r" (exchange_value), [dest] "r" (dest)
: "memory");
return old_val;
-#else
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-#endif
}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
+#endif // AARCH64
// The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp
--- a/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_ppc/atomic_linux_ppc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -32,22 +32,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
//
// machine barrier instructions:
//
@@ -146,12 +130,14 @@
return result;
}
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
-
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- unsigned int old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -179,15 +165,18 @@
"memory"
);
- return (jint) old_value;
+ return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
-
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
// Note that xchg_ptr doesn't necessarily do an acquire
// (see synchronizer.cpp).
- long old_value;
+ T old_value;
const uint64_t zero = 0;
__asm__ __volatile__ (
@@ -215,11 +204,7 @@
"memory"
);
- return (intptr_t) old_value;
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+ return old_value;
}
inline void cmpxchg_pre_membar(cmpxchg_memory_order order) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp
--- a/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_s390/atomic_linux_s390.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -53,20 +53,6 @@
// is an integer multiple of the data length. Furthermore, all stores are ordered:
// a store which occurs conceptually before another store becomes visible to other CPUs
// before the other store becomes visible.
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
//------------
// Atomic::add
@@ -208,8 +194,12 @@
//
// The return value is the (unchanged) value from memory as it was when the
// replacement succeeded.
-inline jint Atomic::xchg (jint xchg_val, volatile jint* dest) {
- unsigned int old;
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T old;
__asm__ __volatile__ (
" LLGF %[old],%[mem] \n\t" // get old value
@@ -219,16 +209,20 @@
: [old] "=&d" (old) // write-only, prev value irrelevant
, [mem] "+Q" (*dest) // read/write, memory to be updated atomically
//---< inputs >---
- : [upd] "d" (xchg_val) // read-only, value to be written to memory
+ : [upd] "d" (exchange_value) // read-only, value to be written to memory
//---< clobbered >---
: "cc", "memory"
);
- return (jint)old;
+ return old;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t xchg_val, volatile intptr_t* dest) {
- unsigned long old;
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old;
__asm__ __volatile__ (
" LG %[old],%[mem] \n\t" // get old value
@@ -238,16 +232,12 @@
: [old] "=&d" (old) // write-only, init from memory
, [mem] "+Q" (*dest) // read/write, memory to be updated atomically
//---< inputs >---
- : [upd] "d" (xchg_val) // read-only, value to be written to memory
+ : [upd] "d" (exchange_value) // read-only, value to be written to memory
//---< clobbered >---
: "cc", "memory"
);
- return (intptr_t)old;
-}
-
-inline void *Atomic::xchg_ptr(void *exchange_value, volatile void *dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+ return old;
}
//----------------
@@ -331,6 +321,4 @@
return old;
}
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#endif // OS_CPU_LINUX_S390_VM_ATOMIC_LINUX_S390_INLINE_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp
--- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -471,7 +471,7 @@
// Info->si_addr need not be the exact address, it is only
// guaranteed to be on the same page as the address that caused
// the SIGSEGV.
- if ((sig == SIGSEGV) &&
+ if ((sig == SIGSEGV) && !UseMembar &&
(os::get_memory_serialize_page() ==
(address)((uintptr_t)info->si_addr & ~(os::vm_page_size()-1)))) {
return true;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp
--- a/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_sparc/atomic_linux_sparc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,22 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
template
struct Atomic::PlatformAdd
: Atomic::AddAndFetch >
@@ -95,9 +79,12 @@
return rv;
}
-
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- intptr_t rv = exchange_value;
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ T rv = exchange_value;
__asm__ volatile(
" swap [%2],%1\n\t"
: "=r" (rv)
@@ -106,8 +93,12 @@
return rv;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- intptr_t rv = exchange_value;
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T rv = exchange_value;
__asm__ volatile(
"1:\n\t"
" mov %1, %%o3\n\t"
@@ -123,10 +114,6 @@
return rv;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
-
// No direct support for cmpxchg of bytes; emulate using int.
template<>
struct Atomic::PlatformCmpxchg<1> : Atomic::CmpxchgByteUsingInt {};
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp
--- a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,19 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-
template
struct Atomic::PlatformAdd
: Atomic::FetchAndAdd >
@@ -61,7 +48,11 @@
return old_value;
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
__asm__ volatile ( "xchgl (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -69,10 +60,6 @@
return exchange_value;
}
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
-
template<>
template
inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
@@ -102,8 +89,6 @@
}
#ifdef AMD64
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
template<>
template
@@ -118,7 +103,11 @@
return old_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
__asm__ __volatile__ ("xchgq (%2),%0"
: "=r" (exchange_value)
: "0" (exchange_value), "r" (dest)
@@ -140,14 +129,8 @@
return exchange_value;
}
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#else // !AMD64
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
extern "C" {
// defined in linux_x86.s
jlong _Atomic_cmpxchg_long(jlong, volatile jlong*, jlong);
@@ -164,18 +147,21 @@
return cmpxchg_using_helper(_Atomic_cmpxchg_long, exchange_value, dest, compare_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- _Atomic_move_long(src, &dest);
- return dest;
+ _Atomic_move_long(reinterpret_cast(src), reinterpret_cast(&dest));
+ return PrimitiveConversions::cast(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- _Atomic_move_long((volatile jlong*)&store_value, dest);
+template<>
+template
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ _Atomic_move_long(reinterpret_cast(&store_value), reinterpret_cast(dest));
}
#endif // AMD64
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp
--- a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -87,7 +87,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int m68k_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int m68k_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until success.
int prev = *ptr;
@@ -148,7 +148,7 @@
/* Atomically write VALUE into `*PTR' and returns the previous
contents of `*PTR'. */
-static inline int arm_lock_test_and_set(volatile int *ptr, int newval) {
+static inline int arm_lock_test_and_set(int newval, volatile int *ptr) {
for (;;) {
// Loop until a __kernel_cmpxchg succeeds.
int prev = *ptr;
@@ -159,14 +159,6 @@
}
#endif // ARM
-inline void Atomic::store(jint store_value, volatile jint* dest) {
- *dest = store_value;
-}
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) {
- *dest = store_value;
-}
-
template
struct Atomic::PlatformAdd
: Atomic::AddAndFetch >
@@ -201,18 +193,22 @@
return __sync_add_and_fetch(dest, add_value);
}
-inline jint Atomic::xchg(jint exchange_value, volatile jint* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper(arm_lock_test_and_set, exchange_value, dest);
#else
#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
+ return xchg_using_helper(m68k_lock_test_and_set, exchange_value, dest);
#else
// __sync_lock_test_and_set is a bizarrely named atomic exchange
// operation. Note that some platforms only support this with the
// limitation that the only valid value to store is the immediate
// constant 1. There is a test for this in JNI_CreateJavaVM().
- jint result = __sync_lock_test_and_set (dest, exchange_value);
+ T result = __sync_lock_test_and_set (dest, exchange_value);
// All atomic operations are expected to be full memory barriers
// (see atomic.hpp). However, __sync_lock_test_and_set is not
// a full memory barrier, but an acquire barrier. Hence, this added
@@ -223,24 +219,14 @@
#endif // ARM
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value,
- volatile intptr_t* dest) {
-#ifdef ARM
- return arm_lock_test_and_set(dest, exchange_value);
-#else
-#ifdef M68K
- return m68k_lock_test_and_set(dest, exchange_value);
-#else
- intptr_t result = __sync_lock_test_and_set (dest, exchange_value);
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T result = __sync_lock_test_and_set (dest, exchange_value);
__sync_synchronize();
return result;
-#endif // M68K
-#endif // ARM
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void *) xchg_ptr((intptr_t) exchange_value,
- (volatile intptr_t*) dest);
}
// No direct support for cmpxchg of bytes; emulate using int.
@@ -275,18 +261,21 @@
return __sync_val_compare_and_swap(dest, compare_value, exchange_value);
}
-inline jlong Atomic::load(const volatile jlong* src) {
+template<>
+template
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
volatile jlong dest;
- os::atomic_copy64(src, &dest);
- return dest;
+ os::atomic_copy64(reinterpret_cast(src), reinterpret_cast(&dest));
+ return PrimitiveConversions::cast(dest);
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, (volatile jlong*)dest);
-}
-
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- os::atomic_copy64((volatile jlong*)&store_value, dest);
+template<>
+template
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ os::atomic_copy64(reinterpret_cast(&store_value), reinterpret_cast(dest));
}
#endif // OS_CPU_LINUX_ZERO_VM_ATOMIC_LINUX_ZERO_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp
--- a/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/solaris_sparc/atomic_solaris_sparc.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -27,32 +27,6 @@
// Implementation of class atomic
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
-inline void Atomic::store(jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store(jlong store_value, volatile jlong* dest) { *dest = store_value; }
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
-
-// This is the interface to the atomic instructions in solaris_sparc.il.
-// It's very messy because we need to support v8 and these instructions
-// are illegal there. When sparc v8 is dropped, we can drop out lots of
-// this code. Also compiler2 does not support v8 so the conditional code
-// omits the instruction set check.
-
-extern "C" jint _Atomic_swap32(jint exchange_value, volatile jint* dest);
-extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest);
-
// Implement ADD using a CAS loop.
template
struct Atomic::PlatformAdd VALUE_OBJ_CLASS_SPEC {
@@ -69,16 +43,30 @@
}
};
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- return _Atomic_swap32(exchange_value, dest);
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ __asm__ volatile ( "swap [%2],%0"
+ : "=r" (exchange_value)
+ : "0" (exchange_value), "r" (dest)
+ : "memory");
+ return exchange_value;
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return _Atomic_swap64(exchange_value, dest);
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ T old_value = *dest;
+ while (true) {
+ T result = cmpxchg(exchange_value, dest, old_value);
+ if (result == old_value) break;
+ old_value = result;
+ }
+ return old_value;
}
// No direct support for cmpxchg of bytes; emulate using int.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il
--- a/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/solaris_sparc/solaris_sparc.il Mon Oct 09 07:08:53 2017 +0000
@@ -32,47 +32,6 @@
.end
- // Support for jint Atomic::xchg(jint exchange_value, volatile jint* dest).
- //
- // Arguments:
- // exchange_value: O0
- // dest: O1
- //
- // Results:
- // O0: the value previously stored in dest
-
- .inline _Atomic_swap32, 2
- .volatile
- swap [%o1],%o0
- .nonvolatile
- .end
-
-
- // Support for intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t * dest).
- //
- // 64-bit
- //
- // Arguments:
- // exchange_value: O0
- // dest: O1
- //
- // Results:
- // O0: the value previously stored in dest
-
- .inline _Atomic_swap64, 2
- .volatile
- 1:
- mov %o0, %o3
- ldx [%o1], %o2
- casx [%o1], %o2, %o3
- cmp %o2, %o3
- bne %xcc, 1b
- nop
- mov %o2, %o0
- .nonvolatile
- .end
-
-
// Support for jlong Atomic::load and Atomic::store on v9.
//
// void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst)
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp
--- a/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -25,20 +25,6 @@
#ifndef OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
#define OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
// For Sun Studio - implementation is in solaris_x86_64.il.
extern "C" {
@@ -84,8 +70,26 @@
reinterpret_cast(dest)));
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- return _Atomic_xchg(exchange_value, dest);
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
+ return PrimitiveConversions::cast(
+ _Atomic_xchg(PrimitiveConversions::cast(exchange_value),
+ reinterpret_cast(dest)));
+}
+
+extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest);
+
+template<>
+template
+inline T Atomic::PlatformXchg<8>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ return PrimitiveConversions::cast(
+ _Atomic_xchg_long(PrimitiveConversions::cast(exchange_value),
+ reinterpret_cast(dest)));
}
// Not using cmpxchg_using_helper here, because some configurations of
@@ -133,18 +137,4 @@
PrimitiveConversions::cast(compare_value)));
}
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-extern "C" jlong _Atomic_xchg_long(jlong exchange_value, volatile jlong* dest);
-
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest);
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)_Atomic_xchg_long((jlong)exchange_value, (volatile jlong*)dest);
-}
-
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#endif // OS_CPU_SOLARIS_X86_VM_ATOMIC_SOLARIS_X86_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp
--- a/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/os_cpu/windows_x86/atomic_windows_x86.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -42,21 +42,6 @@
#pragma warning(disable: 4035) // Disables warnings reporting missing return statement
-inline void Atomic::store (jbyte store_value, jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, jint* dest) { *dest = store_value; }
-
-inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, void* dest) { *(void**)dest = store_value; }
-
-inline void Atomic::store (jbyte store_value, volatile jbyte* dest) { *dest = store_value; }
-inline void Atomic::store (jshort store_value, volatile jshort* dest) { *dest = store_value; }
-inline void Atomic::store (jint store_value, volatile jint* dest) { *dest = store_value; }
-
-
-inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
-inline void Atomic::store_ptr(void* store_value, volatile void* dest) { *(void* volatile *)dest = store_value; }
-
template
struct Atomic::PlatformAdd
: Atomic::AddAndFetch >
@@ -66,9 +51,6 @@
};
#ifdef AMD64
-inline void Atomic::store (jlong store_value, jlong* dest) { *dest = store_value; }
-inline void Atomic::store (jlong store_value, volatile jlong* dest) { *dest = store_value; }
-
template<>
template
inline D Atomic::PlatformAdd<4>::add_and_fetch(I add_value, D volatile* dest) const {
@@ -81,17 +63,19 @@
return add_using_helper(os::atomic_add_ptr_func, add_value, dest);
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
- return (jint)(*os::atomic_xchg_func)(exchange_value, dest);
-}
+#define DEFINE_STUB_XCHG(ByteSize, StubType, StubName) \
+ template<> \
+ template \
+ inline T Atomic::PlatformXchg::operator()(T exchange_value, \
+ T volatile* dest) const { \
+ STATIC_ASSERT(ByteSize == sizeof(T)); \
+ return xchg_using_helper(StubName, exchange_value, dest); \
+ }
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)(os::atomic_xchg_ptr_func)(exchange_value, dest);
-}
+DEFINE_STUB_XCHG(4, jint, os::atomic_xchg_func)
+DEFINE_STUB_XCHG(8, jlong, os::atomic_xchg_ptr_func)
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void *)(os::atomic_xchg_ptr_func)((intptr_t)exchange_value, (volatile intptr_t*)dest);
-}
+#undef DEFINE_STUB_XCHG
#define DEFINE_STUB_CMPXCHG(ByteSize, StubType, StubName) \
template<> \
@@ -110,8 +94,6 @@
#undef DEFINE_STUB_CMPXCHG
-inline jlong Atomic::load(const volatile jlong* src) { return *src; }
-
#else // !AMD64
template<>
@@ -128,7 +110,11 @@
}
}
-inline jint Atomic::xchg (jint exchange_value, volatile jint* dest) {
+template<>
+template
+inline T Atomic::PlatformXchg<4>::operator()(T exchange_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(4 == sizeof(T));
// alternative for InterlockedExchange
__asm {
mov eax, exchange_value;
@@ -137,14 +123,6 @@
}
}
-inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
- return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
-inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) {
- return (void*)xchg((jint)exchange_value, (volatile jint*)dest);
-}
-
template<>
template
inline T Atomic::PlatformCmpxchg<1>::operator()(T exchange_value,
@@ -202,9 +180,12 @@
}
}
-inline jlong Atomic::load(const volatile jlong* src) {
- volatile jlong dest;
- volatile jlong* pdest = &dest;
+template<>
+template
+inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ volatile T dest;
+ volatile T* pdest = &dest;
__asm {
mov eax, src
fild qword ptr [eax]
@@ -214,8 +195,12 @@
return dest;
}
-inline void Atomic::store(jlong store_value, volatile jlong* dest) {
- volatile jlong* src = &store_value;
+template<>
+template
+inline void Atomic::PlatformStore<8>::operator()(T store_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(8 == sizeof(T));
+ volatile T* src = &store_value;
__asm {
mov eax, src
fild qword ptr [eax]
@@ -224,10 +209,6 @@
}
}
-inline void Atomic::store(jlong store_value, jlong* dest) {
- Atomic::store(store_value, (volatile jlong*)dest);
-}
-
#endif // AMD64
#pragma warning(default: 4035) // Enables warnings reporting missing return statement
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/adlc/output_c.cpp
--- a/src/hotspot/share/adlc/output_c.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/adlc/output_c.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -2276,6 +2276,10 @@
if (strcmp(rep_var,"$XMMRegister") == 0) return "as_XMMRegister";
#endif
if (strcmp(rep_var,"$CondRegister") == 0) return "as_ConditionRegister";
+#if defined(PPC64)
+ if (strcmp(rep_var,"$VectorRegister") == 0) return "as_VectorRegister";
+ if (strcmp(rep_var,"$VectorSRegister") == 0) return "as_VectorSRegister";
+#endif
return NULL;
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/c1/c1_LIRGenerator.cpp
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1304,7 +1304,9 @@
// FIXME T_ADDRESS should actually be T_METADATA but it can't because the
// meaning of these two is mixed up (see JDK-8026837).
__ move(new LIR_Address(rcvr.result(), oopDesc::klass_offset_in_bytes(), T_ADDRESS), temp, info);
- __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_OBJECT), result);
+ __ move_wide(new LIR_Address(temp, in_bytes(Klass::java_mirror_offset()), T_ADDRESS), result);
+ // mirror = ((OopHandle)mirror)->resolve();
+ __ move_wide(new LIR_Address(result, T_OBJECT), result);
}
// java.lang.Class::isPrimitive()
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/classfile/classLoaderData.cpp
--- a/src/hotspot/share/classfile/classLoaderData.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/classLoaderData.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -98,7 +98,8 @@
_keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_modules(NULL), _packages(NULL),
- _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
+ _claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
+ _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
_next(NULL), _dependencies(dependencies),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
Monitor::_safepoint_check_never)) {
@@ -207,7 +208,7 @@
oops_do(&cl);
return cl.found();
}
-#endif
+#endif // ASSERT
bool ClassLoaderData::claim() {
if (_claimed == 1) {
@@ -236,19 +237,19 @@
}
}
-void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderData::oops_do(OopClosure* f, bool must_claim, bool clear_mod_oops) {
if (must_claim && !claim()) {
return;
}
+ // Only clear modified_oops after the ClassLoaderData is claimed.
+ if (clear_mod_oops) {
+ clear_modified_oops();
+ }
+
f->do_oop(&_class_loader);
_dependencies.oops_do(f);
-
_handles.oops_do(f);
-
- if (klass_closure != NULL) {
- classes_do(klass_closure);
- }
}
void ClassLoaderData::Dependencies::oops_do(OopClosure* f) {
@@ -368,6 +369,9 @@
// Must handle over GC point.
Handle dependency(THREAD, to);
from_cld->_dependencies.add(dependency, CHECK);
+
+ // Added a potentially young gen oop to the ClassLoaderData
+ record_modified_oops();
}
@@ -764,6 +768,7 @@
OopHandle ClassLoaderData::add_handle(Handle h) {
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+ record_modified_oops();
return OopHandle(_handles.add(h()));
}
@@ -875,8 +880,7 @@
if (Verbose) {
Klass* k = _klasses;
while (k != NULL) {
- out->print_cr("klass " PTR_FORMAT ", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
- k->has_modified_oops(), k->has_accumulated_modified_oops());
+ out->print_cr("klass " PTR_FORMAT ", %s", p2i(k), k->name()->as_C_string());
assert(k != k->next_link(), "no loops!");
k = k->next_link();
}
@@ -1003,25 +1007,25 @@
}
-void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
- cld->oops_do(f, klass_closure, must_claim);
+ cld->oops_do(f, must_claim);
}
}
-void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
if (cld->keep_alive()) {
- cld->oops_do(f, klass_closure, must_claim);
+ cld->oops_do(f, must_claim);
}
}
}
-void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, bool must_claim) {
if (ClassUnloading) {
- keep_alive_oops_do(f, klass_closure, must_claim);
+ keep_alive_oops_do(f, must_claim);
} else {
- oops_do(f, klass_closure, must_claim);
+ oops_do(f, must_claim);
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/classfile/classLoaderData.hpp
--- a/src/hotspot/share/classfile/classLoaderData.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/classLoaderData.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -87,9 +87,9 @@
static void purge();
static void clear_claimed_marks();
// oops do
- static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
- static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
- static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
+ static void oops_do(OopClosure* f, bool must_claim);
+ static void keep_alive_oops_do(OopClosure* blk, bool must_claim);
+ static void always_strong_oops_do(OopClosure* blk, bool must_claim);
// cld do
static void cld_do(CLDClosure* cl);
static void cld_unloading_do(CLDClosure* cl);
@@ -230,10 +230,16 @@
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away
bool _is_anonymous; // if this CLD is for an anonymous class
+
+ // Remembered sets support for the oops in the class loader data.
+ bool _modified_oops; // Card Table Equivalent (YC/CMS support)
+ bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
+
s2 _keep_alive; // if this CLD is kept alive without a keep_alive_object().
// Used for anonymous classes and the boot class
// loader. _keep_alive does not need to be volatile or
// atomic since there is one unique CLD per anonymous class.
+
volatile int _claimed; // true if claimed, for example during GC traces.
// To avoid applying oop closure more than once.
// Has to be an int because we cas it.
@@ -276,6 +282,19 @@
bool claimed() const { return _claimed == 1; }
bool claim();
+ // The CLD are not placed in the Heap, so the Card Table or
+ // the Mod Union Table can't be used to mark when CLD have modified oops.
+ // The CT and MUT bits saves this information for the whole class loader data.
+ void clear_modified_oops() { _modified_oops = false; }
+ public:
+ void record_modified_oops() { _modified_oops = true; }
+ bool has_modified_oops() { return _modified_oops; }
+
+ void accumulate_modified_oops() { if (has_modified_oops()) _accumulated_modified_oops = true; }
+ void clear_accumulated_modified_oops() { _accumulated_modified_oops = false; }
+ bool has_accumulated_modified_oops() { return _accumulated_modified_oops; }
+ private:
+
void unload();
bool keep_alive() const { return _keep_alive > 0; }
void classes_do(void f(Klass*));
@@ -346,8 +365,7 @@
inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
- // Used when tracing from klasses.
- void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
+ void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);
void classes_do(KlassClosure* klass_closure);
Klass* klasses() { return _klasses; }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/classfile/javaClasses.cpp
--- a/src/hotspot/share/classfile/javaClasses.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/javaClasses.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -889,7 +889,7 @@
// Setup indirection from klass->mirror
// after any exceptions can happen during allocations.
- k->set_java_mirror(mirror());
+ k->set_java_mirror(mirror);
// Set the module field in the java_lang_Class instance. This must be done
// after the mirror is set.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/classfile/vmSymbols.hpp
--- a/src/hotspot/share/classfile/vmSymbols.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/classfile/vmSymbols.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -781,6 +781,7 @@
do_name(decrementExact_name,"decrementExact") \
do_name(incrementExact_name,"incrementExact") \
do_name(multiplyExact_name,"multiplyExact") \
+ do_name(multiplyHigh_name,"multiplyHigh") \
do_name(negateExact_name,"negateExact") \
do_name(subtractExact_name,"subtractExact") \
do_name(fma_name, "fma") \
@@ -805,6 +806,7 @@
do_intrinsic(_incrementExactL, java_lang_Math, incrementExact_name, long_long_signature, F_S) \
do_intrinsic(_multiplyExactI, java_lang_Math, multiplyExact_name, int2_int_signature, F_S) \
do_intrinsic(_multiplyExactL, java_lang_Math, multiplyExact_name, long2_long_signature, F_S) \
+ do_intrinsic(_multiplyHigh, java_lang_Math, multiplyHigh_name, long2_long_signature, F_S) \
do_intrinsic(_negateExactI, java_lang_Math, negateExact_name, int_int_signature, F_S) \
do_intrinsic(_negateExactL, java_lang_Math, negateExact_name, long_long_signature, F_S) \
do_intrinsic(_subtractExactI, java_lang_Math, subtractExact_name, int2_int_signature, F_S) \
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/compiler/compileBroker.hpp
--- a/src/hotspot/share/compiler/compileBroker.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/compiler/compileBroker.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -332,7 +332,7 @@
static void disable_compilation_forever() {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
- Atomic::xchg(shutdown_compilation, &_should_compile_new_jobs);
+ Atomic::xchg(jint(shutdown_compilation), &_should_compile_new_jobs);
}
static bool is_compilation_disabled_forever() {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/compiler/methodMatcher.cpp
--- a/src/hotspot/share/compiler/methodMatcher.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/compiler/methodMatcher.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -96,7 +96,7 @@
bool have_colon = (colon != NULL);
if (have_colon) {
// Don't allow multiple '::'
- if (colon + 2 != '\0') {
+ if (colon[2] != '\0') {
if (strstr(colon+2, "::")) {
error_msg = "Method pattern only allows one '::' allowed";
return false;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/cmsOopClosures.hpp
--- a/src/hotspot/share/gc/cms/cmsOopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/cmsOopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,12 +48,7 @@
// because some CMS OopClosures derive from OopsInGenClosure. It would be
// good to get rid of them completely.
class MetadataAwareOopsInGenClosure: public OopsInGenClosure {
- KlassToOopClosure _klass_closure;
public:
- MetadataAwareOopsInGenClosure() {
- _klass_closure.initialize(this);
- }
-
virtual bool do_metadata() { return do_metadata_nv(); }
inline bool do_metadata_nv() { return true; }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp
--- a/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/cmsOopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -40,10 +40,8 @@
inline void MetadataAwareOopsInGenClosure::do_klass(Klass* k) { do_klass_nv(k); }
inline void MetadataAwareOopsInGenClosure::do_cld_nv(ClassLoaderData* cld) {
- assert(_klass_closure._oop_closure == this, "Must be");
-
bool claim = true; // Must claim the class loader data before processing.
- cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim);
+ cld->oops_do(this, claim);
}
// Decode the oop and call do_oop on it.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1553,9 +1553,10 @@
assert(_collectorState != Idling || _modUnionTable.isAllClear(),
"_modUnionTable should be clear if the baton was not passed");
_modUnionTable.clear_all();
- assert(_collectorState != Idling || _ct->klass_rem_set()->mod_union_is_clear(),
+ assert(_collectorState != Idling || _ct->cld_rem_set()->mod_union_is_clear(),
"mod union for klasses should be clear if the baton was passed");
- _ct->klass_rem_set()->clear_mod_union();
+ _ct->cld_rem_set()->clear_mod_union();
+
// We must adjust the allocation statistics being maintained
// in the free list space. We do so by reading and clearing
@@ -2025,7 +2026,7 @@
// that information. Tell the young collection to save the union of all
// modified klasses.
if (duringMarking) {
- _ct->klass_rem_set()->set_accumulate_modified_oops(true);
+ _ct->cld_rem_set()->set_accumulate_modified_oops(true);
}
bool registerClosure = duringMarking;
@@ -2101,7 +2102,7 @@
assert(haveFreelistLocks(), "must have freelist locks");
assert_lock_strong(bitMapLock());
- _ct->klass_rem_set()->set_accumulate_modified_oops(false);
+ _ct->cld_rem_set()->set_accumulate_modified_oops(false);
_cmsGen->gc_epilogue_work(full);
@@ -2380,18 +2381,18 @@
}
}
-class VerifyKlassOopsKlassClosure : public KlassClosure {
- class VerifyKlassOopsClosure : public OopClosure {
+class VerifyCLDOopsCLDClosure : public CLDClosure {
+ class VerifyCLDOopsClosure : public OopClosure {
CMSBitMap* _bitmap;
public:
- VerifyKlassOopsClosure(CMSBitMap* bitmap) : _bitmap(bitmap) { }
+ VerifyCLDOopsClosure(CMSBitMap* bitmap) : _bitmap(bitmap) { }
void do_oop(oop* p) { guarantee(*p == NULL || _bitmap->isMarked((HeapWord*) *p), "Should be marked"); }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
} _oop_closure;
public:
- VerifyKlassOopsKlassClosure(CMSBitMap* bitmap) : _oop_closure(bitmap) {}
- void do_klass(Klass* k) {
- k->oops_do(&_oop_closure);
+ VerifyCLDOopsCLDClosure(CMSBitMap* bitmap) : _oop_closure(bitmap) {}
+ void do_cld(ClassLoaderData* cld) {
+ cld->oops_do(&_oop_closure, false, false);
}
};
@@ -2437,8 +2438,8 @@
assert(verification_mark_stack()->isEmpty(), "Should have been drained");
verify_work_stacks_empty();
- VerifyKlassOopsKlassClosure verify_klass_oops(verification_mark_bm());
- ClassLoaderDataGraph::classes_do(&verify_klass_oops);
+ VerifyCLDOopsCLDClosure verify_cld_oops(verification_mark_bm());
+ ClassLoaderDataGraph::cld_do(&verify_cld_oops);
// Marking completed -- now verify that each bit marked in
// verification_mark_bm() is also marked in markBitMap(); flag all
@@ -2911,7 +2912,7 @@
" or no bits are set in the gc_prologue before the start of the next "
"subsequent marking phase.");
- assert(_ct->klass_rem_set()->mod_union_is_clear(), "Must be");
+ assert(_ct->cld_rem_set()->mod_union_is_clear(), "Must be");
// Save the end of the used_region of the constituent generations
// to be used to limit the extent of sweep in each generation.
@@ -3848,7 +3849,7 @@
}
}
- preclean_klasses(&mrias_cl, _cmsGen->freelistLock());
+ preclean_cld(&mrias_cl, _cmsGen->freelistLock());
curNumCards = preclean_card_table(_cmsGen, &smoac_cl);
cumNumCards += curNumCards;
@@ -4067,21 +4068,21 @@
return cumNumDirtyCards;
}
-class PrecleanKlassClosure : public KlassClosure {
- KlassToOopClosure _cm_klass_closure;
+class PrecleanCLDClosure : public CLDClosure {
+ MetadataAwareOopsInGenClosure* _cm_closure;
public:
- PrecleanKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
- void do_klass(Klass* k) {
- if (k->has_accumulated_modified_oops()) {
- k->clear_accumulated_modified_oops();
-
- _cm_klass_closure.do_klass(k);
+ PrecleanCLDClosure(MetadataAwareOopsInGenClosure* oop_closure) : _cm_closure(oop_closure) {}
+ void do_cld(ClassLoaderData* cld) {
+ if (cld->has_accumulated_modified_oops()) {
+ cld->clear_accumulated_modified_oops();
+
+ _cm_closure->do_cld(cld);
}
}
};
// The freelist lock is needed to prevent asserts, is it really needed?
-void CMSCollector::preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) {
+void CMSCollector::preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock) {
cl->set_freelistLock(freelistLock);
@@ -4089,8 +4090,8 @@
// SSS: Add equivalent to ScanMarkedObjectsAgainCarefullyClosure::do_yield_check and should_abort_preclean?
// SSS: We should probably check if precleaning should be aborted, at suitable intervals?
- PrecleanKlassClosure preclean_klass_closure(cl);
- ClassLoaderDataGraph::classes_do(&preclean_klass_closure);
+ PrecleanCLDClosure preclean_closure(cl);
+ ClassLoaderDataGraph::cld_do(&preclean_closure);
verify_work_stacks_empty();
verify_overflow_empty();
@@ -4250,7 +4251,7 @@
// Call isAllClear() under bitMapLock
assert(_modUnionTable.isAllClear(),
"Should be clear by end of the final marking");
- assert(_ct->klass_rem_set()->mod_union_is_clear(),
+ assert(_ct->cld_rem_set()->mod_union_is_clear(),
"Should be clear by end of the final marking");
}
@@ -4332,26 +4333,26 @@
void do_work_steal(int i, ParMarkRefsIntoAndScanClosure* cl, int* seed);
};
-class RemarkKlassClosure : public KlassClosure {
- KlassToOopClosure _cm_klass_closure;
+class RemarkCLDClosure : public CLDClosure {
+ CLDToOopClosure _cm_closure;
public:
- RemarkKlassClosure(OopClosure* oop_closure) : _cm_klass_closure(oop_closure) {}
- void do_klass(Klass* k) {
- // Check if we have modified any oops in the Klass during the concurrent marking.
- if (k->has_accumulated_modified_oops()) {
- k->clear_accumulated_modified_oops();
+ RemarkCLDClosure(OopClosure* oop_closure) : _cm_closure(oop_closure) {}
+ void do_cld(ClassLoaderData* cld) {
+ // Check if we have modified any oops in the CLD during the concurrent marking.
+ if (cld->has_accumulated_modified_oops()) {
+ cld->clear_accumulated_modified_oops();
// We could have transfered the current modified marks to the accumulated marks,
// like we do with the Card Table to Mod Union Table. But it's not really necessary.
- } else if (k->has_modified_oops()) {
+ } else if (cld->has_modified_oops()) {
// Don't clear anything, this info is needed by the next young collection.
} else {
- // No modified oops in the Klass.
+ // No modified oops in the ClassLoaderData.
return;
}
// The klass has modified fields, need to scan the klass.
- _cm_klass_closure.do_klass(k);
+ _cm_closure.do_cld(cld);
}
};
@@ -4439,24 +4440,24 @@
log_trace(gc, task)("Finished unhandled CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
}
- // ---------- dirty klass scanning ----------
+ // We might have added oops to ClassLoaderData::_handles during the
+ // concurrent marking phase. These oops do not always point to newly allocated objects
+ // that are guaranteed to be kept alive. Hence,
+ // we do have to revisit the _handles block during the remark phase.
+
+ // ---------- dirty CLD scanning ----------
if (worker_id == 0) { // Single threaded at the moment.
_timer.reset();
_timer.start();
// Scan all classes that was dirtied during the concurrent marking phase.
- RemarkKlassClosure remark_klass_closure(&par_mrias_cl);
- ClassLoaderDataGraph::classes_do(&remark_klass_closure);
+ RemarkCLDClosure remark_closure(&par_mrias_cl);
+ ClassLoaderDataGraph::cld_do(&remark_closure);
_timer.stop();
- log_trace(gc, task)("Finished dirty klass scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
- }
-
- // We might have added oops to ClassLoaderData::_handles during the
- // concurrent marking phase. These oops point to newly allocated objects
- // that are guaranteed to be kept alive. Either by the direct allocation
- // code, or when the young collector processes the roots. Hence,
- // we don't have to revisit the _handles block during the remark phase.
+ log_trace(gc, task)("Finished dirty CLD scanning work in %dth thread: %3.3f sec", worker_id, _timer.seconds());
+ }
+
// ---------- rescan dirty cards ------------
_timer.reset();
@@ -4981,23 +4982,21 @@
verify_work_stacks_empty();
}
+ // We might have added oops to ClassLoaderData::_handles during the
+ // concurrent marking phase. These oops do not point to newly allocated objects
+ // that are guaranteed to be kept alive. Hence,
+ // we do have to revisit the _handles block during the remark phase.
{
- GCTraceTime(Trace, gc, phases) t("Dirty Klass Scan", _gc_timer_cm);
+ GCTraceTime(Trace, gc, phases) t("Dirty CLD Scan", _gc_timer_cm);
verify_work_stacks_empty();
- RemarkKlassClosure remark_klass_closure(&mrias_cl);
- ClassLoaderDataGraph::classes_do(&remark_klass_closure);
+ RemarkCLDClosure remark_closure(&mrias_cl);
+ ClassLoaderDataGraph::cld_do(&remark_closure);
verify_work_stacks_empty();
}
- // We might have added oops to ClassLoaderData::_handles during the
- // concurrent marking phase. These oops point to newly allocated objects
- // that are guaranteed to be kept alive. Either by the direct allocation
- // code, or when the young collector processes the roots. Hence,
- // we don't have to revisit the _handles block during the remark phase.
-
verify_work_stacks_empty();
// Restore evacuated mark words, if any, used for overflow list links
restore_preserved_marks_if_any();
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -777,7 +777,7 @@
// Does precleaning work, returning a quantity indicative of
// the amount of "useful work" done.
size_t preclean_work(bool clean_refs, bool clean_survivors);
- void preclean_klasses(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock);
+ void preclean_cld(MarkRefsIntoAndScanClosure* cl, Mutex* freelistLock);
void abortable_preclean(); // Preclean while looking for possible abort
void initialize_sequential_subtasks_for_young_gen_rescan(int i);
// Helper function for above; merge-sorts the per-thread plab samples
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/parNewGeneration.cpp
--- a/src/hotspot/share/gc/cms/parNewGeneration.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -493,7 +493,7 @@
ParScanClosure::ParScanClosure(ParNewGeneration* g,
ParScanThreadState* par_scan_state) :
- OopsInKlassOrGenClosure(g), _par_scan_state(par_scan_state), _g(g) {
+ OopsInClassLoaderDataOrGenClosure(g), _par_scan_state(par_scan_state), _g(g) {
_boundary = _g->reserved().end();
}
@@ -601,11 +601,8 @@
par_scan_state.set_young_old_boundary(_young_old_boundary);
- KlassScanClosure klass_scan_closure(&par_scan_state.to_space_root_closure(),
- gch->rem_set()->klass_rem_set());
- CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
- &par_scan_state.to_space_root_closure(),
- false);
+ CLDScanClosure cld_scan_closure(&par_scan_state.to_space_root_closure(),
+ gch->rem_set()->cld_rem_set()->accumulate_modified_oops());
par_scan_state.start_strong_roots();
gch->young_process_roots(_strong_roots_scope,
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/parOopClosures.hpp
--- a/src/hotspot/share/gc/cms/parOopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/parOopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,7 +37,7 @@
typedef GenericTaskQueueSet ObjToScanQueueSet;
class ParallelTaskTerminator;
-class ParScanClosure: public OopsInKlassOrGenClosure {
+class ParScanClosure: public OopsInClassLoaderDataOrGenClosure {
protected:
ParScanThreadState* _par_scan_state;
ParNewGeneration* _g;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/cms/parOopClosures.inline.hpp
--- a/src/hotspot/share/gc/cms/parOopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/cms/parOopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -126,8 +126,8 @@
(void)_par_scan_state->trim_queues(10 * ParallelGCThreads);
}
}
- if (is_scanning_a_klass()) {
- do_klass_barrier();
+ if (is_scanning_a_cld()) {
+ do_cld_barrier();
} else if (gc_barrier) {
// Now call parent closure
par_do_barrier(p);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/g1/g1CollectedHeap.hpp
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -63,7 +63,6 @@
class GenerationSpec;
class G1ParScanThreadState;
class G1ParScanThreadStateSet;
-class G1KlassScanClosure;
class G1ParScanThreadState;
class ObjectClosure;
class SpaceClosure;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/g1/g1HeapVerifier.cpp
--- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -161,18 +161,18 @@
void reset_count() { _count = 0; };
};
-class VerifyKlassClosure: public KlassClosure {
+class VerifyCLDClosure: public CLDClosure {
YoungRefCounterClosure _young_ref_counter_closure;
OopClosure *_oop_closure;
public:
- VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
- void do_klass(Klass* k) {
- k->oops_do(_oop_closure);
+ VerifyCLDClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {}
+ void do_cld(ClassLoaderData* cld) {
+ cld->oops_do(_oop_closure, false);
_young_ref_counter_closure.reset_count();
- k->oops_do(&_young_ref_counter_closure);
+ cld->oops_do(&_young_ref_counter_closure, false);
if (_young_ref_counter_closure.count() > 0) {
- guarantee(k->has_modified_oops(), "Klass " PTR_FORMAT ", has young refs but is not dirty.", p2i(k));
+ guarantee(cld->has_modified_oops(), "CLD " PTR_FORMAT ", has young %d refs but is not dirty.", p2i(cld), _young_ref_counter_closure.count());
}
}
};
@@ -390,8 +390,7 @@
log_debug(gc, verify)("Roots");
VerifyRootsClosure rootsCl(vo);
- VerifyKlassClosure klassCl(_g1h, &rootsCl);
- CLDToKlassAndOopClosure cldCl(&klassCl, &rootsCl, false);
+ VerifyCLDClosure cldCl(_g1h, &rootsCl);
// We apply the relevant closures to all the oops in the
// system dictionary, class loader data graph, the string table
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/g1/g1OopClosures.cpp
--- a/src/hotspot/share/gc/g1/g1OopClosures.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1OopClosures.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,7 @@
_g1(g1),
_par_scan_state(par_scan_state),
_worker_id(par_scan_state->worker_id()),
- _scanned_klass(NULL),
+ _scanned_cld(NULL),
_cm(_g1->concurrent_mark())
{ }
@@ -42,20 +42,20 @@
_g1(g1), _par_scan_state(par_scan_state), _from(NULL)
{ }
-void G1KlassScanClosure::do_klass(Klass* klass) {
- // If the klass has not been dirtied we know that there's
+void G1CLDScanClosure::do_cld(ClassLoaderData* cld) {
+ // If the class loader data has not been dirtied we know that there's
// no references into the young gen and we can skip it.
- if (!_process_only_dirty || klass->has_modified_oops()) {
- // Clean the klass since we're going to scavenge all the metadata.
- klass->clear_modified_oops();
+ if (!_process_only_dirty || cld->has_modified_oops()) {
- // Tell the closure that this klass is the Klass to scavenge
+ // Tell the closure that this class loader data is the CLD to scavenge
// and is the one to dirty if oops are left pointing into the young gen.
- _closure->set_scanned_klass(klass);
+ _closure->set_scanned_cld(cld);
- klass->oops_do(_closure);
+ // Clean the cld since we're going to scavenge all the metadata.
+ // Clear modified oops only if this cld is claimed.
+ cld->oops_do(_closure, _must_claim, /*clear_modified_oops*/true);
- _closure->set_scanned_klass(NULL);
+ _closure->set_scanned_cld(NULL);
}
_count++;
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/g1/g1OopClosures.hpp
--- a/src/hotspot/share/gc/g1/g1OopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1OopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -107,7 +107,7 @@
G1CollectedHeap* _g1;
G1ParScanThreadState* _par_scan_state;
uint _worker_id; // Cache value from par_scan_state.
- Klass* _scanned_klass;
+ ClassLoaderData* _scanned_cld;
G1ConcurrentMark* _cm;
// Mark the object if it's not already marked. This is used to mark
@@ -124,13 +124,13 @@
~G1ParCopyHelper() { }
public:
- void set_scanned_klass(Klass* k) { _scanned_klass = k; }
- template inline void do_klass_barrier(T* p, oop new_obj);
+ void set_scanned_cld(ClassLoaderData* cld) { _scanned_cld = cld; }
+ inline void do_cld_barrier(oop new_obj);
};
enum G1Barrier {
G1BarrierNone,
- G1BarrierKlass
+ G1BarrierCLD
};
enum G1Mark {
@@ -150,14 +150,16 @@
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
};
-class G1KlassScanClosure : public KlassClosure {
+class G1CLDScanClosure : public CLDClosure {
G1ParCopyHelper* _closure;
bool _process_only_dirty;
+ bool _must_claim;
int _count;
public:
- G1KlassScanClosure(G1ParCopyHelper* closure, bool process_only_dirty)
- : _process_only_dirty(process_only_dirty), _closure(closure), _count(0) {}
- void do_klass(Klass* klass);
+ G1CLDScanClosure(G1ParCopyHelper* closure,
+ bool process_only_dirty, bool must_claim)
+ : _process_only_dirty(process_only_dirty), _must_claim(must_claim), _closure(closure), _count(0) {}
+ void do_cld(ClassLoaderData* cld);
};
// Closure for iterating over object fields during concurrent marking
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/g1/g1OopClosures.inline.hpp
--- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -195,10 +195,9 @@
}
}
-template
-void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) {
+void G1ParCopyHelper::do_cld_barrier(oop new_obj) {
if (_g1->heap_region_containing(new_obj)->is_young()) {
- _scanned_klass->record_modified_oops();
+ _scanned_cld->record_modified_oops();
}
}
@@ -249,8 +248,8 @@
mark_forwarded_object(obj, forwardee);
}
- if (barrier == G1BarrierKlass) {
- do_klass_barrier(p, forwardee);
+ if (barrier == G1BarrierCLD) {
+ do_cld_barrier(forwardee);
}
} else {
if (state.is_humongous()) {
@@ -267,5 +266,4 @@
}
}
}
-
#endif // SHARE_VM_GC_G1_G1OOPCLOSURES_INLINE_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/g1/g1SharedClosures.hpp
--- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,18 +34,17 @@
template
class G1SharedClosures VALUE_OBJ_CLASS_SPEC {
public:
- G1ParCopyClosure _oops;
- G1ParCopyClosure _oop_in_klass;
- G1KlassScanClosure _klass_in_cld_closure;
- CLDToKlassAndOopClosure _clds;
- G1CodeBlobClosure _codeblobs;
- BufferingOopClosure _buffered_oops;
+ G1ParCopyClosure _oops;
+ G1ParCopyClosure _oops_in_cld;
- G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) :
+ G1CLDScanClosure _clds;
+ G1CodeBlobClosure _codeblobs;
+ BufferingOopClosure _buffered_oops;
+
+ G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty, bool must_claim_cld) :
_oops(g1h, pss),
- _oop_in_klass(g1h, pss),
- _klass_in_cld_closure(&_oop_in_klass, process_only_dirty_klasses),
- _clds(&_klass_in_cld_closure, &_oops, must_claim_cld),
+ _oops_in_cld(g1h, pss),
+ _clds(&_oops_in_cld, process_only_dirty, must_claim_cld),
_codeblobs(&_oops),
_buffered_oops(&_oops) {}
};
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/parallel/pcTasks.cpp
--- a/src/hotspot/share/gc/parallel/pcTasks.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/pcTasks.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -81,7 +81,6 @@
ParCompactionManager* cm =
ParCompactionManager::gc_thread_compaction_manager(which);
ParCompactionManager::MarkAndPushClosure mark_and_push_closure(cm);
- ParCompactionManager::FollowKlassClosure follow_klass_closure(&mark_and_push_closure);
switch (_root_type) {
case universe:
@@ -117,7 +116,7 @@
break;
case class_loader_data:
- ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, &follow_klass_closure, true);
+ ClassLoaderDataGraph::always_strong_oops_do(&mark_and_push_closure, true);
break;
case code_cache:
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/parallel/psCompactionManager.hpp
--- a/src/hotspot/share/gc/parallel/psCompactionManager.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psCompactionManager.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -196,17 +196,6 @@
FollowStackClosure(ParCompactionManager* cm) : _compaction_manager(cm) { }
virtual void do_void();
};
-
- // The one and only place to start following the classes.
- // Should only be applied to the ClassLoaderData klasses list.
- class FollowKlassClosure : public KlassClosure {
- private:
- MarkAndPushClosure* _mark_and_push_closure;
- public:
- FollowKlassClosure(MarkAndPushClosure* mark_and_push_closure) :
- _mark_and_push_closure(mark_and_push_closure) { }
- void do_klass(Klass* klass);
- };
};
inline ParCompactionManager* ParCompactionManager::manager_array(uint index) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp
--- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -98,15 +98,10 @@
_compaction_manager->follow_marking_stacks();
}
-inline void ParCompactionManager::FollowKlassClosure::do_klass(Klass* klass) {
- klass->oops_do(_mark_and_push_closure);
-}
-
inline void ParCompactionManager::follow_class_loader(ClassLoaderData* cld) {
MarkAndPushClosure mark_and_push_closure(this);
- FollowKlassClosure follow_klass_closure(&mark_and_push_closure);
- cld->oops_do(&mark_and_push_closure, &follow_klass_closure, true);
+ cld->oops_do(&mark_and_push_closure, true);
}
inline void ParCompactionManager::follow_contents(oop obj) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/parallel/psParallelCompact.cpp
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -838,11 +838,6 @@
bool PSParallelCompact::IsAliveClosure::do_object_b(oop p) { return mark_bitmap()->is_marked(p); }
-void PSParallelCompact::AdjustKlassClosure::do_klass(Klass* klass) {
- PSParallelCompact::AdjustPointerClosure closure(_cm);
- klass->oops_do(&closure);
-}
-
void PSParallelCompact::post_initialize() {
ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
MemRegion mr = heap->reserved_region();
@@ -2162,7 +2157,6 @@
ClassLoaderDataGraph::clear_claimed_marks();
PSParallelCompact::AdjustPointerClosure oop_closure(cm);
- PSParallelCompact::AdjustKlassClosure klass_closure(cm);
// General strong roots.
Universe::oops_do(&oop_closure);
@@ -2172,7 +2166,7 @@
Management::oops_do(&oop_closure);
JvmtiExport::oops_do(&oop_closure);
SystemDictionary::oops_do(&oop_closure);
- ClassLoaderDataGraph::oops_do(&oop_closure, &klass_closure, true);
+ ClassLoaderDataGraph::oops_do(&oop_closure, true);
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/parallel/psScavenge.inline.hpp
--- a/src/hotspot/share/gc/parallel/psScavenge.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psScavenge.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -85,15 +85,15 @@
typedef PSRootsClosure*promote_immediately=*/false> PSScavengeRootsClosure;
typedef PSRootsClosure*promote_immediately=*/true> PSPromoteRootsClosure;
-// Scavenges a single oop in a Klass.
-class PSScavengeFromKlassClosure: public OopClosure {
+// Scavenges a single oop in a ClassLoaderData.
+class PSScavengeFromCLDClosure: public OopClosure {
private:
PSPromotionManager* _pm;
- // Used to redirty a scanned klass if it has oops
+ // Used to redirty a scanned cld if it has oops
// pointing to the young generation after being scanned.
- Klass* _scanned_klass;
+ ClassLoaderData* _scanned_cld;
public:
- PSScavengeFromKlassClosure(PSPromotionManager* pm) : _pm(pm), _scanned_klass(NULL) { }
+ PSScavengeFromCLDClosure(PSPromotionManager* pm) : _pm(pm), _scanned_cld(NULL) { }
void do_oop(narrowOop* p) { ShouldNotReachHere(); }
void do_oop(oop* p) {
ParallelScavengeHeap* psh = ParallelScavengeHeap::heap();
@@ -111,48 +111,46 @@
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
if (PSScavenge::is_obj_in_young(new_obj)) {
- do_klass_barrier();
+ do_cld_barrier();
}
}
}
- void set_scanned_klass(Klass* klass) {
- assert(_scanned_klass == NULL || klass == NULL, "Should always only handling one klass at a time");
- _scanned_klass = klass;
+ void set_scanned_cld(ClassLoaderData* cld) {
+ assert(_scanned_cld == NULL || cld == NULL, "Should always only handling one cld at a time");
+ _scanned_cld = cld;
}
private:
- void do_klass_barrier() {
- assert(_scanned_klass != NULL, "Should not be called without having a scanned klass");
- _scanned_klass->record_modified_oops();
+ void do_cld_barrier() {
+ assert(_scanned_cld != NULL, "Should not be called without having a scanned cld");
+ _scanned_cld->record_modified_oops();
}
-
};
-// Scavenges the oop in a Klass.
-class PSScavengeKlassClosure: public KlassClosure {
+// Scavenges the oop in a ClassLoaderData.
+class PSScavengeCLDClosure: public CLDClosure {
private:
- PSScavengeFromKlassClosure _oop_closure;
+ PSScavengeFromCLDClosure _oop_closure;
protected:
public:
- PSScavengeKlassClosure(PSPromotionManager* pm) : _oop_closure(pm) { }
- void do_klass(Klass* klass) {
- // If the klass has not been dirtied we know that there's
+ PSScavengeCLDClosure(PSPromotionManager* pm) : _oop_closure(pm) { }
+ void do_cld(ClassLoaderData* cld) {
+ // If the cld has not been dirtied we know that there's
// no references into the young gen and we can skip it.
- if (klass->has_modified_oops()) {
- // Clean the klass since we're going to scavenge all the metadata.
- klass->clear_modified_oops();
-
- // Setup the promotion manager to redirty this klass
+ if (cld->has_modified_oops()) {
+ // Setup the promotion manager to redirty this cld
// if references are left in the young gen.
- _oop_closure.set_scanned_klass(klass);
+ _oop_closure.set_scanned_cld(cld);
- klass->oops_do(&_oop_closure);
+ // Clean the cld since we're going to scavenge all the metadata.
+ cld->oops_do(&_oop_closure, false, /*clear_modified_oops*/true);
- _oop_closure.set_scanned_klass(NULL);
+ _oop_closure.set_scanned_cld(NULL);
}
}
};
+
#endif // SHARE_VM_GC_PARALLEL_PSSCAVENGE_INLINE_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/parallel/psTasks.cpp
--- a/src/hotspot/share/gc/parallel/psTasks.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/parallel/psTasks.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -79,8 +79,8 @@
case class_loader_data:
{
- PSScavengeKlassClosure klass_closure(pm);
- ClassLoaderDataGraph::oops_do(&roots_closure, &klass_closure, false);
+ PSScavengeCLDClosure cld_closure(pm);
+ ClassLoaderDataGraph::cld_do(&cld_closure);
}
break;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/serial/defNewGeneration.cpp
--- a/src/hotspot/share/gc/serial/defNewGeneration.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -121,7 +121,7 @@
}
ScanClosure::ScanClosure(DefNewGeneration* g, bool gc_barrier) :
- OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
+ OopsInClassLoaderDataOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
_boundary = _g->reserved().end();
}
@@ -130,7 +130,7 @@
void ScanClosure::do_oop(narrowOop* p) { ScanClosure::do_oop_work(p); }
FastScanClosure::FastScanClosure(DefNewGeneration* g, bool gc_barrier) :
- OopsInKlassOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
+ OopsInClassLoaderDataOrGenClosure(g), _g(g), _gc_barrier(gc_barrier)
{
_boundary = _g->reserved().end();
}
@@ -138,30 +138,28 @@
void FastScanClosure::do_oop(oop* p) { FastScanClosure::do_oop_work(p); }
void FastScanClosure::do_oop(narrowOop* p) { FastScanClosure::do_oop_work(p); }
-void KlassScanClosure::do_klass(Klass* klass) {
+void CLDScanClosure::do_cld(ClassLoaderData* cld) {
NOT_PRODUCT(ResourceMark rm);
- log_develop_trace(gc, scavenge)("KlassScanClosure::do_klass " PTR_FORMAT ", %s, dirty: %s",
- p2i(klass),
- klass->external_name(),
- klass->has_modified_oops() ? "true" : "false");
+ log_develop_trace(gc, scavenge)("CLDScanClosure::do_cld " PTR_FORMAT ", %s, dirty: %s",
+ p2i(cld),
+ cld->loader_name(),
+ cld->has_modified_oops() ? "true" : "false");
- // If the klass has not been dirtied we know that there's
+ // If the cld has not been dirtied we know that there's
// no references into the young gen and we can skip it.
- if (klass->has_modified_oops()) {
+ if (cld->has_modified_oops()) {
if (_accumulate_modified_oops) {
- klass->accumulate_modified_oops();
+ cld->accumulate_modified_oops();
}
- // Clear this state since we're going to scavenge all the metadata.
- klass->clear_modified_oops();
-
- // Tell the closure which Klass is being scanned so that it can be dirtied
+ // Tell the closure which CLD is being scanned so that it can be dirtied
// if oops are left pointing into the young gen.
- _scavenge_closure->set_scanned_klass(klass);
+ _scavenge_closure->set_scanned_cld(cld);
- klass->oops_do(_scavenge_closure);
+ // Clean the cld since we're going to scavenge all the metadata.
+ cld->oops_do(_scavenge_closure, false, /*clear_modified_oops*/true);
- _scavenge_closure->set_scanned_klass(NULL);
+ _scavenge_closure->set_scanned_cld(NULL);
}
}
@@ -177,12 +175,6 @@
void FilteringClosure::do_oop(oop* p) { FilteringClosure::do_oop_work(p); }
void FilteringClosure::do_oop(narrowOop* p) { FilteringClosure::do_oop_work(p); }
-KlassScanClosure::KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure,
- KlassRemSet* klass_rem_set)
- : _scavenge_closure(scavenge_closure),
- _accumulate_modified_oops(klass_rem_set->accumulate_modified_oops()) {}
-
-
DefNewGeneration::DefNewGeneration(ReservedSpace rs,
size_t initial_size,
const char* policy)
@@ -629,11 +621,8 @@
FastScanClosure fsc_with_no_gc_barrier(this, false);
FastScanClosure fsc_with_gc_barrier(this, true);
- KlassScanClosure klass_scan_closure(&fsc_with_no_gc_barrier,
- gch->rem_set()->klass_rem_set());
- CLDToKlassAndOopClosure cld_scan_closure(&klass_scan_closure,
- &fsc_with_no_gc_barrier,
- false);
+ CLDScanClosure cld_scan_closure(&fsc_with_no_gc_barrier,
+ gch->rem_set()->cld_rem_set()->accumulate_modified_oops());
set_promo_failure_scan_stack_closure(&fsc_with_no_gc_barrier);
FastEvacuateFollowersClosure evacuate_followers(gch,
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/shared/cardTableRS.cpp
--- a/src/hotspot/share/gc/shared/cardTableRS.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/cardTableRS.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -34,16 +34,16 @@
#include "runtime/os.hpp"
#include "utilities/macros.hpp"
-class HasAccumulatedModifiedOopsClosure : public KlassClosure {
+class HasAccumulatedModifiedOopsClosure : public CLDClosure {
bool _found;
public:
HasAccumulatedModifiedOopsClosure() : _found(false) {}
- void do_klass(Klass* klass) {
+ void do_cld(ClassLoaderData* cld) {
if (_found) {
return;
}
- if (klass->has_accumulated_modified_oops()) {
+ if (cld->has_accumulated_modified_oops()) {
_found = true;
}
}
@@ -52,28 +52,29 @@
}
};
-bool KlassRemSet::mod_union_is_clear() {
+bool CLDRemSet::mod_union_is_clear() {
HasAccumulatedModifiedOopsClosure closure;
- ClassLoaderDataGraph::classes_do(&closure);
+ ClassLoaderDataGraph::cld_do(&closure);
return !closure.found();
}
-class ClearKlassModUnionClosure : public KlassClosure {
+class ClearCLDModUnionClosure : public CLDClosure {
public:
- void do_klass(Klass* klass) {
- if (klass->has_accumulated_modified_oops()) {
- klass->clear_accumulated_modified_oops();
+ void do_cld(ClassLoaderData* cld) {
+ if (cld->has_accumulated_modified_oops()) {
+ cld->clear_accumulated_modified_oops();
}
}
};
-void KlassRemSet::clear_mod_union() {
- ClearKlassModUnionClosure closure;
- ClassLoaderDataGraph::classes_do(&closure);
+void CLDRemSet::clear_mod_union() {
+ ClearCLDModUnionClosure closure;
+ ClassLoaderDataGraph::cld_do(&closure);
}
+
CardTableRS::CardTableRS(MemRegion whole_heap) :
_bs(NULL),
_cur_youngergen_card_val(youngergenP1_card)
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/shared/cardTableRS.hpp
--- a/src/hotspot/share/gc/shared/cardTableRS.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/cardTableRS.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,11 +31,11 @@
class Space;
class OopsInGenClosure;
-// Helper to remember modified oops in all klasses.
-class KlassRemSet {
+// Helper to remember modified oops in all clds.
+class CLDRemSet {
bool _accumulate_modified_oops;
public:
- KlassRemSet() : _accumulate_modified_oops(false) {}
+ CLDRemSet() : _accumulate_modified_oops(false) {}
void set_accumulate_modified_oops(bool value) { _accumulate_modified_oops = value; }
bool accumulate_modified_oops() { return _accumulate_modified_oops; }
bool mod_union_is_clear();
@@ -64,7 +64,7 @@
return CardTableModRefBSForCTRS::card_is_dirty_wrt_gen_iter(cv);
}
- KlassRemSet _klass_rem_set;
+ CLDRemSet _cld_rem_set;
BarrierSet* _bs;
CardTableModRefBSForCTRS* _ct_bs;
@@ -121,7 +121,7 @@
// Set the barrier set.
void set_bs(BarrierSet* bs) { _bs = bs; }
- KlassRemSet* klass_rem_set() { return &_klass_rem_set; }
+ CLDRemSet* cld_rem_set() { return &_cld_rem_set; }
CardTableModRefBSForCTRS* ct_bs() { return _ct_bs; }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/shared/genOopClosures.hpp
--- a/src/hotspot/share/gc/shared/genOopClosures.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/genOopClosures.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -81,24 +81,25 @@
};
-// Super class for scan closures. It contains code to dirty scanned Klasses.
-class OopsInKlassOrGenClosure: public OopsInGenClosure {
- Klass* _scanned_klass;
+// Super class for scan closures. It contains code to dirty scanned class loader data.
+class OopsInClassLoaderDataOrGenClosure: public OopsInGenClosure {
+ ClassLoaderData* _scanned_cld;
public:
- OopsInKlassOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_klass(NULL) {}
- void set_scanned_klass(Klass* k) {
- assert(k == NULL || _scanned_klass == NULL, "Must be");
- _scanned_klass = k;
+ OopsInClassLoaderDataOrGenClosure(Generation* g) : OopsInGenClosure(g), _scanned_cld(NULL) {}
+ void set_scanned_cld(ClassLoaderData* cld) {
+ assert(cld == NULL || _scanned_cld == NULL, "Must be");
+ _scanned_cld = cld;
}
- bool is_scanning_a_klass() { return _scanned_klass != NULL; }
- void do_klass_barrier();
+ bool is_scanning_a_cld() { return _scanned_cld != NULL; }
+ void do_cld_barrier();
};
+
// Closure for scanning DefNewGeneration.
//
// This closure will perform barrier store calls for ALL
// pointers in scanned oops.
-class ScanClosure: public OopsInKlassOrGenClosure {
+class ScanClosure: public OopsInClassLoaderDataOrGenClosure {
protected:
DefNewGeneration* _g;
HeapWord* _boundary;
@@ -117,7 +118,7 @@
// This closure only performs barrier store calls on
// pointers into the DefNewGeneration. This is less
// precise, but faster, than a ScanClosure
-class FastScanClosure: public OopsInKlassOrGenClosure {
+class FastScanClosure: public OopsInClassLoaderDataOrGenClosure {
protected:
DefNewGeneration* _g;
HeapWord* _boundary;
@@ -131,14 +132,15 @@
inline void do_oop_nv(narrowOop* p);
};
-class KlassScanClosure: public KlassClosure {
- OopsInKlassOrGenClosure* _scavenge_closure;
+class CLDScanClosure: public CLDClosure {
+ OopsInClassLoaderDataOrGenClosure* _scavenge_closure;
// true if the the modified oops state should be saved.
- bool _accumulate_modified_oops;
+ bool _accumulate_modified_oops;
public:
- KlassScanClosure(OopsInKlassOrGenClosure* scavenge_closure,
- KlassRemSet* klass_rem_set_policy);
- void do_klass(Klass* k);
+ CLDScanClosure(OopsInClassLoaderDataOrGenClosure* scavenge_closure,
+ bool accumulate_modified_oops) :
+ _scavenge_closure(scavenge_closure), _accumulate_modified_oops(accumulate_modified_oops) {}
+ void do_cld(ClassLoaderData* cld);
};
class FilteringClosure: public ExtendedOopClosure {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/gc/shared/genOopClosures.inline.hpp
--- a/src/hotspot/share/gc/shared/genOopClosures.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/gc/shared/genOopClosures.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -68,9 +68,11 @@
}
}
-inline void OopsInKlassOrGenClosure::do_klass_barrier() {
- assert(_scanned_klass != NULL, "Must be");
- _scanned_klass->record_modified_oops();
+inline void OopsInClassLoaderDataOrGenClosure::do_cld_barrier() {
+ assert(_scanned_cld != NULL, "Must be");
+ if (!_scanned_cld->has_modified_oops()) {
+ _scanned_cld->record_modified_oops();
+ }
}
// NOTE! Any changes made here should also be made
@@ -87,8 +89,8 @@
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
}
- if (is_scanning_a_klass()) {
- do_klass_barrier();
+ if (is_scanning_a_cld()) {
+ do_cld_barrier();
} else if (_gc_barrier) {
// Now call parent closure
do_barrier(p);
@@ -111,8 +113,8 @@
oop new_obj = obj->is_forwarded() ? obj->forwardee()
: _g->copy_to_survivor_space(obj);
oopDesc::encode_store_heap_oop_not_null(p, new_obj);
- if (is_scanning_a_klass()) {
- do_klass_barrier();
+ if (is_scanning_a_cld()) {
+ do_cld_barrier();
} else if (_gc_barrier) {
// Now call parent closure
do_barrier(p);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -412,6 +412,7 @@
} else if (strcmp(vmField.typeString, "address") == 0 ||
strcmp(vmField.typeString, "intptr_t") == 0 ||
strcmp(vmField.typeString, "uintptr_t") == 0 ||
+ strcmp(vmField.typeString, "OopHandle") == 0 ||
strcmp(vmField.typeString, "size_t") == 0 ||
// All foo* types are addresses.
vmField.typeString[strlen(vmField.typeString) - 1] == '*') {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/jvmci/vmStructs_jvmci.cpp
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
#include "jvmci/vmStructs_compiler_runtime.hpp"
#include "jvmci/vmStructs_jvmci.hpp"
#include "oops/oop.hpp"
+#include "oops/oopHandle.hpp"
#include "oops/objArrayKlass.hpp"
#include "runtime/globals.hpp"
#include "runtime/sharedRuntime.hpp"
@@ -192,7 +193,7 @@
nonstatic_field(Klass, _name, Symbol*) \
nonstatic_field(Klass, _prototype_header, markOop) \
nonstatic_field(Klass, _next_sibling, Klass*) \
- nonstatic_field(Klass, _java_mirror, oop) \
+ nonstatic_field(Klass, _java_mirror, OopHandle) \
nonstatic_field(Klass, _modifier_flags, jint) \
nonstatic_field(Klass, _access_flags, AccessFlags) \
\
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/allocation.hpp
--- a/src/hotspot/share/memory/allocation.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/allocation.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -233,7 +233,6 @@
void print_address_on(outputStream* st) const; // nonvirtual address printing
#define METASPACE_OBJ_TYPES_DO(f) \
- f(Unknown) \
f(Class) \
f(Symbol) \
f(TypeArrayU1) \
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/filemap.cpp
--- a/src/hotspot/share/memory/filemap.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/filemap.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -182,6 +182,7 @@
_obj_alignment = ObjectAlignmentInBytes;
_compact_strings = CompactStrings;
_narrow_oop_mode = Universe::narrow_oop_mode();
+ _narrow_oop_base = Universe::narrow_oop_base();
_narrow_oop_shift = Universe::narrow_oop_shift();
_max_heap_size = MaxHeapSize;
_narrow_klass_base = Universe::narrow_klass_base();
@@ -687,8 +688,14 @@
// open archive objects.
void FileMapInfo::map_heap_regions() {
if (MetaspaceShared::is_heap_object_archiving_allowed()) {
+ log_info(cds)("Archived narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
+ narrow_oop_mode(), p2i(narrow_oop_base()), narrow_oop_shift());
+ log_info(cds)("Archived narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ p2i(narrow_klass_base()), narrow_klass_shift());
+
// Check that all the narrow oop and klass encodings match the archive
if (narrow_oop_mode() != Universe::narrow_oop_mode() ||
+ narrow_oop_base() != Universe::narrow_oop_base() ||
narrow_oop_shift() != Universe::narrow_oop_shift() ||
narrow_klass_base() != Universe::narrow_klass_base() ||
narrow_klass_shift() != Universe::narrow_klass_shift()) {
@@ -697,6 +704,11 @@
"The current CompressedOops/CompressedClassPointers encoding differs from "
"that archived due to heap size change. The archive was dumped using max heap "
"size " UINTX_FORMAT "M.", max_heap_size()/M);
+ log_info(cds)("Current narrow_oop_mode = %d, narrow_oop_base = " PTR_FORMAT ", narrow_oop_shift = %d",
+ Universe::narrow_oop_mode(), p2i(Universe::narrow_oop_base()),
+ Universe::narrow_oop_shift());
+ log_info(cds)("Current narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
+ p2i(Universe::narrow_klass_base()), Universe::narrow_klass_shift());
}
} else {
// First, map string regions as closed archive heap regions.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/filemap.hpp
--- a/src/hotspot/share/memory/filemap.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/filemap.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -112,6 +112,7 @@
int _version; // (from enum, above.)
size_t _alignment; // how shared archive should be aligned
int _obj_alignment; // value of ObjectAlignmentInBytes
+ address _narrow_oop_base; // compressed oop encoding base
int _narrow_oop_shift; // compressed oop encoding shift
bool _compact_strings; // value of CompactStrings
uintx _max_heap_size; // java max heap size during dumping
@@ -203,12 +204,13 @@
int version() { return _header->_version; }
size_t alignment() { return _header->_alignment; }
Universe::NARROW_OOP_MODE narrow_oop_mode() { return _header->_narrow_oop_mode; }
- int narrow_oop_shift() { return _header->_narrow_oop_shift; }
- uintx max_heap_size() { return _header->_max_heap_size; }
- address narrow_klass_base() const { return _header->_narrow_klass_base; }
+ address narrow_oop_base() const { return _header->_narrow_oop_base; }
+ int narrow_oop_shift() const { return _header->_narrow_oop_shift; }
+ uintx max_heap_size() const { return _header->_max_heap_size; }
+ address narrow_klass_base() const { return _header->_narrow_klass_base; }
int narrow_klass_shift() const { return _header->_narrow_klass_shift; }
- struct FileMapHeader* header() { return _header; }
- char* misc_data_patching_start() { return _header->_misc_data_patching_start; }
+ struct FileMapHeader* header() { return _header; }
+ char* misc_data_patching_start() { return _header->_misc_data_patching_start; }
void set_misc_data_patching_start(char* p) { _header->_misc_data_patching_start = p; }
char* read_only_tables_start() { return _header->_read_only_tables_start; }
void set_read_only_tables_start(char* p) { _header->_read_only_tables_start = p; }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/iterator.cpp
--- a/src/hotspot/share/memory/iterator.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/iterator.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,17 +29,8 @@
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
-void KlassToOopClosure::do_klass(Klass* k) {
- assert(_oop_closure != NULL, "Not initialized?");
- k->oops_do(_oop_closure);
-}
-
void CLDToOopClosure::do_cld(ClassLoaderData* cld) {
- cld->oops_do(_oop_closure, &_klass_closure, _must_claim_cld);
-}
-
-void CLDToKlassAndOopClosure::do_cld(ClassLoaderData* cld) {
- cld->oops_do(_oop_closure, _klass_closure, _must_claim_cld);
+ cld->oops_do(_oop_closure, _must_claim_cld);
}
void ObjectToOopClosure::do_object(oop obj) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/iterator.hpp
--- a/src/hotspot/share/memory/iterator.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/iterator.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -138,67 +138,27 @@
virtual void do_cld(ClassLoaderData* cld) = 0;
};
-class KlassToOopClosure : public KlassClosure {
- friend class MetadataAwareOopClosure;
- friend class MetadataAwareOopsInGenClosure;
-
- OopClosure* _oop_closure;
-
- // Used when _oop_closure couldn't be set in an initialization list.
- void initialize(OopClosure* oop_closure) {
- assert(_oop_closure == NULL, "Should only be called once");
- _oop_closure = oop_closure;
- }
-
- public:
- KlassToOopClosure(OopClosure* oop_closure = NULL) : _oop_closure(oop_closure) {}
-
- virtual void do_klass(Klass* k);
-};
class CLDToOopClosure : public CLDClosure {
OopClosure* _oop_closure;
- KlassToOopClosure _klass_closure;
bool _must_claim_cld;
public:
CLDToOopClosure(OopClosure* oop_closure, bool must_claim_cld = true) :
_oop_closure(oop_closure),
- _klass_closure(oop_closure),
_must_claim_cld(must_claim_cld) {}
void do_cld(ClassLoaderData* cld);
};
-class CLDToKlassAndOopClosure : public CLDClosure {
- friend class G1CollectedHeap;
- protected:
- OopClosure* _oop_closure;
- KlassClosure* _klass_closure;
- bool _must_claim_cld;
- public:
- CLDToKlassAndOopClosure(KlassClosure* klass_closure,
- OopClosure* oop_closure,
- bool must_claim_cld) :
- _oop_closure(oop_closure),
- _klass_closure(klass_closure),
- _must_claim_cld(must_claim_cld) {}
- void do_cld(ClassLoaderData* cld);
-};
-
// The base class for all concurrent marking closures,
// that participates in class unloading.
// It's used to proxy through the metadata to the oops defined in them.
class MetadataAwareOopClosure: public ExtendedOopClosure {
- KlassToOopClosure _klass_closure;
public:
- MetadataAwareOopClosure() : ExtendedOopClosure() {
- _klass_closure.initialize(this);
- }
- MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) {
- _klass_closure.initialize(this);
- }
+ MetadataAwareOopClosure() : ExtendedOopClosure() { }
+ MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) { }
bool do_metadata_nv() { return true; }
virtual bool do_metadata() { return do_metadata_nv(); }
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/iterator.inline.hpp
--- a/src/hotspot/share/memory/iterator.inline.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/iterator.inline.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,10 +37,8 @@
#include "utilities/debug.hpp"
inline void MetadataAwareOopClosure::do_cld_nv(ClassLoaderData* cld) {
- assert(_klass_closure._oop_closure == this, "Must be");
-
bool claim = true; // Must claim the class loader data before processing.
- cld->oops_do(_klass_closure._oop_closure, &_klass_closure, claim);
+ cld->oops_do(this, claim);
}
inline void MetadataAwareOopClosure::do_klass_nv(Klass* k) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/metaspace.cpp
--- a/src/hotspot/share/memory/metaspace.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspace.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3103,10 +3103,16 @@
Universe::set_narrow_klass_base(lower_base);
- if ((uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) {
+ // CDS uses LogKlassAlignmentInBytes for narrow_klass_shift. See
+ // MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() for
+ // how dump time narrow_klass_shift is set. Although, CDS can work
+ // with zero-shift mode also, to be consistent with AOT it uses
+ // LogKlassAlignmentInBytes for klass shift so archived java heap objects
+ // can be used at same time as AOT code.
+ if (!UseSharedSpaces
+ && (uint64_t)(higher_address - lower_base) <= UnscaledClassSpaceMax) {
Universe::set_narrow_klass_shift(0);
} else {
- assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces");
Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
}
AOTLoader::set_narrow_klass_shift();
@@ -3325,50 +3331,25 @@
#if INCLUDE_CDS
if (DumpSharedSpaces) {
- MetaspaceShared::initialize_shared_rs();
+ MetaspaceShared::initialize_dumptime_shared_and_meta_spaces();
} else if (UseSharedSpaces) {
- // If using shared space, open the file that contains the shared space
- // and map in the memory before initializing the rest of metaspace (so
- // the addresses don't conflict)
- address cds_address = NULL;
- FileMapInfo* mapinfo = new FileMapInfo();
-
- // Open the shared archive file, read and validate the header. If
- // initialization fails, shared spaces [UseSharedSpaces] are
- // disabled and the file is closed.
- // Map in spaces now also
- if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
- size_t cds_total = MetaspaceShared::core_spaces_size();
- cds_address = (address)mapinfo->header()->region_addr(0);
+ // If any of the archived space fails to map, UseSharedSpaces
+ // is reset to false. Fall through to the
+ // (!DumpSharedSpaces && !UseSharedSpaces) case to set up class
+ // metaspace.
+ MetaspaceShared::initialize_runtime_shared_and_meta_spaces();
+ }
+
+ if (!DumpSharedSpaces && !UseSharedSpaces)
+#endif // INCLUDE_CDS
+ {
#ifdef _LP64
- if (using_class_space()) {
- char* cds_end = (char*)(cds_address + cds_total);
- cds_end = (char *)align_up(cds_end, _reserve_alignment);
- // If UseCompressedClassPointers is set then allocate the metaspace area
- // above the heap and above the CDS area (if it exists).
- allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
- // map_heap_regions() compares the current narrow oop and klass encodings
- // with the archived ones, so it must be done after all encodings are determined.
- mapinfo->map_heap_regions();
- }
-#endif // _LP64
- } else {
- assert(!mapinfo->is_open() && !UseSharedSpaces,
- "archive file not closed or shared spaces not disabled.");
- }
- }
-#endif // INCLUDE_CDS
-
-#ifdef _LP64
- if (!UseSharedSpaces && using_class_space()) {
- if (DumpSharedSpaces) {
- // Already initialized inside MetaspaceShared::initialize_shared_rs()
- } else {
+ if (using_class_space()) {
char* base = (char*)align_up(Universe::heap()->reserved_region().end(), _reserve_alignment);
allocate_metaspace_compressed_klass_ptrs(base, 0);
}
+#endif // _LP64
}
-#endif // _LP64
// Initialize these before initializing the VirtualSpaceList
_first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/metaspace.hpp
--- a/src/hotspot/share/memory/metaspace.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspace.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -179,6 +179,10 @@
assert(DumpSharedSpaces, "sanity");
DEBUG_ONLY(_frozen = true;)
}
+#ifdef _LP64
+ static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base);
+#endif
+
private:
#ifdef _LP64
@@ -187,8 +191,6 @@
// Returns true if can use CDS with metaspace allocated as specified address.
static bool can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base);
- static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base);
-
static void initialize_class_space(ReservedSpace rs);
#endif
size_t class_chunk_size(size_t word_size);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/metaspaceShared.cpp
--- a/src/hotspot/share/memory/metaspaceShared.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspaceShared.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -165,7 +165,7 @@
}
void print(size_t total_bytes) const {
- tty->print_cr("%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
+ tty->print_cr("%-3s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT,
_name, used(), perc(used(), total_bytes), reserved(), perc(used(), reserved()), p2i(_base));
}
void print_out_of_space_msg(const char* failing_region, size_t needed_bytes) {
@@ -214,7 +214,42 @@
return _ro_region.allocate(num_bytes);
}
-void MetaspaceShared::initialize_shared_rs() {
+void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
+ assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled");
+
+ // If using shared space, open the file that contains the shared space
+ // and map in the memory before initializing the rest of metaspace (so
+ // the addresses don't conflict)
+ address cds_address = NULL;
+ FileMapInfo* mapinfo = new FileMapInfo();
+
+ // Open the shared archive file, read and validate the header. If
+ // initialization fails, shared spaces [UseSharedSpaces] are
+ // disabled and the file is closed.
+ // Map in spaces now also
+ if (mapinfo->initialize() && map_shared_spaces(mapinfo)) {
+ size_t cds_total = core_spaces_size();
+ cds_address = (address)mapinfo->header()->region_addr(0);
+#ifdef _LP64
+ if (Metaspace::using_class_space()) {
+ char* cds_end = (char*)(cds_address + cds_total);
+ cds_end = (char *)align_up(cds_end, Metaspace::reserve_alignment());
+ // If UseCompressedClassPointers is set then allocate the metaspace area
+ // above the heap and above the CDS area (if it exists).
+ Metaspace::allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
+ // map_heap_regions() compares the current narrow oop and klass encodings
+ // with the archived ones, so it must be done after all encodings are determined.
+ mapinfo->map_heap_regions();
+ }
+#endif // _LP64
+ } else {
+ assert(!mapinfo->is_open() && !UseSharedSpaces,
+ "archive file not closed or shared spaces not disabled.");
+ }
+}
+
+void MetaspaceShared::initialize_dumptime_shared_and_meta_spaces() {
+ assert(DumpSharedSpaces, "should be called for dump time only");
const size_t reserve_alignment = Metaspace::reserve_alignment();
bool large_pages = false; // No large pages when dumping the CDS archive.
char* shared_base = (char*)align_up((char*)SharedBaseAddress, reserve_alignment);
@@ -223,12 +258,12 @@
// On 64-bit VM, the heap and class space layout will be the same as if
// you're running in -Xshare:on mode:
//
- // +-- SharedBaseAddress (default = 0x800000000)
- // v
- // +-..---------+----+ ... +----+----+----+----+----+---------------+
- // | Heap | ST | | MC | RW | RO | MD | OD | class space |
- // +-..---------+----+ ... +----+----+----+----+----+---------------+
- // |<--MaxHeapSize->| |<-- UnscaledClassSpaceMax = 4GB ------->|
+ // +-- SharedBaseAddress (default = 0x800000000)
+ // v
+ // +-..---------+---------+ ... +----+----+----+----+----+---------------+
+ // | Heap | Archive | | MC | RW | RO | MD | OD | class space |
+ // +-..---------+---------+ ... +----+----+----+----+----+---------------+
+ // |<-- MaxHeapSize -->| |<-- UnscaledClassSpaceMax = 4GB ------->|
//
const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1);
const size_t cds_total = align_down(UnscaledClassSpaceMax, reserve_alignment);
@@ -268,12 +303,9 @@
// Set up compress class pointers.
Universe::set_narrow_klass_base((address)_shared_rs.base());
- if (UseAOT || cds_total > UnscaledClassSpaceMax) {
- // AOT forces narrow_klass_shift=LogKlassAlignmentInBytes
- Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
- } else {
- Universe::set_narrow_klass_shift(0);
- }
+ // Set narrow_klass_shift to be LogKlassAlignmentInBytes. This is consistent
+ // with AOT.
+ Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes);
Metaspace::initialize_class_space(tmp_class_space);
tty->print_cr("narrow_klass_base = " PTR_FORMAT ", narrow_klass_shift = %d",
@@ -1405,7 +1437,7 @@
print_heap_region_stats(_string_regions, "st", total_reserved);
print_heap_region_stats(_open_archive_heap_regions, "oa", total_reserved);
- tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
+ tty->print_cr("total : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
total_bytes, total_reserved, total_u_perc);
}
@@ -1416,7 +1448,7 @@
char* start = (char*)heap_mem->at(i).start();
size_t size = heap_mem->at(i).byte_size();
char* top = start + size;
- tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100%% used] at " INTPTR_FORMAT,
+ tty->print_cr("%s%d space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [100.0%% used] at " INTPTR_FORMAT,
name, i, size, size/double(total_size)*100.0, size, p2i(start));
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/metaspaceShared.hpp
--- a/src/hotspot/share/memory/metaspaceShared.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/metaspaceShared.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -146,7 +146,8 @@
static size_t core_spaces_size() {
return _core_spaces_size;
}
- static void initialize_shared_rs() NOT_CDS_RETURN;
+ static void initialize_dumptime_shared_and_meta_spaces() NOT_CDS_RETURN;
+ static void initialize_runtime_shared_and_meta_spaces() NOT_CDS_RETURN;
// Delta of this object from the bottom of the archive.
static uintx object_delta(void* obj) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/resourceArea.cpp
--- a/src/hotspot/share/memory/resourceArea.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/resourceArea.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,15 @@
#include "memory/resourceArea.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.inline.hpp"
+#include "services/memTracker.hpp"
+
+void ResourceArea::bias_to(MEMFLAGS new_flags) {
+ if (new_flags != _flags) {
+ MemTracker::record_arena_free(_flags);
+ MemTracker::record_new_arena(new_flags);
+ _flags = new_flags;
+ }
+}
//------------------------------ResourceMark-----------------------------------
debug_only(int ResourceArea::_warned;) // to suppress multiple warnings
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/memory/resourceArea.hpp
--- a/src/hotspot/share/memory/resourceArea.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/memory/resourceArea.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -70,7 +70,11 @@
return (char*)Amalloc(size, alloc_failmode);
}
- debug_only(int nesting() const { return _nesting; });
+ // Bias this resource area to specific memory type
+ // (by default, ResourceArea is tagged as mtThread, per-thread general purpose storage)
+ void bias_to(MEMFLAGS flags);
+
+ debug_only(int nesting() const { return _nesting; })
};
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/oops/instanceKlass.cpp
--- a/src/hotspot/share/oops/instanceKlass.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/oops/instanceKlass.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -285,6 +285,9 @@
java_lang_Class::set_klass(java_mirror(), NULL);
}
+ // Also remove mirror from handles
+ loader_data->remove_handle(_java_mirror);
+
// Need to take this class off the class loader data list.
loader_data->remove_class(this);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/oops/klass.cpp
--- a/src/hotspot/share/oops/klass.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/oops/klass.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -43,9 +43,16 @@
#include "trace/traceMacros.hpp"
#include "utilities/macros.hpp"
#include "utilities/stack.inline.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1SATBCardTableModRefBS.hpp"
-#endif // INCLUDE_ALL_GCS
+
+void Klass::set_java_mirror(Handle m) {
+ assert(!m.is_null(), "New mirror should never be null.");
+ assert(_java_mirror.resolve() == NULL, "should only be used to initialize mirror");
+ _java_mirror = class_loader_data()->add_handle(m);
+}
+
+oop Klass::java_mirror() const {
+ return _java_mirror.resolve();
+}
bool Klass::is_cloneable() const {
return _access_flags.is_cloneable_fast() ||
@@ -441,51 +448,6 @@
}
}
-void Klass::klass_update_barrier_set(oop v) {
- record_modified_oops();
-}
-
-// This barrier is used by G1 to remember the old oop values, so
-// that we don't forget any objects that were live at the snapshot at
-// the beginning. This function is only used when we write oops into Klasses.
-void Klass::klass_update_barrier_set_pre(oop* p, oop v) {
-#if INCLUDE_ALL_GCS
- if (UseG1GC) {
- oop obj = *p;
- if (obj != NULL) {
- G1SATBCardTableModRefBS::enqueue(obj);
- }
- }
-#endif
-}
-
-void Klass::klass_oop_store(oop* p, oop v) {
- assert(!Universe::heap()->is_in_reserved((void*)p), "Should store pointer into metadata");
- assert(v == NULL || Universe::heap()->is_in_reserved((void*)v), "Should store pointer to an object");
-
- // do the store
- if (always_do_update_barrier) {
- klass_oop_store((volatile oop*)p, v);
- } else {
- klass_update_barrier_set_pre(p, v);
- *p = v;
- klass_update_barrier_set(v);
- }
-}
-
-void Klass::klass_oop_store(volatile oop* p, oop v) {
- assert(!Universe::heap()->is_in_reserved((void*)p), "Should store pointer into metadata");
- assert(v == NULL || Universe::heap()->is_in_reserved((void*)v), "Should store pointer to an object");
-
- klass_update_barrier_set_pre((oop*)p, v); // Cast away volatile.
- OrderAccess::release_store_ptr(p, v);
- klass_update_barrier_set(v);
-}
-
-void Klass::oops_do(OopClosure* cl) {
- cl->do_oop(&_java_mirror);
-}
-
void Klass::metaspace_pointers_do(MetaspaceClosure* it) {
if (log_is_enabled(Trace, cds)) {
ResourceMark rm;
@@ -532,7 +494,8 @@
ResourceMark rm;
log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
}
- set_java_mirror(NULL);
+ // Just null out the mirror. The class_loader_data() no longer exists.
+ _java_mirror = NULL;
}
void Klass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/oops/klass.hpp
--- a/src/hotspot/share/oops/klass.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/oops/klass.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -30,6 +30,7 @@
#include "memory/memRegion.hpp"
#include "oops/metadata.hpp"
#include "oops/oop.hpp"
+#include "oops/oopHandle.hpp"
#include "trace/traceMacros.hpp"
#include "utilities/accessFlags.hpp"
#include "utilities/macros.hpp"
@@ -119,7 +120,7 @@
// Ordered list of all primary supertypes
Klass* _primary_supers[_primary_super_limit];
// java/lang/Class instance mirroring this class
- oop _java_mirror;
+ OopHandle _java_mirror;
// Superclass
Klass* _super;
// First subclass (NULL if none); _subklass->next_sibling() is next one
@@ -148,10 +149,6 @@
// vtable length
int _vtable_len;
- // Remembered sets support for the oops in the klasses.
- jbyte _modified_oops; // Card Table Equivalent (YC/CMS support)
- jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
-
private:
// This is an index into FileMapHeader::_classpath_entry_table[], to
// associate this class with the JAR file where it's loaded from during
@@ -228,13 +225,15 @@
}
}
- // store an oop into a field of a Klass
- void klass_oop_store(oop* p, oop v);
- void klass_oop_store(volatile oop* p, oop v);
+ // java mirror
+ oop java_mirror() const;
+ void set_java_mirror(Handle m);
- // java mirror
- oop java_mirror() const { return _java_mirror; }
- void set_java_mirror(oop m) { klass_oop_store(&_java_mirror, m); }
+ // Temporary mirror switch used by RedefineClasses
+ // Both mirrors are on the ClassLoaderData::_handles list already so no
+ // barriers are needed.
+ void set_java_mirror_handle(OopHandle mirror) { _java_mirror = mirror; }
+ OopHandle java_mirror_handle() const { return _java_mirror; }
// modifier flags
jint modifier_flags() const { return _modifier_flags; }
@@ -260,17 +259,6 @@
ClassLoaderData* class_loader_data() const { return _class_loader_data; }
void set_class_loader_data(ClassLoaderData* loader_data) { _class_loader_data = loader_data; }
- // The Klasses are not placed in the Heap, so the Card Table or
- // the Mod Union Table can't be used to mark when klasses have modified oops.
- // The CT and MUT bits saves this information for the individual Klasses.
- void record_modified_oops() { _modified_oops = 1; }
- void clear_modified_oops() { _modified_oops = 0; }
- bool has_modified_oops() { return _modified_oops == 1; }
-
- void accumulate_modified_oops() { if (has_modified_oops()) _accumulated_modified_oops = 1; }
- void clear_accumulated_modified_oops() { _accumulated_modified_oops = 0; }
- bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; }
-
int shared_classpath_index() const {
return _shared_class_path_index;
};
@@ -598,9 +586,6 @@
TRACE_DEFINE_TRACE_ID_METHODS;
- // garbage collection support
- void oops_do(OopClosure* cl);
-
virtual void metaspace_pointers_do(MetaspaceClosure* iter);
virtual MetaspaceObj::Type type() const { return ClassType; }
@@ -687,11 +672,6 @@
static Klass* decode_klass_not_null(narrowKlass v);
static Klass* decode_klass(narrowKlass v);
-
- private:
- // barriers used by klass_oop_store
- void klass_update_barrier_set(oop v);
- void klass_update_barrier_set_pre(oop* p, oop v);
};
// Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/c2compiler.cpp
--- a/src/hotspot/share/opto/c2compiler.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/c2compiler.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -410,6 +410,9 @@
case vmIntrinsics::_multiplyExactL:
if (!Matcher::match_rule_supported(Op_OverflowMulL)) return false;
break;
+ case vmIntrinsics::_multiplyHigh:
+ if (!Matcher::match_rule_supported(Op_MulHiL)) return false;
+ break;
case vmIntrinsics::_getCallerClass:
if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return false;
break;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/library_call.cpp
--- a/src/hotspot/share/opto/library_call.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/library_call.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -231,6 +231,7 @@
bool inline_math_addExactL(bool is_increment);
bool inline_math_multiplyExactI();
bool inline_math_multiplyExactL();
+ bool inline_math_multiplyHigh();
bool inline_math_negateExactI();
bool inline_math_negateExactL();
bool inline_math_subtractExactI(bool is_decrement);
@@ -549,6 +550,7 @@
case vmIntrinsics::_incrementExactL: return inline_math_addExactL(true /* increment */);
case vmIntrinsics::_multiplyExactI: return inline_math_multiplyExactI();
case vmIntrinsics::_multiplyExactL: return inline_math_multiplyExactL();
+ case vmIntrinsics::_multiplyHigh: return inline_math_multiplyHigh();
case vmIntrinsics::_negateExactI: return inline_math_negateExactI();
case vmIntrinsics::_negateExactL: return inline_math_negateExactL();
case vmIntrinsics::_subtractExactI: return inline_math_subtractExactI(false /* subtract */);
@@ -1897,6 +1899,11 @@
return inline_math_overflow(argument(0), argument(2));
}
+bool LibraryCallKit::inline_math_multiplyHigh() {
+ set_result(_gvn.transform(new MulHiLNode(argument(0), argument(2))));
+ return true;
+}
+
Node*
LibraryCallKit::generate_min_max(vmIntrinsics::ID id, Node* x0, Node* y0) {
// These are the candidate return value:
@@ -3453,7 +3460,8 @@
// Given a klass oop, load its java mirror (a java.lang.Class oop).
Node* LibraryCallKit::load_mirror_from_klass(Node* klass) {
Node* p = basic_plus_adr(klass, in_bytes(Klass::java_mirror_offset()));
- return make_load(NULL, p, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered);
+ Node* load = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered);
+ return make_load(NULL, load, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered);
}
//-----------------------load_klass_from_mirror_common-------------------------
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/loopTransform.cpp
--- a/src/hotspot/share/opto/loopTransform.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/loopTransform.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -666,7 +666,7 @@
_local_loop_unroll_limit = LoopUnrollLimit;
_local_loop_unroll_factor = 4;
int future_unroll_ct = cl->unrolled_count() * 2;
- if (!cl->do_unroll_only()) {
+ if (!cl->is_vectorized_loop()) {
if (future_unroll_ct > LoopMaxUnroll) return false;
} else {
// obey user constraints on vector mapped loops with additional unrolling applied
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/loopopts.cpp
--- a/src/hotspot/share/opto/loopopts.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/loopopts.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -311,6 +311,7 @@
}
return NULL;
}
+ assert(m->is_Phi() || is_dominator(get_ctrl(m), n_ctrl), "m has strange control");
}
return n_ctrl;
@@ -615,6 +616,7 @@
// Now replace all Phis with CMOV's
Node *cmov_ctrl = iff->in(0);
uint flip = (lp->Opcode() == Op_IfTrue);
+ Node_List wq;
while (1) {
PhiNode* phi = NULL;
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
@@ -627,17 +629,21 @@
if (phi == NULL) break;
if (PrintOpto && VerifyLoopOptimizations) { tty->print_cr("CMOV"); }
// Move speculative ops
- for (uint j = 1; j < region->req(); j++) {
- Node *proj = region->in(j);
- Node *inp = phi->in(j);
- if (get_ctrl(inp) == proj) { // Found local op
+ wq.push(phi);
+ while (wq.size() > 0) {
+ Node *n = wq.pop();
+ for (uint j = 1; j < n->req(); j++) {
+ Node* m = n->in(j);
+ if (m != NULL && !is_dominator(get_ctrl(m), cmov_ctrl)) {
#ifndef PRODUCT
- if (PrintOpto && VerifyLoopOptimizations) {
- tty->print(" speculate: ");
- inp->dump();
+ if (PrintOpto && VerifyLoopOptimizations) {
+ tty->print(" speculate: ");
+ m->dump();
+ }
+#endif
+ set_ctrl(m, cmov_ctrl);
+ wq.push(m);
}
-#endif
- set_ctrl(inp, cmov_ctrl);
}
}
Node *cmov = CMoveNode::make(cmov_ctrl, iff->in(1), phi->in(1+flip), phi->in(2-flip), _igvn.type(phi));
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/machnode.hpp
--- a/src/hotspot/share/opto/machnode.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/machnode.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -115,6 +115,18 @@
ConditionRegister as_ConditionRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const {
return ::as_ConditionRegister(reg(ra_, node, idx));
}
+ VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node) const {
+ return ::as_VectorRegister(reg(ra_, node));
+ }
+ VectorRegister as_VectorRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const {
+ return ::as_VectorRegister(reg(ra_, node, idx));
+ }
+ VectorSRegister as_VectorSRegister(PhaseRegAlloc *ra_, const Node *node) const {
+ return ::as_VectorSRegister(reg(ra_, node));
+ }
+ VectorSRegister as_VectorSRegister(PhaseRegAlloc *ra_, const Node *node, int idx) const {
+ return ::as_VectorSRegister(reg(ra_, node, idx));
+ }
#endif
virtual intptr_t constant() const;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/memnode.cpp
--- a/src/hotspot/share/opto/memnode.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/memnode.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1771,6 +1771,23 @@
Opcode() == Op_LoadKlass,
"Field accesses must be precise" );
// For klass/static loads, we expect the _type to be precise
+ } else if (tp->base() == Type::RawPtr && adr->is_Load() && off == 0) {
+ /* With mirrors being an indirect in the Klass*
+ * the VM is now using two loads. LoadKlass(LoadP(LoadP(Klass, mirror_offset), zero_offset))
+ * The LoadP from the Klass has a RawPtr type (see LibraryCallKit::load_mirror_from_klass).
+ *
+ * So check the type and klass of the node before the LoadP.
+ */
+ Node* adr2 = adr->in(MemNode::Address);
+ const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
+ if (tkls != NULL && !StressReflectiveCode) {
+ ciKlass* klass = tkls->klass();
+ if (klass->is_loaded() && tkls->klass_is_exact() && tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
+ assert(adr->Opcode() == Op_LoadP, "must load an oop from _java_mirror");
+ assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror");
+ return TypeInstPtr::make(klass->java_mirror());
+ }
+ }
}
const TypeKlassPtr *tkls = tp->isa_klassptr();
@@ -1798,12 +1815,6 @@
}
const Type* aift = load_array_final_field(tkls, klass);
if (aift != NULL) return aift;
- if (tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
- // The field is Klass::_java_mirror. Return its (constant) value.
- // (Folds up the 2nd indirection in anObjConstant.getClass().)
- assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror");
- return TypeInstPtr::make(klass->java_mirror());
- }
}
// We can still check if we are loading from the primary_supers array at a
@@ -2203,22 +2214,24 @@
// This improves reflective code, often making the Class
// mirror go completely dead. (Current exception: Class
// mirrors may appear in debug info, but we could clean them out by
- // introducing a new debug info operator for Klass*.java_mirror).
+ // introducing a new debug info operator for Klass.java_mirror).
+
if (toop->isa_instptr() && toop->klass() == phase->C->env()->Class_klass()
&& offset == java_lang_Class::klass_offset_in_bytes()) {
- // We are loading a special hidden field from a Class mirror,
- // the field which points to its Klass or ArrayKlass metaobject.
if (base->is_Load()) {
- Node* adr2 = base->in(MemNode::Address);
- const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
- if (tkls != NULL && !tkls->empty()
- && (tkls->klass()->is_instance_klass() ||
+ Node* base2 = base->in(MemNode::Address);
+ if (base2->is_Load()) { /* direct load of a load which is the oophandle */
+ Node* adr2 = base2->in(MemNode::Address);
+ const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
+ if (tkls != NULL && !tkls->empty()
+ && (tkls->klass()->is_instance_klass() ||
tkls->klass()->is_array_klass())
- && adr2->is_AddP()
- ) {
- int mirror_field = in_bytes(Klass::java_mirror_offset());
- if (tkls->offset() == mirror_field) {
- return adr2->in(AddPNode::Base);
+ && adr2->is_AddP()
+ ) {
+ int mirror_field = in_bytes(Klass::java_mirror_offset());
+ if (tkls->offset() == mirror_field) {
+ return adr2->in(AddPNode::Base);
+ }
}
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/subnode.cpp
--- a/src/hotspot/share/opto/subnode.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/subnode.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -877,8 +877,8 @@
}
static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n) {
- // Return the klass node for
- // LoadP(AddP(foo:Klass, #java_mirror))
+ // Return the klass node for (indirect load from OopHandle)
+ // LoadP(LoadP(AddP(foo:Klass, #java_mirror)))
// or NULL if not matching.
if (n->Opcode() != Op_LoadP) return NULL;
@@ -886,6 +886,10 @@
if (!tp || tp->klass() != phase->C->env()->Class_klass()) return NULL;
Node* adr = n->in(MemNode::Address);
+ // First load from OopHandle
+ if (adr->Opcode() != Op_LoadP || !phase->type(adr)->isa_rawptr()) return NULL;
+ adr = adr->in(MemNode::Address);
+
intptr_t off = 0;
Node* k = AddPNode::Ideal_base_and_offset(adr, phase, off);
if (k == NULL) return NULL;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/superword.cpp
--- a/src/hotspot/share/opto/superword.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/superword.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -145,6 +145,8 @@
// Skip any loops already optimized by slp
if (cl->is_vectorized_loop()) return;
+ if (cl->do_unroll_only()) return;
+
if (cl->is_main_loop()) {
// Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit))))
CountedLoopEndNode* pre_end = get_pre_loop_end(cl);
@@ -2163,7 +2165,15 @@
//------------------------------output---------------------------
// Convert packs into vector node operations
void SuperWord::output() {
- if (_packset.length() == 0) return;
+ CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
+ Compile* C = _phase->C;
+ if (_packset.length() == 0) {
+ // Instigate more unrolling for optimization when vectorization fails.
+ C->set_major_progress();
+ cl->set_notpassed_slp();
+ cl->mark_do_unroll_only();
+ return;
+ }
#ifndef PRODUCT
if (TraceLoopOpts) {
@@ -2172,7 +2182,6 @@
}
#endif
- CountedLoopNode *cl = lpt()->_head->as_CountedLoop();
if (cl->is_main_loop()) {
// MUST ENSURE main loop's initial value is properly aligned:
// (iv_initial_value + min_iv_offset) % vector_width_in_bytes() == 0
@@ -2185,7 +2194,6 @@
}
}
- Compile* C = _phase->C;
uint max_vlen_in_bytes = 0;
uint max_vlen = 0;
bool can_process_post_loop = (PostLoopMultiversioning && Matcher::has_predicated_vectors() && cl->is_post_loop());
@@ -4493,4 +4501,3 @@
return true;
}
-
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/opto/type.cpp
--- a/src/hotspot/share/opto/type.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/opto/type.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -67,7 +67,13 @@
{ Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX
{ Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY
{ Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ
-#elif defined(PPC64) || defined(S390)
+#elif defined(PPC64)
+ { Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS
+ { Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD
+ { Bad, T_ILLEGAL, "vectorx:", false, Op_VecX, relocInfo::none }, // VectorX
+ { Bad, T_ILLEGAL, "vectory:", false, 0, relocInfo::none }, // VectorY
+ { Bad, T_ILLEGAL, "vectorz:", false, 0, relocInfo::none }, // VectorZ
+#elif defined(S390)
{ Bad, T_ILLEGAL, "vectors:", false, 0, relocInfo::none }, // VectorS
{ Bad, T_ILLEGAL, "vectord:", false, Op_RegL, relocInfo::none }, // VectorD
{ Bad, T_ILLEGAL, "vectorx:", false, 0, relocInfo::none }, // VectorX
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/prims/jvmtiRedefineClasses.cpp
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -158,6 +158,11 @@
ClassLoaderData* cld = _scratch_classes[i]->class_loader_data();
// Free the memory for this class at class unloading time. Not before
// because CMS might think this is still live.
+ InstanceKlass* ik = get_ik(_class_defs[i].klass);
+ if (ik->get_cached_class_file() == _scratch_classes[i]->get_cached_class_file()) {
+ // Don't double-free cached_class_file copied from the original class if error.
+ _scratch_classes[i]->set_cached_class_file(NULL);
+ }
cld->add_to_deallocate_list(InstanceKlass::cast(_scratch_classes[i]));
}
}
@@ -3946,12 +3951,12 @@
// with them was cached on the scratch class, move to the_class.
// Note: we still want to do this if nothing needed caching since it
// should get cleared in the_class too.
- if (the_class->get_cached_class_file_bytes() == 0) {
+ if (the_class->get_cached_class_file() == 0) {
// the_class doesn't have a cache yet so copy it
the_class->set_cached_class_file(scratch_class->get_cached_class_file());
}
- else if (scratch_class->get_cached_class_file_bytes() !=
- the_class->get_cached_class_file_bytes()) {
+ else if (scratch_class->get_cached_class_file() !=
+ the_class->get_cached_class_file()) {
// The same class can be present twice in the scratch classes list or there
// are multiple concurrent RetransformClasses calls on different threads.
// In such cases we have to deallocate scratch_class cached_class_file.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/prims/jvmtiTagMap.cpp
--- a/src/hotspot/share/prims/jvmtiTagMap.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/jvmtiTagMap.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3026,8 +3026,7 @@
// Preloaded classes and loader from the system dictionary
blk.set_kind(JVMTI_HEAP_REFERENCE_SYSTEM_CLASS);
SystemDictionary::always_strong_oops_do(&blk);
- KlassToOopClosure klass_blk(&blk);
- ClassLoaderDataGraph::always_strong_oops_do(&blk, &klass_blk, false);
+ ClassLoaderDataGraph::always_strong_oops_do(&blk, false);
if (blk.stopped()) {
return false;
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/prims/jvmtiThreadState.hpp
--- a/src/hotspot/share/prims/jvmtiThreadState.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/jvmtiThreadState.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -411,21 +411,21 @@
private:
JvmtiThreadState* _state;
Klass* _scratch_class;
- Handle _scratch_mirror;
+ OopHandle _scratch_mirror;
public:
RedefineVerifyMark(Klass* the_class, Klass* scratch_class,
JvmtiThreadState *state) : _state(state), _scratch_class(scratch_class)
{
_state->set_class_versions_map(the_class, scratch_class);
- _scratch_mirror = Handle(Thread::current(), _scratch_class->java_mirror());
- _scratch_class->set_java_mirror(the_class->java_mirror());
+ _scratch_mirror = _scratch_class->java_mirror_handle();
+ _scratch_class->set_java_mirror_handle(the_class->java_mirror_handle());
}
~RedefineVerifyMark() {
// Restore the scratch class's mirror, so when scratch_class is removed
// the correct mirror pointing to it can be cleared.
- _scratch_class->set_java_mirror(_scratch_mirror());
+ _scratch_class->set_java_mirror_handle(_scratch_mirror);
_state->clear_class_versions_map();
}
};
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/prims/whitebox.cpp
--- a/src/hotspot/share/prims/whitebox.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/prims/whitebox.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -73,6 +73,9 @@
#include "utilities/nativeCallStack.hpp"
#endif // INCLUDE_NMT
+#ifdef LINUX
+#include "utilities/elfFile.hpp"
+#endif
#define SIZE_T_MAX_VALUE ((size_t) -1)
@@ -1823,6 +1826,20 @@
DirectivesStack::pop(count);
WB_END
+// Checks that the library libfile has the noexecstack bit set.
+WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstring libfile))
+ jboolean ret = false;
+#ifdef LINUX
+ // Can't be in VM when we call JNI.
+ ThreadToNativeFromVM ttnfv(thread);
+ const char* lf = env->GetStringUTFChars(libfile, NULL);
+ CHECK_JNI_EXCEPTION_(env, 0);
+ ret = (jboolean) ElfFile::specifies_noexecstack(lf);
+ env->ReleaseStringUTFChars(libfile, lf);
+#endif
+ return ret;
+WB_END
+
#define CC (char*)
static JNINativeMethod methods[] = {
@@ -2027,6 +2044,8 @@
(void*)&WB_GetConcurrentGCPhases},
{CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z",
(void*)&WB_RequestConcurrentGCPhase},
+ {CC"checkLibSpecifiesNoexecstack", CC"(Ljava/lang/String;)Z",
+ (void*)&WB_CheckLibSpecifiesNoexecstack},
};
#undef CC
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/runtime/arguments.cpp
--- a/src/hotspot/share/runtime/arguments.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/arguments.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -377,6 +377,7 @@
// --- Non-alias flags - sorted by obsolete_in then expired_in:
{ "MaxGCMinorPauseMillis", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
{ "UseConcMarkSweepGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() },
+ { "AssumeMP", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() },
{ "MonitorInUseLists", JDK_Version::jdk(10),JDK_Version::undefined(), JDK_Version::undefined() },
{ "MaxRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
{ "MinRAMFraction", JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
@@ -4476,16 +4477,6 @@
set_shared_spaces_flags();
-#if defined(SPARC)
- // BIS instructions require 'membar' instruction regardless of the number
- // of CPUs because in virtualized/container environments which might use only 1
- // CPU, BIS instructions may produce incorrect results.
-
- if (FLAG_IS_DEFAULT(AssumeMP)) {
- FLAG_SET_DEFAULT(AssumeMP, true);
- }
-#endif
-
// Check the GC selections again.
if (!check_gc_consistency()) {
return JNI_EINVAL;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/runtime/atomic.hpp
--- a/src/hotspot/share/runtime/atomic.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/atomic.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -64,24 +64,25 @@
// we can prove that a weaker form is sufficiently safe.
// Atomically store to a location
- inline static void store (jbyte store_value, jbyte* dest);
- inline static void store (jshort store_value, jshort* dest);
- inline static void store (jint store_value, jint* dest);
- // See comment above about using jlong atomics on 32-bit platforms
- inline static void store (jlong store_value, jlong* dest);
- inline static void store_ptr(intptr_t store_value, intptr_t* dest);
- inline static void store_ptr(void* store_value, void* dest);
+ // The type T must be either a pointer type convertible to or equal
+ // to D, an integral/enum type equal to D, or a type equal to D that
+ // is primitive convertible using PrimitiveConversions.
+ template
+ inline static void store(T store_value, volatile D* dest);
+
+ inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest) {
+ Atomic::store(store_value, dest);
+ }
- inline static void store (jbyte store_value, volatile jbyte* dest);
- inline static void store (jshort store_value, volatile jshort* dest);
- inline static void store (jint store_value, volatile jint* dest);
- // See comment above about using jlong atomics on 32-bit platforms
- inline static void store (jlong store_value, volatile jlong* dest);
- inline static void store_ptr(intptr_t store_value, volatile intptr_t* dest);
- inline static void store_ptr(void* store_value, volatile void* dest);
+ inline static void store_ptr(void* store_value, volatile void* dest) {
+ Atomic::store(store_value, reinterpret_cast(dest));
+ }
- // See comment above about using jlong atomics on 32-bit platforms
- inline static jlong load(const volatile jlong* src);
+ // Atomically load from a location
+ // The type T must be either a pointer type, an integral/enum type,
+ // or a type that is primitive convertible using PrimitiveConversions.
+ template
+ inline static T load(const volatile T* dest);
// Atomically add to a location. Returns updated value. add*() provide:
// add-value-to-dest
@@ -116,10 +117,19 @@
// Performs atomic exchange of *dest with exchange_value. Returns old
// prior value of *dest. xchg*() provide:
// exchange-value-with-dest
- inline static jint xchg (jint exchange_value, volatile jint* dest);
- inline static unsigned int xchg (unsigned int exchange_value, volatile unsigned int* dest);
- inline static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest);
- inline static void* xchg_ptr(void* exchange_value, volatile void* dest);
+ // The type T must be either a pointer type convertible to or equal
+ // to D, an integral/enum type equal to D, or a type equal to D that
+ // is primitive convertible using PrimitiveConversions.
+ template
+ inline static D xchg(T exchange_value, volatile D* dest);
+
+ inline static intptr_t xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
+ return xchg(exchange_value, dest);
+ }
+
+ inline static void* xchg_ptr(void* exchange_value, volatile void* dest) {
+ return xchg(exchange_value, reinterpret_cast(dest));
+ }
// Performs atomic compare of *dest and compare_value, and exchanges
// *dest with exchange_value if the comparison succeeded. Returns prior
@@ -165,6 +175,57 @@
// that is needed here.
template struct IsPointerConvertible;
+ // Dispatch handler for store. Provides type-based validity
+ // checking and limited conversions around calls to the platform-
+ // specific implementation layer provided by PlatformOp.
+ template
+ struct StoreImpl;
+
+ // Platform-specific implementation of store. Support for sizes
+ // of 1, 2, 4, and (if different) pointer size bytes are required.
+ // The class is a function object that must be default constructable,
+ // with these requirements:
+ //
+ // either:
+ // - dest is of type D*, an integral, enum or pointer type.
+ // - new_value are of type T, an integral, enum or pointer type D or
+ // pointer type convertible to D.
+ // or:
+ // - T and D are the same and are primitive convertible using PrimitiveConversions
+ // and either way:
+ // - platform_store is an object of type PlatformStore.
+ //
+ // Then
+ // platform_store(new_value, dest)
+ // must be a valid expression.
+ //
+ // The default implementation is a volatile store. If a platform
+ // requires more for e.g. 64 bit stores, a specialization is required
+ template struct PlatformStore;
+
+ // Dispatch handler for load. Provides type-based validity
+ // checking and limited conversions around calls to the platform-
+ // specific implementation layer provided by PlatformOp.
+ template
+ struct LoadImpl;
+
+ // Platform-specific implementation of load. Support for sizes of
+ // 1, 2, 4 bytes and (if different) pointer size bytes are required.
+ // The class is a function object that must be default
+ // constructable, with these requirements:
+ //
+ // - dest is of type T*, an integral, enum or pointer type, or
+ // T is convertible to a primitive type using PrimitiveConversions
+ // - platform_load is an object of type PlatformLoad.
+ //
+ // Then
+ // platform_load(src)
+ // must be a valid expression, returning a result convertible to T.
+ //
+ // The default implementation is a volatile load. If a platform
+ // requires more for e.g. 64 bit loads, a specialization is required
+ template struct PlatformLoad;
+
// Dispatch handler for add. Provides type-based validity checking
// and limited conversions around calls to the platform-specific
// implementation layer provided by PlatformAdd.
@@ -280,6 +341,45 @@
public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11.
struct CmpxchgByteUsingInt;
private:
+
+ // Dispatch handler for xchg. Provides type-based validity
+ // checking and limited conversions around calls to the
+ // platform-specific implementation layer provided by
+ // PlatformXchg.
+ template
+ struct XchgImpl;
+
+ // Platform-specific implementation of xchg. Support for sizes
+ // of 4, and sizeof(intptr_t) are required. The class is a function
+ // object that must be default constructable, with these requirements:
+ //
+ // - dest is of type T*.
+ // - exchange_value is of type T.
+ // - platform_xchg is an object of type PlatformXchg.
+ //
+ // Then
+ // platform_xchg(exchange_value, dest)
+ // must be a valid expression, returning a result convertible to T.
+ //
+ // A default definition is provided, which declares a function template
+ // T operator()(T, T volatile*, T, cmpxchg_memory_order) const
+ //
+ // For each required size, a platform must either provide an
+ // appropriate definition of that function, or must entirely
+ // specialize the class template for that size.
+ template struct PlatformXchg;
+
+ // Support for platforms that implement some variants of xchg
+ // using a (typically out of line) non-template helper function.
+ // The generic arguments passed to PlatformXchg need to be
+ // translated to the appropriate type for the helper function, the
+ // helper invoked on the translated arguments, and the result
+ // translated back. Type is the parameter / return type of the
+ // helper function.
+ template
+ static T xchg_using_helper(Fn fn,
+ T exchange_value,
+ T volatile* dest);
};
template
@@ -296,6 +396,131 @@
static const bool value = (sizeof(yes) == sizeof(test(test_value)));
};
+// Handle load for pointer, integral and enum types.
+template
+struct Atomic::LoadImpl<
+ T,
+ PlatformOp,
+ typename EnableIf::value || IsRegisteredEnum::value || IsPointer::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T const volatile* dest) const {
+ // Forward to the platform handler for the size of T.
+ return PlatformOp()(dest);
+ }
+};
+
+// Handle load for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments, and returns the recovered result of that translated
+// call.
+template
+struct Atomic::LoadImpl<
+ T,
+ PlatformOp,
+ typename EnableIf::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T const volatile* dest) const {
+ typedef PrimitiveConversions::Translate Translator;
+ typedef typename Translator::Decayed Decayed;
+ STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+ Decayed result = PlatformOp()(reinterpret_cast(dest));
+ return Translator::recover(result);
+ }
+};
+
+// Default implementation of atomic load if a specific platform
+// does not provide a specialization for a certain size class.
+// For increased safety, the default implementation only allows
+// load types that are pointer sized or smaller. If a platform still
+// supports wide atomics, then it has to use specialization
+// of Atomic::PlatformLoad for that wider size class.
+template
+struct Atomic::PlatformLoad VALUE_OBJ_CLASS_SPEC {
+ template
+ T operator()(T const volatile* dest) const {
+ STATIC_ASSERT(sizeof(T) <= sizeof(void*)); // wide atomics need specialization
+ return *dest;
+ }
+};
+
+// Handle store for integral and enum types.
+//
+// All the involved types must be identical.
+template
+struct Atomic::StoreImpl<
+ T, T,
+ PlatformOp,
+ typename EnableIf::value || IsRegisteredEnum::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ void operator()(T new_value, T volatile* dest) const {
+ // Forward to the platform handler for the size of T.
+ PlatformOp()(new_value, dest);
+ }
+};
+
+// Handle store for pointer types.
+//
+// The new_value must be implicitly convertible to the
+// destination's type; it must be type-correct to store the
+// new_value in the destination.
+template
+struct Atomic::StoreImpl<
+ T*, D*,
+ PlatformOp,
+ typename EnableIf::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ void operator()(T* new_value, D* volatile* dest) const {
+ // Allow derived to base conversion, and adding cv-qualifiers.
+ D* value = new_value;
+ PlatformOp()(value, dest);
+ }
+};
+
+// Handle store for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments.
+template
+struct Atomic::StoreImpl<
+ T, T,
+ PlatformOp,
+ typename EnableIf::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ void operator()(T new_value, T volatile* dest) const {
+ typedef PrimitiveConversions::Translate Translator;
+ typedef typename Translator::Decayed Decayed;
+ STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+ PlatformOp()(Translator::decay(new_value),
+ reinterpret_cast(dest));
+ }
+};
+
+// Default implementation of atomic store if a specific platform
+// does not provide a specialization for a certain size class.
+// For increased safety, the default implementation only allows
+// storing types that are pointer sized or smaller. If a platform still
+// supports wide atomics, then it has to use specialization
+// of Atomic::PlatformStore for that wider size class.
+template
+struct Atomic::PlatformStore VALUE_OBJ_CLASS_SPEC {
+ template
+ void operator()(T new_value,
+ T volatile* dest) const {
+ STATIC_ASSERT(sizeof(T) <= sizeof(void*)); // wide atomics need specialization
+ (void)const_cast(*dest = new_value);
+ }
+};
+
// Define FetchAndAdd and AddAndFetch helper classes before including
// platform file, which may use these as base classes, requiring they
// be complete.
@@ -353,6 +578,18 @@
cmpxchg_memory_order order) const;
};
+// Define the class before including platform file, which may specialize
+// the operator definition. No generic definition of specializations
+// of the operator template are provided, nor are there any generic
+// specializations of the class. The platform file is responsible for
+// providing those.
+template
+struct Atomic::PlatformXchg VALUE_OBJ_CLASS_SPEC {
+ template
+ T operator()(T exchange_value,
+ T volatile* dest) const;
+};
+
// platform specific in-line definitions - must come before shared definitions
#include OS_CPU_HEADER(atomic)
@@ -364,6 +601,16 @@
#error size_t is not WORD_SIZE, interesting platform, but missing implementation here
#endif
+template
+inline T Atomic::load(const volatile T* dest) {
+ return LoadImpl >()(dest);
+}
+
+template
+inline void Atomic::store(T store_value, volatile D* dest) {
+ StoreImpl >()(store_value, dest);
+}
+
template
inline D Atomic::add(I add_value, D volatile* dest) {
return AddImpl()(add_value, dest);
@@ -594,9 +841,75 @@
return PrimitiveConversions::cast(cur_as_bytes[offset]);
}
-inline unsigned Atomic::xchg(unsigned int exchange_value, volatile unsigned int* dest) {
- assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
- return (unsigned int)Atomic::xchg((jint)exchange_value, (volatile jint*)dest);
+// Handle xchg for integral and enum types.
+//
+// All the involved types must be identical.
+template
+struct Atomic::XchgImpl<
+ T, T,
+ typename EnableIf::value || IsRegisteredEnum::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T exchange_value, T volatile* dest) const {
+ // Forward to the platform handler for the size of T.
+ return PlatformXchg()(exchange_value, dest);
+ }
+};
+
+// Handle xchg for pointer types.
+//
+// The exchange_value must be implicitly convertible to the
+// destination's type; it must be type-correct to store the
+// exchange_value in the destination.
+template
+struct Atomic::XchgImpl<
+ T*, D*,
+ typename EnableIf::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ D* operator()(T* exchange_value, D* volatile* dest) const {
+ // Allow derived to base conversion, and adding cv-qualifiers.
+ D* new_value = exchange_value;
+ return PlatformXchg()(new_value, dest);
+ }
+};
+
+// Handle xchg for types that have a translator.
+//
+// All the involved types must be identical.
+//
+// This translates the original call into a call on the decayed
+// arguments, and returns the recovered result of that translated
+// call.
+template
+struct Atomic::XchgImpl<
+ T, T,
+ typename EnableIf::value>::type>
+ VALUE_OBJ_CLASS_SPEC
+{
+ T operator()(T exchange_value, T volatile* dest) const {
+ typedef PrimitiveConversions::Translate Translator;
+ typedef typename Translator::Decayed Decayed;
+ STATIC_ASSERT(sizeof(T) == sizeof(Decayed));
+ return Translator::recover(
+ xchg(Translator::decay(exchange_value),
+ reinterpret_cast(dest)));
+ }
+};
+
+template
+inline T Atomic::xchg_using_helper(Fn fn,
+ T exchange_value,
+ T volatile* dest) {
+ STATIC_ASSERT(sizeof(Type) == sizeof(T));
+ return PrimitiveConversions::cast(
+ fn(PrimitiveConversions::cast(exchange_value),
+ reinterpret_cast(dest)));
+}
+
+template
+inline D Atomic::xchg(T exchange_value, volatile D* dest) {
+ return XchgImpl()(exchange_value, dest);
}
#endif // SHARE_VM_RUNTIME_ATOMIC_HPP
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/runtime/globals.hpp
--- a/src/hotspot/share/runtime/globals.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/globals.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -592,8 +592,8 @@
range(8, 256) \
constraint(ObjectAlignmentInBytesConstraintFunc,AtParse) \
\
- product(bool, AssumeMP, false, \
- "Instruct the VM to assume multiple processors are available") \
+ product(bool, AssumeMP, true, \
+ "(Deprecated) Instruct the VM to assume multiple processors are available")\
\
/* UseMembar is theoretically a temp flag used for memory barrier */ \
/* removal testing. It was supposed to be removed before FCS but has */ \
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/runtime/os.hpp
--- a/src/hotspot/share/runtime/os.hpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/os.hpp Mon Oct 09 07:08:53 2017 +0000
@@ -213,7 +213,7 @@
// the bootstrap routine for the stub generator needs to check
// the processor count directly and leave the bootstrap routine
// in place until called after initialization has ocurred.
- return (_processor_count != 1) || AssumeMP;
+ return AssumeMP || (_processor_count != 1);
}
static julong available_memory();
static julong physical_memory();
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/thread.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -3263,6 +3263,9 @@
_buffer_blob = NULL;
_compiler = NULL;
+ // Compiler uses resource area for compilation, let's bias it to mtCompiler
+ resource_area()->bias_to(mtCompiler);
+
#ifndef PRODUCT
_ideal_graph_printer = NULL;
#endif
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/runtime/vmStructs.cpp
--- a/src/hotspot/share/runtime/vmStructs.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/runtime/vmStructs.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -277,7 +277,7 @@
nonstatic_field(Klass, _secondary_super_cache, Klass*) \
nonstatic_field(Klass, _secondary_supers, Array*) \
nonstatic_field(Klass, _primary_supers[0], Klass*) \
- nonstatic_field(Klass, _java_mirror, oop) \
+ nonstatic_field(Klass, _java_mirror, OopHandle) \
nonstatic_field(Klass, _modifier_flags, jint) \
nonstatic_field(Klass, _super, Klass*) \
nonstatic_field(Klass, _subklass, Klass*) \
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/services/jmm.h
--- a/src/hotspot/share/services/jmm.h Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/services/jmm.h Mon Oct 09 07:08:53 2017 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,7 +50,8 @@
JMM_VERSION_1_2 = 0x20010200, // JDK 7
JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
JMM_VERSION_1_2_2 = 0x20010202,
- JMM_VERSION = 0x20010203
+ JMM_VERSION_2 = 0x20020000, // JDK 10
+ JMM_VERSION = 0x20020000
};
typedef struct {
@@ -315,7 +316,8 @@
jobjectArray (JNICALL *DumpThreads) (JNIEnv *env,
jlongArray ids,
jboolean lockedMonitors,
- jboolean lockedSynchronizers);
+ jboolean lockedSynchronizers,
+ jint maxDepth);
void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env,
jobject mgr,
jboolean enabled);
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/services/management.cpp
--- a/src/hotspot/share/services/management.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/services/management.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -1160,7 +1160,8 @@
// locked_monitors - if true, dump locked object monitors
// locked_synchronizers - if true, dump locked JSR-166 synchronizers
//
-JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors, jboolean locked_synchronizers))
+JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors,
+ jboolean locked_synchronizers, jint maxDepth))
ResourceMark rm(THREAD);
// make sure the AbstractOwnableSynchronizer klass is loaded before taking thread snapshots
@@ -1181,14 +1182,14 @@
do_thread_dump(&dump_result,
ids_ah,
num_threads,
- -1, /* entire stack */
+ maxDepth, /* stack depth */
(locked_monitors ? true : false), /* with locked monitors */
(locked_synchronizers ? true : false), /* with locked synchronizers */
CHECK_NULL);
} else {
// obtain thread dump of all threads
VM_ThreadDump op(&dump_result,
- -1, /* entire stack */
+ maxDepth, /* stack depth */
(locked_monitors ? true : false), /* with locked monitors */
(locked_synchronizers ? true : false) /* with locked synchronizers */);
VMThread::execute(&op);
@@ -2237,7 +2238,7 @@
void* Management::get_jmm_interface(int version) {
#if INCLUDE_MANAGEMENT
- if (version == JMM_VERSION_1_0) {
+ if (version == JMM_VERSION) {
return (void*) &jmm_interface;
}
#endif // INCLUDE_MANAGEMENT
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/hotspot/share/services/threadService.cpp
--- a/src/hotspot/share/services/threadService.cpp Sat Oct 07 22:45:12 2017 +0900
+++ b/src/hotspot/share/services/threadService.cpp Mon Oct 09 07:08:53 2017 +0000
@@ -562,6 +562,10 @@
vframe* start_vf = _thread->last_java_vframe(®_map);
int count = 0;
for (vframe* f = start_vf; f; f = f->sender() ) {
+ if (maxDepth >= 0 && count == maxDepth) {
+ // Skip frames if more than maxDepth
+ break;
+ }
if (f->is_java_frame()) {
javaVFrame* jvf = javaVFrame::cast(f);
add_stack_frame(jvf);
@@ -569,10 +573,6 @@
} else {
// Ignore non-Java frames
}
- if (maxDepth > 0 && count == maxDepth) {
- // Skip frames if more than maxDepth
- break;
- }
}
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/ClassLoader.java
--- a/src/java.base/share/classes/java/lang/ClassLoader.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java Mon Oct 09 07:08:53 2017 +0000
@@ -2160,10 +2160,12 @@
* if a package of the given {@code name} is already
* defined by this class loader
*
+ *
* @since 1.2
* @revised 9
* @spec JPMS
*
+ * @jvms 5.3 Run-time package
* @see
* The JAR File Specification: Package Sealing
*/
@@ -2186,17 +2188,19 @@
}
/**
- * Returns a {@code Package} of the given name that has been
- * defined by this class loader.
+ * Returns a {@code Package} of the given name that
+ * has been defined by this class loader.
*
* @param name The package name
*
- * @return The {@code Package} of the given name defined by this class loader,
- * or {@code null} if not found
+ * @return The {@code Package} of the given name that has been defined
+ * by this class loader, or {@code null} if not found
*
* @throws NullPointerException
* if {@code name} is {@code null}.
*
+ * @jvms 5.3 Run-time package
+ *
* @since 9
* @spec JPMS
*/
@@ -2211,14 +2215,18 @@
}
/**
- * Returns all of the {@code Package}s defined by this class loader.
- * The returned array has no duplicated {@code Package}s of the same name.
+ * Returns all of the {@code Package}s that have been defined by
+ * this class loader. The returned array has no duplicated {@code Package}s
+ * of the same name.
*
* @apiNote This method returns an array rather than a {@code Set} or {@code Stream}
* for consistency with the existing {@link #getPackages} method.
*
- * @return The array of {@code Package} objects defined by this class loader;
- * or an zero length array if no package has been defined by this class loader.
+ * @return The array of {@code Package} objects that have been defined by
+ * this class loader; or an zero length array if no package has been
+ * defined by this class loader.
+ *
+ * @jvms 5.3 Run-time package
*
* @since 9
* @spec JPMS
@@ -2244,7 +2252,7 @@
* @param name
* The package name
*
- * @return The {@code Package} corresponding to the given name defined by
+ * @return The {@code Package} of the given name that has been defined by
* this class loader or its ancestors, or {@code null} if not found.
*
* @throws NullPointerException
@@ -2263,6 +2271,8 @@
* {@link ClassLoader#getDefinedPackage} method which returns
* a {@code Package} for the specified class loader.
*
+ * @see ClassLoader#getDefinedPackage(String)
+ *
* @since 1.2
* @revised 9
* @spec JPMS
@@ -2281,10 +2291,10 @@
}
/**
- * Returns all of the {@code Package}s defined by this class loader
- * and its ancestors. The returned array may contain more than one
- * {@code Package} object of the same package name, each defined by
- * a different class loader in the class loader hierarchy.
+ * Returns all of the {@code Package}s that have been defined by
+ * this class loader and its ancestors. The returned array may contain
+ * more than one {@code Package} object of the same package name, each
+ * defined by a different class loader in the class loader hierarchy.
*
* @apiNote The {@link #getPlatformClassLoader() platform class loader}
* may delegate to the application class loader. In other words,
@@ -2294,8 +2304,10 @@
* when invoked on the platform class loader, this method will not
* return any packages defined to the application class loader.
*
- * @return The array of {@code Package} objects defined by this
- * class loader and its ancestors
+ * @return The array of {@code Package} objects that have been defined by
+ * this class loader and its ancestors
+ *
+ * @see ClassLoader#getDefinedPackages()
*
* @since 1.2
* @revised 9
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/Math.java
--- a/src/java.base/share/classes/java/lang/Math.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/Math.java Mon Oct 09 07:08:53 2017 +0000
@@ -1094,6 +1094,7 @@
* @return the result
* @since 9
*/
+ @HotSpotIntrinsicCandidate
public static long multiplyHigh(long x, long y) {
if (x < 0 || y < 0) {
// Use technique from section 8-2 of Henry S. Warren, Jr.,
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/StackFrameInfo.java
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java Mon Oct 09 07:08:53 2017 +0000
@@ -29,6 +29,7 @@
import static java.lang.StackWalker.Option.*;
import java.lang.StackWalker.StackFrame;
+import java.lang.invoke.MethodType;
class StackFrameInfo implements StackFrame {
private final static JavaLangInvokeAccess JLIA =
@@ -79,6 +80,17 @@
}
@Override
+ public MethodType getMethodType() {
+ walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE);
+ return JLIA.getMethodType(memberName);
+ }
+
+ @Override
+ public String getDescriptor() {
+ return JLIA.getMethodDescriptor(memberName);
+ }
+
+ @Override
public int getByteCodeIndex() {
// bci not available for native methods
if (isNativeMethod())
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/StackWalker.java
--- a/src/java.base/share/classes/java/lang/StackWalker.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/StackWalker.java Mon Oct 09 07:08:53 2017 +0000
@@ -26,10 +26,12 @@
import jdk.internal.reflect.CallerSensitive;
-import java.util.*;
+import java.lang.invoke.MethodType;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
-import java.util.function.Predicate;
import java.util.stream.Stream;
/**
@@ -96,7 +98,7 @@
* @since 9
* @jvms 2.6
*/
- public static interface StackFrame {
+ public interface StackFrame {
/**
* Gets the binary name
* of the declaring class of the method represented by this stack frame.
@@ -128,6 +130,47 @@
public Class> getDeclaringClass();
/**
+ * Returns the {@link MethodType} representing the parameter types and
+ * the return type for the method represented by this stack frame.
+ *
+ * @implSpec
+ * The default implementation throws {@code UnsupportedOperationException}.
+ *
+ * @return the {@code MethodType} for this stack frame
+ *
+ * @throws UnsupportedOperationException if this {@code StackWalker}
+ * is not configured with {@link Option#RETAIN_CLASS_REFERENCE
+ * Option.RETAIN_CLASS_REFERENCE}.
+ *
+ * @since 10
+ */
+ public default MethodType getMethodType() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the descriptor of the method represented by
+ * this stack frame as defined by
+ * The Java Virtual Machine Specification.
+ *
+ * @implSpec
+ * The default implementation throws {@code UnsupportedOperationException}.
+ *
+ * @return the descriptor of the method represented by
+ * this stack frame
+ *
+ * @see MethodType#fromMethodDescriptorString(String, ClassLoader)
+ * @see MethodType#toMethodDescriptorString()
+ * @jvms 4.3.3 Method Descriptor
+ *
+ * @since 10
+ */
+ public default String getDescriptor() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ /**
* Returns the index to the code array of the {@code Code} attribute
* containing the execution point represented by this stack frame.
* The code array gives the actual bytes of Java Virtual Machine code
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java
--- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java Mon Oct 09 07:08:53 2017 +0000
@@ -28,6 +28,7 @@
import java.util.Arrays;
import static java.lang.invoke.LambdaForm.*;
import static java.lang.invoke.LambdaForm.Kind.*;
+import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
import static java.lang.invoke.MethodHandleStatics.*;
/**
@@ -158,8 +159,11 @@
static final NamedFunction NF_getTarget;
static {
try {
- NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
- .getDeclaredMethod("getTarget"));
+ MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget",
+ MethodType.methodType(MethodHandle.class), REF_invokeVirtual);
+ NF_getTarget = new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class));
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);
}
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Mon Oct 09 07:08:53 2017 +0000
@@ -753,42 +753,38 @@
return nf;
}
+ private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
+
+ private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
+
private static NamedFunction createFunction(byte func) {
try {
switch (func) {
case NF_internalMemberName:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberName", Object.class));
+ return getNamedFunction("internalMemberName", OBJ_OBJ_TYPE);
case NF_internalMemberNameEnsureInit:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+ return getNamedFunction("internalMemberNameEnsureInit", OBJ_OBJ_TYPE);
case NF_ensureInitialized:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("ensureInitialized", Object.class));
+ return getNamedFunction("ensureInitialized", MethodType.methodType(void.class, Object.class));
case NF_fieldOffset:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("fieldOffset", Object.class));
+ return getNamedFunction("fieldOffset", LONG_OBJ_TYPE);
case NF_checkBase:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkBase", Object.class));
+ return getNamedFunction("checkBase", OBJ_OBJ_TYPE);
case NF_staticBase:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticBase", Object.class));
+ return getNamedFunction("staticBase", OBJ_OBJ_TYPE);
case NF_staticOffset:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("staticOffset", Object.class));
+ return getNamedFunction("staticOffset", LONG_OBJ_TYPE);
case NF_checkCast:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("checkCast", Object.class, Object.class));
+ return getNamedFunction("checkCast", MethodType.methodType(Object.class, Object.class, Object.class));
case NF_allocateInstance:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("allocateInstance", Object.class));
+ return getNamedFunction("allocateInstance", OBJ_OBJ_TYPE);
case NF_constructorMethod:
- return new NamedFunction(DirectMethodHandle.class
- .getDeclaredMethod("constructorMethod", Object.class));
+ return getNamedFunction("constructorMethod", OBJ_OBJ_TYPE);
case NF_UNSAFE:
- return new NamedFunction(new MemberName(MethodHandleStatics.class
- .getDeclaredField("UNSAFE")));
+ MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getField);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
default:
throw newInternalError("Unknown function: " + func);
}
@@ -797,6 +793,15 @@
}
}
+ private static NamedFunction getNamedFunction(String name, MethodType type)
+ throws ReflectiveOperationException
+ {
+ MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeStatic, member, DirectMethodHandle.class, NoSuchMethodException.class));
+ }
+
static {
// The Holder class will contain pre-generated DirectMethodHandles resolved
// speculatively using MemberName.getFactory().resolveOrNull. However, that
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/invoke/Invokers.java
--- a/src/java.base/share/classes/java/lang/invoke/Invokers.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java Mon Oct 09 07:08:53 2017 +0000
@@ -611,23 +611,17 @@
try {
switch (func) {
case NF_checkExactType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkExactType", MethodHandle.class, MethodType.class));
+ return getNamedFunction("checkExactType", MethodType.methodType(void.class, MethodHandle.class, MethodType.class));
case NF_checkGenericType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkGenericType", MethodHandle.class, MethodType.class));
+ return getNamedFunction("checkGenericType", MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
case NF_getCallSiteTarget:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("getCallSiteTarget", CallSite.class));
+ return getNamedFunction("getCallSiteTarget", MethodType.methodType(MethodHandle.class, CallSite.class));
case NF_checkCustomized:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkCustomized", MethodHandle.class));
+ return getNamedFunction("checkCustomized", MethodType.methodType(void.class, MethodHandle.class));
case NF_checkVarHandleGenericType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class));
+ return getNamedFunction("checkVarHandleGenericType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
case NF_checkVarHandleExactType:
- return new NamedFunction(Invokers.class
- .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class));
+ return getNamedFunction("checkVarHandleExactType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
default:
throw newInternalError("Unknown function: " + func);
}
@@ -636,6 +630,15 @@
}
}
+ private static NamedFunction getNamedFunction(String name, MethodType type)
+ throws ReflectiveOperationException
+ {
+ MemberName member = new MemberName(Invokers.class, name, type, REF_invokeStatic);
+ return new NamedFunction(
+ MemberName.getFactory()
+ .resolveOrFail(REF_invokeStatic, member, Invokers.class, NoSuchMethodException.class));
+ }
+
private static class Lazy {
private static final MethodHandle MH_asSpreader;
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/invoke/MemberName.java
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java Mon Oct 09 07:08:53 2017 +0000
@@ -162,6 +162,29 @@
return (MethodType) type;
}
+ /** Return the descriptor of this member, which
+ * must be a method or constructor.
+ */
+ String getMethodDescriptor() {
+ if (type == null) {
+ expandFromVM();
+ if (type == null) {
+ return null;
+ }
+ }
+ if (!isInvocable()) {
+ throw newIllegalArgumentException("not invocable, no method type");
+ }
+
+ // Get a snapshot of type which doesn't get changed by racing threads.
+ final Object type = this.type;
+ if (type instanceof String) {
+ return (String) type;
+ } else {
+ return getMethodType().toMethodDescriptorString();
+ }
+ }
+
/** Return the actual type under which this method or constructor must be invoked.
* For non-static methods or constructors, this is the type with a leading parameter,
* a reference to declaring class. For static methods, it is the same as the declared type.
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Mon Oct 09 07:08:53 2017 +0000
@@ -1786,6 +1786,18 @@
}
@Override
+ public MethodType getMethodType(Object mname) {
+ MemberName memberName = (MemberName)mname;
+ return memberName.getMethodType();
+ }
+
+ @Override
+ public String getMethodDescriptor(Object mname) {
+ MemberName memberName = (MemberName)mname;
+ return memberName.getMethodDescriptor();
+ }
+
+ @Override
public boolean isNative(Object mname) {
MemberName memberName = (MemberName)mname;
return memberName.isNative();
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/util/ArrayDeque.java
--- a/src/java.base/share/classes/java/util/ArrayDeque.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java Mon Oct 09 07:08:53 2017 +0000
@@ -211,7 +211,7 @@
}
/**
- * Increments i, mod modulus.
+ * Circularly increments i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int inc(int i, int modulus) {
@@ -220,7 +220,7 @@
}
/**
- * Decrements i, mod modulus.
+ * Circularly decrements i, mod modulus.
* Precondition and postcondition: 0 <= i < modulus.
*/
static final int dec(int i, int modulus) {
@@ -233,7 +233,7 @@
* Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
* @return index 0 <= i < modulus
*/
- static final int add(int i, int distance, int modulus) {
+ static final int inc(int i, int distance, int modulus) {
if ((i += distance) - modulus >= 0) i -= modulus;
return i;
}
@@ -825,7 +825,7 @@
final int i, n;
return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
? null
- : new DeqSpliterator(i, cursor = add(i, n, es.length));
+ : new DeqSpliterator(i, cursor = inc(i, n, es.length));
}
public void forEachRemaining(Consumer super E> action) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/util/HashMap.java
--- a/src/java.base/share/classes/java/util/HashMap.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/HashMap.java Mon Oct 09 07:08:53 2017 +0000
@@ -490,7 +490,7 @@
}
/**
- * Implements Map.putAll and Map constructor
+ * Implements Map.putAll and Map constructor.
*
* @param m the map
* @param evict false when initially constructing this map, else
@@ -557,7 +557,7 @@
}
/**
- * Implements Map.get and related methods
+ * Implements Map.get and related methods.
*
* @param hash hash for key
* @param key the key
@@ -612,7 +612,7 @@
}
/**
- * Implements Map.put and related methods
+ * Implements Map.put and related methods.
*
* @param hash hash for key
* @param key the key
@@ -700,7 +700,7 @@
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
- Node[] newTab = (Node[])new Node[newCap];
+ Node[] newTab = (Node[])new Node[newCap];
table = newTab;
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
@@ -800,7 +800,7 @@
}
/**
- * Implements Map.remove and related methods
+ * Implements Map.remove and related methods.
*
* @param hash hash for key
* @param key the key
@@ -875,7 +875,7 @@
public boolean containsValue(Object value) {
Node[] tab; V v;
if ((tab = table) != null && size > 0) {
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next) {
if ((v = e.value) == value ||
(value != null && value.equals(v)))
@@ -927,7 +927,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next)
action.accept(e.key);
}
@@ -975,7 +975,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next)
action.accept(e.value);
}
@@ -1038,7 +1038,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next)
action.accept(e);
}
@@ -1335,7 +1335,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next)
action.accept(e.key, e.value);
}
@@ -1351,7 +1351,7 @@
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next) {
e.value = function.apply(e.key, e.value);
}
@@ -1394,9 +1394,10 @@
}
/**
- * Save the state of the {@code HashMap} instance to a stream (i.e.,
- * serialize it).
+ * Saves this map to a stream (that is, serializes it).
*
+ * @param s the stream
+ * @throws IOException if an I/O error occurs
* @serialData The capacity of the HashMap (the length of the
* bucket array) is emitted (int), followed by the
* size (an int, the number of key-value
@@ -1415,8 +1416,11 @@
}
/**
- * Reconstitute the {@code HashMap} instance from a stream (i.e.,
- * deserialize it).
+ * Reconstitutes this map from a stream (that is, deserializes it).
+ * @param s the stream
+ * @throws ClassNotFoundException if the class of a serialized object
+ * could not be found
+ * @throws IOException if an I/O error occurs
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
@@ -1445,7 +1449,7 @@
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
@SuppressWarnings({"rawtypes","unchecked"})
- Node[] tab = (Node[])new Node[cap];
+ Node[] tab = (Node[])new Node[cap];
table = tab;
// Read the keys and values, and put the mappings in the HashMap
@@ -1830,7 +1834,7 @@
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
Node[] tab;
if (size > 0 && (tab = table) != null) {
- for (Node e : tab) {
+ for (Node e : tab) {
for (; e != null; e = e.next) {
s.writeObject(e.key);
s.writeObject(e.value);
@@ -1951,7 +1955,6 @@
/**
* Forms tree of the nodes linked from this node.
- * @return root of tree
*/
final void treeify(Node[] tab) {
TreeNode root = null;
@@ -2089,8 +2092,11 @@
return;
if (root.parent != null)
root = root.root();
- if (root == null || root.right == null ||
- (rl = root.left) == null || rl.left == null) {
+ if (root == null
+ || (movable
+ && (root.right == null
+ || (rl = root.left) == null
+ || rl.left == null))) {
tab[index] = first.untreeify(map); // too small
return;
}
@@ -2319,7 +2325,7 @@
static TreeNode balanceDeletion(TreeNode root,
TreeNode x) {
- for (TreeNode xp, xpl, xpr;;) {
+ for (TreeNode xp, xpl, xpr;;) {
if (x == null || x == root)
return root;
else if ((xp = x.parent) == null) {
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/util/concurrent/CompletableFuture.java
--- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java Mon Oct 09 07:08:53 2017 +0000
@@ -2490,13 +2490,13 @@
for (Completion p = stack; p != null; p = p.next)
++count;
return super.toString() +
- ((r == null) ?
- ((count == 0) ?
- "[Not completed]" :
- "[Not completed, " + count + " dependents]") :
- (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
- "[Completed exceptionally]" :
- "[Completed normally]"));
+ ((r == null)
+ ? ((count == 0)
+ ? "[Not completed]"
+ : "[Not completed, " + count + " dependents]")
+ : (((r instanceof AltResult) && ((AltResult)r).ex != null)
+ ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
+ : "[Completed normally]"));
}
// jdk9 additions
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java Mon Oct 09 07:08:53 2017 +0000
@@ -1394,8 +1394,8 @@
}
/**
- * Saves the state of the {@code ConcurrentHashMap} instance to a
- * stream (i.e., serializes it).
+ * Saves this map to a stream (that is, serializes it).
+ *
* @param s the stream
* @throws java.io.IOException if an I/O error occurs
* @serialData
@@ -1439,7 +1439,7 @@
}
/**
- * Reconstitutes the instance from a stream (that is, deserializes it).
+ * Reconstitutes this map from a stream (that is, deserializes it).
* @param s the stream
* @throws ClassNotFoundException if the class of a serialized object
* could not be found
diff -r d4380ee1cbe9 -r f5f98c9f1884 src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Sat Oct 07 22:45:12 2017 +0900
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java Mon Oct 09 07:08:53 2017 +0000
@@ -58,6 +58,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.concurrent.atomic.LongAdder;
/**
* A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -86,12 +87,7 @@
* associated map using {@code put}, {@code putIfAbsent}, or
* {@code replace}, depending on exactly which effect you need.)
*
- * Beware that, unlike in most collections, the {@code size}
- * method is not a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current number
- * of elements requires a traversal of the elements, and so may report
- * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code putAll}, {@code equals},
+ *
Beware that bulk operations {@code putAll}, {@code equals},
* {@code toArray}, {@code containsValue}, and {@code clear} are
* not guaranteed to be performed atomically. For example, an
* iterator operating concurrently with a {@code putAll} operation
@@ -158,42 +154,35 @@
* be slow and space-intensive using AtomicMarkedReference), nodes
* use direct CAS'able next pointers. On deletion, instead of
* marking a pointer, they splice in another node that can be
- * thought of as standing for a marked pointer (indicating this by
- * using otherwise impossible field values). Using plain nodes
- * acts roughly like "boxed" implementations of marked pointers,
- * but uses new nodes only when nodes are deleted, not for every
- * link. This requires less space and supports faster
- * traversal. Even if marked references were better supported by
- * JVMs, traversal using this technique might still be faster
- * because any search need only read ahead one more node than
- * otherwise required (to check for trailing marker) rather than
- * unmasking mark bits or whatever on each read.
+ * thought of as standing for a marked pointer (see method
+ * unlinkNode). Using plain nodes acts roughly like "boxed"
+ * implementations of marked pointers, but uses new nodes only
+ * when nodes are deleted, not for every link. This requires less
+ * space and supports faster traversal. Even if marked references
+ * were better supported by JVMs, traversal using this technique
+ * might still be faster because any search need only read ahead
+ * one more node than otherwise required (to check for trailing
+ * marker) rather than unmasking mark bits or whatever on each
+ * read.
*
* This approach maintains the essential property needed in the HM
* algorithm of changing the next-pointer of a deleted node so
* that any other CAS of it will fail, but implements the idea by
- * changing the pointer to point to a different node, not by
- * marking it. While it would be possible to further squeeze
- * space by defining marker nodes not to have key/value fields, it
- * isn't worth the extra type-testing overhead. The deletion
- * markers are rarely encountered during traversal and are
- * normally quickly garbage collected. (Note that this technique
- * would not work well in systems without garbage collection.)
+ * changing the pointer to point to a different node (with
+ * otherwise illegal null fields), not by marking it. While it
+ * would be possible to further squeeze space by defining marker
+ * nodes not to have key/value fields, it isn't worth the extra
+ * type-testing overhead. The deletion markers are rarely
+ * encountered during traversal, are easily detected via null
+ * checks that are needed anyway, and are normally quickly garbage
+ * collected. (Note that this technique would not work well in
+ * systems without garbage collection.)
*
* In addition to using deletion markers, the lists also use
* nullness of value fields to indicate deletion, in a style
* similar to typical lazy-deletion schemes. If a node's value is
* null, then it is considered logically deleted and ignored even
- * though it is still reachable. This maintains proper control of
- * concurrent replace vs delete operations -- an attempted replace
- * must fail if a delete beat it by nulling field, and a delete
- * must return the last non-null value held in the field. (Note:
- * Null, rather than some special marker, is used for value fields
- * here because it just so happens to mesh with the Map API
- * requirement that method get returns null if there is no
- * mapping, which allows nodes to remain concurrently readable
- * even when deleted. Using any other marker value here would be
- * messy at best.)
+ * though it is still reachable.
*
* Here's the sequence of events for a deletion of node n with
* predecessor b and successor f, initially:
@@ -203,9 +192,8 @@
* +------+ +------+ +------+
*
* 1. CAS n's value field from non-null to null.
- * From this point on, no public operations encountering
- * the node consider this mapping to exist. However, other
- * ongoing insertions and deletions might still modify
+ * Traversals encountering a node with null value ignore it.
+ * However, ongoing insertions and deletions might still modify
* n's next pointer.
*
* 2. CAS n's next pointer to point to a new marker node.
@@ -228,12 +216,7 @@
* thread noticed during a traversal a node with null value and
* helped out by marking and/or unlinking. This helping-out
* ensures that no thread can become stuck waiting for progress of
- * the deleting thread. The use of marker nodes slightly
- * complicates helping-out code because traversals must track
- * consistent reads of up to four nodes (b, n, marker, f), not
- * just (b, n, f), although the next field of a marker is
- * immutable, and once a next field is CAS'ed to point to a
- * marker, it never again changes, so this requires less care.
+ * the deleting thread.
*
* Skip lists add indexing to this scheme, so that the base-level
* traversals start close to the locations being found, inserted
@@ -243,113 +226,101 @@
* b) that are not (structurally) deleted, otherwise retrying
* after processing the deletion.
*
- * Index levels are maintained as lists with volatile next fields,
- * using CAS to link and unlink. Races are allowed in index-list
- * operations that can (rarely) fail to link in a new index node
- * or delete one. (We can't do this of course for data nodes.)
- * However, even when this happens, the index lists remain sorted,
- * so correctly serve as indices. This can impact performance,
- * but since skip lists are probabilistic anyway, the net result
- * is that under contention, the effective "p" value may be lower
- * than its nominal value. And race windows are kept small enough
- * that in practice these failures are rare, even under a lot of
- * contention.
+ * Index levels are maintained using CAS to link and unlink
+ * successors ("right" fields). Races are allowed in index-list
+ * operations that can (rarely) fail to link in a new index node.
+ * (We can't do this of course for data nodes.) However, even
+ * when this happens, the index lists correctly guide search.
+ * This can impact performance, but since skip lists are
+ * probabilistic anyway, the net result is that under contention,
+ * the effective "p" value may be lower than its nominal value.
*
- * The fact that retries (for both base and index lists) are
- * relatively cheap due to indexing allows some minor
- * simplifications of retry logic. Traversal restarts are
- * performed after most "helping-out" CASes. This isn't always
- * strictly necessary, but the implicit backoffs tend to help
- * reduce other downstream failed CAS's enough to outweigh restart
- * cost. This worsens the worst case, but seems to improve even
- * highly contended cases.
- *
- * Unlike most skip-list implementations, index insertion and
- * deletion here require a separate traversal pass occurring after
- * the base-level action, to add or remove index nodes. This adds
- * to single-threaded overhead, but improves contended
- * multithreaded performance by narrowing interference windows,
- * and allows deletion to ensure that all index nodes will be made
- * unreachable upon return from a public remove operation, thus
- * avoiding unwanted garbage retention. This is more important
- * here than in some other data structures because we cannot null
- * out node fields referencing user keys since they might still be
- * read by other ongoing traversals.
+ * Index insertion and deletion sometimes require a separate
+ * traversal pass occurring after the base-level action, to add or
+ * remove index nodes. This adds to single-threaded overhead, but
+ * improves contended multithreaded performance by narrowing
+ * interference windows, and allows deletion to ensure that all
+ * index nodes will be made unreachable upon return from a public
+ * remove operation, thus avoiding unwanted garbage retention.
*
* Indexing uses skip list parameters that maintain good search
* performance while using sparser-than-usual indices: The
- * hardwired parameters k=1, p=0.5 (see method doPut) mean
- * that about one-quarter of the nodes have indices. Of those that
- * do, half have one level, a quarter have two, and so on (see
- * Pugh's Skip List Cookbook, sec 3.4). The expected total space
- * requirement for a map is slightly less than for the current
- * implementation of java.util.TreeMap.
+ * hardwired parameters k=1, p=0.5 (see method doPut) mean that
+ * about one-quarter of the nodes have indices. Of those that do,
+ * half have one level, a quarter have two, and so on (see Pugh's
+ * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
+ * (appropriate for up to 2^63 elements). The expected total
+ * space requirement for a map is slightly less than for the
+ * current implementation of java.util.TreeMap.
*
* Changing the level of the index (i.e, the height of the
- * tree-like structure) also uses CAS. The head index has initial
- * level/height of one. Creation of an index with height greater
- * than the current level adds a level to the head index by
- * CAS'ing on a new top-most head. To maintain good performance
- * after a lot of removals, deletion methods heuristically try to
- * reduce the height if the topmost levels appear to be empty.
- * This may encounter races in which it possible (but rare) to
- * reduce and "lose" a level just as it is about to contain an
- * index (that will then never be encountered). This does no
- * structural harm, and in practice appears to be a better option
- * than allowing unrestrained growth of levels.
+ * tree-like structure) also uses CAS. Creation of an index with
+ * height greater than the current level adds a level to the head
+ * index by CAS'ing on a new top-most head. To maintain good
+ * performance after a lot of removals, deletion methods
+ * heuristically try to reduce the height if the topmost levels
+ * appear to be empty. This may encounter races in which it is
+ * possible (but rare) to reduce and "lose" a level just as it is
+ * about to contain an index (that will then never be
+ * encountered). This does no structural harm, and in practice
+ * appears to be a better option than allowing unrestrained growth
+ * of levels.
*
- * The code for all this is more verbose than you'd like. Most
- * operations entail locating an element (or position to insert an
- * element). The code to do this can't be nicely factored out
- * because subsequent uses require a snapshot of predecessor
- * and/or successor and/or value fields which can't be returned
- * all at once, at least not without creating yet another object
- * to hold them -- creating such little objects is an especially
- * bad idea for basic internal search operations because it adds
- * to GC overhead. (This is one of the few times I've wished Java
- * had macros.) Instead, some traversal code is interleaved within
- * insertion and removal operations. The control logic to handle
- * all the retry conditions is sometimes twisty. Most search is
- * broken into 2 parts. findPredecessor() searches index nodes
- * only, returning a base-level predecessor of the key. findNode()
- * finishes out the base-level search. Even with this factoring,
- * there is a fair amount of near-duplication of code to handle
- * variants.
+ * This class provides concurrent-reader-style memory consistency,
+ * ensuring that read-only methods report status and/or values no
+ * staler than those holding at method entry. This is done by
+ * performing all publication and structural updates using
+ * (volatile) CAS, placing an acquireFence in a few access
+ * methods, and ensuring that linked objects are transitively
+ * acquired via dependent reads (normally once) unless performing
+ * a volatile-mode CAS operation (that also acts as an acquire and
+ * release). This form of fence-hoisting is similar to RCU and
+ * related techniques (see McKenney's online book
+ * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
+ * It minimizes overhead that may otherwise occur when using so
+ * many volatile-mode reads. Using explicit acquireFences is
+ * logistically easier than targeting particular fields to be read
+ * in acquire mode: fences are just hoisted up as far as possible,
+ * to the entry points or loop headers of a few methods. A
+ * potential disadvantage is that these few remaining fences are
+ * not easily optimized away by compilers under exclusively
+ * single-thread use. It requires some care to avoid volatile
+ * mode reads of other fields. (Note that the memory semantics of
+ * a reference dependently read in plain mode exactly once are
+ * equivalent to those for atomic opaque mode.) Iterators and
+ * other traversals encounter each node and value exactly once.
+ * Other operations locate an element (or position to insert an
+ * element) via a sequence of dereferences. This search is broken
+ * into two parts. Method findPredecessor (and its specialized
+ * embeddings) searches index nodes only, returning a base-level
+ * predecessor of the key. Callers carry out the base-level
+ * search, restarting if encountering a marker preventing link
+ * modification. In some cases, it is possible to encounter a
+ * node multiple times while descending levels. For mutative
+ * operations, the reported value is validated using CAS (else
+ * retrying), preserving linearizability with respect to each
+ * other. Others may return any (non-null) value holding in the
+ * course of the method call. (Search-based methods also include
+ * some useless-looking explicit null checks designed to allow
+ * more fields to be nulled out upon removal, to reduce floating
+ * garbage, but which is not currently done, pending discovery of
+ * a way to do this with less impact on other operations.)
*
* To produce random values without interference across threads,
* we use within-JDK thread local random support (via the
* "secondary seed", to avoid interference with user-level
* ThreadLocalRandom.)
*
- * A previous version of this class wrapped non-comparable keys
- * with their comparators to emulate Comparables when using
- * comparators vs Comparables. However, JVMs now appear to better
- * handle infusing comparator-vs-comparable choice into search
- * loops. Static method cpr(comparator, x, y) is used for all
- * comparisons, which works well as long as the comparator
- * argument is set up outside of loops (thus sometimes passed as
- * an argument to internal methods) to avoid field re-reads.
- *
* For explanation of algorithms sharing at least a couple of
* features with this one, see Mikhail Fomitchev's thesis
* (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
* (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
* thesis (http://www.cs.chalmers.se/~phs/).
*
- * Given the use of tree-like index nodes, you might wonder why
- * this doesn't use some kind of search tree instead, which would
- * support somewhat faster search operations. The reason is that
- * there are no known efficient lock-free insertion and deletion
- * algorithms for search trees. The immutability of the "down"
- * links of index nodes (as opposed to mutable "left" fields in
- * true trees) makes this tractable using only CAS operations.
- *
* Notation guide for local variables
- * Node: b, n, f for predecessor, node, successor
+ * Node: b, n, f, p for predecessor, node, successor, aux
* Index: q, r, d for index node, right, down.
- * t for another index node
* Head: h
- * Levels: j
* Keys: k, key
* Values: v, value
* Comparisons: c
@@ -358,16 +329,6 @@
private static final long serialVersionUID = -8627078645895051609L;
/**
- * Special value used to identify base-level header.
- */
- static final Object BASE_HEADER = new Object();
-
- /**
- * The topmost head index of the skiplist.
- */
- private transient volatile HeadIndex head;
-
- /**
* The comparator used to maintain order in this map, or null if
* using natural ordering. (Non-private to simplify access in
* nested classes.)
@@ -375,311 +336,152 @@
*/
final Comparator super K> comparator;
+ /** Lazily initialized topmost index of the skiplist. */
+ private transient Index head;
+ /** Lazily initialized element count */
+ private transient LongAdder adder;
/** Lazily initialized key set */
private transient KeySet keySet;
/** Lazily initialized values collection */
private transient Values values;
/** Lazily initialized entry set */
private transient EntrySet entrySet;
- /** Lazily initialized descending key set */
+ /** Lazily initialized descending map */
private transient SubMap descendingMap;
/**
- * Initializes or resets state. Needed by constructors, clone,
- * clear, readObject. and ConcurrentSkipListSet.clone.
- * (Note that comparator must be separately initialized.)
- */
- private void initialize() {
- keySet = null;
- entrySet = null;
- values = null;
- descendingMap = null;
- head = new HeadIndex(new Node(null, BASE_HEADER, null),
- null, null, 1);
- }
-
- /**
- * compareAndSet head node.
- */
- private boolean casHead(HeadIndex cmp, HeadIndex val) {
- return HEAD.compareAndSet(this, cmp, val);
- }
-
- /* ---------------- Nodes -------------- */
-
- /**
* Nodes hold keys and values, and are singly linked in sorted
* order, possibly with some intervening marker nodes. The list is
- * headed by a dummy node accessible as head.node. The value field
- * is declared only as Object because it takes special non-V
- * values for marker and header nodes.
+ * headed by a header node accessible as head.node. Headers and
+ * marker nodes have null keys. The val field (but currently not
+ * the key field) is nulled out upon deletion.
*/
static final class Node {
- final K key;
- volatile Object value;
- volatile Node next;
-
- /**
- * Creates a new regular node.
- */
- Node(K key, Object value, Node next) {
+ final K key; // currently, never detached
+ V val;
+ Node next;
+ Node(K key, V value, Node next) {
this.key = key;
- this.value = value;
- this.next = next;
- }
-
- /**
- * Creates a new marker node. A marker is distinguished by
- * having its value field point to itself. Marker nodes also
- * have null keys, a fact that is exploited in a few places,
- * but this doesn't distinguish markers from the base-level
- * header node (head.node), which also has a null key.
- */
- Node(Node next) {
- this.key = null;
- this.value = this;
+ this.val = value;
this.next = next;
}
-
- /**
- * compareAndSet value field.
- */
- boolean casValue(Object cmp, Object val) {
- return VALUE.compareAndSet(this, cmp, val);
- }
-
- /**
- * compareAndSet next field.
- */
- boolean casNext(Node cmp, Node val) {
- return NEXT.compareAndSet(this, cmp, val);
- }
-
- /**
- * Returns true if this node is a marker. This method isn't
- * actually called in any current code checking for markers
- * because callers will have already read value field and need
- * to use that read (not another done here) and so directly
- * test if value points to node.
- *
- * @return true if this node is a marker node
- */
- boolean isMarker() {
- return value == this;
- }
-
- /**
- * Returns true if this node is the header of base-level list.
- * @return true if this node is header node
- */
- boolean isBaseHeader() {
- return value == BASE_HEADER;
- }
-
- /**
- * Tries to append a deletion marker to this node.
- * @param f the assumed current successor of this node
- * @return true if successful
- */
- boolean appendMarker(Node f) {
- return casNext(f, new Node(f));
- }
-
- /**
- * Helps out a deletion by appending marker or unlinking from
- * predecessor. This is called during traversals when value
- * field seen to be null.
- * @param b predecessor
- * @param f successor
- */
- void helpDelete(Node b, Node f) {
- /*
- * Rechecking links and then doing only one of the
- * help-out stages per call tends to minimize CAS
- * interference among helping threads.
- */
- if (f == next && this == b.next) {
- if (f == null || f.value != f) // not already marked
- casNext(f, new Node(f));
- else
- b.casNext(this, f.next);
- }
- }
-
- /**
- * Returns value if this node contains a valid key-value pair,
- * else null.
- * @return this node's value if it isn't a marker or header or
- * is deleted, else null
- */
- V getValidValue() {
- Object v = value;
- if (v == this || v == BASE_HEADER)
- return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return vv;
- }
-
- /**
- * Creates and returns a new SimpleImmutableEntry holding current
- * mapping if this node holds a valid value, else null.
- * @return new entry or null
- */
- AbstractMap.SimpleImmutableEntry createSnapshot() {
- Object v = value;
- if (v == null || v == this || v == BASE_HEADER)
- return null;
- @SuppressWarnings("unchecked") V vv = (V)v;
- return new AbstractMap.SimpleImmutableEntry(key, vv);
- }
-
- // VarHandle mechanics
- private static final VarHandle VALUE;
- private static final VarHandle NEXT;
- static {
- try {
- MethodHandles.Lookup l = MethodHandles.lookup();
- VALUE = l.findVarHandle(Node.class, "value", Object.class);
- NEXT = l.findVarHandle(Node.class, "next", Node.class);
- } catch (ReflectiveOperationException e) {
- throw new Error(e);
- }
- }
}
- /* ---------------- Indexing -------------- */
-
/**
- * Index nodes represent the levels of the skip list. Note that
- * even though both Nodes and Indexes have forward-pointing
- * fields, they have different types and are handled in different
- * ways, that can't nicely be captured by placing field in a
- * shared abstract class.
+ * Index nodes represent the levels of the skip list.
*/
- static class Index