From c04d1331fc0099569cc4c6e65c982cecae4b3646 Mon Sep 17 00:00:00 2001 From: Sharath Ballal Date: Sat, 2 Dec 2017 11:25:35 +0530 Subject: [PATCH 01/22] 8192823: SA: Testcase for 'clhsdb source' command Reviewed-by: sspitsyn, jgeorge --- .../jtreg/serviceability/sa/ClhsdbSource.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/hotspot/jtreg/serviceability/sa/ClhsdbSource.java diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbSource.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbSource.java new file mode 100644 index 00000000000..3d6dd5a5fb0 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbSource.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import jdk.test.lib.apps.LingeredApp; + +/* + * @test + * @bug 8192823 + * @summary Test clhsdb source command + * @library /test/lib + * @run main/othervm ClhsdbSource + */ + +public class ClhsdbSource { + + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbSource test"); + + LingeredApp theApp = null; + try { + ClhsdbLauncher test = new ClhsdbLauncher(); + theApp = LingeredApp.startApp(); + System.out.println("Started LingeredApp with pid " + theApp.getPid()); + + Path file = Paths.get("clhsdb_cmd_file"); + Files.write(file, "jstack -v\nhelp".getBytes()); + List cmds = List.of("source clhsdb_cmd_file"); + + Map> expStrMap = new HashMap<>(); + expStrMap.put("source clhsdb_cmd_file", List.of( + "No deadlocks found", + "Common-Cleaner", + "Signal Dispatcher", + "java.lang.ref.Finalizer$FinalizerThread.run", + "java.lang.ref.Reference", + "Method*", + "LingeredApp.main", + "Available commands:", + "attach pid | exec core", + "intConstant [ name [ value ] ]", + "type [ type [ name super isOop isInteger isUnsigned size ] ]", + "symboltable name")); + + Map> unExpStrMap = new HashMap<>(); + unExpStrMap.put("source clhsdb_cmd_file", List.of( + "No such file or directory")); + + test.run(theApp.getPid(), cmds, expStrMap, unExpStrMap); + Files.delete(file); + } catch (Exception ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } finally { + LingeredApp.stopApp(theApp); + } + System.out.println("Test PASSED"); + } +} From 8b4b92c1a14d43cf12c94d9d8aa1aad9f5e808cc Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Sat, 2 Dec 2017 13:50:04 +0100 Subject: [PATCH 02/22] 8191950: assertion failed: no insertions allowed Check for dead loops before incremental inlining. Reviewed-by: thartmann --- src/hotspot/share/opto/callGenerator.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/hotspot/share/opto/callGenerator.cpp b/src/hotspot/share/opto/callGenerator.cpp index a5aaa552fee..3a0dd830ac1 100644 --- a/src/hotspot/share/opto/callGenerator.cpp +++ b/src/hotspot/share/opto/callGenerator.cpp @@ -362,6 +362,20 @@ void LateInlineCallGenerator::do_late_inline() { return; } + // check for unreachable loop + CallProjections callprojs; + call->extract_projections(&callprojs, true); + if (callprojs.fallthrough_catchproj == call->in(0) || + callprojs.catchall_catchproj == call->in(0) || + callprojs.fallthrough_memproj == call->in(TypeFunc::Memory) || + callprojs.catchall_memproj == call->in(TypeFunc::Memory) || + callprojs.fallthrough_ioproj == call->in(TypeFunc::I_O) || + callprojs.catchall_ioproj == call->in(TypeFunc::I_O) || + (callprojs.resproj != NULL && call->find_edge(callprojs.resproj) != -1) || + (callprojs.exobj != NULL && call->find_edge(callprojs.exobj) != -1)) { + return; + } + Compile* C = Compile::current(); // Remove inlined methods from Compiler's lists. if (call->is_macro()) { From 05f99dfe85080d97f3a01af15a1ccb232285a2b9 Mon Sep 17 00:00:00 2001 From: Tom Rodriguez Date: Mon, 4 Dec 2017 13:13:44 -0800 Subject: [PATCH 03/22] 8191052: [Graal] java/lang/invoke/CallSiteTest.java intermittently fails with "Failed dependency of type call_site_target_value" when running with Graal as JIT Reviewed-by: kvn, iveresov, dlong --- src/hotspot/share/ci/ciEnv.cpp | 64 ++++------------------- src/hotspot/share/code/dependencies.cpp | 68 +++++++++++++++++++++++++ src/hotspot/share/code/dependencies.hpp | 2 + src/hotspot/share/jvmci/jvmciEnv.cpp | 50 ++++++++---------- src/hotspot/share/jvmci/jvmciEnv.hpp | 4 +- 5 files changed, 101 insertions(+), 87 deletions(-) diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index af2dc7ed8a7..70a7818aed1 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -899,64 +899,18 @@ bool ciEnv::system_dictionary_modification_counter_changed() { void ciEnv::validate_compile_task_dependencies(ciMethod* target) { if (failing()) return; // no need for further checks - // First, check non-klass dependencies as we might return early and - // not check klass dependencies if the system dictionary - // modification counter hasn't changed (see below). - for (Dependencies::DepStream deps(dependencies()); deps.next(); ) { - if (deps.is_klass_type()) continue; // skip klass dependencies - Klass* witness = deps.check_dependency(); - if (witness != NULL) { - if (deps.type() == Dependencies::call_site_target_value) { - _inc_decompile_count_on_failure = false; - record_failure("call site target change"); - } else { - record_failure("invalid non-klass dependency"); - } - return; - } - } - - // Klass dependencies must be checked when the system dictionary - // changes. If logging is enabled all violated dependences will be - // recorded in the log. In debug mode check dependencies even if - // the system dictionary hasn't changed to verify that no invalid - // dependencies were inserted. Any violated dependences in this - // case are dumped to the tty. bool counter_changed = system_dictionary_modification_counter_changed(); - - bool verify_deps = trueInDebug; - if (!counter_changed && !verify_deps) return; - - int klass_violations = 0; - for (Dependencies::DepStream deps(dependencies()); deps.next(); ) { - if (!deps.is_klass_type()) continue; // skip non-klass dependencies - Klass* witness = deps.check_dependency(); - if (witness != NULL) { - klass_violations++; - if (!counter_changed) { - // Dependence failed but counter didn't change. Log a message - // describing what failed and allow the assert at the end to - // trigger. - deps.print_dependency(witness); - } else if (xtty == NULL) { - // If we're not logging then a single violation is sufficient, - // otherwise we want to log all the dependences which were - // violated. - break; - } + Dependencies::DepType result = dependencies()->validate_dependencies(_task, counter_changed); + if (result != Dependencies::end_marker) { + if (result == Dependencies::call_site_target_value) { + _inc_decompile_count_on_failure = false; + record_failure("call site target change"); + } else if (Dependencies::is_klass_type(result)) { + record_failure("invalid non-klass dependency"); + } else { + record_failure("concurrent class loading"); } } - - if (klass_violations != 0) { -#ifdef ASSERT - if (!counter_changed && !PrintCompilation) { - // Print out the compile task that failed - _task->print_tty(); - } -#endif - assert(counter_changed, "failed dependencies, but counter didn't change"); - record_failure("concurrent class loading"); - } } // ------------------------------------------------------------------ diff --git a/src/hotspot/share/code/dependencies.cpp b/src/hotspot/share/code/dependencies.cpp index 32d8a13b274..79d272e154e 100644 --- a/src/hotspot/share/code/dependencies.cpp +++ b/src/hotspot/share/code/dependencies.cpp @@ -30,6 +30,8 @@ #include "classfile/javaClasses.inline.hpp" #include "code/dependencies.hpp" #include "compiler/compileLog.hpp" +#include "compiler/compileBroker.hpp" +#include "compiler/compileTask.hpp" #include "memory/resourceArea.hpp" #include "oops/oop.inline.hpp" #include "oops/objArrayKlass.hpp" @@ -620,6 +622,72 @@ void Dependencies::check_valid_dependency_type(DepType dept) { guarantee(FIRST_TYPE <= dept && dept < TYPE_LIMIT, "invalid dependency type: %d", (int) dept); } +Dependencies::DepType Dependencies::validate_dependencies(CompileTask* task, bool counter_changed, char** failure_detail) { + // First, check non-klass dependencies as we might return early and + // not check klass dependencies if the system dictionary + // modification counter hasn't changed (see below). + for (Dependencies::DepStream deps(this); deps.next(); ) { + if (deps.is_klass_type()) continue; // skip klass dependencies + Klass* witness = deps.check_dependency(); + if (witness != NULL) { + return deps.type(); + } + } + + // Klass dependencies must be checked when the system dictionary + // changes. If logging is enabled all violated dependences will be + // recorded in the log. In debug mode check dependencies even if + // the system dictionary hasn't changed to verify that no invalid + // dependencies were inserted. Any violated dependences in this + // case are dumped to the tty. + if (!counter_changed && !trueInDebug) { + return end_marker; + } + + int klass_violations = 0; + DepType result = end_marker; + for (Dependencies::DepStream deps(this); deps.next(); ) { + if (!deps.is_klass_type()) continue; // skip non-klass dependencies + Klass* witness = deps.check_dependency(); + if (witness != NULL) { + if (klass_violations == 0) { + result = deps.type(); + if (failure_detail != NULL && klass_violations == 0) { + // Use a fixed size buffer to prevent the string stream from + // resizing in the context of an inner resource mark. + char* buffer = NEW_RESOURCE_ARRAY(char, O_BUFLEN); + stringStream st(buffer, O_BUFLEN); + deps.print_dependency(witness, true, &st); + *failure_detail = st.as_string(); + } + } + klass_violations++; + if (!counter_changed) { + // Dependence failed but counter didn't change. Log a message + // describing what failed and allow the assert at the end to + // trigger. + deps.print_dependency(witness); + } else if (xtty == NULL) { + // If we're not logging then a single violation is sufficient, + // otherwise we want to log all the dependences which were + // violated. + break; + } + } + } + + if (klass_violations != 0) { +#ifdef ASSERT + if (task != NULL && !counter_changed && !PrintCompilation) { + // Print out the compile task that failed + task->print_tty(); + } +#endif + assert(counter_changed, "failed dependencies, but counter didn't change"); + } + return result; +} + // for the sake of the compiler log, print out current dependencies: void Dependencies::log_all_dependencies() { if (log() == NULL) return; diff --git a/src/hotspot/share/code/dependencies.hpp b/src/hotspot/share/code/dependencies.hpp index 0c0f7f611bc..9726375540f 100644 --- a/src/hotspot/share/code/dependencies.hpp +++ b/src/hotspot/share/code/dependencies.hpp @@ -457,6 +457,8 @@ class Dependencies: public ResourceObj { void copy_to(nmethod* nm); + DepType validate_dependencies(CompileTask* task, bool counter_changed, char** failure_detail = NULL); + void log_all_dependencies(); void log_dependency(DepType dept, GrowableArray* args) { diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index eb18f1079b1..52be625be9d 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -410,8 +410,8 @@ methodHandle JVMCIEnv::get_method_by_index(const constantPoolHandle& cpool, // ------------------------------------------------------------------ // Check for changes to the system dictionary during compilation // class loads, evolution, breakpoints -JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(Dependencies* dependencies, Handle compiled_code, - JVMCIEnv* env, char** failure_detail) { +JVMCIEnv::CodeInstallResult JVMCIEnv::validate_compile_task_dependencies(Dependencies* dependencies, Handle compiled_code, + JVMCIEnv* env, char** failure_detail) { // If JVMTI capabilities were enabled during compile, the compilation is invalidated. if (env != NULL) { if (!env->_jvmti_can_hotswap_or_post_breakpoint && JvmtiExport::can_hotswap_or_post_breakpoint()) { @@ -422,37 +422,20 @@ JVMCIEnv::CodeInstallResult JVMCIEnv::check_for_system_dictionary_modification(D // Dependencies must be checked when the system dictionary changes // or if we don't know whether it has changed (i.e., env == NULL). - // In debug mode, always check dependencies. - bool counter_changed = env != NULL && env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications(); - bool verify_deps = env == NULL || trueInDebug || JavaAssertions::enabled(SystemDictionary::HotSpotInstalledCode_klass()->name()->as_C_string(), true); - if (!counter_changed && !verify_deps) { + bool counter_changed = env == NULL || env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications(); + CompileTask* task = env == NULL ? NULL : env->task(); + Dependencies::DepType result = dependencies->validate_dependencies(task, counter_changed, failure_detail); + if (result == Dependencies::end_marker) { return JVMCIEnv::ok; } - for (Dependencies::DepStream deps(dependencies); deps.next(); ) { - Klass* witness = deps.check_dependency(); - if (witness != NULL) { - // Use a fixed size buffer to prevent the string stream from - // resizing in the context of an inner resource mark. - char* buffer = NEW_RESOURCE_ARRAY(char, O_BUFLEN); - stringStream st(buffer, O_BUFLEN); - deps.print_dependency(witness, true, &st); - *failure_detail = st.as_string(); - if (env == NULL || counter_changed || deps.type() == Dependencies::evol_method) { - return JVMCIEnv::dependencies_failed; - } else { - // The dependencies were invalid at the time of installation - // without any intervening modification of the system - // dictionary. That means they were invalidly constructed. - return JVMCIEnv::dependencies_invalid; - } - } - if (LogCompilation) { - deps.log_dependency(); - } + if (!Dependencies::is_klass_type(result) || counter_changed) { + return JVMCIEnv::dependencies_failed; } - - return JVMCIEnv::ok; + // The dependencies were invalid at the time of installation + // without any intervening modification of the system + // dictionary. That means they were invalidly constructed. + return JVMCIEnv::dependencies_invalid; } // ------------------------------------------------------------------ @@ -492,8 +475,15 @@ JVMCIEnv::CodeInstallResult JVMCIEnv::register_method( // Encode the dependencies now, so we can check them right away. dependencies->encode_content_bytes(); + // Record the dependencies for the current compile in the log + if (LogCompilation) { + for (Dependencies::DepStream deps(dependencies); deps.next(); ) { + deps.log_dependency(); + } + } + // Check for {class loads, evolution, breakpoints} during compilation - result = check_for_system_dictionary_modification(dependencies, compiled_code, env, &failure_detail); + result = validate_compile_task_dependencies(dependencies, compiled_code, env, &failure_detail); if (result != JVMCIEnv::ok) { // While not a true deoptimization, it is a preemptive decompile. MethodData* mdp = method()->method_data(); diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index b28eb79bf8e..8a8c207535f 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -138,8 +138,8 @@ private: // Helper routine for determining the validity of a compilation // with respect to concurrent class loading. - static JVMCIEnv::CodeInstallResult check_for_system_dictionary_modification(Dependencies* target, Handle compiled_code, - JVMCIEnv* env, char** failure_detail); + static JVMCIEnv::CodeInstallResult validate_compile_task_dependencies(Dependencies* target, Handle compiled_code, + JVMCIEnv* env, char** failure_detail); public: CompileTask* task() { return _task; } From a06ef68dcf8586cf9a30e7dd2ae3c1f13dbc3fdd Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 4 Dec 2017 23:55:52 +0100 Subject: [PATCH 04/22] 8190484: Move jvm.h, jmm.h et al to hotspot/*/include Reviewed-by: dholmes, erikj, mchung --- make/autoconf/flags.m4 | 4 +- make/autoconf/generated-configure.sh | 26 +++-------- make/autoconf/platform.m4 | 7 --- make/autoconf/spec.gmk.in | 1 - make/copy/Copy-java.base.gmk | 18 -------- make/copy/Copy-java.desktop.gmk | 16 +------ make/copy/Copy-jdk.accessibility.gmk | 20 ++------- make/copy/Copy-jdk.jdwp.agent.gmk | 14 ++---- make/copy/CopyCommon.gmk | 44 ++++++++++++++++--- make/gensrc/GensrcX11Wrappers.gmk | 6 ++- make/hotspot/lib/CompileJvm.gmk | 3 +- make/hotspot/lib/CompileLibjsig.gmk | 2 +- make/lib/Lib-java.management.gmk | 6 +-- .../os/posix}/include/jvm_md.h | 0 .../os/windows}/include/jvm_md.h | 0 .../native => hotspot/share}/include/jmm.h | 0 .../native => hotspot/share}/include/jvm.h | 0 17 files changed, 68 insertions(+), 99 deletions(-) rename src/{java.base/unix/native => hotspot/os/posix}/include/jvm_md.h (100%) rename src/{java.base/windows/native => hotspot/os/windows}/include/jvm_md.h (100%) rename src/{java.management/share/native => hotspot/share}/include/jmm.h (100%) rename src/{java.base/share/native => hotspot/share}/include/jvm.h (100%) diff --git a/make/autoconf/flags.m4 b/make/autoconf/flags.m4 index 89bb736f2bf..d272c0c3f6d 100644 --- a/make/autoconf/flags.m4 +++ b/make/autoconf/flags.m4 @@ -1166,7 +1166,9 @@ AC_DEFUN([FLAGS_SETUP_COMPILER_FLAGS_FOR_JDK_HELPER], -I${TOPDIR}/src/java.base/$OPENJDK_$1_OS/native/include \ -I${TOPDIR}/src/java.base/$OPENJDK_$1_OS_TYPE/native/include \ -I${TOPDIR}/src/java.base/share/native/libjava \ - -I${TOPDIR}/src/java.base/$OPENJDK_$1_OS_TYPE/native/libjava" + -I${TOPDIR}/src/java.base/$OPENJDK_$1_OS_TYPE/native/libjava \ + -I${TOPDIR}/src/hotspot/share/include \ + -I${TOPDIR}/src/hotspot/os/${HOTSPOT_$1_OS_TYPE}/include" # The shared libraries are compiled using the picflag. $2CFLAGS_JDKLIB="[$]$2COMMON_CCXXFLAGS_JDK \ diff --git a/make/autoconf/generated-configure.sh b/make/autoconf/generated-configure.sh index 49d0fb17a09..311e18ab98e 100644 --- a/make/autoconf/generated-configure.sh +++ b/make/autoconf/generated-configure.sh @@ -972,7 +972,6 @@ HOTSPOT_BUILD_CPU HOTSPOT_BUILD_OS_TYPE HOTSPOT_BUILD_OS OPENJDK_BUILD_BUNDLE_PLATFORM -OPENJDK_BUILD_OS_EXPORT_DIR OPENJDK_BUILD_CPU_OSARCH OPENJDK_BUILD_CPU_ISADIR OPENJDK_BUILD_CPU_LEGACY_LIB @@ -984,7 +983,6 @@ HOTSPOT_TARGET_OS_TYPE HOTSPOT_TARGET_OS DEFINE_CROSS_COMPILE_ARCH OPENJDK_TARGET_BUNDLE_PLATFORM -OPENJDK_TARGET_OS_EXPORT_DIR OPENJDK_TARGET_CPU_OSARCH OPENJDK_TARGET_CPU_ISADIR OPENJDK_TARGET_CPU_LEGACY_LIB @@ -5159,7 +5157,7 @@ VS_SDK_PLATFORM_NAME_2013= #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1512085548 +DATE_WHEN_GENERATED=1512428089 ############################################################################### # @@ -16200,13 +16198,6 @@ $as_echo "$COMPILE_TYPE" >&6; } OPENJDK_TARGET_CPU_JLI="amd64" fi - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - OPENJDK_TARGET_OS_EXPORT_DIR=macosx - else - OPENJDK_TARGET_OS_EXPORT_DIR=${OPENJDK_TARGET_OS_TYPE} - fi - - # The new version string in JDK 9 also defined new naming of OS and ARCH for bundles # Macosx is osx and x86_64 is x64 if test "x$OPENJDK_TARGET_OS" = xmacosx; then @@ -16358,13 +16349,6 @@ $as_echo "$COMPILE_TYPE" >&6; } OPENJDK_BUILD_CPU_JLI="amd64" fi - if test "x$OPENJDK_BUILD_OS" = xmacosx; then - OPENJDK_BUILD_OS_EXPORT_DIR=macosx - else - OPENJDK_BUILD_OS_EXPORT_DIR=${OPENJDK_BUILD_OS_TYPE} - fi - - # The new version string in JDK 9 also defined new naming of OS and ARCH for bundles # Macosx is osx and x86_64 is x64 if test "x$OPENJDK_BUILD_OS" = xmacosx; then @@ -52817,7 +52801,9 @@ fi -I${TOPDIR}/src/java.base/$OPENJDK_TARGET_OS/native/include \ -I${TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/include \ -I${TOPDIR}/src/java.base/share/native/libjava \ - -I${TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava" + -I${TOPDIR}/src/java.base/$OPENJDK_TARGET_OS_TYPE/native/libjava \ + -I${TOPDIR}/src/hotspot/share/include \ + -I${TOPDIR}/src/hotspot/os/${HOTSPOT_TARGET_OS_TYPE}/include" # The shared libraries are compiled using the picflag. CFLAGS_JDKLIB="$COMMON_CCXXFLAGS_JDK \ @@ -53698,7 +53684,9 @@ fi -I${TOPDIR}/src/java.base/$OPENJDK_BUILD_OS/native/include \ -I${TOPDIR}/src/java.base/$OPENJDK_BUILD_OS_TYPE/native/include \ -I${TOPDIR}/src/java.base/share/native/libjava \ - -I${TOPDIR}/src/java.base/$OPENJDK_BUILD_OS_TYPE/native/libjava" + -I${TOPDIR}/src/java.base/$OPENJDK_BUILD_OS_TYPE/native/libjava \ + -I${TOPDIR}/src/hotspot/share/include \ + -I${TOPDIR}/src/hotspot/os/${HOTSPOT_BUILD_OS_TYPE}/include" # The shared libraries are compiled using the picflag. OPENJDK_BUILD_CFLAGS_JDKLIB="$OPENJDK_BUILD_COMMON_CCXXFLAGS_JDK \ diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4 index 0479e145884..f62f94daace 100644 --- a/make/autoconf/platform.m4 +++ b/make/autoconf/platform.m4 @@ -388,13 +388,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], OPENJDK_$1_CPU_JLI="amd64" fi - if test "x$OPENJDK_$1_OS" = xmacosx; then - OPENJDK_$1_OS_EXPORT_DIR=macosx - else - OPENJDK_$1_OS_EXPORT_DIR=${OPENJDK_$1_OS_TYPE} - fi - AC_SUBST(OPENJDK_$1_OS_EXPORT_DIR) - # The new version string in JDK 9 also defined new naming of OS and ARCH for bundles # Macosx is osx and x86_64 is x64 if test "x$OPENJDK_$1_OS" = xmacosx; then diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index f9bb23a305c..58893e12d22 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -78,7 +78,6 @@ OPENJDK_TARGET_CPU_ISADIR:=@OPENJDK_TARGET_CPU_ISADIR@ OPENJDK_TARGET_CPU_LEGACY:=@OPENJDK_TARGET_CPU_LEGACY@ OPENJDK_TARGET_CPU_LEGACY_LIB:=@OPENJDK_TARGET_CPU_LEGACY_LIB@ OPENJDK_TARGET_CPU_OSARCH:=@OPENJDK_TARGET_CPU_OSARCH@ -OPENJDK_TARGET_OS_EXPORT_DIR:=@OPENJDK_TARGET_OS_EXPORT_DIR@ HOTSPOT_TARGET_OS := @HOTSPOT_TARGET_OS@ HOTSPOT_TARGET_OS_TYPE := @HOTSPOT_TARGET_OS_TYPE@ diff --git a/make/copy/Copy-java.base.gmk b/make/copy/Copy-java.base.gmk index cc489211b24..a0bcffbc12a 100644 --- a/make/copy/Copy-java.base.gmk +++ b/make/copy/Copy-java.base.gmk @@ -27,24 +27,6 @@ include CopyCommon.gmk $(eval $(call IncludeCustomExtension, copy/Copy-java.base.gmk)) -################################################################################ -# -# Copy exported header files to outputdir. -# -TARGETS += \ - $(INCLUDE_DST_DIR)/jni.h \ - $(INCLUDE_DST_DIR)/jvmticmlr.h \ - $(INCLUDE_DST_DIR)/classfile_constants.h \ - $(INCLUDE_DST_OS_DIR)/jni_md.h \ - # - -$(INCLUDE_DST_DIR)/%.h: $(TOPDIR)/src/java.base/share/native/include/%.h - $(call install-file) - -$(INCLUDE_DST_OS_DIR)/%.h: \ - $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/include/%.h - $(call install-file) - ################################################################################ ifneq ($(findstring $(OPENJDK_TARGET_OS), windows aix),) diff --git a/make/copy/Copy-java.desktop.gmk b/make/copy/Copy-java.desktop.gmk index 954faa9eaef..4afbed8f7a4 100644 --- a/make/copy/Copy-java.desktop.gmk +++ b/make/copy/Copy-java.desktop.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2016, 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 @@ -29,20 +29,6 @@ $(eval $(call IncludeCustomExtension, copy/Copy-java.desktop.gmk)) ################################################################################ -TARGETS += \ - $(INCLUDE_DST_DIR)/jawt.h \ - $(INCLUDE_DST_OS_DIR)/jawt_md.h \ - # - -$(INCLUDE_DST_DIR)/%.h: $(TOPDIR)/src/java.desktop/share/native/include/%.h - $(call install-file) - -$(INCLUDE_DST_OS_DIR)/%.h: \ - $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_EXPORT_DIR)/native/include/%.h - $(call install-file) - -################################################################################ - ifneq ($(FREETYPE_BUNDLE_LIB_PATH), ) # We need to bundle the freetype library, so it will be available at runtime # as well as link time. diff --git a/make/copy/Copy-jdk.accessibility.gmk b/make/copy/Copy-jdk.accessibility.gmk index bde3206d670..cd8aeba5a11 100644 --- a/make/copy/Copy-jdk.accessibility.gmk +++ b/make/copy/Copy-jdk.accessibility.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2104, 2016, 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 @@ -23,19 +23,7 @@ # questions. # +################################################################################ +# Include CopyCommon.gmk to get exported header files to be properly copied. + include CopyCommon.gmk - -################################################################################ - -ifeq ($(OPENJDK_TARGET_OS), windows) - TARGETS += $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgeCallbacks.h \ - $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgeCalls.h \ - $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgePackages.h - - $(INCLUDE_DST_OS_DIR)/bridge/%: \ - $(TOPDIR)/src/jdk.accessibility/windows/native/include/bridge/% - $(install-file) - -endif - -################################################################################ diff --git a/make/copy/Copy-jdk.jdwp.agent.gmk b/make/copy/Copy-jdk.jdwp.agent.gmk index a765567fdd9..cd8aeba5a11 100644 --- a/make/copy/Copy-jdk.jdwp.agent.gmk +++ b/make/copy/Copy-jdk.jdwp.agent.gmk @@ -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 @@ -23,13 +23,7 @@ # questions. # +################################################################################ +# Include CopyCommon.gmk to get exported header files to be properly copied. + include CopyCommon.gmk - -################################################################################ - -TARGETS := $(INCLUDE_DST_DIR)/jdwpTransport.h - -$(INCLUDE_DST_DIR)/%.h: $(TOPDIR)/src/jdk.jdwp.agent/share/native/include/%.h - $(call install-file) - -################################################################################ diff --git a/make/copy/CopyCommon.gmk b/make/copy/CopyCommon.gmk index c82edd29d4e..7b777cd3645 100644 --- a/make/copy/CopyCommon.gmk +++ b/make/copy/CopyCommon.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -23,15 +23,49 @@ # questions. # -INCLUDE_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_include/$(MODULE) LIB_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE) CONF_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_conf/$(MODULE) LEGAL_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_legal/$(MODULE) -INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/$(OPENJDK_TARGET_OS) +################################################################################ +# +# Copy exported include headers files to output directory, if present. +# +INCLUDE_TARGET_DIR := $(SUPPORT_OUTPUTDIR)/modules_include/$(MODULE) + +$(eval $(call SetupCopyFiles, COPY_EXPORTED_INCLUDE, \ + SRC := $(TOPDIR)/src/$(MODULE)/share/native/include, \ + DEST := $(INCLUDE_TARGET_DIR), \ + FILES := $(wildcard \ + $(TOPDIR)/src/$(MODULE)/share/native/include/* \ + $(TOPDIR)/src/$(MODULE)/share/native/include/*/*), \ +)) + +TARGETS += $(COPY_EXPORTED_INCLUDE) + +# For historical reasons, the OS include directories have odd names. +INCLUDE_TARGET_OS_SUBDIR := $(OPENJDK_TARGET_OS) ifeq ($(OPENJDK_TARGET_OS), windows) - INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/win32 + INCLUDE_TARGET_OS_SUBDIR := win32 else ifeq ($(OPENJDK_TARGET_OS), macosx) - INCLUDE_DST_OS_DIR := $(INCLUDE_DST_DIR)/darwin + INCLUDE_TARGET_OS_SUBDIR := darwin endif + +# Use the most specific of OS and OS_TYPE. +ifneq ($(wildcard $(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS)/native/include/*), ) + INCLUDE_SOURCE_OS_SUBDIR := $(OPENJDK_TARGET_OS) +else + INCLUDE_SOURCE_OS_SUBDIR := $(OPENJDK_TARGET_OS_TYPE) +endif + +$(eval $(call SetupCopyFiles, COPY_EXPORTED_INCLUDE_OS, \ + SRC := $(TOPDIR)/src/$(MODULE)/$(INCLUDE_SOURCE_OS_SUBDIR)/native/include, \ + DEST := $(INCLUDE_TARGET_DIR)/$(INCLUDE_TARGET_OS_SUBDIR), \ + FILES := $(wildcard \ + $(TOPDIR)/src/$(MODULE)/$(INCLUDE_SOURCE_OS_SUBDIR)/native/include/* \ + $(TOPDIR)/src/$(MODULE)/$(INCLUDE_SOURCE_OS_SUBDIR)/native/include/*/*), \ +)) + +TARGETS += $(COPY_EXPORTED_INCLUDE_OS) + diff --git a/make/gensrc/GensrcX11Wrappers.gmk b/make/gensrc/GensrcX11Wrappers.gmk index b3081b2637a..e506c5c01ff 100644 --- a/make/gensrc/GensrcX11Wrappers.gmk +++ b/make/gensrc/GensrcX11Wrappers.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 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 @@ -92,8 +92,10 @@ ifneq ($(COMPILE_TYPE), cross) endif SIZER_CFLAGS := \ + -I${TOPDIR}/src/hotspot/share/include \ + -I${TOPDIR}/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include \ -I$(TOPDIR)/src/java.base/share/native/include \ - -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_EXPORT_DIR)/native/include \ + -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/include \ -I$(TOPDIR)/src/java.base/share/native/libjava \ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava \ -I$(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE)/native/common/awt \ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 66ba5033562..77ee5d99df1 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -57,9 +57,10 @@ JVM_CFLAGS_INCLUDES += \ $(patsubst %,-I%,$(filter-out $(JVM_VARIANT_OUTPUTDIR)/gensrc/%, $(JVM_SRC_DIRS))) \ -I$(JVM_VARIANT_OUTPUTDIR)/gensrc \ -I$(TOPDIR)/src/hotspot/share/precompiled \ + -I$(TOPDIR)/src/hotspot/share/include \ + -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include \ -I$(TOPDIR)/src/java.base/share/native/include \ -I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/include \ - -I$(TOPDIR)/src/java.management/share/native/include \ -I$(TOPDIR)/src/java.base/share/native/libjimage \ # diff --git a/make/hotspot/lib/CompileLibjsig.gmk b/make/hotspot/lib/CompileLibjsig.gmk index abdb16261a1..4cd6d39d3f4 100644 --- a/make/hotspot/lib/CompileLibjsig.gmk +++ b/make/hotspot/lib/CompileLibjsig.gmk @@ -57,7 +57,7 @@ ifneq ($(OPENJDK_TARGET_OS), windows) endif else ifeq ($(OPENJDK_TARGET_OS), solaris) - LIBJSIG_CFLAGS := -m64 -KPIC -mt -I $(TOPDIR)/src/java.base/unix/native/include + LIBJSIG_CFLAGS := -m64 -KPIC -mt -I $(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include LIBJSIG_LDFLAGS := -m64 -mt -xnolib LIBJSIG_LIBS := $(LIBDL) diff --git a/make/lib/Lib-java.management.gmk b/make/lib/Lib-java.management.gmk index 6e7edc3b115..f59a6ac05e1 100644 --- a/make/lib/Lib-java.management.gmk +++ b/make/lib/Lib-java.management.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -30,8 +30,8 @@ $(eval $(call IncludeCustomExtension, lib/Lib-java.management.gmk)) ################################################################################ -LIBMANAGEMENT_SRC += $(TOPDIR)/src/java.management/share/native/libmanagement -LIBMANAGEMENT_CFLAGS := -I$(TOPDIR)/src/java.management/share/native/include \ +LIBMANAGEMENT_SRC += $(TOPDIR)/src/java.management/share/native/libmanagement +LIBMANAGEMENT_CFLAGS := -I$(TOPDIR)/src/hotspot/share/include \ $(addprefix -I,$(LIBMANAGEMENT_SRC)) \ -I$(SUPPORT_OUTPUTDIR)/headers/java.management \ $(LIBJAVA_HEADER_FLAGS) \ diff --git a/src/java.base/unix/native/include/jvm_md.h b/src/hotspot/os/posix/include/jvm_md.h similarity index 100% rename from src/java.base/unix/native/include/jvm_md.h rename to src/hotspot/os/posix/include/jvm_md.h diff --git a/src/java.base/windows/native/include/jvm_md.h b/src/hotspot/os/windows/include/jvm_md.h similarity index 100% rename from src/java.base/windows/native/include/jvm_md.h rename to src/hotspot/os/windows/include/jvm_md.h diff --git a/src/java.management/share/native/include/jmm.h b/src/hotspot/share/include/jmm.h similarity index 100% rename from src/java.management/share/native/include/jmm.h rename to src/hotspot/share/include/jmm.h diff --git a/src/java.base/share/native/include/jvm.h b/src/hotspot/share/include/jvm.h similarity index 100% rename from src/java.base/share/native/include/jvm.h rename to src/hotspot/share/include/jvm.h From b6252a4d4d2abdd2741e9214644112887dc1d7a8 Mon Sep 17 00:00:00 2001 From: Yasumasa Suenaga Date: Mon, 4 Dec 2017 10:23:08 +0900 Subject: [PATCH 05/22] 8192897: NPE occurs on clhsdb jstack Reviewed-by: dholmes, sspitsyn, jgeorge, sballal --- .../jvm/hotspot/runtime/CompiledVFrame.java | 3 +++ .../jtreg/serviceability/sa/ClhsdbJstack.java | 21 +++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java index a2d67b3fe3e..8e9f67a2cd4 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/CompiledVFrame.java @@ -128,6 +128,9 @@ public class CompiledVFrame extends JavaVFrame { /** Returns List */ public List getMonitors() { + if (getScope() == null) { + return new ArrayList<>(); + } List monitors = getScope().getMonitors(); if (monitors == null) { return new ArrayList<>(); diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbJstack.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbJstack.java index bbbc81e1963..a3588e0e944 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbJstack.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbJstack.java @@ -38,14 +38,17 @@ import jdk.test.lib.Platform; public class ClhsdbJstack { - public static void main(String[] args) throws Exception { - System.out.println("Starting ClhsdbJstack test"); - + private static void testJstack(boolean withXcomp) throws Exception { LingeredApp theApp = null; try { ClhsdbLauncher test = new ClhsdbLauncher(); - theApp = LingeredApp.startApp(); - System.out.println("Started LingeredApp with pid " + theApp.getPid()); + theApp = withXcomp ? LingeredApp.startApp(List.of("-Xcomp")) + : LingeredApp.startApp(); + System.out.print("Started LingeredApp "); + if (withXcomp) { + System.out.print("(-Xcomp) "); + } + System.out.println("with pid " + theApp.getPid()); List cmds = List.of("jstack -v"); @@ -61,10 +64,16 @@ public class ClhsdbJstack { test.run(theApp.getPid(), cmds, expStrMap, null); } catch (Exception ex) { - throw new RuntimeException("Test ERROR " + ex, ex); + throw new RuntimeException("Test ERROR (with -Xcomp=" + withXcomp + ") " + ex, ex); } finally { LingeredApp.stopApp(theApp); } + } + + public static void main(String[] args) throws Exception { + System.out.println("Starting ClhsdbJstack test"); + testJstack(false); + testJstack(true); System.out.println("Test PASSED"); } } From 23424e9e0ad71a0bdbd444ac10f29414c71eacf7 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Tue, 5 Dec 2017 08:27:54 +0100 Subject: [PATCH 06/22] 8191360: Lookup of critical JNI method causes duplicate library loading with leaking handler Unload shared library after lookup to avoid keeping it live. Reviewed-by: vlivanov, dholmes --- src/hotspot/share/prims/nativeLookup.cpp | 9 +++++++-- .../ClassLoader/nativeLibrary/NativeLibraryTest.java | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index c840b388ef0..fe51c19d434 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -224,7 +224,13 @@ address NativeLookup::lookup_critical_style(const methodHandle& method, char* pu st.print_raw(long_name); if (os_style) os::print_jni_name_suffix_on(&st, args_size); char* jni_name = st.as_string(); - return (address)os::dll_lookup(dll, jni_name); + address critical_entry = (address)os::dll_lookup(dll, jni_name); + // Close the handle to avoid keeping the library alive if the native method holder is unloaded. + // This is fine because the library is still kept alive by JNI (see JVM_LoadLibrary). As soon + // as the holder class and the library are unloaded (see JVM_UnloadLibrary), the native wrapper + // that calls 'critical_entry' becomes unreachable and is unloaded as well. + os::dll_unload(dll); + return critical_entry; } } @@ -245,7 +251,6 @@ address NativeLookup::lookup_entry(const methodHandle& method, bool& in_base_lib + (method->is_static() ? 1 : 0) // class for static methods + method->size_of_parameters(); // actual parameters - // 1) Try JNI short style entry = lookup_style(method, pure_name, "", args_size, true, in_base_library, CHECK_NULL); if (entry != NULL) return entry; diff --git a/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java b/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java index 488cec23612..dd886ef9ff6 100644 --- a/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java +++ b/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8164512 + * @bug 8164512 8191360 * @summary verify if the native library is unloaded when the class loader is GC'ed * @build p.Test * @run main/othervm/native -Xcheck:jni NativeLibraryTest From 234b300eb261fe01c4b1617ad7e919a3bfe3d58b Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 5 Dec 2017 02:55:44 -0500 Subject: [PATCH 07/22] 8192950: Missing -nativepath for svc tests Reviewed-by: ihse --- make/jprt.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/make/jprt.properties b/make/jprt.properties index 8f73ca13f24..9e10f8cf1a2 100644 --- a/make/jprt.properties +++ b/make/jprt.properties @@ -177,6 +177,7 @@ jprt.make.rule.test.targets=${my.make.rule.test.targets.${jprt.test.set}} # Not all test targets need the test image jprt.test.bundle.targets=\ + ${my.make.rule.test.targets.svc}, \ ${my.make.rule.test.targets.hotspot.reg}, \ ${my.make.rule.test.targets.hotspot.gtest} \ ${my.make.rule.test.targets.nativesanity} \ From bece28d6ccf19460f1d7050dbc01aabe63320f14 Mon Sep 17 00:00:00 2001 From: Patric Hedlin Date: Thu, 30 Nov 2017 15:54:45 +0100 Subject: [PATCH 08/22] 8191232: compiler/intrinsics/bigInteger/TestMultiplyToLen.java fails with java.lang.Exception: Failed Generating the wrong insn for pointer comparison in intrinsic (on SPARC). Reviewed-by: neliasso, kvn --- src/hotspot/cpu/sparc/stubGenerator_sparc.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp index d93b294574b..3d8305cd2d2 100644 --- a/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp +++ b/src/hotspot/cpu/sparc/stubGenerator_sparc.cpp @@ -5157,8 +5157,8 @@ class StubGenerator: public StubCodeGenerator { const Register gxp = G1; // Need to use global registers across RWs. const Register gyp = G2; const Register gzp = G3; - const Register offs = G4; - const Register disp = G5; + const Register disp = G4; + const Register offs = G5; __ mov(xptr, gxp); __ mov(yptr, gyp); @@ -5569,8 +5569,8 @@ class StubGenerator: public StubCodeGenerator { // for (int i = xn; i >= 0; i--) __ bind(L_loop_i); - __ cmp_and_br_short(xpc, xp,// i >= 0 - Assembler::less, Assembler::pn, L_exit_loop_i); + __ cmp_and_brx_short(xpc, xp,// i >= 0 + Assembler::lessUnsigned, Assembler::pn, L_exit_loop_i); __ lduw(xpc, 0, rt); // u64 x = xp[i] __ lduw(xpc, 4, rx); // ... __ sllx(rt, 32, rt); @@ -5598,8 +5598,8 @@ class StubGenerator: public StubCodeGenerator { __ bind(L_loop_j); - __ cmp_and_br_short(ypc, yp,// j >= 0 - Assembler::less, Assembler::pn, L_exit); + __ cmp_and_brx_short(ypc, yp,// j >= 0 + Assembler::lessUnsigned, Assembler::pn, L_exit); __ clr(rc); // u64 c = 0 __ lduw(ypc, 0, rt); // u64 y = yp[j] (= *ypc) __ lduw(ypc, 4, ry); // ... @@ -5615,8 +5615,8 @@ class StubGenerator: public StubCodeGenerator { __ bind(L_loop_i2); - __ cmp_and_br_short(xpc, xp,// i >= 0 - Assembler::less, Assembler::pn, L_exit_loop_i2); + __ cmp_and_brx_short(xpc, xp,// i >= 0 + Assembler::lessUnsigned, Assembler::pn, L_exit_loop_i2); __ lduw(xpc, 0, rt); // u64 x = xp[i] (= *xpc) __ lduw(xpc, 4, rx); // ... __ sllx(rt, 32, rt); From 5fb516acc07510380392f2d1f17d32dcb04435b5 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Tue, 5 Dec 2017 11:23:27 +0100 Subject: [PATCH 09/22] 8193045: JDK-8190484 breaks build on Windows Reviewed-by: dholmes --- make/copy/CopyCommon.gmk | 41 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/make/copy/CopyCommon.gmk b/make/copy/CopyCommon.gmk index 7b777cd3645..2956e9ddf92 100644 --- a/make/copy/CopyCommon.gmk +++ b/make/copy/CopyCommon.gmk @@ -33,16 +33,17 @@ LEGAL_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_legal/$(MODULE) # INCLUDE_TARGET_DIR := $(SUPPORT_OUTPUTDIR)/modules_include/$(MODULE) +INCLUDE_SOURCE_DIR := $(TOPDIR)/src/$(MODULE)/share/native/include -$(eval $(call SetupCopyFiles, COPY_EXPORTED_INCLUDE, \ - SRC := $(TOPDIR)/src/$(MODULE)/share/native/include, \ - DEST := $(INCLUDE_TARGET_DIR), \ - FILES := $(wildcard \ - $(TOPDIR)/src/$(MODULE)/share/native/include/* \ - $(TOPDIR)/src/$(MODULE)/share/native/include/*/*), \ -)) +ifneq ($(wildcard $(INCLUDE_SOURCE_DIR)/*), ) + $(eval $(call SetupCopyFiles, COPY_EXPORTED_INCLUDE, \ + SRC := $(INCLUDE_SOURCE_DIR), \ + DEST := $(INCLUDE_TARGET_DIR), \ + FILES := $(shell $(FIND) $(INCLUDE_SOURCE_DIR) -type f), \ + )) -TARGETS += $(COPY_EXPORTED_INCLUDE) + TARGETS += $(COPY_EXPORTED_INCLUDE) +endif # For historical reasons, the OS include directories have odd names. INCLUDE_TARGET_OS_SUBDIR := $(OPENJDK_TARGET_OS) @@ -53,19 +54,17 @@ else ifeq ($(OPENJDK_TARGET_OS), macosx) endif # Use the most specific of OS and OS_TYPE. -ifneq ($(wildcard $(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS)/native/include/*), ) - INCLUDE_SOURCE_OS_SUBDIR := $(OPENJDK_TARGET_OS) -else - INCLUDE_SOURCE_OS_SUBDIR := $(OPENJDK_TARGET_OS_TYPE) +INCLUDE_SOURCE_OS_DIR := $(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS)/native/include +ifeq ($(wildcard $(INCLUDE_SOURCE_OS_DIR)/*), ) + INCLUDE_SOURCE_OS_DIR := $(TOPDIR)/src/$(MODULE)/$(OPENJDK_TARGET_OS_TYPE)/native/include endif -$(eval $(call SetupCopyFiles, COPY_EXPORTED_INCLUDE_OS, \ - SRC := $(TOPDIR)/src/$(MODULE)/$(INCLUDE_SOURCE_OS_SUBDIR)/native/include, \ - DEST := $(INCLUDE_TARGET_DIR)/$(INCLUDE_TARGET_OS_SUBDIR), \ - FILES := $(wildcard \ - $(TOPDIR)/src/$(MODULE)/$(INCLUDE_SOURCE_OS_SUBDIR)/native/include/* \ - $(TOPDIR)/src/$(MODULE)/$(INCLUDE_SOURCE_OS_SUBDIR)/native/include/*/*), \ -)) - -TARGETS += $(COPY_EXPORTED_INCLUDE_OS) +ifneq ($(wildcard $(INCLUDE_SOURCE_OS_DIR)/*), ) + $(eval $(call SetupCopyFiles, COPY_EXPORTED_INCLUDE_OS, \ + SRC := $(INCLUDE_SOURCE_OS_DIR), \ + DEST := $(INCLUDE_TARGET_DIR)/$(INCLUDE_TARGET_OS_SUBDIR), \ + FILES := $(shell $(FIND) $(INCLUDE_SOURCE_OS_DIR) -type f), \ + )) + TARGETS += $(COPY_EXPORTED_INCLUDE_OS) +endif From 657b951fabcf9007a7f1c06eeb0f4a0f1cd7a60a Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 5 Dec 2017 13:58:55 +0100 Subject: [PATCH 10/22] 8192983: gc/g1/TestVerifyGCType.java might fail on loaded machines Reviewed-by: tschatzl, jwilhelm --- .../hotspot/jtreg/gc/g1/TestVerifyGCType.java | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java b/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java index 35cf30374f9..033aed25492 100644 --- a/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java +++ b/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java @@ -142,8 +142,9 @@ public class TestVerifyGCType { "-XX:+UnlockDiagnosticVMOptions", "-XX:+UseG1GC", "-XX:+WhiteBoxAPI", - "-XX:+ExplicitGCInvokesConcurrent", "-Xlog:gc,gc+start,gc+verify=info", + "-Xms16m", + "-Xmx16m", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC", "-XX:+VerifyDuringGC"}); @@ -173,7 +174,7 @@ public class TestVerifyGCType { private static void verifyCollection(String name, boolean expectBefore, boolean expectDuring, boolean expectAfter, String data) { CollectionInfo ci = CollectionInfo.parseFirst(name, data); - Asserts.assertTrue(ci != null, "Expected GC not found: " + name); + Asserts.assertTrue(ci != null, "Expected GC not found: " + name + "\n" + data); // Verify Before verifyType(ci, expectBefore, VERIFY_BEFORE); @@ -243,14 +244,41 @@ public class TestVerifyGCType { public static class TriggerGCs { public static void main(String args[]) throws Exception { WhiteBox wb = WhiteBox.getWhiteBox(); - // Trigger the different GCs using the WhiteBox API and System.gc() - // to start a concurrent cycle with -XX:+ExplicitGCInvokesConcurrent. + // Allocate some memory that can be turned into garbage. + Object[] used = alloc1M(); + + // Trigger the different GCs using the WhiteBox API. wb.fullGC(); // full - System.gc(); // initial-mark, remark and cleanup + + // Memory have been promoted to old by full GC. Free + // some memory to be reclaimed by concurrent cycle. + partialFree(used); + wb.g1StartConcMarkCycle(); // initial-mark, remark and cleanup + // Sleep to make sure concurrent cycle is done - Thread.sleep(1000); + while (wb.g1InConcurrentMark()) { + Thread.sleep(1000); + } + + // Trigger two young GCs, first will be young-only, second will be mixed. wb.youngGC(); // young-only wb.youngGC(); // mixed } + + private static Object[] alloc1M() { + Object[] ret = new Object[1024]; + // Alloc 1024 1k byte arrays (~1M) + for (int i = 0; i < ret.length; i++) { + ret[i] = new byte[1024]; + } + return ret; + } + + private static void partialFree(Object[] array) { + // Free every other element + for (int i = 0; i < array.length; i+=2) { + array[i] = null; + } + } } } From 06bf91bacca0315472bb99cbe79031a3f7ecbec7 Mon Sep 17 00:00:00 2001 From: Stefan Johansson Date: Tue, 5 Dec 2017 16:34:03 +0100 Subject: [PATCH 11/22] 8193068: Add gc/g1/TestVerifyGCType.java to problem list Reviewed-by: tschatzl --- test/hotspot/jtreg/ProblemList.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index d1c9d42e0a4..a07b9c9e792 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -65,6 +65,7 @@ gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 gener gc/survivorAlignment/TestPromotionToSurvivor.java 8129886 generic-all gc/g1/logging/TestG1LoggingFailure.java 8169634 generic-all gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all +gc/g1/TestVerifyGCType.java 8193067 generic-all gc/stress/gclocker/TestGCLockerWithG1.java 8179226 generic-all gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java 8177765 generic-all From c8bf23d93ac485cf1ebb24bf9fbec4ae7869f39a Mon Sep 17 00:00:00 2001 From: Harsha Wardhana B Date: Tue, 5 Dec 2017 21:26:11 +0530 Subject: [PATCH 12/22] 8192909: Invalid username or password in HashedPasswordFileTest.java Reviewed-by: clanger, dfuchs --- .../security/HashedPasswordFileTest.java | 87 +++++++++---------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/test/jdk/javax/management/security/HashedPasswordFileTest.java b/test/jdk/javax/management/security/HashedPasswordFileTest.java index cae574c36a6..4ae4981c2e5 100644 --- a/test/jdk/javax/management/security/HashedPasswordFileTest.java +++ b/test/jdk/javax/management/security/HashedPasswordFileTest.java @@ -31,43 +31,26 @@ * */ -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Test; + +import javax.management.MBeanServer; +import javax.management.remote.*; +import java.io.*; import java.lang.management.ManagementFactory; -import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.attribute.PosixFilePermission; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Base64; -import java.util.HashMap; -import java.util.HashSet; +import java.util.*; import java.util.List; -import java.util.Map; -import java.util.Random; import java.util.Set; import java.util.concurrent.*; -import javax.management.MBeanServer; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; - -import org.testng.Assert; -import org.testng.annotations.Test; -import org.testng.annotations.AfterClass; - -import jdk.test.lib.Utils; -import jdk.test.lib.process.ProcessTools; @Test public class HashedPasswordFileTest { @@ -96,13 +79,12 @@ public class HashedPasswordFileTest { "SHA3-512" }; - private final Random rnd = new Random(); private final Random random = Utils.getRandomInstance(); private JMXConnectorServer cs; private String randomWord() { - int idx = rnd.nextInt(randomWords.length); + int idx = random.nextInt(randomWords.length); return randomWords[idx]; } @@ -146,9 +128,12 @@ public class HashedPasswordFileTest { BufferedWriter br; try (FileWriter fw = new FileWriter(file)) { br = new BufferedWriter(fw); - int numentries = rnd.nextInt(5) + 3; + int numentries = random.nextInt(5) + 3; for (int i = 0; i < numentries; i++) { - String username = randomWord(); + String username; + do { + username = randomWord(); + } while (props.get(username) != null); String password = randomWord(); props.put(username, password); br.write(username + " " + password + "\n"); @@ -182,11 +167,14 @@ public class HashedPasswordFileTest { BufferedWriter br; try (FileWriter fw = new FileWriter(file)) { br = new BufferedWriter(fw); - int numentries = rnd.nextInt(5) + 3; + int numentries = random.nextInt(5) + 3; for (int i = 0; i < numentries; i++) { - String username = randomWord(); + String username; + do { + username = randomWord(); + } while (props.get(username) != null); String password = randomWord(); - String alg = hashAlgs[rnd.nextInt(hashAlgs.length)]; + String alg = hashAlgs[random.nextInt(hashAlgs.length)]; String[] b64str = getHash(alg, password); br.write(username + " " + b64str[0] + " " + b64str[1] + " " + alg + "\n"); props.put(username, password); @@ -307,7 +295,7 @@ public class HashedPasswordFileTest { JMXServiceURL serverUrl = createServerSide(true); Assert.assertEquals(isPasswordFileHashed(), false); // create random number of clients - int numClients = rnd.nextInt(20) + 10; + int numClients = random.nextInt(20) + 10; List futures = new ArrayList<>(); ExecutorService executor = Executors.newFixedThreadPool(numClients); for (int i = 0; i < numClients; i++) { @@ -355,32 +343,41 @@ public class HashedPasswordFileTest { sbuild.append(line).append("\n"); continue; } - String[] tokens = line.split("\\s+"); + // Change password for random entries - if ((tokens.length == 4 || tokens.length == 3) && rnd.nextBoolean()) { - String password = randomWord(); - credentials.put(tokens[0], password); - sbuild.append(tokens[0]).append(" ").append(password).append("\n"); + if (random.nextBoolean()) { + String[] tokens = line.split("\\s+"); + if ((tokens.length == 4 || tokens.length == 3)) { + String password = randomWord(); + credentials.put(tokens[0], password); + sbuild.append(tokens[0]).append(" ").append(password).append("\n"); + } } else { sbuild.append(line).append("\n"); } } // Add new entries in clear - int newentries = rnd.nextInt(2) + 3; + int newentries = random.nextInt(2) + 3; for (int i = 0; i < newentries; i++) { - String username = randomWord(); + String username; + do { + username = randomWord(); + } while (credentials.get(username) != null); String password = randomWord(); credentials.put(username, password); sbuild.append(username).append(" ").append(password).append("\n"); } // Add new entries as a hash - int numentries = rnd.nextInt(2) + 3; + int numentries = random.nextInt(2) + 3; for (int i = 0; i < numentries; i++) { - String username = randomWord(); + String username; + do { + username = randomWord(); + } while (credentials.get(username) != null); String password = randomWord(); - String alg = hashAlgs[rnd.nextInt(hashAlgs.length)]; + String alg = hashAlgs[random.nextInt(hashAlgs.length)]; String[] b64str = getHash(alg, password); credentials.put(username, password); sbuild.append(username).append(" ").append(b64str[0]) From b96c85c640ee4690279d91f6650e2a309fa8cd84 Mon Sep 17 00:00:00 2001 From: Razvan A Lupusoru Date: Tue, 5 Dec 2017 09:49:23 -0800 Subject: [PATCH 13/22] 8192846: Support cmov vectorization for float Reviewed-by: kvn --- src/hotspot/cpu/x86/assembler_x86.cpp | 21 +++++++++++++++++++++ src/hotspot/cpu/x86/assembler_x86.hpp | 4 +++- src/hotspot/cpu/x86/x86.ad | 20 ++++++++++++++++++++ src/hotspot/share/adlc/formssel.cpp | 2 +- src/hotspot/share/opto/c2_globals.hpp | 3 +++ src/hotspot/share/opto/classes.hpp | 1 + src/hotspot/share/opto/loopopts.cpp | 8 ++++---- src/hotspot/share/opto/matcher.cpp | 1 + src/hotspot/share/opto/superword.cpp | 21 +++++++++++++++------ src/hotspot/share/opto/vectornode.cpp | 3 +++ src/hotspot/share/opto/vectornode.hpp | 10 +++++++++- src/hotspot/share/runtime/vmStructs.cpp | 1 + 12 files changed, 82 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 961ebb531be..b13a911398b 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -7449,6 +7449,27 @@ void Assembler::blendvpd(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMM emit_int8((unsigned char)(0xF0 & src2_enc<<4)); } +void Assembler::cmpps(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len) { + assert(VM_Version::supports_avx(), ""); + assert(!VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = simd_prefix_and_encode(dst, nds, src, VEX_SIMD_NONE, VEX_OPCODE_0F, &attributes); + emit_int8((unsigned char)0xC2); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8((unsigned char)(0xF & cop)); +} + +void Assembler::blendvps(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len) { + assert(VM_Version::supports_avx(), ""); + assert(!VM_Version::supports_evex(), ""); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src1->encoding(), VEX_SIMD_66, VEX_OPCODE_0F_3A, &attributes); + emit_int8((unsigned char)0x4A); + emit_int8((unsigned char)(0xC0 | encode)); + int src2_enc = src2->encoding(); + emit_int8((unsigned char)(0xF0 & src2_enc<<4)); +} + void Assembler::vpblendd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8, int vector_len) { assert(VM_Version::supports_avx2(), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ true, /* no_mask_reg */ false, /* uses_vl */ false); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 2739cf3b5eb..dbab8fbcf52 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -2114,9 +2114,11 @@ private: // runtime code and native libraries. void vzeroupper(); - // AVX support for vectorized conditional move (double). The following two instructions used only coupled. + // AVX support for vectorized conditional move (float/double). The following two instructions used only coupled. void cmppd(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len); void blendvpd(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len); + void cmpps(XMMRegister dst, XMMRegister nds, XMMRegister src, int cop, int vector_len); + void blendvps(XMMRegister dst, XMMRegister nds, XMMRegister src1, XMMRegister src2, int vector_len); void vpblendd(XMMRegister dst, XMMRegister nds, XMMRegister src, int imm8, int vector_len); protected: diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 124e95a4dcd..b28e3215fe0 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1263,6 +1263,7 @@ const bool Matcher::match_rule_supported(int opcode) { if (!VM_Version::supports_cx8()) ret_value = false; break; + case Op_CMoveVF: case Op_CMoveVD: if (UseAVX < 1 || UseAVX > 2) ret_value = false; @@ -1304,6 +1305,9 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen) { if ((vlen == 32) && (VM_Version::supports_avx512bw() == false)) ret_value = false; break; + case Op_CMoveVF: + if (vlen != 8) + ret_value = false; case Op_CMoveVD: if (vlen != 4) ret_value = false; @@ -8170,6 +8174,22 @@ instruct vmul8D_mem(vecZ dst, vecZ src, memory mem) %{ ins_pipe( pipe_slow ); %} +instruct vcmov8F_reg(vecY dst, vecY src1, vecY src2, immI8 cop, cmpOp_vcmppd copnd) %{ + predicate(UseAVX > 0 && UseAVX < 3 && n->as_Vector()->length() == 8); + match(Set dst (CMoveVF (Binary copnd cop) (Binary src1 src2))); + effect(TEMP dst, USE src1, USE src2); + format %{ "cmpps.$copnd $dst, $src1, $src2 ! vcmovevf, cond=$cop\n\t" + "blendvps $dst,$src1,$src2,$dst ! vcmovevf\n\t" + %} + ins_encode %{ + int vector_len = 1; + int cond = (Assembler::Condition)($copnd$$cmpcode); + __ cmpps($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, cond, vector_len); + __ blendvps($dst$$XMMRegister, $src1$$XMMRegister, $src2$$XMMRegister, $dst$$XMMRegister, vector_len); + %} + ins_pipe( pipe_slow ); +%} + instruct vcmov4D_reg(vecY dst, vecY src1, vecY src2, immI8 cop, cmpOp_vcmppd copnd) %{ predicate(UseAVX > 0 && UseAVX < 3 && n->as_Vector()->length() == 4); match(Set dst (CMoveVD (Binary copnd cop) (Binary src1 src2))); diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index fafd0ce7b27..b72c25f6e0a 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -4164,7 +4164,7 @@ bool MatchRule::is_vector() const { "AddVB","AddVS","AddVI","AddVL","AddVF","AddVD", "SubVB","SubVS","SubVI","SubVL","SubVF","SubVD", "MulVS","MulVI","MulVL","MulVF","MulVD", - "CMoveVD", + "CMoveVD", "CMoveVF", "DivVF","DivVD", "AbsVF","AbsVD", "NegVF","NegVD", diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 9f105299402..1d0e16532b3 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -195,6 +195,9 @@ product(bool, UseSubwordForMaxVector, true, \ "Use Subword Analysis to set maximum vector size") \ \ + product(bool, UseVectorCmov, false, \ + "Use Vectorized Cmov") \ + \ develop(intx, UnrollLimitForProfileCheck, 1, \ "Don't use profile_trip_cnt() to restrict unrolling until " \ "unrolling would push the number of unrolled iterations above " \ diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 235021f8660..dcbee6b4f69 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -66,6 +66,7 @@ macro(ConstraintCast) macro(CMoveD) macro(CMoveVD) macro(CMoveF) +macro(CMoveVF) macro(CMoveI) macro(CMoveL) macro(CMoveP) diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index d6ddc5723fe..d7a46ada7cd 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -528,13 +528,12 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { BasicType bt = phi->type()->basic_type(); switch (bt) { case T_DOUBLE: + case T_FLOAT: if (C->use_cmove()) { continue; //TODO: maybe we want to add some cost } - case T_FLOAT: { cost += Matcher::float_cmove_cost(); // Could be very expensive break; - } case T_LONG: { cost += Matcher::long_cmove_cost(); // May encodes as 2 CMOV's } @@ -613,8 +612,9 @@ Node *PhaseIdealLoop::conditional_move( Node *region ) { } // Check for highly predictable branch. No point in CMOV'ing if // we are going to predict accurately all the time. - if (C->use_cmove() && cmp_op == Op_CmpD) ;//keep going - else if (iff->_prob < infrequent_prob || + if (C->use_cmove() && (cmp_op == Op_CmpF || cmp_op == Op_CmpD)) { + //keep going + } else if (iff->_prob < infrequent_prob || iff->_prob > (1.0f - infrequent_prob)) return NULL; diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 19cdfb99584..b304bc3b3fa 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -2267,6 +2267,7 @@ void Matcher::find_shared( Node *n ) { case Op_CMoveL: case Op_CMoveN: case Op_CMoveP: + case Op_CMoveVF: case Op_CMoveVD: { // Restructure into a binary tree for Matching. It's possible that // we could move this code up next to the graph reshaping for IfNodes diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 39a525a1955..497f058a275 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -58,7 +58,7 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : _mem_slice_tail(arena(), 8, 0, NULL), // memory slice tails _node_info(arena(), 8, 0, SWNodeInfo::initial), // info needed per node _clone_map(phase->C->clone_map()), // map of nodes created in cloning - _cmovev_kit(_arena, this), // map to facilitate CMoveVD creation + _cmovev_kit(_arena, this), // map to facilitate CMoveV creation _align_to_ref(NULL), // memory reference to align vectors to _disjoint_ptrs(arena(), 8, 0, OrderedPair::initial), // runtime disambiguated pointer pairs _dg(_arena), // dependence graph @@ -511,8 +511,7 @@ void SuperWord::SLP_extract() { combine_packs(); construct_my_pack_map(); - - if (_do_vector_loop) { + if (UseVectorCmov) { merge_packs_to_cmovd(); } @@ -1249,8 +1248,8 @@ void SuperWord::set_alignment(Node* s1, Node* s2, int align) { //------------------------------data_size--------------------------- int SuperWord::data_size(Node* s) { - Node* use = NULL; //test if the node is a candidate for CMoveVD optimization, then return the size of CMov - if (_do_vector_loop) { + Node* use = NULL; //test if the node is a candidate for CMoveV optimization, then return the size of CMov + if (UseVectorCmov) { use = _cmovev_kit.is_Bool_candidate(s); if (use != NULL) { return data_size(use); @@ -1260,6 +1259,7 @@ int SuperWord::data_size(Node* s) { return data_size(use); } } + int bsize = type2aelembytes(velt_basic_type(s)); assert(bsize != 0, "valid size"); return bsize; @@ -1718,6 +1718,9 @@ Node_List* CMoveKit::make_cmovevd_pack(Node_List* cmovd_pk) { if (!cmovd->is_CMove()) { return NULL; } + if (cmovd->Opcode() != Op_CMoveF && cmovd->Opcode() != Op_CMoveD) { + return NULL; + } if (pack(cmovd) != NULL) { // already in the cmov pack return NULL; } @@ -2377,7 +2380,13 @@ void SuperWord::output() { } BasicType bt = velt_basic_type(n); const TypeVect* vt = TypeVect::make(bt, vlen); - vn = new CMoveVDNode(cc, src1, src2, vt); + assert(bt == T_FLOAT || bt == T_DOUBLE, "Only vectorization for FP cmovs is supported"); + if (bt == T_FLOAT) { + vn = new CMoveVFNode(cc, src1, src2, vt); + } else { + assert(bt == T_DOUBLE, "Expected double"); + vn = new CMoveVDNode(cc, src1, src2, vt); + } NOT_PRODUCT(if(is_trace_cmov()) {tty->print("SWPointer::output: created new CMove node %d: ", vn->_idx); vn->dump();}) } else if (opc == Op_FmaD || opc == Op_FmaF) { // Promote operands to vector diff --git a/src/hotspot/share/opto/vectornode.cpp b/src/hotspot/share/opto/vectornode.cpp index 57b0ecf0e7b..5bf5623b558 100644 --- a/src/hotspot/share/opto/vectornode.cpp +++ b/src/hotspot/share/opto/vectornode.cpp @@ -92,6 +92,9 @@ int VectorNode::opcode(int sopc, BasicType bt) { case Op_FmaF: assert(bt == T_FLOAT, "must be"); return Op_FmaVF; + case Op_CMoveF: + assert(bt == T_FLOAT, "must be"); + return Op_CMoveVF; case Op_CMoveD: assert(bt == T_DOUBLE, "must be"); return Op_CMoveVD; diff --git a/src/hotspot/share/opto/vectornode.hpp b/src/hotspot/share/opto/vectornode.hpp index 93da7bc4b7c..a774eafc4df 100644 --- a/src/hotspot/share/opto/vectornode.hpp +++ b/src/hotspot/share/opto/vectornode.hpp @@ -277,8 +277,16 @@ public: virtual int Opcode() const; }; +//------------------------------CMoveVFNode-------------------------------------- +// Vector float conditional move +class CMoveVFNode : public VectorNode { +public: + CMoveVFNode(Node* in1, Node* in2, Node* in3, const TypeVect* vt) : VectorNode(in1, in2, in3, vt) {} + virtual int Opcode() const; +}; + //------------------------------CMoveVDNode-------------------------------------- -// Vector multiply double +// Vector double conditional move class CMoveVDNode : public VectorNode { public: CMoveVDNode(Node* in1, Node* in2, Node* in3, const TypeVect* vt) : VectorNode(in1, in2, in3, vt) {} diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 9fb22233abb..28b5259c892 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -1991,6 +1991,7 @@ typedef PaddedEnd PaddedObjectMonitor; declare_c2_type(MulVDNode, VectorNode) \ declare_c2_type(FmaVDNode, VectorNode) \ declare_c2_type(FmaVFNode, VectorNode) \ + declare_c2_type(CMoveVFNode, VectorNode) \ declare_c2_type(CMoveVDNode, VectorNode) \ declare_c2_type(MulReductionVDNode, ReductionNode) \ declare_c2_type(DivVFNode, VectorNode) \ From 18e7fa9b4cc8f4ecc58d71fbb8c21c4e7df251b8 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 5 Dec 2017 10:38:31 -0800 Subject: [PATCH 14/22] 8145579: SimpleThresholdPolicy assumes non-trivial methods to be trivial Reviewed-by: shade, kvn, thartmann --- src/hotspot/share/c1/c1_GraphBuilder.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 5cd4fea84a9..5978fc5f3d7 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -1439,6 +1439,9 @@ void GraphBuilder::call_register_finalizer() { } if (needs_check) { + // Not a trivial method because C2 can do better with inlined check. + compilation()->set_would_profile(true); + // Perform the registration of finalizable objects. ValueStack* state_before = copy_state_for_exception(); load_local(objectType, 0); @@ -3556,6 +3559,9 @@ void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee, bool ignore_retur } bool GraphBuilder::try_inline_intrinsics(ciMethod* callee, bool ignore_return) { + // Not a trivial method because C2 may do intrinsics better. + compilation()->set_would_profile(true); + // For calling is_intrinsic_available we need to transition to // the '_thread_in_vm' state because is_intrinsic_available() // accesses critical VM-internal data. From 318c0d74ab6a7297cc7697f9686a5373e7163e4a Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 5 Dec 2017 11:16:03 -0800 Subject: [PATCH 15/22] 8192870: [Testbug] runtime/handshake/HandshakeTransitionTest throws NPE Reviewed-by: dholmes, rehn --- .../runtime/handshake/HandshakeTransitionTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java b/test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java index 3bcac9bbdf1..4ffefcc558c 100644 --- a/test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java +++ b/test/hotspot/jtreg/runtime/handshake/HandshakeTransitionTest.java @@ -49,6 +49,14 @@ public class HandshakeTransitionTest { public static void main(String[] args) throws Exception { String lib = System.getProperty("test.nativepath"); WhiteBox wb = WhiteBox.getWhiteBox(); + Boolean useJVMCICompiler = wb.getBooleanVMFlag("UseJVMCICompiler"); + String useJVMCICompilerStr; + if (useJVMCICompiler != null) { + useJVMCICompilerStr = useJVMCICompiler ? "-XX:+UseJVMCICompiler" : "-XX:-UseJVMCICompiler"; + } else { + // pass something innocuous + useJVMCICompilerStr = "-XX:+UnlockExperimentalVMOptions"; + } ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( true, @@ -60,7 +68,7 @@ public class HandshakeTransitionTest { "-XX:ConcGCThreads=1", "-XX:CICompilerCount=2", "-XX:+UnlockExperimentalVMOptions", - (wb.getBooleanVMFlag("UseJVMCICompiler") ? "-XX:+UseJVMCICompiler" : "-XX:-UseJVMCICompiler"), + useJVMCICompilerStr, "HandshakeTransitionTest$Test"); From 230b5768d786dc4fd2d3094959770b51875d937c Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 6 Dec 2017 15:19:30 -0500 Subject: [PATCH 16/22] 8191789: migrate more Thread-SMR stuff from thread.[ch]pp -> threadSMR.[ch]pp Reviewed-by: stefank, coleenp, dholmes, gthornbr --- src/hotspot/share/runtime/java.cpp | 4 +- src/hotspot/share/runtime/thread.cpp | 968 +---------------- src/hotspot/share/runtime/thread.hpp | 86 +- src/hotspot/share/runtime/thread.inline.hpp | 23 - src/hotspot/share/runtime/threadSMR.cpp | 983 +++++++++++++++++- src/hotspot/share/runtime/threadSMR.hpp | 76 +- .../share/runtime/threadSMR.inline.hpp | 41 + src/hotspot/share/runtime/vm_operations.hpp | 1 + src/hotspot/share/services/threadService.hpp | 1 + 9 files changed, 1114 insertions(+), 1069 deletions(-) diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index 9c19095f142..4edb5d82604 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -357,7 +357,7 @@ void print_statistics() { MemTracker::final_report(tty); } - Threads::log_smr_statistics(); + ThreadsSMRSupport::log_smr_statistics(); } #else // PRODUCT MODE STATISTICS @@ -399,7 +399,7 @@ void print_statistics() { Method::print_touched_methods(tty); } - Threads::log_smr_statistics(); + ThreadsSMRSupport::log_smr_statistics(); } #endif diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index d4191b0d89f..e95bd2f2e88 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -107,7 +107,6 @@ #include "utilities/events.hpp" #include "utilities/macros.hpp" #include "utilities/preserveException.hpp" -#include "utilities/resourceHash.hpp" #include "utilities/vmError.hpp" #if INCLUDE_ALL_GCS #include "gc/cms/concurrentMarkSweepThread.hpp" @@ -207,7 +206,7 @@ void Thread::operator delete(void* p) { void JavaThread::smr_delete() { if (_on_thread_list) { - Threads::smr_delete(this); + ThreadsSMRSupport::smr_delete(this); } else { delete this; } @@ -419,7 +418,7 @@ void Thread::check_for_dangling_thread_pointer(Thread *thread) { assert(!thread->is_Java_thread() || Thread::current() == thread || !((JavaThread *) thread)->on_thread_list() || SafepointSynchronize::is_at_safepoint() || - Threads::is_a_protected_JavaThread_with_lock((JavaThread *) thread), + ThreadsSMRSupport::is_a_protected_JavaThread_with_lock((JavaThread *) thread), "possibility of dangling Thread pointer"); } #endif @@ -3443,103 +3442,15 @@ void CodeCacheSweeperThread::nmethods_do(CodeBlobClosure* cf) { // would like. We are actively migrating Threads_lock uses to other // mechanisms in order to reduce Threads_lock contention. -JavaThread* Threads::_thread_list = NULL; -int Threads::_number_of_threads = 0; -int Threads::_number_of_non_daemon_threads = 0; -int Threads::_return_code = 0; -int Threads::_thread_claim_parity = 0; -size_t JavaThread::_stack_size_at_create = 0; -// Safe Memory Reclamation (SMR) support: -Monitor* Threads::_smr_delete_lock = - new Monitor(Monitor::special, "smr_delete_lock", - false /* allow_vm_block */, - Monitor::_safepoint_check_never); -// The '_cnt', '_max' and '_times" fields are enabled via -// -XX:+EnableThreadSMRStatistics: - -// # of parallel threads in _smr_delete_lock->wait(). -// Impl note: Hard to imagine > 64K waiting threads so this could be 16-bit, -// but there is no nice 16-bit _FORMAT support. -uint Threads::_smr_delete_lock_wait_cnt = 0; - -// Max # of parallel threads in _smr_delete_lock->wait(). -// Impl note: See _smr_delete_lock_wait_cnt note. -uint Threads::_smr_delete_lock_wait_max = 0; - -// Flag to indicate when an _smr_delete_lock->notify() is needed. -// Impl note: See _smr_delete_lock_wait_cnt note. -volatile uint Threads::_smr_delete_notify = 0; - -// # of threads deleted over VM lifetime. -// Impl note: Atomically incremented over VM lifetime so use unsigned for more -// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc -// isn't available everywhere (or is it?). -volatile uint Threads::_smr_deleted_thread_cnt = 0; - -// Max time in millis to delete a thread. -// Impl note: 16-bit might be too small on an overloaded machine. Use -// unsigned since this is a time value. Set via Atomic::cmpxchg() in a -// loop for correctness. -volatile uint Threads::_smr_deleted_thread_time_max = 0; - -// Cumulative time in millis to delete threads. -// Impl note: Atomically added to over VM lifetime so use unsigned for more -// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc -// isn't available everywhere (or is it?). -volatile uint Threads::_smr_deleted_thread_times = 0; - -ThreadsList* volatile Threads::_smr_java_thread_list = new ThreadsList(0); - -// # of ThreadsLists allocated over VM lifetime. -// Impl note: We allocate a new ThreadsList for every thread create and -// every thread delete so we need a bigger type than the -// _smr_deleted_thread_cnt field. -uint64_t Threads::_smr_java_thread_list_alloc_cnt = 1; - -// # of ThreadsLists freed over VM lifetime. -// Impl note: See _smr_java_thread_list_alloc_cnt note. -uint64_t Threads::_smr_java_thread_list_free_cnt = 0; - -// Max size ThreadsList allocated. -// Impl note: Max # of threads alive at one time should fit in unsigned 32-bit. -uint Threads::_smr_java_thread_list_max = 0; - -// Max # of nested ThreadsLists for a thread. -// Impl note: Hard to imagine > 64K nested ThreadsLists so this could be -// 16-bit, but there is no nice 16-bit _FORMAT support. -uint Threads::_smr_nested_thread_list_max = 0; - -// # of ThreadsListHandles deleted over VM lifetime. -// Impl note: Atomically incremented over VM lifetime so use unsigned for -// more range. There will be fewer ThreadsListHandles than threads so -// unsigned 32-bit should be fine. -volatile uint Threads::_smr_tlh_cnt = 0; - -// Max time in millis to delete a ThreadsListHandle. -// Impl note: 16-bit might be too small on an overloaded machine. Use -// unsigned since this is a time value. Set via Atomic::cmpxchg() in a -// loop for correctness. -volatile uint Threads::_smr_tlh_time_max = 0; - -// Cumulative time in millis to delete ThreadsListHandles. -// Impl note: Atomically added to over VM lifetime so use unsigned for more -// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc -// isn't available everywhere (or is it?). -volatile uint Threads::_smr_tlh_times = 0; - -ThreadsList* Threads::_smr_to_delete_list = NULL; - -// # of parallel ThreadsLists on the to-delete list. -// Impl note: Hard to imagine > 64K ThreadsLists needing to be deleted so -// this could be 16-bit, but there is no nice 16-bit _FORMAT support. -uint Threads::_smr_to_delete_list_cnt = 0; - -// Max # of parallel ThreadsLists on the to-delete list. -// Impl note: See _smr_to_delete_list_cnt note. -uint Threads::_smr_to_delete_list_max = 0; +JavaThread* Threads::_thread_list = NULL; +int Threads::_number_of_threads = 0; +int Threads::_number_of_non_daemon_threads = 0; +int Threads::_return_code = 0; +int Threads::_thread_claim_parity = 0; +size_t JavaThread::_stack_size_at_create = 0; #ifdef ASSERT -bool Threads::_vm_complete = false; +bool Threads::_vm_complete = false; #endif static inline void *prefetch_and_load_ptr(void **addr, intx prefetch_interval) { @@ -3561,12 +3472,8 @@ static inline void *prefetch_and_load_ptr(void **addr, intx prefetch_interval) { MACRO_current_p++, \ X = (JavaThread*)prefetch_and_load_ptr((void**)MACRO_current_p, (intx)MACRO_scan_interval)) -inline ThreadsList* Threads::get_smr_java_thread_list() { - return (ThreadsList*)OrderAccess::load_acquire(&_smr_java_thread_list); -} - // All JavaThreads -#define ALL_JAVA_THREADS(X) DO_JAVA_THREADS(get_smr_java_thread_list(), X) +#define ALL_JAVA_THREADS(X) DO_JAVA_THREADS(ThreadsSMRSupport::get_smr_java_thread_list(), X) // All JavaThreads + all non-JavaThreads (i.e., every thread in the system) void Threads::threads_do(ThreadClosure* tc) { @@ -3667,240 +3574,6 @@ static void call_initPhase3(TRAPS) { vmSymbols::void_method_signature(), CHECK); } -// Safe Memory Reclamation (SMR) support: -// - -// Acquire a stable ThreadsList. -// -ThreadsList *Threads::acquire_stable_list(Thread *self, bool is_ThreadsListSetter) { - assert(self != NULL, "sanity check"); - // acquire_stable_list_nested_path() will grab the Threads_lock - // so let's make sure the ThreadsListHandle is in a safe place. - // ThreadsListSetter cannot make this check on this code path. - debug_only(if (!is_ThreadsListSetter && StrictSafepointChecks) self->check_for_valid_safepoint_state(/* potential_vm_operation */ false);) - - if (self->get_threads_hazard_ptr() == NULL) { - // The typical case is first. - return acquire_stable_list_fast_path(self); - } - - // The nested case is rare. - return acquire_stable_list_nested_path(self); -} - -// Fast path (and lock free) way to acquire a stable ThreadsList. -// -ThreadsList *Threads::acquire_stable_list_fast_path(Thread *self) { - assert(self != NULL, "sanity check"); - assert(self->get_threads_hazard_ptr() == NULL, "sanity check"); - assert(self->get_nested_threads_hazard_ptr() == NULL, - "cannot have a nested hazard ptr with a NULL regular hazard ptr"); - - ThreadsList* threads; - - // Stable recording of a hazard ptr for SMR. This code does not use - // locks so its use of the _smr_java_thread_list & _threads_hazard_ptr - // fields is racy relative to code that uses those fields with locks. - // OrderAccess and Atomic functions are used to deal with those races. - // - while (true) { - threads = get_smr_java_thread_list(); - - // Publish a tagged hazard ptr to denote that the hazard ptr is not - // yet verified as being stable. Due to the fence after the hazard - // ptr write, it will be sequentially consistent w.r.t. the - // sequentially consistent writes of the ThreadsList, even on - // non-multiple copy atomic machines where stores can be observed - // in different order from different observer threads. - ThreadsList* unverified_threads = Thread::tag_hazard_ptr(threads); - self->set_threads_hazard_ptr(unverified_threads); - - // If _smr_java_thread_list has changed, we have lost a race with - // Threads::add() or Threads::remove() and have to try again. - if (get_smr_java_thread_list() != threads) { - continue; - } - - // We try to remove the tag which will verify the hazard ptr as - // being stable. This exchange can race with a scanning thread - // which might invalidate the tagged hazard ptr to keep it from - // being followed to access JavaThread ptrs. If we lose the race, - // we simply retry. If we win the race, then the stable hazard - // ptr is officially published. - if (self->cmpxchg_threads_hazard_ptr(threads, unverified_threads) == unverified_threads) { - break; - } - } - - // A stable hazard ptr has been published letting other threads know - // that the ThreadsList and the JavaThreads reachable from this list - // are protected and hence they should not be deleted until everyone - // agrees it is safe to do so. - - return threads; -} - -// Acquire a nested stable ThreadsList; this is rare so it uses -// Threads_lock. -// -ThreadsList *Threads::acquire_stable_list_nested_path(Thread *self) { - assert(self != NULL, "sanity check"); - assert(self->get_threads_hazard_ptr() != NULL, - "cannot have a NULL regular hazard ptr when acquiring a nested hazard ptr"); - - // The thread already has a hazard ptr (ThreadsList ref) so we need - // to create a nested ThreadsListHandle with the current ThreadsList - // since it might be different than our current hazard ptr. The need - // for a nested ThreadsListHandle is rare so we do this while holding - // the Threads_lock so we don't race with the scanning code; the code - // is so much simpler this way. - - NestedThreadsList* node; - { - // Only grab the Threads_lock if we don't already own it. - MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock); - node = new NestedThreadsList(get_smr_java_thread_list()); - // We insert at the front of the list to match up with the delete - // in release_stable_list(). - node->set_next(self->get_nested_threads_hazard_ptr()); - self->set_nested_threads_hazard_ptr(node); - if (EnableThreadSMRStatistics) { - self->inc_nested_threads_hazard_ptr_cnt(); - if (self->nested_threads_hazard_ptr_cnt() > _smr_nested_thread_list_max) { - _smr_nested_thread_list_max = self->nested_threads_hazard_ptr_cnt(); - } - } - } - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::acquire_stable_list: add NestedThreadsList node containing ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(node->t_list())); - - return node->t_list(); -} - -inline void Threads::add_smr_deleted_thread_times(uint add_value) { - Atomic::add(add_value, &_smr_deleted_thread_times); -} - -inline void Threads::inc_smr_deleted_thread_cnt() { - Atomic::inc(&_smr_deleted_thread_cnt); -} - -// Release a stable ThreadsList. -// -void Threads::release_stable_list(Thread *self) { - assert(self != NULL, "sanity check"); - // release_stable_list_nested_path() will grab the Threads_lock - // so let's make sure the ThreadsListHandle is in a safe place. - debug_only(if (StrictSafepointChecks) self->check_for_valid_safepoint_state(/* potential_vm_operation */ false);) - - if (self->get_nested_threads_hazard_ptr() == NULL) { - // The typical case is first. - release_stable_list_fast_path(self); - return; - } - - // The nested case is rare. - release_stable_list_nested_path(self); -} - -// Fast path way to release a stable ThreadsList. The release portion -// is lock-free, but the wake up portion is not. -// -void Threads::release_stable_list_fast_path(Thread *self) { - assert(self != NULL, "sanity check"); - assert(self->get_threads_hazard_ptr() != NULL, "sanity check"); - assert(self->get_nested_threads_hazard_ptr() == NULL, - "cannot have a nested hazard ptr when releasing a regular hazard ptr"); - - // After releasing the hazard ptr, other threads may go ahead and - // free up some memory temporarily used by a ThreadsList snapshot. - self->set_threads_hazard_ptr(NULL); - - // We use double-check locking to reduce traffic on the system - // wide smr_delete_lock. - if (Threads::smr_delete_notify()) { - // An exiting thread might be waiting in smr_delete(); we need to - // check with smr_delete_lock to be sure. - release_stable_list_wake_up((char *) "regular hazard ptr"); - } -} - -// Release a nested stable ThreadsList; this is rare so it uses -// Threads_lock. -// -void Threads::release_stable_list_nested_path(Thread *self) { - assert(self != NULL, "sanity check"); - assert(self->get_nested_threads_hazard_ptr() != NULL, "sanity check"); - assert(self->get_threads_hazard_ptr() != NULL, - "must have a regular hazard ptr to have nested hazard ptrs"); - - // We have a nested ThreadsListHandle so we have to release it first. - // The need for a nested ThreadsListHandle is rare so we do this while - // holding the Threads_lock so we don't race with the scanning code; - // the code is so much simpler this way. - - NestedThreadsList *node; - { - // Only grab the Threads_lock if we don't already own it. - MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock); - // We remove from the front of the list to match up with the insert - // in acquire_stable_list(). - node = self->get_nested_threads_hazard_ptr(); - self->set_nested_threads_hazard_ptr(node->next()); - if (EnableThreadSMRStatistics) { - self->dec_nested_threads_hazard_ptr_cnt(); - } - } - - // An exiting thread might be waiting in smr_delete(); we need to - // check with smr_delete_lock to be sure. - release_stable_list_wake_up((char *) "nested hazard ptr"); - - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::release_stable_list: delete NestedThreadsList node containing ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(node->t_list())); - - delete node; -} - -// Wake up portion of the release stable ThreadsList protocol; -// uses the smr_delete_lock(). -// -void Threads::release_stable_list_wake_up(char *log_str) { - assert(log_str != NULL, "sanity check"); - - // Note: smr_delete_lock is held in smr_delete() for the entire - // hazard ptr search so that we do not lose this notify() if - // the exiting thread has to wait. That code path also holds - // Threads_lock (which was grabbed before smr_delete_lock) so that - // threads_do() can be called. This means the system can't start a - // safepoint which means this thread can't take too long to get to - // a safepoint because of being blocked on smr_delete_lock. - // - MonitorLockerEx ml(Threads::smr_delete_lock(), Monitor::_no_safepoint_check_flag); - if (Threads::smr_delete_notify()) { - // Notify any exiting JavaThreads that are waiting in smr_delete() - // that we've released a ThreadsList. - ml.notify_all(); - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::release_stable_list notified %s", os::current_thread_id(), log_str); - } -} - -inline void Threads::update_smr_deleted_thread_time_max(uint new_value) { - while (true) { - uint cur_value = _smr_deleted_thread_time_max; - if (new_value <= cur_value) { - // No need to update max value so we're done. - break; - } - if (Atomic::cmpxchg(new_value, &_smr_deleted_thread_time_max, cur_value) == cur_value) { - // Updated max value so we're done. Otherwise try it all again. - break; - } - } -} - -inline ThreadsList* Threads::xchg_smr_java_thread_list(ThreadsList* new_list) { - return (ThreadsList*)Atomic::xchg(new_list, &_smr_java_thread_list); -} - void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { TraceTime timer("Initialize java.lang classes", TRACETIME_LOG(Info, startuptime)); @@ -4666,501 +4339,6 @@ jboolean Threads::is_supported_jni_version(jint version) { return JNI_FALSE; } -// Hash table of pointers found by a scan. Used for collecting hazard -// pointers (ThreadsList references). Also used for collecting JavaThreads -// that are indirectly referenced by hazard ptrs. An instance of this -// class only contains one type of pointer. -// -class ThreadScanHashtable : public CHeapObj { - private: - static bool ptr_equals(void * const& s1, void * const& s2) { - return s1 == s2; - } - - static unsigned int ptr_hash(void * const& s1) { - // 2654435761 = 2^32 * Phi (golden ratio) - return (unsigned int)(((uint32_t)(uintptr_t)s1) * 2654435761u); - } - - int _table_size; - // ResourceHashtable SIZE is specified at compile time so our - // dynamic _table_size is unused for now; 1031 is the first prime - // after 1024. - typedef ResourceHashtable PtrTable; - PtrTable * _ptrs; - - public: - // ResourceHashtable is passed to various functions and populated in - // different places so we allocate it using C_HEAP to make it immune - // from any ResourceMarks that happen to be in the code paths. - ThreadScanHashtable(int table_size) : _table_size(table_size), _ptrs(new (ResourceObj::C_HEAP, mtThread) PtrTable()) {} - - ~ThreadScanHashtable() { delete _ptrs; } - - bool has_entry(void *pointer) { - int *val_ptr = _ptrs->get(pointer); - return val_ptr != NULL && *val_ptr == 1; - } - - void add_entry(void *pointer) { - _ptrs->put(pointer, 1); - } -}; - -// Closure to gather JavaThreads indirectly referenced by hazard ptrs -// (ThreadsList references) into a hash table. This closure handles part 2 -// of the dance - adding all the JavaThreads referenced by the hazard -// pointer (ThreadsList reference) to the hash table. -// -class AddThreadHazardPointerThreadClosure : public ThreadClosure { - private: - ThreadScanHashtable *_table; - - public: - AddThreadHazardPointerThreadClosure(ThreadScanHashtable *table) : _table(table) {} - - virtual void do_thread(Thread *thread) { - if (!_table->has_entry((void*)thread)) { - // The same JavaThread might be on more than one ThreadsList or - // more than one thread might be using the same ThreadsList. In - // either case, we only need a single entry for a JavaThread. - _table->add_entry((void*)thread); - } - } -}; - -// Closure to gather JavaThreads indirectly referenced by hazard ptrs -// (ThreadsList references) into a hash table. This closure handles part 1 -// of the dance - hazard ptr chain walking and dispatch to another -// closure. -// -class ScanHazardPtrGatherProtectedThreadsClosure : public ThreadClosure { - private: - ThreadScanHashtable *_table; - public: - ScanHazardPtrGatherProtectedThreadsClosure(ThreadScanHashtable *table) : _table(table) {} - - virtual void do_thread(Thread *thread) { - assert_locked_or_safepoint(Threads_lock); - - if (thread == NULL) return; - - // This code races with Threads::acquire_stable_list() which is - // lock-free so we have to handle some special situations. - // - ThreadsList *current_list = NULL; - while (true) { - current_list = thread->get_threads_hazard_ptr(); - // No hazard ptr so nothing more to do. - if (current_list == NULL) { - assert(thread->get_nested_threads_hazard_ptr() == NULL, - "cannot have a nested hazard ptr with a NULL regular hazard ptr"); - return; - } - - // If the hazard ptr is verified as stable (since it is not tagged), - // then it is safe to use. - if (!Thread::is_hazard_ptr_tagged(current_list)) break; - - // The hazard ptr is tagged as not yet verified as being stable - // so we are racing with acquire_stable_list(). This exchange - // attempts to invalidate the hazard ptr. If we win the race, - // then we can ignore this unstable hazard ptr and the other - // thread will retry the attempt to publish a stable hazard ptr. - // If we lose the race, then we retry our attempt to look at the - // hazard ptr. - if (thread->cmpxchg_threads_hazard_ptr(NULL, current_list) == current_list) return; - } - - // The current JavaThread has a hazard ptr (ThreadsList reference) - // which might be _smr_java_thread_list or it might be an older - // ThreadsList that has been removed but not freed. In either case, - // the hazard ptr is protecting all the JavaThreads on that - // ThreadsList. - AddThreadHazardPointerThreadClosure add_cl(_table); - current_list->threads_do(&add_cl); - - // Any NestedThreadsLists are also protecting JavaThreads so - // gather those also; the ThreadsLists may be different. - for (NestedThreadsList* node = thread->get_nested_threads_hazard_ptr(); - node != NULL; node = node->next()) { - node->t_list()->threads_do(&add_cl); - } - } -}; - -// Closure to print JavaThreads that have a hazard ptr (ThreadsList -// reference) that contains an indirect reference to a specific JavaThread. -// -class ScanHazardPtrPrintMatchingThreadsClosure : public ThreadClosure { - private: - JavaThread *_thread; - public: - ScanHazardPtrPrintMatchingThreadsClosure(JavaThread *thread) : _thread(thread) {} - - virtual void do_thread(Thread *thread) { - assert_locked_or_safepoint(Threads_lock); - - if (thread == NULL) return; - ThreadsList *current_list = thread->get_threads_hazard_ptr(); - if (current_list == NULL) { - assert(thread->get_nested_threads_hazard_ptr() == NULL, - "cannot have a nested hazard ptr with a NULL regular hazard ptr"); - return; - } - // If the hazard ptr is unverified, then ignore it. - if (Thread::is_hazard_ptr_tagged(current_list)) return; - - // The current JavaThread has a hazard ptr (ThreadsList reference) - // which might be _smr_java_thread_list or it might be an older - // ThreadsList that has been removed but not freed. In either case, - // the hazard ptr is protecting all the JavaThreads on that - // ThreadsList, but we only care about matching a specific JavaThread. - DO_JAVA_THREADS(current_list, p) { - if (p == _thread) { - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::smr_delete: thread1=" INTPTR_FORMAT " has a hazard pointer for thread2=" INTPTR_FORMAT, os::current_thread_id(), p2i(thread), p2i(_thread)); - break; - } - } - - // Any NestedThreadsLists are also protecting JavaThreads so - // check those also; the ThreadsLists may be different. - for (NestedThreadsList* node = thread->get_nested_threads_hazard_ptr(); - node != NULL; node = node->next()) { - DO_JAVA_THREADS(node->t_list(), p) { - if (p == _thread) { - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::smr_delete: thread1=" INTPTR_FORMAT " has a nested hazard pointer for thread2=" INTPTR_FORMAT, os::current_thread_id(), p2i(thread), p2i(_thread)); - return; - } - } - } - } -}; - -// Return true if the specified JavaThread is protected by a hazard -// pointer (ThreadsList reference). Otherwise, returns false. -// -bool Threads::is_a_protected_JavaThread(JavaThread *thread) { - assert_locked_or_safepoint(Threads_lock); - - // Hash table size should be first power of two higher than twice - // the length of the Threads list. - int hash_table_size = MIN2(_number_of_threads, 32) << 1; - hash_table_size--; - hash_table_size |= hash_table_size >> 1; - hash_table_size |= hash_table_size >> 2; - hash_table_size |= hash_table_size >> 4; - hash_table_size |= hash_table_size >> 8; - hash_table_size |= hash_table_size >> 16; - hash_table_size++; - - // Gather a hash table of the JavaThreads indirectly referenced by - // hazard ptrs. - ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size); - ScanHazardPtrGatherProtectedThreadsClosure scan_cl(scan_table); - Threads::threads_do(&scan_cl); - - bool thread_is_protected = false; - if (scan_table->has_entry((void*)thread)) { - thread_is_protected = true; - } - delete scan_table; - return thread_is_protected; -} - -// Safely delete a JavaThread when it is no longer in use by a -// ThreadsListHandle. -// -void Threads::smr_delete(JavaThread *thread) { - assert(!Threads_lock->owned_by_self(), "sanity"); - - bool has_logged_once = false; - elapsedTimer timer; - if (EnableThreadSMRStatistics) { - timer.start(); - } - - while (true) { - { - // No safepoint check because this JavaThread is not on the - // Threads list. - MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag); - // Cannot use a MonitorLockerEx helper here because we have - // to drop the Threads_lock first if we wait. - Threads::smr_delete_lock()->lock_without_safepoint_check(); - // Set the smr_delete_notify flag after we grab smr_delete_lock - // and before we scan hazard ptrs because we're doing - // double-check locking in release_stable_list(). - Threads::set_smr_delete_notify(); - - if (!is_a_protected_JavaThread(thread)) { - // This is the common case. - Threads::clear_smr_delete_notify(); - Threads::smr_delete_lock()->unlock(); - break; - } - if (!has_logged_once) { - has_logged_once = true; - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::smr_delete: thread=" INTPTR_FORMAT " is not deleted.", os::current_thread_id(), p2i(thread)); - if (log_is_enabled(Debug, os, thread)) { - ScanHazardPtrPrintMatchingThreadsClosure scan_cl(thread); - Threads::threads_do(&scan_cl); - } - } - } // We have to drop the Threads_lock to wait or delete the thread - - if (EnableThreadSMRStatistics) { - _smr_delete_lock_wait_cnt++; - if (_smr_delete_lock_wait_cnt > _smr_delete_lock_wait_max) { - _smr_delete_lock_wait_max = _smr_delete_lock_wait_cnt; - } - } - // Wait for a release_stable_list() call before we check again. No - // safepoint check, no timeout, and not as suspend equivalent flag - // because this JavaThread is not on the Threads list. - Threads::smr_delete_lock()->wait(Mutex::_no_safepoint_check_flag, 0, - !Mutex::_as_suspend_equivalent_flag); - if (EnableThreadSMRStatistics) { - _smr_delete_lock_wait_cnt--; - } - - Threads::clear_smr_delete_notify(); - Threads::smr_delete_lock()->unlock(); - // Retry the whole scenario. - } - - if (ThreadLocalHandshakes) { - // The thread is about to be deleted so cancel any handshake. - thread->cancel_handshake(); - } - - delete thread; - if (EnableThreadSMRStatistics) { - timer.stop(); - uint millis = (uint)timer.milliseconds(); - Threads::inc_smr_deleted_thread_cnt(); - Threads::add_smr_deleted_thread_times(millis); - Threads::update_smr_deleted_thread_time_max(millis); - } - - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::smr_delete: thread=" INTPTR_FORMAT " is deleted.", os::current_thread_id(), p2i(thread)); -} - -bool Threads::smr_delete_notify() { - // Use load_acquire() in order to see any updates to _smr_delete_notify - // earlier than when smr_delete_lock is grabbed. - return (OrderAccess::load_acquire(&_smr_delete_notify) != 0); -} - -// set_smr_delete_notify() and clear_smr_delete_notify() are called -// under the protection of the smr_delete_lock, but we also use an -// Atomic operation to ensure the memory update is seen earlier than -// when the smr_delete_lock is dropped. -// -void Threads::set_smr_delete_notify() { - Atomic::inc(&_smr_delete_notify); -} - -void Threads::clear_smr_delete_notify() { - Atomic::dec(&_smr_delete_notify); -} - -// Closure to gather hazard ptrs (ThreadsList references) into a hash table. -// -class ScanHazardPtrGatherThreadsListClosure : public ThreadClosure { - private: - ThreadScanHashtable *_table; - public: - ScanHazardPtrGatherThreadsListClosure(ThreadScanHashtable *table) : _table(table) {} - - virtual void do_thread(Thread* thread) { - assert_locked_or_safepoint(Threads_lock); - - if (thread == NULL) return; - ThreadsList *threads = thread->get_threads_hazard_ptr(); - if (threads == NULL) { - assert(thread->get_nested_threads_hazard_ptr() == NULL, - "cannot have a nested hazard ptr with a NULL regular hazard ptr"); - return; - } - // In this closure we always ignore the tag that might mark this - // hazard ptr as not yet verified. If we happen to catch an - // unverified hazard ptr that is subsequently discarded (not - // published), then the only side effect is that we might keep a - // to-be-deleted ThreadsList alive a little longer. - threads = Thread::untag_hazard_ptr(threads); - if (!_table->has_entry((void*)threads)) { - _table->add_entry((void*)threads); - } - - // Any NestedThreadsLists are also protecting JavaThreads so - // gather those also; the ThreadsLists may be different. - for (NestedThreadsList* node = thread->get_nested_threads_hazard_ptr(); - node != NULL; node = node->next()) { - threads = node->t_list(); - if (!_table->has_entry((void*)threads)) { - _table->add_entry((void*)threads); - } - } - } -}; - -// Safely free a ThreadsList after a Threads::add() or Threads::remove(). -// The specified ThreadsList may not get deleted during this call if it -// is still in-use (referenced by a hazard ptr). Other ThreadsLists -// in the chain may get deleted by this call if they are no longer in-use. -void Threads::smr_free_list(ThreadsList* threads) { - assert_locked_or_safepoint(Threads_lock); - - threads->set_next_list(_smr_to_delete_list); - _smr_to_delete_list = threads; - if (EnableThreadSMRStatistics) { - _smr_to_delete_list_cnt++; - if (_smr_to_delete_list_cnt > _smr_to_delete_list_max) { - _smr_to_delete_list_max = _smr_to_delete_list_cnt; - } - } - - // Hash table size should be first power of two higher than twice the length of the ThreadsList - int hash_table_size = MIN2(_number_of_threads, 32) << 1; - hash_table_size--; - hash_table_size |= hash_table_size >> 1; - hash_table_size |= hash_table_size >> 2; - hash_table_size |= hash_table_size >> 4; - hash_table_size |= hash_table_size >> 8; - hash_table_size |= hash_table_size >> 16; - hash_table_size++; - - // Gather a hash table of the current hazard ptrs: - ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size); - ScanHazardPtrGatherThreadsListClosure scan_cl(scan_table); - Threads::threads_do(&scan_cl); - - // Walk through the linked list of pending freeable ThreadsLists - // and free the ones that are not referenced from hazard ptrs. - ThreadsList* current = _smr_to_delete_list; - ThreadsList* prev = NULL; - ThreadsList* next = NULL; - bool threads_is_freed = false; - while (current != NULL) { - next = current->next_list(); - if (!scan_table->has_entry((void*)current)) { - // This ThreadsList is not referenced by a hazard ptr. - if (prev != NULL) { - prev->set_next_list(next); - } - if (_smr_to_delete_list == current) { - _smr_to_delete_list = next; - } - - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::smr_free_list: threads=" INTPTR_FORMAT " is freed.", os::current_thread_id(), p2i(current)); - if (current == threads) threads_is_freed = true; - delete current; - if (EnableThreadSMRStatistics) { - _smr_java_thread_list_free_cnt++; - _smr_to_delete_list_cnt--; - } - } else { - prev = current; - } - current = next; - } - - if (!threads_is_freed) { - // Only report "is not freed" on the original call to - // smr_free_list() for this ThreadsList. - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::smr_free_list: threads=" INTPTR_FORMAT " is not freed.", os::current_thread_id(), p2i(threads)); - } - - delete scan_table; -} - -// Remove a JavaThread from a ThreadsList. The returned ThreadsList is a -// new copy of the specified ThreadsList with the specified JavaThread -// removed. -ThreadsList *ThreadsList::remove_thread(ThreadsList* list, JavaThread* java_thread) { - assert(list->_length > 0, "sanity"); - - uint i = 0; - DO_JAVA_THREADS(list, current) { - if (current == java_thread) { - break; - } - i++; - } - assert(i < list->_length, "did not find JavaThread on the list"); - const uint index = i; - const uint new_length = list->_length - 1; - const uint head_length = index; - const uint tail_length = (new_length >= index) ? (new_length - index) : 0; - ThreadsList *const new_list = new ThreadsList(new_length); - - if (head_length > 0) { - Copy::disjoint_words((HeapWord*)list->_threads, (HeapWord*)new_list->_threads, head_length); - } - if (tail_length > 0) { - Copy::disjoint_words((HeapWord*)list->_threads + index + 1, (HeapWord*)new_list->_threads + index, tail_length); - } - - return new_list; -} - -// Add a JavaThread to a ThreadsList. The returned ThreadsList is a -// new copy of the specified ThreadsList with the specified JavaThread -// appended to the end. -ThreadsList *ThreadsList::add_thread(ThreadsList *list, JavaThread *java_thread) { - const uint index = list->_length; - const uint new_length = index + 1; - const uint head_length = index; - ThreadsList *const new_list = new ThreadsList(new_length); - - if (head_length > 0) { - Copy::disjoint_words((HeapWord*)list->_threads, (HeapWord*)new_list->_threads, head_length); - } - *(JavaThread**)(new_list->_threads + index) = java_thread; - - return new_list; -} - -int ThreadsList::find_index_of_JavaThread(JavaThread *target) { - if (target == NULL) { - return -1; - } - for (uint i = 0; i < length(); i++) { - if (target == thread_at(i)) { - return (int)i; - } - } - return -1; -} - -JavaThread* ThreadsList::find_JavaThread_from_java_tid(jlong java_tid) const { - DO_JAVA_THREADS(this, thread) { - oop tobj = thread->threadObj(); - // Ignore the thread if it hasn't run yet, has exited - // or is starting to exit. - if (tobj != NULL && !thread->is_exiting() && - java_tid == java_lang_Thread::thread_id(tobj)) { - // found a match - return thread; - } - } - return NULL; -} - -bool ThreadsList::includes(const JavaThread * const p) const { - if (p == NULL) { - return false; - } - DO_JAVA_THREADS(this, q) { - if (q == p) { - return true; - } - } - return false; -} void Threads::add(JavaThread* p, bool force_daemon) { // The threads lock must be owned at this point @@ -5189,18 +4367,7 @@ void Threads::add(JavaThread* p, bool force_daemon) { ThreadService::add_thread(p, daemon); // Maintain fast thread list - ThreadsList *new_list = ThreadsList::add_thread(get_smr_java_thread_list(), p); - if (EnableThreadSMRStatistics) { - _smr_java_thread_list_alloc_cnt++; - if (new_list->length() > _smr_java_thread_list_max) { - _smr_java_thread_list_max = new_list->length(); - } - } - // Initial _smr_java_thread_list will not generate a "Threads::add" mesg. - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::add: new ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(new_list)); - - ThreadsList *old_list = xchg_smr_java_thread_list(new_list); - smr_free_list(old_list); + ThreadsSMRSupport::add_thread(p); // Possible GC point. Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p)); @@ -5215,20 +4382,10 @@ void Threads::remove(JavaThread* p) { // that we do not remove thread without safepoint code notice { MutexLocker ml(Threads_lock); - assert(get_smr_java_thread_list()->includes(p), "p must be present"); + assert(ThreadsSMRSupport::get_smr_java_thread_list()->includes(p), "p must be present"); // Maintain fast thread list - ThreadsList *new_list = ThreadsList::remove_thread(get_smr_java_thread_list(), p); - if (EnableThreadSMRStatistics) { - _smr_java_thread_list_alloc_cnt++; - // This list is smaller so no need to check for a "longest" update. - } - - // Final _smr_java_thread_list will not generate a "Threads::remove" mesg. - log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::remove: new ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(new_list)); - - ThreadsList *old_list = xchg_smr_java_thread_list(new_list); - smr_free_list(old_list); + ThreadsSMRSupport::remove_thread(p); JavaThread* current = _thread_list; JavaThread* prev = NULL; @@ -5453,7 +4610,7 @@ void Threads::print_on(outputStream* st, bool print_stacks, } #endif // INCLUDE_SERVICES - print_smr_info_on(st); + ThreadsSMRSupport::print_smr_info_on(st); st->cr(); ALL_JAVA_THREADS(p) { @@ -5486,101 +4643,6 @@ void Threads::print_on(outputStream* st, bool print_stacks, st->flush(); } -// Log Threads class SMR info. -void Threads::log_smr_statistics() { - LogTarget(Info, thread, smr) log; - if (log.is_enabled()) { - LogStream out(log); - print_smr_info_on(&out); - } -} - -// Print Threads class SMR info. -void Threads::print_smr_info_on(outputStream* st) { - // Only grab the Threads_lock if we don't already own it - // and if we are not reporting an error. - MutexLockerEx ml((Threads_lock->owned_by_self() || VMError::is_error_reported()) ? NULL : Threads_lock); - - st->print_cr("Threads class SMR info:"); - st->print_cr("_smr_java_thread_list=" INTPTR_FORMAT ", length=%u, " - "elements={", p2i(_smr_java_thread_list), - _smr_java_thread_list->length()); - print_smr_info_elements_on(st, _smr_java_thread_list); - st->print_cr("}"); - if (_smr_to_delete_list != NULL) { - st->print_cr("_smr_to_delete_list=" INTPTR_FORMAT ", length=%u, " - "elements={", p2i(_smr_to_delete_list), - _smr_to_delete_list->length()); - print_smr_info_elements_on(st, _smr_to_delete_list); - st->print_cr("}"); - for (ThreadsList *t_list = _smr_to_delete_list->next_list(); - t_list != NULL; t_list = t_list->next_list()) { - st->print("next-> " INTPTR_FORMAT ", length=%u, " - "elements={", p2i(t_list), t_list->length()); - print_smr_info_elements_on(st, t_list); - st->print_cr("}"); - } - } - if (!EnableThreadSMRStatistics) { - return; - } - st->print_cr("_smr_java_thread_list_alloc_cnt=" UINT64_FORMAT "," - "_smr_java_thread_list_free_cnt=" UINT64_FORMAT "," - "_smr_java_thread_list_max=%u, " - "_smr_nested_thread_list_max=%u", - _smr_java_thread_list_alloc_cnt, - _smr_java_thread_list_free_cnt, - _smr_java_thread_list_max, - _smr_nested_thread_list_max); - if (_smr_tlh_cnt > 0) { - st->print_cr("_smr_tlh_cnt=%u" - ", _smr_tlh_times=%u" - ", avg_smr_tlh_time=%0.2f" - ", _smr_tlh_time_max=%u", - _smr_tlh_cnt, _smr_tlh_times, - ((double) _smr_tlh_times / _smr_tlh_cnt), - _smr_tlh_time_max); - } - if (_smr_deleted_thread_cnt > 0) { - st->print_cr("_smr_deleted_thread_cnt=%u" - ", _smr_deleted_thread_times=%u" - ", avg_smr_deleted_thread_time=%0.2f" - ", _smr_deleted_thread_time_max=%u", - _smr_deleted_thread_cnt, _smr_deleted_thread_times, - ((double) _smr_deleted_thread_times / _smr_deleted_thread_cnt), - _smr_deleted_thread_time_max); - } - st->print_cr("_smr_delete_lock_wait_cnt=%u, _smr_delete_lock_wait_max=%u", - _smr_delete_lock_wait_cnt, _smr_delete_lock_wait_max); - st->print_cr("_smr_to_delete_list_cnt=%u, _smr_to_delete_list_max=%u", - _smr_to_delete_list_cnt, _smr_to_delete_list_max); -} - -// Print ThreadsList elements (4 per line). -void Threads::print_smr_info_elements_on(outputStream* st, - ThreadsList* t_list) { - uint cnt = 0; - JavaThreadIterator jti(t_list); - for (JavaThread *jt = jti.first(); jt != NULL; jt = jti.next()) { - st->print(INTPTR_FORMAT, p2i(jt)); - if (cnt < t_list->length() - 1) { - // Separate with comma or comma-space except for the last one. - if (((cnt + 1) % 4) == 0) { - // Four INTPTR_FORMAT fit on an 80 column line so end the - // current line with just a comma. - st->print_cr(","); - } else { - // Not the last one on the current line so use comma-space: - st->print(", "); - } - } else { - // Last one so just end the current line. - st->cr(); - } - cnt++; - } -} - void Threads::print_on_error(Thread* this_thread, outputStream* st, Thread* current, char* buf, int buflen, bool* found_current) { if (this_thread != NULL) { @@ -5617,7 +4679,7 @@ class PrintOnErrorClosure : public ThreadClosure { // memory (even in resource area), it might deadlock the error handler. void Threads::print_on_error(outputStream* st, Thread* current, char* buf, int buflen) { - print_smr_info_on(st); + ThreadsSMRSupport::print_smr_info_on(st); st->cr(); bool found_current = false; diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index db1d465c751..59af4c23b85 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -58,6 +58,7 @@ class ThreadSafepointState; class ThreadsList; +class ThreadsSMRSupport; class NestedThreadsList; class JvmtiThreadState; @@ -103,7 +104,6 @@ class WorkerThread; // - WatcherThread class Thread: public ThreadShadow { - friend class Threads; friend class VMStructs; friend class JVMCIVMStructs; private: @@ -121,12 +121,14 @@ class Thread: public ThreadShadow { protected: // Support for forcing alignment of thread objects for biased locking void* _real_malloc_address; + // JavaThread lifecycle support: - friend class ScanHazardPtrGatherProtectedThreadsClosure; - friend class ScanHazardPtrGatherThreadsListClosure; - friend class ScanHazardPtrPrintMatchingThreadsClosure; - friend class ThreadsListHandle; - friend class ThreadsListSetter; + friend class ScanHazardPtrGatherProtectedThreadsClosure; // for cmpxchg_threads_hazard_ptr(), get_threads_hazard_ptr(), is_hazard_ptr_tagged() access + friend class ScanHazardPtrGatherThreadsListClosure; // for get_nested_threads_hazard_ptr(), get_threads_hazard_ptr(), untag_hazard_ptr() access + friend class ScanHazardPtrPrintMatchingThreadsClosure; // for get_threads_hazard_ptr(), is_hazard_ptr_tagged() access + friend class ThreadsListSetter; // for get_threads_hazard_ptr() access + friend class ThreadsSMRSupport; // for get_threads_hazard_ptr() access + ThreadsList* volatile _threads_hazard_ptr; ThreadsList* cmpxchg_threads_hazard_ptr(ThreadsList* exchange_value, ThreadsList* compare_value); ThreadsList* get_threads_hazard_ptr(); @@ -2126,62 +2128,18 @@ inline CompilerThread* CompilerThread::current() { class Threads: AllStatic { friend class VMStructs; private: - // Safe Memory Reclamation (SMR) support: - // The coordination between Threads::release_stable_list() and - // Threads::smr_delete() uses the smr_delete_lock in order to - // reduce the traffic on the Threads_lock. - static Monitor* _smr_delete_lock; - // The '_cnt', '_max' and '_times" fields are enabled via - // -XX:+EnableThreadSMRStatistics (see thread.cpp for a - // description about each field): - static uint _smr_delete_lock_wait_cnt; - static uint _smr_delete_lock_wait_max; - // The smr_delete_notify flag is used for proper double-check - // locking in order to reduce the traffic on the smr_delete_lock. - static volatile uint _smr_delete_notify; - static volatile uint _smr_deleted_thread_cnt; - static volatile uint _smr_deleted_thread_time_max; - static volatile uint _smr_deleted_thread_times; - static ThreadsList* volatile _smr_java_thread_list; - static uint64_t _smr_java_thread_list_alloc_cnt; - static uint64_t _smr_java_thread_list_free_cnt; - static uint _smr_java_thread_list_max; - static uint _smr_nested_thread_list_max; - static volatile uint _smr_tlh_cnt; - static volatile uint _smr_tlh_time_max; - static volatile uint _smr_tlh_times; - static ThreadsList* _smr_to_delete_list; - static uint _smr_to_delete_list_cnt; - static uint _smr_to_delete_list_max; - - static JavaThread* _thread_list; - static int _number_of_threads; - static int _number_of_non_daemon_threads; - static int _return_code; - static int _thread_claim_parity; + static JavaThread* _thread_list; + static int _number_of_threads; + static int _number_of_non_daemon_threads; + static int _return_code; + static int _thread_claim_parity; #ifdef ASSERT - static bool _vm_complete; + static bool _vm_complete; #endif static void initialize_java_lang_classes(JavaThread* main_thread, TRAPS); static void initialize_jsr292_core_classes(TRAPS); - static ThreadsList *acquire_stable_list_fast_path(Thread *self); - static ThreadsList *acquire_stable_list_nested_path(Thread *self); - static void add_smr_deleted_thread_times(uint add_value); - static void clear_smr_delete_notify(); - static ThreadsList* get_smr_java_thread_list(); - static void inc_smr_deleted_thread_cnt(); - static void release_stable_list_fast_path(Thread *self); - static void release_stable_list_nested_path(Thread *self); - static void release_stable_list_wake_up(char *log_str); - static void set_smr_delete_notify(); - static Monitor* smr_delete_lock() { return _smr_delete_lock; } - static bool smr_delete_notify(); - static void smr_free_list(ThreadsList* threads); - static void update_smr_deleted_thread_time_max(uint new_value); - static ThreadsList* xchg_smr_java_thread_list(ThreadsList* new_list); - public: // Thread management // force_daemon is a concession to JNI, where we may need to add a @@ -2191,19 +2149,6 @@ class Threads: AllStatic { static void threads_do(ThreadClosure* tc); static void possibly_parallel_threads_do(bool is_par, ThreadClosure* tc); - // SMR support: - static ThreadsList *acquire_stable_list(Thread *self, bool is_ThreadsListSetter); - static void release_stable_list(Thread *self); - static bool is_a_protected_JavaThread(JavaThread *thread); - static bool is_a_protected_JavaThread_with_lock(JavaThread *thread) { - MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock); - return is_a_protected_JavaThread(thread); - } - static void smr_delete(JavaThread *thread); - static void inc_smr_tlh_cnt(); - static void update_smr_tlh_time_max(uint new_value); - static void add_smr_tlh_times(uint add_value); - // Initializes the vm and creates the vm thread static jint create_vm(JavaVMInitArgs* args, bool* canTryAgain); static void convert_vm_init_libraries_to_agents(); @@ -2264,10 +2209,7 @@ class Threads: AllStatic { // Verification static void verify(); - static void log_smr_statistics(); static void print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks); - static void print_smr_info_on(outputStream* st); - static void print_smr_info_elements_on(outputStream* st, ThreadsList* t_list); static void print(bool print_stacks, bool internal_format) { // this function is only used by debug.cpp print_on(tty, print_stacks, internal_format, false /* no concurrent lock printed */); diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index 3821d9317bf..e98b5d8eacf 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -28,7 +28,6 @@ #include "runtime/atomic.hpp" #include "runtime/os.inline.hpp" #include "runtime/thread.hpp" -#include "runtime/threadSMR.hpp" inline void Thread::set_suspend_flag(SuspendFlags f) { assert(sizeof(jint) == sizeof(_suspend_flags), "size mismatch"); @@ -212,26 +211,4 @@ inline void JavaThread::set_terminated_value() { OrderAccess::release_store((volatile jint *) &_terminated, (jint) _thread_terminated); } -inline void Threads::add_smr_tlh_times(uint add_value) { - Atomic::add(add_value, &_smr_tlh_times); -} - -inline void Threads::inc_smr_tlh_cnt() { - Atomic::inc(&_smr_tlh_cnt); -} - -inline void Threads::update_smr_tlh_time_max(uint new_value) { - while (true) { - uint cur_value = _smr_tlh_time_max; - if (new_value <= cur_value) { - // No need to update max value so we're done. - break; - } - if (Atomic::cmpxchg(new_value, &_smr_tlh_time_max, cur_value) == cur_value) { - // Updated max value so we're done. Otherwise try it all again. - break; - } - } -} - #endif // SHARE_VM_RUNTIME_THREAD_INLINE_HPP diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index 82ecc2590eb..faafbbae05e 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -23,10 +23,357 @@ */ #include "precompiled.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/threadSMR.hpp" +#include "runtime/threadSMR.inline.hpp" #include "services/threadService.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/resourceHash.hpp" + +Monitor* ThreadsSMRSupport::_smr_delete_lock = + new Monitor(Monitor::special, "smr_delete_lock", + false /* allow_vm_block */, + Monitor::_safepoint_check_never); +// The '_cnt', '_max' and '_times" fields are enabled via +// -XX:+EnableThreadSMRStatistics: + +// # of parallel threads in _smr_delete_lock->wait(). +// Impl note: Hard to imagine > 64K waiting threads so this could be 16-bit, +// but there is no nice 16-bit _FORMAT support. +uint ThreadsSMRSupport::_smr_delete_lock_wait_cnt = 0; + +// Max # of parallel threads in _smr_delete_lock->wait(). +// Impl note: See _smr_delete_lock_wait_cnt note. +uint ThreadsSMRSupport::_smr_delete_lock_wait_max = 0; + +// Flag to indicate when an _smr_delete_lock->notify() is needed. +// Impl note: See _smr_delete_lock_wait_cnt note. +volatile uint ThreadsSMRSupport::_smr_delete_notify = 0; + +// # of threads deleted over VM lifetime. +// Impl note: Atomically incremented over VM lifetime so use unsigned for more +// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc +// isn't available everywhere (or is it?). +volatile uint ThreadsSMRSupport::_smr_deleted_thread_cnt = 0; + +// Max time in millis to delete a thread. +// Impl note: 16-bit might be too small on an overloaded machine. Use +// unsigned since this is a time value. Set via Atomic::cmpxchg() in a +// loop for correctness. +volatile uint ThreadsSMRSupport::_smr_deleted_thread_time_max = 0; + +// Cumulative time in millis to delete threads. +// Impl note: Atomically added to over VM lifetime so use unsigned for more +// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc +// isn't available everywhere (or is it?). +volatile uint ThreadsSMRSupport::_smr_deleted_thread_times = 0; + +ThreadsList* volatile ThreadsSMRSupport::_smr_java_thread_list = new ThreadsList(0); + +// # of ThreadsLists allocated over VM lifetime. +// Impl note: We allocate a new ThreadsList for every thread create and +// every thread delete so we need a bigger type than the +// _smr_deleted_thread_cnt field. +uint64_t ThreadsSMRSupport::_smr_java_thread_list_alloc_cnt = 1; + +// # of ThreadsLists freed over VM lifetime. +// Impl note: See _smr_java_thread_list_alloc_cnt note. +uint64_t ThreadsSMRSupport::_smr_java_thread_list_free_cnt = 0; + +// Max size ThreadsList allocated. +// Impl note: Max # of threads alive at one time should fit in unsigned 32-bit. +uint ThreadsSMRSupport::_smr_java_thread_list_max = 0; + +// Max # of nested ThreadsLists for a thread. +// Impl note: Hard to imagine > 64K nested ThreadsLists so this could be +// 16-bit, but there is no nice 16-bit _FORMAT support. +uint ThreadsSMRSupport::_smr_nested_thread_list_max = 0; + +// # of ThreadsListHandles deleted over VM lifetime. +// Impl note: Atomically incremented over VM lifetime so use unsigned for +// more range. There will be fewer ThreadsListHandles than threads so +// unsigned 32-bit should be fine. +volatile uint ThreadsSMRSupport::_smr_tlh_cnt = 0; + +// Max time in millis to delete a ThreadsListHandle. +// Impl note: 16-bit might be too small on an overloaded machine. Use +// unsigned since this is a time value. Set via Atomic::cmpxchg() in a +// loop for correctness. +volatile uint ThreadsSMRSupport::_smr_tlh_time_max = 0; + +// Cumulative time in millis to delete ThreadsListHandles. +// Impl note: Atomically added to over VM lifetime so use unsigned for more +// range. Unsigned 64-bit would be more future proof, but 64-bit atomic inc +// isn't available everywhere (or is it?). +volatile uint ThreadsSMRSupport::_smr_tlh_times = 0; + +ThreadsList* ThreadsSMRSupport::_smr_to_delete_list = NULL; + +// # of parallel ThreadsLists on the to-delete list. +// Impl note: Hard to imagine > 64K ThreadsLists needing to be deleted so +// this could be 16-bit, but there is no nice 16-bit _FORMAT support. +uint ThreadsSMRSupport::_smr_to_delete_list_cnt = 0; + +// Max # of parallel ThreadsLists on the to-delete list. +// Impl note: See _smr_to_delete_list_cnt note. +uint ThreadsSMRSupport::_smr_to_delete_list_max = 0; + + +// 'inline' functions first so the definitions are before first use: + +inline void ThreadsSMRSupport::add_smr_deleted_thread_times(uint add_value) { + Atomic::add(add_value, &_smr_deleted_thread_times); +} + +inline void ThreadsSMRSupport::inc_smr_deleted_thread_cnt() { + Atomic::inc(&_smr_deleted_thread_cnt); +} + +inline void ThreadsSMRSupport::inc_smr_java_thread_list_alloc_cnt() { + _smr_java_thread_list_alloc_cnt++; +} + +inline void ThreadsSMRSupport::update_smr_deleted_thread_time_max(uint new_value) { + while (true) { + uint cur_value = _smr_deleted_thread_time_max; + if (new_value <= cur_value) { + // No need to update max value so we're done. + break; + } + if (Atomic::cmpxchg(new_value, &_smr_deleted_thread_time_max, cur_value) == cur_value) { + // Updated max value so we're done. Otherwise try it all again. + break; + } + } +} + +inline void ThreadsSMRSupport::update_smr_java_thread_list_max(uint new_value) { + if (new_value > _smr_java_thread_list_max) { + _smr_java_thread_list_max = new_value; + } +} + +inline ThreadsList* ThreadsSMRSupport::xchg_smr_java_thread_list(ThreadsList* new_list) { + return (ThreadsList*)Atomic::xchg(new_list, &_smr_java_thread_list); +} + + +// Hash table of pointers found by a scan. Used for collecting hazard +// pointers (ThreadsList references). Also used for collecting JavaThreads +// that are indirectly referenced by hazard ptrs. An instance of this +// class only contains one type of pointer. +// +class ThreadScanHashtable : public CHeapObj { + private: + static bool ptr_equals(void * const& s1, void * const& s2) { + return s1 == s2; + } + + static unsigned int ptr_hash(void * const& s1) { + // 2654435761 = 2^32 * Phi (golden ratio) + return (unsigned int)(((uint32_t)(uintptr_t)s1) * 2654435761u); + } + + int _table_size; + // ResourceHashtable SIZE is specified at compile time so our + // dynamic _table_size is unused for now; 1031 is the first prime + // after 1024. + typedef ResourceHashtable PtrTable; + PtrTable * _ptrs; + + public: + // ResourceHashtable is passed to various functions and populated in + // different places so we allocate it using C_HEAP to make it immune + // from any ResourceMarks that happen to be in the code paths. + ThreadScanHashtable(int table_size) : _table_size(table_size), _ptrs(new (ResourceObj::C_HEAP, mtThread) PtrTable()) {} + + ~ThreadScanHashtable() { delete _ptrs; } + + bool has_entry(void *pointer) { + int *val_ptr = _ptrs->get(pointer); + return val_ptr != NULL && *val_ptr == 1; + } + + void add_entry(void *pointer) { + _ptrs->put(pointer, 1); + } +}; + +// Closure to gather JavaThreads indirectly referenced by hazard ptrs +// (ThreadsList references) into a hash table. This closure handles part 2 +// of the dance - adding all the JavaThreads referenced by the hazard +// pointer (ThreadsList reference) to the hash table. +// +class AddThreadHazardPointerThreadClosure : public ThreadClosure { + private: + ThreadScanHashtable *_table; + + public: + AddThreadHazardPointerThreadClosure(ThreadScanHashtable *table) : _table(table) {} + + virtual void do_thread(Thread *thread) { + if (!_table->has_entry((void*)thread)) { + // The same JavaThread might be on more than one ThreadsList or + // more than one thread might be using the same ThreadsList. In + // either case, we only need a single entry for a JavaThread. + _table->add_entry((void*)thread); + } + } +}; + +// Closure to gather JavaThreads indirectly referenced by hazard ptrs +// (ThreadsList references) into a hash table. This closure handles part 1 +// of the dance - hazard ptr chain walking and dispatch to another +// closure. +// +class ScanHazardPtrGatherProtectedThreadsClosure : public ThreadClosure { + private: + ThreadScanHashtable *_table; + public: + ScanHazardPtrGatherProtectedThreadsClosure(ThreadScanHashtable *table) : _table(table) {} + + virtual void do_thread(Thread *thread) { + assert_locked_or_safepoint(Threads_lock); + + if (thread == NULL) return; + + // This code races with ThreadsSMRSupport::acquire_stable_list() which + // is lock-free so we have to handle some special situations. + // + ThreadsList *current_list = NULL; + while (true) { + current_list = thread->get_threads_hazard_ptr(); + // No hazard ptr so nothing more to do. + if (current_list == NULL) { + assert(thread->get_nested_threads_hazard_ptr() == NULL, + "cannot have a nested hazard ptr with a NULL regular hazard ptr"); + return; + } + + // If the hazard ptr is verified as stable (since it is not tagged), + // then it is safe to use. + if (!Thread::is_hazard_ptr_tagged(current_list)) break; + + // The hazard ptr is tagged as not yet verified as being stable + // so we are racing with acquire_stable_list(). This exchange + // attempts to invalidate the hazard ptr. If we win the race, + // then we can ignore this unstable hazard ptr and the other + // thread will retry the attempt to publish a stable hazard ptr. + // If we lose the race, then we retry our attempt to look at the + // hazard ptr. + if (thread->cmpxchg_threads_hazard_ptr(NULL, current_list) == current_list) return; + } + + // The current JavaThread has a hazard ptr (ThreadsList reference) + // which might be _smr_java_thread_list or it might be an older + // ThreadsList that has been removed but not freed. In either case, + // the hazard ptr is protecting all the JavaThreads on that + // ThreadsList. + AddThreadHazardPointerThreadClosure add_cl(_table); + current_list->threads_do(&add_cl); + + // Any NestedThreadsLists are also protecting JavaThreads so + // gather those also; the ThreadsLists may be different. + for (NestedThreadsList* node = thread->get_nested_threads_hazard_ptr(); + node != NULL; node = node->next()) { + node->t_list()->threads_do(&add_cl); + } + } +}; + +// Closure to gather hazard ptrs (ThreadsList references) into a hash table. +// +class ScanHazardPtrGatherThreadsListClosure : public ThreadClosure { + private: + ThreadScanHashtable *_table; + public: + ScanHazardPtrGatherThreadsListClosure(ThreadScanHashtable *table) : _table(table) {} + + virtual void do_thread(Thread* thread) { + assert_locked_or_safepoint(Threads_lock); + + if (thread == NULL) return; + ThreadsList *threads = thread->get_threads_hazard_ptr(); + if (threads == NULL) { + assert(thread->get_nested_threads_hazard_ptr() == NULL, + "cannot have a nested hazard ptr with a NULL regular hazard ptr"); + return; + } + // In this closure we always ignore the tag that might mark this + // hazard ptr as not yet verified. If we happen to catch an + // unverified hazard ptr that is subsequently discarded (not + // published), then the only side effect is that we might keep a + // to-be-deleted ThreadsList alive a little longer. + threads = Thread::untag_hazard_ptr(threads); + if (!_table->has_entry((void*)threads)) { + _table->add_entry((void*)threads); + } + + // Any NestedThreadsLists are also protecting JavaThreads so + // gather those also; the ThreadsLists may be different. + for (NestedThreadsList* node = thread->get_nested_threads_hazard_ptr(); + node != NULL; node = node->next()) { + threads = node->t_list(); + if (!_table->has_entry((void*)threads)) { + _table->add_entry((void*)threads); + } + } + } +}; + +// Closure to print JavaThreads that have a hazard ptr (ThreadsList +// reference) that contains an indirect reference to a specific JavaThread. +// +class ScanHazardPtrPrintMatchingThreadsClosure : public ThreadClosure { + private: + JavaThread *_thread; + public: + ScanHazardPtrPrintMatchingThreadsClosure(JavaThread *thread) : _thread(thread) {} + + virtual void do_thread(Thread *thread) { + assert_locked_or_safepoint(Threads_lock); + + if (thread == NULL) return; + ThreadsList *current_list = thread->get_threads_hazard_ptr(); + if (current_list == NULL) { + assert(thread->get_nested_threads_hazard_ptr() == NULL, + "cannot have a nested hazard ptr with a NULL regular hazard ptr"); + return; + } + // If the hazard ptr is unverified, then ignore it. + if (Thread::is_hazard_ptr_tagged(current_list)) return; + + // The current JavaThread has a hazard ptr (ThreadsList reference) + // which might be _smr_java_thread_list or it might be an older + // ThreadsList that has been removed but not freed. In either case, + // the hazard ptr is protecting all the JavaThreads on that + // ThreadsList, but we only care about matching a specific JavaThread. + JavaThreadIterator jti(current_list); + for (JavaThread *p = jti.first(); p != NULL; p = jti.next()) { + if (p == _thread) { + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread1=" INTPTR_FORMAT " has a hazard pointer for thread2=" INTPTR_FORMAT, os::current_thread_id(), p2i(thread), p2i(_thread)); + break; + } + } + + // Any NestedThreadsLists are also protecting JavaThreads so + // check those also; the ThreadsLists may be different. + for (NestedThreadsList* node = thread->get_nested_threads_hazard_ptr(); + node != NULL; node = node->next()) { + JavaThreadIterator jti(node->t_list()); + for (JavaThread *p = jti.first(); p != NULL; p = jti.next()) { + if (p == _thread) { + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread1=" INTPTR_FORMAT " has a nested hazard pointer for thread2=" INTPTR_FORMAT, os::current_thread_id(), p2i(thread), p2i(_thread)); + return; + } + } + } + } +}; + // 'entries + 1' so we always have at least one entry. ThreadsList::ThreadsList(int entries) : _length(entries), _threads(NEW_C_HEAP_ARRAY(JavaThread*, entries + 1, mtThread)), _next_list(NULL) { @@ -37,20 +384,87 @@ ThreadsList::~ThreadsList() { FREE_C_HEAP_ARRAY(JavaThread*, _threads); } -ThreadsListSetter::~ThreadsListSetter() { - if (_target_needs_release) { - // The hazard ptr in the target needs to be released. - Threads::release_stable_list(_target); +// Add a JavaThread to a ThreadsList. The returned ThreadsList is a +// new copy of the specified ThreadsList with the specified JavaThread +// appended to the end. +ThreadsList *ThreadsList::add_thread(ThreadsList *list, JavaThread *java_thread) { + const uint index = list->_length; + const uint new_length = index + 1; + const uint head_length = index; + ThreadsList *const new_list = new ThreadsList(new_length); + + if (head_length > 0) { + Copy::disjoint_words((HeapWord*)list->_threads, (HeapWord*)new_list->_threads, head_length); } + *(JavaThread**)(new_list->_threads + index) = java_thread; + + return new_list; } -void ThreadsListSetter::set() { - assert(_target->get_threads_hazard_ptr() == NULL, "hazard ptr should not already be set"); - (void) Threads::acquire_stable_list(_target, /* is_ThreadsListSetter */ true); - _target_needs_release = true; +int ThreadsList::find_index_of_JavaThread(JavaThread *target) { + if (target == NULL) { + return -1; + } + for (uint i = 0; i < length(); i++) { + if (target == thread_at(i)) { + return (int)i; + } + } + return -1; } -ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(Threads::acquire_stable_list(self, /* is_ThreadsListSetter */ false)), _self(self) { +JavaThread* ThreadsList::find_JavaThread_from_java_tid(jlong java_tid) const { + for (uint i = 0; i < length(); i++) { + JavaThread* thread = thread_at(i); + oop tobj = thread->threadObj(); + // Ignore the thread if it hasn't run yet, has exited + // or is starting to exit. + if (tobj != NULL && !thread->is_exiting() && + java_tid == java_lang_Thread::thread_id(tobj)) { + // found a match + return thread; + } + } + return NULL; +} + +bool ThreadsList::includes(const JavaThread * const p) const { + if (p == NULL) { + return false; + } + for (uint i = 0; i < length(); i++) { + if (thread_at(i) == p) { + return true; + } + } + return false; +} + +// Remove a JavaThread from a ThreadsList. The returned ThreadsList is a +// new copy of the specified ThreadsList with the specified JavaThread +// removed. +ThreadsList *ThreadsList::remove_thread(ThreadsList* list, JavaThread* java_thread) { + assert(list->_length > 0, "sanity"); + + uint i = (uint)list->find_index_of_JavaThread(java_thread); + assert(i < list->_length, "did not find JavaThread on the list"); + const uint index = i; + const uint new_length = list->_length - 1; + const uint head_length = index; + const uint tail_length = (new_length >= index) ? (new_length - index) : 0; + ThreadsList *const new_list = new ThreadsList(new_length); + + if (head_length > 0) { + Copy::disjoint_words((HeapWord*)list->_threads, (HeapWord*)new_list->_threads, head_length); + } + if (tail_length > 0) { + Copy::disjoint_words((HeapWord*)list->_threads + index + 1, (HeapWord*)new_list->_threads + index, tail_length); + } + + return new_list; +} + +ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(ThreadsSMRSupport::acquire_stable_list(self, /* is_ThreadsListSetter */ false)), _self(self) { assert(self == Thread::current(), "sanity check"); if (EnableThreadSMRStatistics) { _timer.start(); @@ -58,13 +472,11 @@ ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(Threads::acquire_stab } ThreadsListHandle::~ThreadsListHandle() { - Threads::release_stable_list(_self); + ThreadsSMRSupport::release_stable_list(_self); if (EnableThreadSMRStatistics) { _timer.stop(); uint millis = (uint)_timer.milliseconds(); - Threads::inc_smr_tlh_cnt(); - Threads::add_smr_tlh_times(millis); - Threads::update_smr_tlh_time_max(millis); + ThreadsSMRSupport::update_smr_tlh_stats(millis); } } @@ -119,3 +531,546 @@ bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread, *jt_pp = java_thread; return true; } + +ThreadsListSetter::~ThreadsListSetter() { + if (_target_needs_release) { + // The hazard ptr in the target needs to be released. + ThreadsSMRSupport::release_stable_list(_target); + } +} + +void ThreadsListSetter::set() { + assert(_target->get_threads_hazard_ptr() == NULL, "hazard ptr should not already be set"); + (void) ThreadsSMRSupport::acquire_stable_list(_target, /* is_ThreadsListSetter */ true); + _target_needs_release = true; +} + +// Acquire a stable ThreadsList. +// +ThreadsList *ThreadsSMRSupport::acquire_stable_list(Thread *self, bool is_ThreadsListSetter) { + assert(self != NULL, "sanity check"); + // acquire_stable_list_nested_path() will grab the Threads_lock + // so let's make sure the ThreadsListHandle is in a safe place. + // ThreadsListSetter cannot make this check on this code path. + debug_only(if (!is_ThreadsListSetter && StrictSafepointChecks) self->check_for_valid_safepoint_state(/* potential_vm_operation */ false);) + + if (self->get_threads_hazard_ptr() == NULL) { + // The typical case is first. + return acquire_stable_list_fast_path(self); + } + + // The nested case is rare. + return acquire_stable_list_nested_path(self); +} + +// Fast path (and lock free) way to acquire a stable ThreadsList. +// +ThreadsList *ThreadsSMRSupport::acquire_stable_list_fast_path(Thread *self) { + assert(self != NULL, "sanity check"); + assert(self->get_threads_hazard_ptr() == NULL, "sanity check"); + assert(self->get_nested_threads_hazard_ptr() == NULL, + "cannot have a nested hazard ptr with a NULL regular hazard ptr"); + + ThreadsList* threads; + + // Stable recording of a hazard ptr for SMR. This code does not use + // locks so its use of the _smr_java_thread_list & _threads_hazard_ptr + // fields is racy relative to code that uses those fields with locks. + // OrderAccess and Atomic functions are used to deal with those races. + // + while (true) { + threads = get_smr_java_thread_list(); + + // Publish a tagged hazard ptr to denote that the hazard ptr is not + // yet verified as being stable. Due to the fence after the hazard + // ptr write, it will be sequentially consistent w.r.t. the + // sequentially consistent writes of the ThreadsList, even on + // non-multiple copy atomic machines where stores can be observed + // in different order from different observer threads. + ThreadsList* unverified_threads = Thread::tag_hazard_ptr(threads); + self->set_threads_hazard_ptr(unverified_threads); + + // If _smr_java_thread_list has changed, we have lost a race with + // Threads::add() or Threads::remove() and have to try again. + if (get_smr_java_thread_list() != threads) { + continue; + } + + // We try to remove the tag which will verify the hazard ptr as + // being stable. This exchange can race with a scanning thread + // which might invalidate the tagged hazard ptr to keep it from + // being followed to access JavaThread ptrs. If we lose the race, + // we simply retry. If we win the race, then the stable hazard + // ptr is officially published. + if (self->cmpxchg_threads_hazard_ptr(threads, unverified_threads) == unverified_threads) { + break; + } + } + + // A stable hazard ptr has been published letting other threads know + // that the ThreadsList and the JavaThreads reachable from this list + // are protected and hence they should not be deleted until everyone + // agrees it is safe to do so. + + return threads; +} + +// Acquire a nested stable ThreadsList; this is rare so it uses +// Threads_lock. +// +ThreadsList *ThreadsSMRSupport::acquire_stable_list_nested_path(Thread *self) { + assert(self != NULL, "sanity check"); + assert(self->get_threads_hazard_ptr() != NULL, + "cannot have a NULL regular hazard ptr when acquiring a nested hazard ptr"); + + // The thread already has a hazard ptr (ThreadsList ref) so we need + // to create a nested ThreadsListHandle with the current ThreadsList + // since it might be different than our current hazard ptr. The need + // for a nested ThreadsListHandle is rare so we do this while holding + // the Threads_lock so we don't race with the scanning code; the code + // is so much simpler this way. + + NestedThreadsList* node; + { + // Only grab the Threads_lock if we don't already own it. + MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock); + node = new NestedThreadsList(get_smr_java_thread_list()); + // We insert at the front of the list to match up with the delete + // in release_stable_list(). + node->set_next(self->get_nested_threads_hazard_ptr()); + self->set_nested_threads_hazard_ptr(node); + if (EnableThreadSMRStatistics) { + self->inc_nested_threads_hazard_ptr_cnt(); + if (self->nested_threads_hazard_ptr_cnt() > _smr_nested_thread_list_max) { + _smr_nested_thread_list_max = self->nested_threads_hazard_ptr_cnt(); + } + } + } + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::acquire_stable_list: add NestedThreadsList node containing ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(node->t_list())); + + return node->t_list(); +} + +void ThreadsSMRSupport::add_thread(JavaThread *thread){ + ThreadsList *new_list = ThreadsList::add_thread(ThreadsSMRSupport::get_smr_java_thread_list(), thread); + if (EnableThreadSMRStatistics) { + ThreadsSMRSupport::inc_smr_java_thread_list_alloc_cnt(); + ThreadsSMRSupport::update_smr_java_thread_list_max(new_list->length()); + } + // Initial _smr_java_thread_list will not generate a "Threads::add" mesg. + log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::add: new ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(new_list)); + + ThreadsList *old_list = ThreadsSMRSupport::xchg_smr_java_thread_list(new_list); + ThreadsSMRSupport::smr_free_list(old_list); +} + +// set_smr_delete_notify() and clear_smr_delete_notify() are called +// under the protection of the smr_delete_lock, but we also use an +// Atomic operation to ensure the memory update is seen earlier than +// when the smr_delete_lock is dropped. +// +void ThreadsSMRSupport::clear_smr_delete_notify() { + Atomic::dec(&_smr_delete_notify); +} + +// Return true if the specified JavaThread is protected by a hazard +// pointer (ThreadsList reference). Otherwise, returns false. +// +bool ThreadsSMRSupport::is_a_protected_JavaThread(JavaThread *thread) { + assert_locked_or_safepoint(Threads_lock); + + // Hash table size should be first power of two higher than twice + // the length of the Threads list. + int hash_table_size = MIN2((int)get_smr_java_thread_list()->length(), 32) << 1; + hash_table_size--; + hash_table_size |= hash_table_size >> 1; + hash_table_size |= hash_table_size >> 2; + hash_table_size |= hash_table_size >> 4; + hash_table_size |= hash_table_size >> 8; + hash_table_size |= hash_table_size >> 16; + hash_table_size++; + + // Gather a hash table of the JavaThreads indirectly referenced by + // hazard ptrs. + ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size); + ScanHazardPtrGatherProtectedThreadsClosure scan_cl(scan_table); + Threads::threads_do(&scan_cl); + + bool thread_is_protected = false; + if (scan_table->has_entry((void*)thread)) { + thread_is_protected = true; + } + delete scan_table; + return thread_is_protected; +} + +// Release a stable ThreadsList. +// +void ThreadsSMRSupport::release_stable_list(Thread *self) { + assert(self != NULL, "sanity check"); + // release_stable_list_nested_path() will grab the Threads_lock + // so let's make sure the ThreadsListHandle is in a safe place. + debug_only(if (StrictSafepointChecks) self->check_for_valid_safepoint_state(/* potential_vm_operation */ false);) + + if (self->get_nested_threads_hazard_ptr() == NULL) { + // The typical case is first. + release_stable_list_fast_path(self); + return; + } + + // The nested case is rare. + release_stable_list_nested_path(self); +} + +// Fast path way to release a stable ThreadsList. The release portion +// is lock-free, but the wake up portion is not. +// +void ThreadsSMRSupport::release_stable_list_fast_path(Thread *self) { + assert(self != NULL, "sanity check"); + assert(self->get_threads_hazard_ptr() != NULL, "sanity check"); + assert(self->get_nested_threads_hazard_ptr() == NULL, + "cannot have a nested hazard ptr when releasing a regular hazard ptr"); + + // After releasing the hazard ptr, other threads may go ahead and + // free up some memory temporarily used by a ThreadsList snapshot. + self->set_threads_hazard_ptr(NULL); + + // We use double-check locking to reduce traffic on the system + // wide smr_delete_lock. + if (ThreadsSMRSupport::smr_delete_notify()) { + // An exiting thread might be waiting in smr_delete(); we need to + // check with smr_delete_lock to be sure. + release_stable_list_wake_up((char *) "regular hazard ptr"); + } +} + +// Release a nested stable ThreadsList; this is rare so it uses +// Threads_lock. +// +void ThreadsSMRSupport::release_stable_list_nested_path(Thread *self) { + assert(self != NULL, "sanity check"); + assert(self->get_nested_threads_hazard_ptr() != NULL, "sanity check"); + assert(self->get_threads_hazard_ptr() != NULL, + "must have a regular hazard ptr to have nested hazard ptrs"); + + // We have a nested ThreadsListHandle so we have to release it first. + // The need for a nested ThreadsListHandle is rare so we do this while + // holding the Threads_lock so we don't race with the scanning code; + // the code is so much simpler this way. + + NestedThreadsList *node; + { + // Only grab the Threads_lock if we don't already own it. + MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock); + // We remove from the front of the list to match up with the insert + // in acquire_stable_list(). + node = self->get_nested_threads_hazard_ptr(); + self->set_nested_threads_hazard_ptr(node->next()); + if (EnableThreadSMRStatistics) { + self->dec_nested_threads_hazard_ptr_cnt(); + } + } + + // An exiting thread might be waiting in smr_delete(); we need to + // check with smr_delete_lock to be sure. + release_stable_list_wake_up((char *) "nested hazard ptr"); + + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::release_stable_list: delete NestedThreadsList node containing ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(node->t_list())); + + delete node; +} + +// Wake up portion of the release stable ThreadsList protocol; +// uses the smr_delete_lock(). +// +void ThreadsSMRSupport::release_stable_list_wake_up(char *log_str) { + assert(log_str != NULL, "sanity check"); + + // Note: smr_delete_lock is held in smr_delete() for the entire + // hazard ptr search so that we do not lose this notify() if + // the exiting thread has to wait. That code path also holds + // Threads_lock (which was grabbed before smr_delete_lock) so that + // threads_do() can be called. This means the system can't start a + // safepoint which means this thread can't take too long to get to + // a safepoint because of being blocked on smr_delete_lock. + // + MonitorLockerEx ml(ThreadsSMRSupport::smr_delete_lock(), Monitor::_no_safepoint_check_flag); + if (ThreadsSMRSupport::smr_delete_notify()) { + // Notify any exiting JavaThreads that are waiting in smr_delete() + // that we've released a ThreadsList. + ml.notify_all(); + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::release_stable_list notified %s", os::current_thread_id(), log_str); + } +} + +void ThreadsSMRSupport::remove_thread(JavaThread *thread) { + ThreadsList *new_list = ThreadsList::remove_thread(ThreadsSMRSupport::get_smr_java_thread_list(), thread); + if (EnableThreadSMRStatistics) { + ThreadsSMRSupport::inc_smr_java_thread_list_alloc_cnt(); + // This list is smaller so no need to check for a "longest" update. + } + + // Final _smr_java_thread_list will not generate a "Threads::remove" mesg. + log_debug(thread, smr)("tid=" UINTX_FORMAT ": Threads::remove: new ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(new_list)); + + ThreadsList *old_list = ThreadsSMRSupport::xchg_smr_java_thread_list(new_list); + ThreadsSMRSupport::smr_free_list(old_list); +} + +// See note for clear_smr_delete_notify(). +// +void ThreadsSMRSupport::set_smr_delete_notify() { + Atomic::inc(&_smr_delete_notify); +} + +// Safely delete a JavaThread when it is no longer in use by a +// ThreadsListHandle. +// +void ThreadsSMRSupport::smr_delete(JavaThread *thread) { + assert(!Threads_lock->owned_by_self(), "sanity"); + + bool has_logged_once = false; + elapsedTimer timer; + if (EnableThreadSMRStatistics) { + timer.start(); + } + + while (true) { + { + // No safepoint check because this JavaThread is not on the + // Threads list. + MutexLockerEx ml(Threads_lock, Mutex::_no_safepoint_check_flag); + // Cannot use a MonitorLockerEx helper here because we have + // to drop the Threads_lock first if we wait. + ThreadsSMRSupport::smr_delete_lock()->lock_without_safepoint_check(); + // Set the smr_delete_notify flag after we grab smr_delete_lock + // and before we scan hazard ptrs because we're doing + // double-check locking in release_stable_list(). + ThreadsSMRSupport::set_smr_delete_notify(); + + if (!is_a_protected_JavaThread(thread)) { + // This is the common case. + ThreadsSMRSupport::clear_smr_delete_notify(); + ThreadsSMRSupport::smr_delete_lock()->unlock(); + break; + } + if (!has_logged_once) { + has_logged_once = true; + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread=" INTPTR_FORMAT " is not deleted.", os::current_thread_id(), p2i(thread)); + if (log_is_enabled(Debug, os, thread)) { + ScanHazardPtrPrintMatchingThreadsClosure scan_cl(thread); + Threads::threads_do(&scan_cl); + } + } + } // We have to drop the Threads_lock to wait or delete the thread + + if (EnableThreadSMRStatistics) { + _smr_delete_lock_wait_cnt++; + if (_smr_delete_lock_wait_cnt > _smr_delete_lock_wait_max) { + _smr_delete_lock_wait_max = _smr_delete_lock_wait_cnt; + } + } + // Wait for a release_stable_list() call before we check again. No + // safepoint check, no timeout, and not as suspend equivalent flag + // because this JavaThread is not on the Threads list. + ThreadsSMRSupport::smr_delete_lock()->wait(Mutex::_no_safepoint_check_flag, 0, + !Mutex::_as_suspend_equivalent_flag); + if (EnableThreadSMRStatistics) { + _smr_delete_lock_wait_cnt--; + } + + ThreadsSMRSupport::clear_smr_delete_notify(); + ThreadsSMRSupport::smr_delete_lock()->unlock(); + // Retry the whole scenario. + } + + if (ThreadLocalHandshakes) { + // The thread is about to be deleted so cancel any handshake. + thread->cancel_handshake(); + } + + delete thread; + if (EnableThreadSMRStatistics) { + timer.stop(); + uint millis = (uint)timer.milliseconds(); + ThreadsSMRSupport::inc_smr_deleted_thread_cnt(); + ThreadsSMRSupport::add_smr_deleted_thread_times(millis); + ThreadsSMRSupport::update_smr_deleted_thread_time_max(millis); + } + + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread=" INTPTR_FORMAT " is deleted.", os::current_thread_id(), p2i(thread)); +} + +bool ThreadsSMRSupport::smr_delete_notify() { + // Use load_acquire() in order to see any updates to _smr_delete_notify + // earlier than when smr_delete_lock is grabbed. + return (OrderAccess::load_acquire(&_smr_delete_notify) != 0); +} + +// Safely free a ThreadsList after a Threads::add() or Threads::remove(). +// The specified ThreadsList may not get deleted during this call if it +// is still in-use (referenced by a hazard ptr). Other ThreadsLists +// in the chain may get deleted by this call if they are no longer in-use. +void ThreadsSMRSupport::smr_free_list(ThreadsList* threads) { + assert_locked_or_safepoint(Threads_lock); + + threads->set_next_list(_smr_to_delete_list); + _smr_to_delete_list = threads; + if (EnableThreadSMRStatistics) { + _smr_to_delete_list_cnt++; + if (_smr_to_delete_list_cnt > _smr_to_delete_list_max) { + _smr_to_delete_list_max = _smr_to_delete_list_cnt; + } + } + + // Hash table size should be first power of two higher than twice the length of the ThreadsList + int hash_table_size = MIN2((int)get_smr_java_thread_list()->length(), 32) << 1; + hash_table_size--; + hash_table_size |= hash_table_size >> 1; + hash_table_size |= hash_table_size >> 2; + hash_table_size |= hash_table_size >> 4; + hash_table_size |= hash_table_size >> 8; + hash_table_size |= hash_table_size >> 16; + hash_table_size++; + + // Gather a hash table of the current hazard ptrs: + ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size); + ScanHazardPtrGatherThreadsListClosure scan_cl(scan_table); + Threads::threads_do(&scan_cl); + + // Walk through the linked list of pending freeable ThreadsLists + // and free the ones that are not referenced from hazard ptrs. + ThreadsList* current = _smr_to_delete_list; + ThreadsList* prev = NULL; + ThreadsList* next = NULL; + bool threads_is_freed = false; + while (current != NULL) { + next = current->next_list(); + if (!scan_table->has_entry((void*)current)) { + // This ThreadsList is not referenced by a hazard ptr. + if (prev != NULL) { + prev->set_next_list(next); + } + if (_smr_to_delete_list == current) { + _smr_to_delete_list = next; + } + + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_free_list: threads=" INTPTR_FORMAT " is freed.", os::current_thread_id(), p2i(current)); + if (current == threads) threads_is_freed = true; + delete current; + if (EnableThreadSMRStatistics) { + _smr_java_thread_list_free_cnt++; + _smr_to_delete_list_cnt--; + } + } else { + prev = current; + } + current = next; + } + + if (!threads_is_freed) { + // Only report "is not freed" on the original call to + // smr_free_list() for this ThreadsList. + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_free_list: threads=" INTPTR_FORMAT " is not freed.", os::current_thread_id(), p2i(threads)); + } + + delete scan_table; +} + + +// Debug, logging, and printing stuff at the end: + +// Log Threads class SMR info. +void ThreadsSMRSupport::log_smr_statistics() { + LogTarget(Info, thread, smr) log; + if (log.is_enabled()) { + LogStream out(log); + print_smr_info_on(&out); + } +} + +// Print Threads class SMR info. +void ThreadsSMRSupport::print_smr_info_on(outputStream* st) { + // Only grab the Threads_lock if we don't already own it + // and if we are not reporting an error. + MutexLockerEx ml((Threads_lock->owned_by_self() || VMError::is_error_reported()) ? NULL : Threads_lock); + + st->print_cr("Threads class SMR info:"); + st->print_cr("_smr_java_thread_list=" INTPTR_FORMAT ", length=%u, " + "elements={", p2i(_smr_java_thread_list), + _smr_java_thread_list->length()); + print_smr_info_elements_on(st, _smr_java_thread_list); + st->print_cr("}"); + if (_smr_to_delete_list != NULL) { + st->print_cr("_smr_to_delete_list=" INTPTR_FORMAT ", length=%u, " + "elements={", p2i(_smr_to_delete_list), + _smr_to_delete_list->length()); + print_smr_info_elements_on(st, _smr_to_delete_list); + st->print_cr("}"); + for (ThreadsList *t_list = _smr_to_delete_list->next_list(); + t_list != NULL; t_list = t_list->next_list()) { + st->print("next-> " INTPTR_FORMAT ", length=%u, " + "elements={", p2i(t_list), t_list->length()); + print_smr_info_elements_on(st, t_list); + st->print_cr("}"); + } + } + if (!EnableThreadSMRStatistics) { + return; + } + st->print_cr("_smr_java_thread_list_alloc_cnt=" UINT64_FORMAT "," + "_smr_java_thread_list_free_cnt=" UINT64_FORMAT "," + "_smr_java_thread_list_max=%u, " + "_smr_nested_thread_list_max=%u", + _smr_java_thread_list_alloc_cnt, + _smr_java_thread_list_free_cnt, + _smr_java_thread_list_max, + _smr_nested_thread_list_max); + if (_smr_tlh_cnt > 0) { + st->print_cr("_smr_tlh_cnt=%u" + ", _smr_tlh_times=%u" + ", avg_smr_tlh_time=%0.2f" + ", _smr_tlh_time_max=%u", + _smr_tlh_cnt, _smr_tlh_times, + ((double) _smr_tlh_times / _smr_tlh_cnt), + _smr_tlh_time_max); + } + if (_smr_deleted_thread_cnt > 0) { + st->print_cr("_smr_deleted_thread_cnt=%u" + ", _smr_deleted_thread_times=%u" + ", avg_smr_deleted_thread_time=%0.2f" + ", _smr_deleted_thread_time_max=%u", + _smr_deleted_thread_cnt, _smr_deleted_thread_times, + ((double) _smr_deleted_thread_times / _smr_deleted_thread_cnt), + _smr_deleted_thread_time_max); + } + st->print_cr("_smr_delete_lock_wait_cnt=%u, _smr_delete_lock_wait_max=%u", + _smr_delete_lock_wait_cnt, _smr_delete_lock_wait_max); + st->print_cr("_smr_to_delete_list_cnt=%u, _smr_to_delete_list_max=%u", + _smr_to_delete_list_cnt, _smr_to_delete_list_max); +} + +// Print ThreadsList elements (4 per line). +void ThreadsSMRSupport::print_smr_info_elements_on(outputStream* st, + ThreadsList* t_list) { + uint cnt = 0; + JavaThreadIterator jti(t_list); + for (JavaThread *jt = jti.first(); jt != NULL; jt = jti.next()) { + st->print(INTPTR_FORMAT, p2i(jt)); + if (cnt < t_list->length() - 1) { + // Separate with comma or comma-space except for the last one. + if (((cnt + 1) % 4) == 0) { + // Four INTPTR_FORMAT fit on an 80 column line so end the + // current line with just a comma. + st->print_cr(","); + } else { + // Not the last one on the current line so use comma-space: + st->print(", "); + } + } else { + // Last one so just end the current line. + st->cr(); + } + cnt++; + } +} diff --git a/src/hotspot/share/runtime/threadSMR.hpp b/src/hotspot/share/runtime/threadSMR.hpp index 1e177b7f435..cb41daf4d6f 100644 --- a/src/hotspot/share/runtime/threadSMR.hpp +++ b/src/hotspot/share/runtime/threadSMR.hpp @@ -77,11 +77,77 @@ // longer protected by a ThreadsListHandle. +// SMR Support for the Threads class. +// +class ThreadsSMRSupport : AllStatic { + // The coordination between ThreadsSMRSupport::release_stable_list() and + // ThreadsSMRSupport::smr_delete() uses the smr_delete_lock in order to + // reduce the traffic on the Threads_lock. + static Monitor* _smr_delete_lock; + // The '_cnt', '_max' and '_times" fields are enabled via + // -XX:+EnableThreadSMRStatistics (see thread.cpp for a + // description about each field): + static uint _smr_delete_lock_wait_cnt; + static uint _smr_delete_lock_wait_max; + // The smr_delete_notify flag is used for proper double-check + // locking in order to reduce the traffic on the smr_delete_lock. + static volatile uint _smr_delete_notify; + static volatile uint _smr_deleted_thread_cnt; + static volatile uint _smr_deleted_thread_time_max; + static volatile uint _smr_deleted_thread_times; + static ThreadsList* volatile _smr_java_thread_list; + static uint64_t _smr_java_thread_list_alloc_cnt; + static uint64_t _smr_java_thread_list_free_cnt; + static uint _smr_java_thread_list_max; + static uint _smr_nested_thread_list_max; + static volatile uint _smr_tlh_cnt; + static volatile uint _smr_tlh_time_max; + static volatile uint _smr_tlh_times; + static ThreadsList* _smr_to_delete_list; + static uint _smr_to_delete_list_cnt; + static uint _smr_to_delete_list_max; + + static ThreadsList *acquire_stable_list_fast_path(Thread *self); + static ThreadsList *acquire_stable_list_nested_path(Thread *self); + static void add_smr_deleted_thread_times(uint add_value); + static void add_smr_tlh_times(uint add_value); + static void clear_smr_delete_notify(); + static void inc_smr_deleted_thread_cnt(); + static void inc_smr_java_thread_list_alloc_cnt(); + static void inc_smr_tlh_cnt(); + static bool is_a_protected_JavaThread(JavaThread *thread); + static void release_stable_list_fast_path(Thread *self); + static void release_stable_list_nested_path(Thread *self); + static void release_stable_list_wake_up(char *log_str); + static void set_smr_delete_notify(); + static Monitor* smr_delete_lock() { return _smr_delete_lock; } + static bool smr_delete_notify(); + static void smr_free_list(ThreadsList* threads); + static void update_smr_deleted_thread_time_max(uint new_value); + static void update_smr_java_thread_list_max(uint new_value); + static void update_smr_tlh_time_max(uint new_value); + static ThreadsList* xchg_smr_java_thread_list(ThreadsList* new_list); + + public: + static ThreadsList *acquire_stable_list(Thread *self, bool is_ThreadsListSetter); + static void add_thread(JavaThread *thread); + static ThreadsList* get_smr_java_thread_list(); + static bool is_a_protected_JavaThread_with_lock(JavaThread *thread); + static void release_stable_list(Thread *self); + static void remove_thread(JavaThread *thread); + static void smr_delete(JavaThread *thread); + static void update_smr_tlh_stats(uint millis); + + // Logging and printing support: + static void log_smr_statistics(); + static void print_smr_info_elements_on(outputStream* st, ThreadsList* t_list); + static void print_smr_info_on(outputStream* st); +}; + // A fast list of JavaThreads. // class ThreadsList : public CHeapObj { - friend class ScanHazardPtrGatherProtectedThreadsClosure; - friend class Threads; + friend class ThreadsSMRSupport; // for next_list(), set_next_list() access const uint _length; ThreadsList* _next_list; @@ -93,6 +159,9 @@ class ThreadsList : public CHeapObj { ThreadsList *next_list() const { return _next_list; } void set_next_list(ThreadsList *list) { _next_list = list; } + static ThreadsList* add_thread(ThreadsList* list, JavaThread* java_thread); + static ThreadsList* remove_thread(ThreadsList* list, JavaThread* java_thread); + public: ThreadsList(int entries); ~ThreadsList(); @@ -110,9 +179,6 @@ public: int find_index_of_JavaThread(JavaThread* target); JavaThread* find_JavaThread_from_java_tid(jlong java_tid) const; bool includes(const JavaThread * const p) const; - - static ThreadsList* add_thread(ThreadsList* list, JavaThread* java_thread); - static ThreadsList* remove_thread(ThreadsList* list, JavaThread* java_thread); }; // Linked list of ThreadsLists to support nested ThreadsListHandles. diff --git a/src/hotspot/share/runtime/threadSMR.inline.hpp b/src/hotspot/share/runtime/threadSMR.inline.hpp index 0203fc6e55f..d516cd39308 100644 --- a/src/hotspot/share/runtime/threadSMR.inline.hpp +++ b/src/hotspot/share/runtime/threadSMR.inline.hpp @@ -52,6 +52,32 @@ inline void ThreadsList::threads_do(T *cl) const { } } +// These three inlines are private to ThreadsSMRSupport, but +// they are called by public inline update_smr_tlh_stats() below: + +inline void ThreadsSMRSupport::add_smr_tlh_times(uint add_value) { + Atomic::add(add_value, &_smr_tlh_times); +} + +inline void ThreadsSMRSupport::inc_smr_tlh_cnt() { + Atomic::inc(&_smr_tlh_cnt); +} + +inline void ThreadsSMRSupport::update_smr_tlh_time_max(uint new_value) { + while (true) { + uint cur_value = _smr_tlh_time_max; + if (new_value <= cur_value) { + // No need to update max value so we're done. + break; + } + if (Atomic::cmpxchg(new_value, &_smr_tlh_time_max, cur_value) == cur_value) { + // Updated max value so we're done. Otherwise try it all again. + break; + } + } +} + + inline ThreadsList* ThreadsListSetter::list() { ThreadsList *ret = _target->get_threads_hazard_ptr(); assert(ret != NULL, "hazard ptr should be set"); @@ -59,4 +85,19 @@ inline ThreadsList* ThreadsListSetter::list() { return ret; } +inline ThreadsList* ThreadsSMRSupport::get_smr_java_thread_list() { + return (ThreadsList*)OrderAccess::load_acquire(&_smr_java_thread_list); +} + +inline bool ThreadsSMRSupport::is_a_protected_JavaThread_with_lock(JavaThread *thread) { + MutexLockerEx ml(Threads_lock->owned_by_self() ? NULL : Threads_lock); + return is_a_protected_JavaThread(thread); +} + +inline void ThreadsSMRSupport::update_smr_tlh_stats(uint millis) { + ThreadsSMRSupport::inc_smr_tlh_cnt(); + ThreadsSMRSupport::add_smr_tlh_times(millis); + ThreadsSMRSupport::update_smr_tlh_time_max(millis); +} + #endif // SHARE_VM_RUNTIME_THREADSMR_INLINE_HPP diff --git a/src/hotspot/share/runtime/vm_operations.hpp b/src/hotspot/share/runtime/vm_operations.hpp index 3311ee8be25..145337a8d01 100644 --- a/src/hotspot/share/runtime/vm_operations.hpp +++ b/src/hotspot/share/runtime/vm_operations.hpp @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" #include "oops/oop.hpp" #include "runtime/thread.hpp" +#include "runtime/threadSMR.hpp" #include "code/codeCache.hpp" // The following classes are used for operations diff --git a/src/hotspot/share/services/threadService.hpp b/src/hotspot/share/services/threadService.hpp index 950482e462d..8643dd8878d 100644 --- a/src/hotspot/share/services/threadService.hpp +++ b/src/hotspot/share/services/threadService.hpp @@ -33,6 +33,7 @@ #include "runtime/objectMonitor.inline.hpp" #include "runtime/perfData.hpp" #include "runtime/thread.hpp" +#include "runtime/threadSMR.hpp" #include "services/management.hpp" #include "services/serviceUtil.hpp" From 3d7e063f0ff4d50c8965c39f2bd76dc9c4c10812 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Wed, 6 Dec 2017 20:06:43 -0500 Subject: [PATCH 17/22] 8193065: [TESTBUG] [TESTBUG]GCSharedStringsDuringDump.java: Exception in thread "main" java.lang.RuntimeException: String is not shared Check if 'oa' region is missing. Reviewed-by: hseigel, ccheung --- .../jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java b/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java index 38e23c31a30..8faffaaf14e 100644 --- a/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java +++ b/test/hotspot/jtreg/runtime/appcds/javaldr/GCSharedStringsDuringDump.java @@ -101,6 +101,7 @@ public class GCSharedStringsDuringDump { if (output.getStdout().contains("Too many string space regions") || output.getStderr().contains("Unable to write archive heap memory regions") || output.getStdout().contains("Try increasing NewSize") || + !output.getStdout().contains("oa0 space:") || output.getExitValue() != 0) { // Try again with larger heap and NewSize, this should increase the // G1 heap region size to 2M From f390377be21df5b2ed2e1908f3aeb078d4a2e4b3 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Wed, 6 Dec 2017 18:37:57 -0800 Subject: [PATCH 18/22] 8193009: compiler/c2/Test7029152.java crashes with SIGILL in java.lang.StringLatin1.indexOf with -XX:+UseJVMCICompiler Reviewed-by: iveresov, kvn --- src/hotspot/cpu/x86/nativeInst_x86.hpp | 11 ++--- src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp | 42 ++++++++++++++++++-- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp index 436a48caf34..de4b448396b 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp @@ -706,14 +706,11 @@ inline bool NativeInstruction::is_cond_jump() { return (int_at(0) & 0xF0FF) = inline bool NativeInstruction::is_safepoint_poll() { #ifdef AMD64 if (SafepointMechanism::uses_thread_local_poll()) { - // We know that the poll must have a REX_B prefix since we enforce its source to be - // a rex-register and the destination to be rax. const bool has_rex_prefix = ubyte_at(0) == NativeTstRegMem::instruction_rex_b_prefix; - const bool is_test_opcode = ubyte_at(1) == NativeTstRegMem::instruction_code_memXregl; - const bool is_rax_target = (ubyte_at(2) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg; - if (has_rex_prefix && is_test_opcode && is_rax_target) { - return true; - } + const int test_offset = has_rex_prefix ? 1 : 0; + const bool is_test_opcode = ubyte_at(test_offset) == NativeTstRegMem::instruction_code_memXregl; + const bool is_rax_target = (ubyte_at(test_offset + 1) & NativeTstRegMem::modrm_mask) == NativeTstRegMem::modrm_reg; + return is_test_opcode && is_rax_target; } // Try decoding a near safepoint first: if (ubyte_at(0) == NativeTstRegMem::instruction_code_memXregl && diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index 3f0d57bcce0..b02015a08c2 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -3388,23 +3388,57 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t // No exception case __ bind(noException); - Label no_adjust, bail, no_prefix; + Label no_adjust, bail, no_prefix, not_special; if (SafepointMechanism::uses_thread_local_poll() && !cause_return) { // If our stashed return pc was modified by the runtime we avoid touching it __ cmpptr(rbx, Address(rbp, wordSize)); __ jccb(Assembler::notEqual, no_adjust); - // Verify the correct encoding of the poll we're about to skip. + // Skip over the poll instruction. // See NativeInstruction::is_safepoint_poll() + // Possible encodings: + // 85 00 test %eax,(%rax) + // 85 01 test %eax,(%rcx) + // 85 02 test %eax,(%rdx) + // 85 03 test %eax,(%rbx) + // 85 06 test %eax,(%rsi) + // 85 07 test %eax,(%rdi) + // + // 41 85 00 test %eax,(%r8) + // 41 85 01 test %eax,(%r9) + // 41 85 02 test %eax,(%r10) + // 41 85 03 test %eax,(%r11) + // 41 85 06 test %eax,(%r14) + // 41 85 07 test %eax,(%r15) + // + // 85 04 24 test %eax,(%rsp) + // 41 85 04 24 test %eax,(%r12) + // 85 45 00 test %eax,0x0(%rbp) + // 41 85 45 00 test %eax,0x0(%r13) + __ cmpb(Address(rbx, 0), NativeTstRegMem::instruction_rex_b_prefix); __ jcc(Assembler::notEqual, no_prefix); __ addptr(rbx, 1); __ bind(no_prefix); #ifdef ASSERT - __ cmpb(Address(rbx, 0), NativeTstRegMem::instruction_code_memXregl); + __ movptr(rax, rbx); // remember where 0x85 should be, for verification below +#endif + // r12/r13/rsp/rbp base encoding takes 3 bytes with the following register values: + // r12/rsp 0x04 + // r13/rbp 0x05 + __ movzbq(rcx, Address(rbx, 1)); + __ andptr(rcx, 0x07); // looking for 0x04 .. 0x05 + __ subptr(rcx, 4); // looking for 0x00 .. 0x01 + __ cmpptr(rcx, 1); + __ jcc(Assembler::above, not_special); + __ addptr(rbx, 1); + __ bind(not_special); +#ifdef ASSERT + // Verify the correct encoding of the poll we're about to skip. + __ cmpb(Address(rax, 0), NativeTstRegMem::instruction_code_memXregl); __ jcc(Assembler::notEqual, bail); // Mask out the modrm bits - __ testb(Address(rbx, 1), NativeTstRegMem::modrm_mask); + __ testb(Address(rax, 1), NativeTstRegMem::modrm_mask); // rax encodes to 0, so if the bits are nonzero it's incorrect __ jcc(Assembler::notZero, bail); #endif From 29bab311abb0fc1d453025efcd495987c5fdb4cb Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 7 Dec 2017 15:52:46 +0100 Subject: [PATCH 19/22] 8192908: -XX:+UseCountedLoopSafepoints alone doesn't disable strip mining with G1 -XX:+UseCountedLoopSafepoints should disable loop strip mining. Reviewed-by: kvn, thartmann --- src/hotspot/share/gc/g1/g1Arguments.cpp | 6 +++--- .../compiler/loopopts/UseCountedLoopSafepointsTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index b9ad5a02951..57ef5dac158 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -98,9 +98,9 @@ void G1Arguments::initialize_flags() { // Enable loop strip mining to offer better pause time guarantees if (FLAG_IS_DEFAULT(UseCountedLoopSafepoints)) { FLAG_SET_DEFAULT(UseCountedLoopSafepoints, true); - } - if (UseCountedLoopSafepoints && FLAG_IS_DEFAULT(LoopStripMiningIter)) { - FLAG_SET_DEFAULT(LoopStripMiningIter, 1000); + if (FLAG_IS_DEFAULT(LoopStripMiningIter)) { + FLAG_SET_DEFAULT(LoopStripMiningIter, 1000); + } } #endif } diff --git a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java index e581f4ea3c8..3b4983cf91f 100644 --- a/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java +++ b/test/hotspot/jtreg/compiler/loopopts/UseCountedLoopSafepointsTest.java @@ -62,7 +62,7 @@ public class UseCountedLoopSafepointsTest { try { oa = ProcessTools.executeTestJvm("-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:" + (enabled ? "+" : "-") + "UseCountedLoopSafepoints", - "-XX:LoopStripMiningIter=" + (enabled ? "1" : "0"), "-XX:+WhiteBoxAPI", + "-XX:+WhiteBoxAPI", "-XX:-Inline", "-Xbatch", "-XX:+PrintIdeal", "-XX:LoopUnrollLimit=0", "-XX:CompileOnly=" + UseCountedLoopSafepoints.class.getName() + "::testMethod", UseCountedLoopSafepoints.class.getName()); From 0ce6f0b889f26d61da90aaf88fcaf24c4322b4c1 Mon Sep 17 00:00:00 2001 From: Sangheon Kim Date: Thu, 7 Dec 2017 10:21:13 -0800 Subject: [PATCH 20/22] 8193105: Print error code when map_memory_to_file() fails Reviewed-by: dholmes, kbarrett --- src/hotspot/os/posix/os_posix.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 8c7cf351ef0..dcee2bd9359 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -243,8 +243,9 @@ char* os::map_memory_to_file(char* base, size_t size, int fd) { assert(fd != -1, "File descriptor is not valid"); // allocate space for the file - if (util_posix_fallocate(fd, 0, (off_t)size) != 0) { - vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory.")); + int ret = util_posix_fallocate(fd, 0, (off_t)size); + if (ret != 0) { + vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory. error(%d)", ret)); return NULL; } @@ -256,12 +257,13 @@ char* os::map_memory_to_file(char* base, size_t size, int fd) { char* addr = (char*)mmap(base, size, prot, flags, fd, 0); if (addr == MAP_FAILED) { + warning("Failed mmap to file. (%s)", os::strerror(errno)); return NULL; } if (base != NULL && addr != base) { if (!os::release_memory(addr, size)) { warning("Could not release memory on unsuccessful file mapping"); - } + } return NULL; } return addr; From c1741e54a6b331f8bab58904e9a48ab100acd982 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 7 Dec 2017 15:26:49 -0500 Subject: [PATCH 21/22] 8182307: Error during JRMP connection establishment Only use SO_REUSEADDR if we're using a fixed ServerSocket port. Reviewed-by: gthornbr, rriggs, sspitsyn --- .../rmi/transport/tcp/TCPDirectSocketFactory.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java index 8274742ec1b..9a8ead75cf1 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -25,6 +25,7 @@ package sun.rmi.transport.tcp; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.ServerSocket; import java.rmi.server.RMISocketFactory; @@ -42,6 +43,14 @@ public class TCPDirectSocketFactory extends RMISocketFactory { public ServerSocket createServerSocket(int port) throws IOException { - return new ServerSocket(port); + ServerSocket ss = new ServerSocket(); + if (port == 0) { + // Only need SO_REUSEADDR if we're using a fixed port. If we + // start seeing EADDRINUSE due to collisions in free ports + // then we should retry the bind() a few times. + ss.setReuseAddress(false); + } + ss.bind(new InetSocketAddress(port)); + return ss; } } From 069af6b6a7f44fb2238659bc8a2cc4f9a3d77204 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 7 Dec 2017 20:08:10 -0500 Subject: [PATCH 22/22] 8193225: [BACKOUT] fix for 8182307 Error during JRMP connection establishment Reviewed-by: iignatyev --- .../rmi/transport/tcp/TCPDirectSocketFactory.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java index 9a8ead75cf1..8274742ec1b 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPDirectSocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package sun.rmi.transport.tcp; import java.io.IOException; -import java.net.InetSocketAddress; import java.net.Socket; import java.net.ServerSocket; import java.rmi.server.RMISocketFactory; @@ -43,14 +42,6 @@ public class TCPDirectSocketFactory extends RMISocketFactory { public ServerSocket createServerSocket(int port) throws IOException { - ServerSocket ss = new ServerSocket(); - if (port == 0) { - // Only need SO_REUSEADDR if we're using a fixed port. If we - // start seeing EADDRINUSE due to collisions in free ports - // then we should retry the bind() a few times. - ss.setReuseAddress(false); - } - ss.bind(new InetSocketAddress(port)); - return ss; + return new ServerSocket(port); } }