changeset 50481:a87f2e7a527c

8191798: redo nested ThreadsListHandle to drop Threads_lock Summary: Refactor Thread hazard ptrs and nested ThreadsLists into SafeThreadsListPtr. Reviewed-by: dcubed, eosterlund, rehn Contributed-by: erik.osterlund@oracle.com, daniel.daugherty@oracle.com
author dcubed
date Wed, 02 May 2018 16:47:40 -0400
parents ea246151be08
children 746229cc1ab0
files src/hotspot/share/runtime/thread.cpp src/hotspot/share/runtime/thread.hpp src/hotspot/share/runtime/threadSMR.cpp src/hotspot/share/runtime/threadSMR.hpp src/hotspot/share/runtime/threadSMR.inline.hpp src/hotspot/share/services/threadService.hpp test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java
diffstat 8 files changed, 411 insertions(+), 417 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/runtime/thread.cpp	Wed May 02 11:21:27 2018 -0700
+++ b/src/hotspot/share/runtime/thread.cpp	Wed May 02 16:47:40 2018 -0400
@@ -243,7 +243,7 @@
   // This initial value ==> never claimed.
   _oops_do_parity = 0;
   _threads_hazard_ptr = NULL;
-  _nested_threads_hazard_ptr = NULL;
+  _threads_list_ptr = NULL;
   _nested_threads_hazard_ptr_cnt = 0;
   _rcu_counter = 0;
 
@@ -881,33 +881,11 @@
     st->print("tid=" INTPTR_FORMAT " ", p2i(this));
     osthread()->print_on(st);
   }
-  if (_threads_hazard_ptr != NULL) {
-    st->print("_threads_hazard_ptr=" INTPTR_FORMAT, p2i(_threads_hazard_ptr));
-  }
-  if (_nested_threads_hazard_ptr != NULL) {
-    print_nested_threads_hazard_ptrs_on(st);
-  }
+  ThreadsSMRSupport::print_info_on(this, st);
   st->print(" ");
   debug_only(if (WizardMode) print_owned_locks_on(st);)
 }
 
-void Thread::print_nested_threads_hazard_ptrs_on(outputStream* st) const {
-  assert(_nested_threads_hazard_ptr != NULL, "must be set to print");
-
-  if (EnableThreadSMRStatistics) {
-    st->print(", _nested_threads_hazard_ptr_cnt=%u", _nested_threads_hazard_ptr_cnt);
-  }
-  st->print(", _nested_threads_hazard_ptrs=");
-  for (NestedThreadsList* node = _nested_threads_hazard_ptr; node != NULL;
-       node = node->next()) {
-    if (node != _nested_threads_hazard_ptr) {
-      // First node does not need a comma-space separator.
-      st->print(", ");
-    }
-    st->print(INTPTR_FORMAT, p2i(node->t_list()));
-  }
-}
-
 // Thread::print_on_error() is called by fatal error handler. Don't use
 // any lock or allocate memory.
 void Thread::print_on_error(outputStream* st, char* buf, int buflen) const {
@@ -930,12 +908,7 @@
     st->print(" [id=%d]", osthread()->thread_id());
   }
 
-  if (_threads_hazard_ptr != NULL) {
-    st->print(" _threads_hazard_ptr=" INTPTR_FORMAT, p2i(_threads_hazard_ptr));
-  }
-  if (_nested_threads_hazard_ptr != NULL) {
-    print_nested_threads_hazard_ptrs_on(st);
-  }
+  ThreadsSMRSupport::print_info_on(this, st);
 }
 
 void Thread::print_value_on(outputStream* st) const {
@@ -2995,12 +2968,7 @@
             p2i(stack_end()), p2i(stack_base()));
   st->print("]");
 
-  if (_threads_hazard_ptr != NULL) {
-    st->print(" _threads_hazard_ptr=" INTPTR_FORMAT, p2i(_threads_hazard_ptr));
-  }
-  if (_nested_threads_hazard_ptr != NULL) {
-    print_nested_threads_hazard_ptrs_on(st);
-  }
+  ThreadsSMRSupport::print_info_on(this, st);
   return;
 }
 
--- a/src/hotspot/share/runtime/thread.hpp	Wed May 02 11:21:27 2018 -0700
+++ b/src/hotspot/share/runtime/thread.hpp	Wed May 02 16:47:40 2018 -0400
@@ -52,10 +52,10 @@
 # include "stack_zero.hpp"
 #endif
 
+class SafeThreadsListPtr;
 class ThreadSafepointState;
 class ThreadsList;
 class ThreadsSMRSupport;
-class NestedThreadsList;
 
 class JvmtiThreadState;
 class JvmtiGetLoadedClassesClosure;
@@ -135,13 +135,14 @@
   void*       _real_malloc_address;
 
   // JavaThread lifecycle support:
+  friend class SafeThreadsListPtr;  // for _threads_list_ptr, cmpxchg_threads_hazard_ptr(), {dec_,inc_,}nested_threads_hazard_ptr_cnt(), {g,s}et_threads_hazard_ptr(), inc_nested_handle_cnt(), tag_hazard_ptr() access
   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 ScanHazardPtrGatherThreadsListClosure;  // for 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
+  friend class ThreadsSMRSupport;  // for _nested_threads_hazard_ptr_cnt, _threads_hazard_ptr, _threads_list_ptr access
 
   ThreadsList* volatile _threads_hazard_ptr;
+  SafeThreadsListPtr*   _threads_list_ptr;
   ThreadsList*          cmpxchg_threads_hazard_ptr(ThreadsList* exchange_value, ThreadsList* compare_value);
   ThreadsList*          get_threads_hazard_ptr();
   void                  set_threads_hazard_ptr(ThreadsList* new_list);
@@ -154,15 +155,6 @@
   static ThreadsList*   untag_hazard_ptr(ThreadsList* list) {
     return (ThreadsList*)(intptr_t(list) & ~intptr_t(1));
   }
-  NestedThreadsList* _nested_threads_hazard_ptr;
-  NestedThreadsList* get_nested_threads_hazard_ptr() {
-    return _nested_threads_hazard_ptr;
-  }
-  void set_nested_threads_hazard_ptr(NestedThreadsList* value) {
-    assert(Threads_lock->owned_by_self(),
-           "must own Threads_lock for _nested_threads_hazard_ptr to be valid.");
-    _nested_threads_hazard_ptr = value;
-  }
   // This field is enabled via -XX:+EnableThreadSMRStatistics:
   uint _nested_threads_hazard_ptr_cnt;
   void dec_nested_threads_hazard_ptr_cnt() {
@@ -640,7 +632,6 @@
 
   // Printing
   virtual void print_on(outputStream* st) const;
-  virtual void print_nested_threads_hazard_ptrs_on(outputStream* st) const;
   void print() const { print_on(tty); }
   virtual void print_on_error(outputStream* st, char* buf, int buflen) const;
   void print_value_on(outputStream* st) const;
--- a/src/hotspot/share/runtime/threadSMR.cpp	Wed May 02 11:21:27 2018 -0700
+++ b/src/hotspot/share/runtime/threadSMR.cpp	Wed May 02 16:47:40 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 #include "services/threadService.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
 #include "utilities/resourceHash.hpp"
 #include "utilities/vmError.hpp"
 
@@ -252,8 +253,6 @@
       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;
       }
 
@@ -278,13 +277,6 @@
     // 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);
-    }
   }
 };
 
@@ -302,8 +294,6 @@
     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
@@ -315,16 +305,6 @@
     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);
-      }
-    }
   }
 };
 
@@ -343,8 +323,6 @@
     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.
@@ -362,25 +340,218 @@
         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;
-        }
-      }
+// Closure to determine if the specified JavaThread is found by
+// threads_do().
+//
+class VerifyHazardPtrThreadClosure : public ThreadClosure {
+ private:
+  bool _found;
+  Thread *_self;
+
+ public:
+  VerifyHazardPtrThreadClosure(Thread *self) : _found(false), _self(self) {}
+
+  bool found() const { return _found; }
+
+  virtual void do_thread(Thread *thread) {
+    if (thread == _self) {
+      _found = true;
     }
   }
 };
 
 
+// Acquire a stable ThreadsList.
+//
+void SafeThreadsListPtr::acquire_stable_list() {
+  assert(_thread != NULL, "sanity check");
+  _needs_release = true;
+  _previous = _thread->_threads_list_ptr;
+  _thread->_threads_list_ptr = this;
+
+  if (_thread->get_threads_hazard_ptr() == NULL) {
+    // The typical case is first.
+    acquire_stable_list_fast_path();
+    return;
+  }
+
+  // The nested case is rare.
+  acquire_stable_list_nested_path();
+}
+
+// Fast path way to acquire a stable ThreadsList.
+//
+void SafeThreadsListPtr::acquire_stable_list_fast_path() {
+  assert(_thread != NULL, "sanity check");
+  assert(_thread->get_threads_hazard_ptr() == NULL, "sanity check");
+
+  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 = ThreadsSMRSupport::get_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);
+    _thread->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 (ThreadsSMRSupport::get_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 (_thread->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.
+
+  _list = threads;
+
+  verify_hazard_ptr_scanned();
+}
+
+// Acquire a nested stable ThreadsList; this is rare so it uses
+// reference counting.
+//
+void SafeThreadsListPtr::acquire_stable_list_nested_path() {
+  assert(_thread != NULL, "sanity check");
+  assert(_thread->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. To remedy
+  // the situation, the ThreadsList pointed to by the pre-existing
+  // stable hazard ptr is reference counted before the hazard ptr may
+  // be released and moved to a new ThreadsList. The old ThreadsList
+  // is remembered in the ThreadsListHandle.
+
+  ThreadsList* current_list = _previous->_list;
+  if (EnableThreadSMRStatistics) {
+    _thread->inc_nested_threads_hazard_ptr_cnt();
+  }
+  current_list->inc_nested_handle_cnt();
+  _previous->_has_ref_count = true;  // promote SafeThreadsListPtr to be reference counted
+  _thread->_threads_hazard_ptr = NULL;  // clear the hazard ptr so we can go through the fast path below
+
+  if (EnableThreadSMRStatistics && _thread->nested_threads_hazard_ptr_cnt() > ThreadsSMRSupport::_nested_thread_list_max) {
+    ThreadsSMRSupport::_nested_thread_list_max = _thread->nested_threads_hazard_ptr_cnt();
+  }
+
+  acquire_stable_list_fast_path();
+
+  verify_hazard_ptr_scanned();
+
+  log_debug(thread, smr)("tid=" UINTX_FORMAT ": SafeThreadsListPtr::acquire_stable_list: add nested list pointer to ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(_list));
+}
+
+// Release a stable ThreadsList.
+//
+void SafeThreadsListPtr::release_stable_list() {
+  assert(_thread != NULL, "sanity check");
+  assert(_thread->_threads_list_ptr == this, "sanity check");
+  _thread->_threads_list_ptr = _previous;
+
+  if (_has_ref_count) {
+    // If a SafeThreadsListPtr has been promoted to use reference counting
+    // due to nesting of ThreadsListHandles, then the reference count must be
+    // decremented, at which point it may be freed. The forgotten value of
+    // the list no longer matters at this point and should already be NULL.
+    assert(_thread->get_threads_hazard_ptr() == NULL, "sanity check");
+    if (EnableThreadSMRStatistics) {
+      _thread->dec_nested_threads_hazard_ptr_cnt();
+    }
+    _list->dec_nested_handle_cnt();
+
+    log_debug(thread, smr)("tid=" UINTX_FORMAT ": SafeThreadsListPtr::release_stable_list: delete nested list pointer to ThreadsList=" INTPTR_FORMAT, os::current_thread_id(), p2i(_list));
+  } else {
+    // The normal case: a leaf ThreadsListHandle. This merely requires setting
+    // the thread hazard ptr back to NULL.
+    assert(_thread->get_threads_hazard_ptr() != NULL, "sanity check");
+    _thread->set_threads_hazard_ptr(NULL);
+  }
+
+  // After releasing the hazard ptr, other threads may go ahead and
+  // free up some memory temporarily used by a ThreadsList snapshot.
+
+  // We use double-check locking to reduce traffic on the system
+  // wide Thread-SMR delete_lock.
+  if (ThreadsSMRSupport::delete_notify()) {
+    // An exiting thread might be waiting in smr_delete(); we need to
+    // check with delete_lock to be sure.
+    ThreadsSMRSupport::release_stable_list_wake_up(_has_ref_count);
+  }
+}
+
+// Verify that the stable hazard ptr used to safely keep threads
+// alive is scanned by threads_do() which is a key piece of honoring
+// the Thread-SMR protocol.
+void SafeThreadsListPtr::verify_hazard_ptr_scanned() {
+#ifdef ASSERT
+  assert(_list != NULL, "_list must not be NULL");
+
+  // The closure will attempt to verify that the calling thread can
+  // be found by threads_do() on the specified ThreadsList. If it
+  // is successful, then the specified ThreadsList was acquired as
+  // a stable hazard ptr by the calling thread in a way that honored
+  // the Thread-SMR protocol.
+  //
+  // If the calling thread cannot be found by threads_do() and if
+  // it is not the shutdown thread, then the calling thread is not
+  // honoring the Thread-SMR ptotocol. This means that the specified
+  // ThreadsList is not a stable hazard ptr and can be freed by
+  // another thread from the to-be-deleted list at any time.
+  //
+  // Note: The shutdown thread has removed itself from the Threads
+  // list and is safe to have a waiver from this check because
+  // VM_Exit::_shutdown_thread is not set until after the VMThread
+  // has started the final safepoint which holds the Threads_lock
+  // for the remainder of the VM's life.
+  //
+  VerifyHazardPtrThreadClosure cl(_thread);
+  ThreadsSMRSupport::threads_do(&cl, _list);
+
+  // If the calling thread is not honoring the Thread-SMR protocol,
+  // then we will either crash in threads_do() above because 'threads'
+  // was freed by another thread or we will fail the assert() below.
+  // In either case, we won't get past this point with a badly placed
+  // ThreadsListHandle.
+
+  assert(cl.found() || _thread == VM_Exit::shutdown_thread(), "Acquired a ThreadsList snapshot from a thread not recognized by the Thread-SMR protocol.");
+#endif
+}
+
 // '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) {
+ThreadsList::ThreadsList(int entries) :
+  _length(entries),
+  _next_list(NULL),
+  _threads(NEW_C_HEAP_ARRAY(JavaThread*, entries + 1, mtThread)),
+  _nested_handle_cnt(0)
+{
   *(JavaThread**)(_threads + entries) = NULL;  // Make sure the extra entry is NULL.
 }
 
@@ -405,6 +576,15 @@
   return new_list;
 }
 
+void ThreadsList::dec_nested_handle_cnt() {
+  // The decrement needs to be MO_ACQ_REL. At the moment, the Atomic::dec
+  // backend on PPC does not yet conform to these requirements. Therefore
+  // the decrement is simulated with an Atomic::sub(1, &addr).
+  // Without this MO_ACQ_REL Atomic::dec simulation, the nested SMR mechanism
+  // is not generally safe to use.
+  Atomic::sub(1, &_nested_handle_cnt);
+}
+
 int ThreadsList::find_index_of_JavaThread(JavaThread *target) {
   if (target == NULL) {
     return -1;
@@ -432,6 +612,22 @@
   return NULL;
 }
 
+void ThreadsList::inc_nested_handle_cnt() {
+  // The increment needs to be MO_SEQ_CST. At the moment, the Atomic::inc
+  // backend on PPC does not yet conform to these requirements. Therefore
+  // the increment is simulated with a load phi; cas phi + 1; loop.
+  // Without this MO_SEQ_CST Atomic::inc simulation, the nested SMR mechanism
+  // is not generally safe to use.
+  intx sample = OrderAccess::load_acquire(&_nested_handle_cnt);
+  for (;;) {
+    if (Atomic::cmpxchg(sample + 1, &_nested_handle_cnt, sample) == sample) {
+      return;
+    } else {
+      sample = OrderAccess::load_acquire(&_nested_handle_cnt);
+    }
+  }
+}
+
 bool ThreadsList::includes(const JavaThread * const p) const {
   if (p == NULL) {
     return false;
@@ -468,7 +664,7 @@
   return new_list;
 }
 
-ThreadsListHandle::ThreadsListHandle(Thread *self) : _list(ThreadsSMRSupport::acquire_stable_list(self, /* is_ThreadsListSetter */ false)), _self(self) {
+ThreadsListHandle::ThreadsListHandle(Thread *self) : _list_ptr(self, /* acquire */ true) {
   assert(self == Thread::current(), "sanity check");
   if (EnableThreadSMRStatistics) {
     _timer.start();
@@ -476,7 +672,6 @@
 }
 
 ThreadsListHandle::~ThreadsListHandle() {
-  ThreadsSMRSupport::release_stable_list(_self);
   if (EnableThreadSMRStatistics) {
     _timer.stop();
     uint millis = (uint)_timer.milliseconds();
@@ -536,210 +731,17 @@
   return true;
 }
 
-ThreadsListSetter::~ThreadsListSetter() {
-  if (_target_needs_release) {
-    // The hazard ptr in the target needs to be released.
-    ThreadsSMRSupport::release_stable_list(_target);
-  }
-}
-
-// Closure to determine if the specified JavaThread is found by
-// threads_do().
-//
-class VerifyHazardPointerThreadClosure : public ThreadClosure {
- private:
-  bool _found;
-  Thread *_self;
-
- public:
-  VerifyHazardPointerThreadClosure(Thread *self) : _found(false), _self(self) {}
-
-  bool found() const { return _found; }
-
-  virtual void do_thread(Thread *thread) {
-    if (thread == _self) {
-      _found = true;
-    }
-  }
-};
-
-// Apply the closure to all threads in the system, with a snapshot of
-// all JavaThreads provided by the list parameter.
-void ThreadsSMRSupport::threads_do(ThreadClosure *tc, ThreadsList *list) {
-  list->threads_do(tc);
-  Threads::non_java_threads_do(tc);
-}
-
-// Apply the closure to all threads in the system.
-void ThreadsSMRSupport::threads_do(ThreadClosure *tc) {
-  threads_do(tc, _java_thread_list);
-}
-
-// Verify that the stable hazard pointer used to safely keep threads
-// alive is scanned by threads_do() which is a key piece of honoring
-// the Thread-SMR protocol.
-void ThreadsSMRSupport::verify_hazard_pointer_scanned(Thread *self, ThreadsList *threads) {
-#ifdef ASSERT
-  assert(threads != NULL, "threads must not be NULL");
-
-  // The closure will attempt to verify that the calling thread can
-  // be found by threads_do() on the specified ThreadsList. If it
-  // is successful, then the specified ThreadsList was acquired as
-  // a stable hazard pointer by the calling thread in a way that
-  // honored the Thread-SMR protocol.
-  //
-  // If the calling thread cannot be found by threads_do() and if
-  // it is not the shutdown thread, then the calling thread is not
-  // honoring the Thread-SMR ptotocol. This means that the specified
-  // ThreadsList is not a stable hazard pointer and can be freed
-  // by another thread from the to-be-deleted list at any time.
-  //
-  // Note: The shutdown thread has removed itself from the Threads
-  // list and is safe to have a waiver from this check because
-  // VM_Exit::_shutdown_thread is not set until after the VMThread
-  // has started the final safepoint which holds the Threads_lock
-  // for the remainder of the VM's life.
-  //
-  VerifyHazardPointerThreadClosure cl(self);
-  threads_do(&cl, threads);
-
-  // If the calling thread is not honoring the Thread-SMR protocol,
-  // then we will either crash in threads_do() above because 'threads'
-  // was freed by another thread or we will fail the assert() below.
-  // In either case, we won't get past this point with a badly placed
-  // ThreadsListHandle.
-
-  assert(cl.found() || self == VM_Exit::shutdown_thread(), "Acquired a ThreadsList snapshot from a thread not recognized by the Thread-SMR protocol.");
-#endif
-}
-
-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 _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_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 _java_thread_list has changed, we have lost a race with
-    // Threads::add() or Threads::remove() and have to try again.
-    if (get_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.
-
-  verify_hazard_pointer_scanned(self, threads);
-
-  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_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() > _nested_thread_list_max) {
-        _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()));
-
-  verify_hazard_pointer_scanned(self, node->t_list());
-
-  return node->t_list();
-}
-
 void ThreadsSMRSupport::add_thread(JavaThread *thread){
-  ThreadsList *new_list = ThreadsList::add_thread(ThreadsSMRSupport::get_java_thread_list(), thread);
+  ThreadsList *new_list = ThreadsList::add_thread(get_java_thread_list(), thread);
   if (EnableThreadSMRStatistics) {
-    ThreadsSMRSupport::inc_java_thread_list_alloc_cnt();
-    ThreadsSMRSupport::update_java_thread_list_max(new_list->length());
+    inc_java_thread_list_alloc_cnt();
+    update_java_thread_list_max(new_list->length());
   }
   // Initial _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_java_thread_list(new_list);
-  ThreadsSMRSupport::free_list(old_list);
+  ThreadsList *old_list = xchg_java_thread_list(new_list);
+  free_list(old_list);
 }
 
 // set_delete_notify() and clear_delete_notify() are called
@@ -787,6 +789,8 @@
   ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size);
   ScanHazardPtrGatherThreadsListClosure scan_cl(scan_table);
   threads_do(&scan_cl);
+  OrderAccess::acquire(); // Must order reads of hazard ptr before reads of
+                          // nested reference counters
 
   // Walk through the linked list of pending freeable ThreadsLists
   // and free the ones that are not referenced from hazard ptrs.
@@ -796,7 +800,7 @@
   bool threads_is_freed = false;
   while (current != NULL) {
     next = current->next_list();
-    if (!scan_table->has_entry((void*)current)) {
+    if (!scan_table->has_entry((void*)current) && current->_nested_handle_cnt == 0) {
       // This ThreadsList is not referenced by a hazard ptr.
       if (prev != NULL) {
         prev->set_next_list(next);
@@ -849,6 +853,22 @@
   ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size);
   ScanHazardPtrGatherProtectedThreadsClosure scan_cl(scan_table);
   threads_do(&scan_cl);
+  OrderAccess::acquire(); // Must order reads of hazard ptr before reads of
+                          // nested reference counters
+
+  // Walk through the linked list of pending freeable ThreadsLists
+  // and include the ones that are currently in use by a nested
+  // ThreadsListHandle in the search set.
+  ThreadsList* current = _to_delete_list;
+  while (current != NULL) {
+    if (current->_nested_handle_cnt != 0) {
+      // 'current' is in use by a nested ThreadsListHandle so the hazard
+      // ptr is protecting all the JavaThreads on that ThreadsList.
+      AddThreadHazardPointerThreadClosure add_cl(scan_table);
+      current->threads_do(&add_cl);
+    }
+    current = current->next_list();
+  }
 
   bool thread_is_protected = false;
   if (scan_table->has_entry((void*)thread)) {
@@ -858,87 +878,11 @@
   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 Thread-SMR delete_lock.
-  if (ThreadsSMRSupport::delete_notify()) {
-    // An exiting thread might be waiting in smr_delete(); we need to
-    // check with 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 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 delete_lock().
 //
-void ThreadsSMRSupport::release_stable_list_wake_up(char *log_str) {
-  assert(log_str != NULL, "sanity check");
+void ThreadsSMRSupport::release_stable_list_wake_up(bool is_nested) {
+  const char* log_str = is_nested ? "nested hazard ptr" : "regular hazard ptr";
 
   // Note: delete_lock is held in smr_delete() for the entire
   // hazard ptr search so that we do not lose this notify() if
@@ -1014,6 +958,13 @@
         if (log_is_enabled(Debug, os, thread)) {
           ScanHazardPtrPrintMatchingThreadsClosure scan_cl(thread);
           threads_do(&scan_cl);
+          ThreadsList* current = _to_delete_list;
+          while (current != NULL) {
+            if (current->_nested_handle_cnt != 0 && current->includes(thread)) {
+              log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: found nested hazard pointer to thread=" INTPTR_FORMAT, os::current_thread_id(), p2i(thread));
+            }
+            current = current->next_list();
+          }
         }
       }
     } // We have to drop the Threads_lock to wait or delete the thread
@@ -1055,9 +1006,32 @@
   log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread=" INTPTR_FORMAT " is deleted.", os::current_thread_id(), p2i(thread));
 }
 
+// Apply the closure to all threads in the system, with a snapshot of
+// all JavaThreads provided by the list parameter.
+void ThreadsSMRSupport::threads_do(ThreadClosure *tc, ThreadsList *list) {
+  list->threads_do(tc);
+  Threads::non_java_threads_do(tc);
+}
+
+// Apply the closure to all threads in the system.
+void ThreadsSMRSupport::threads_do(ThreadClosure *tc) {
+  threads_do(tc, _java_thread_list);
+}
+
 
 // Debug, logging, and printing stuff at the end:
 
+// Print SMR info for a SafeThreadsListPtr to a given output stream.
+void SafeThreadsListPtr::print_on(outputStream* st) {
+  if (this == _thread->_threads_list_ptr) {
+    // The top level hazard ptr.
+    st->print(" _threads_hazard_ptr=" INTPTR_FORMAT, p2i(_list));
+  } else {
+    // Nested hazard ptrs.
+    st->print(", _nested_threads_hazard_ptr=" INTPTR_FORMAT, p2i(_list));
+  }
+}
+
 // Log Threads class SMR info.
 void ThreadsSMRSupport::log_statistics() {
   LogTarget(Info, thread, smr) log;
@@ -1067,6 +1041,30 @@
   }
 }
 
+// Print SMR info for a thread to a given output stream.
+void ThreadsSMRSupport::print_info_on(const Thread* thread, outputStream* st) {
+  if (thread->_threads_hazard_ptr != NULL) {
+    st->print(" _threads_hazard_ptr=" INTPTR_FORMAT, p2i(thread->_threads_hazard_ptr));
+  }
+  if (EnableThreadSMRStatistics && thread->_threads_list_ptr != NULL) {
+    // The count is only interesting if we have a _threads_list_ptr.
+    st->print(", _nested_threads_hazard_ptr_cnt=%u", thread->_nested_threads_hazard_ptr_cnt);
+  }
+  if (SafepointSynchronize::is_at_safepoint() || Thread::current() == thread) {
+    // It is only safe to walk the list if we're at a safepoint or the
+    // calling thread is walking its own list.
+    SafeThreadsListPtr* current = thread->_threads_list_ptr;
+    if (current != NULL) {
+      // Skip the top nesting level as it is always printed above.
+      current = current->previous();
+    }
+    while (current != NULL) {
+      current->print_on(st);
+      current = current->previous();
+    }
+  }
+}
+
 // Print Threads class SMR info.
 void ThreadsSMRSupport::print_info_on(outputStream* st) {
   // Only grab the Threads_lock if we don't already own it
@@ -1096,8 +1094,8 @@
   if (!EnableThreadSMRStatistics) {
     return;
   }
-  st->print_cr("_java_thread_list_alloc_cnt=" UINT64_FORMAT ","
-               "_java_thread_list_free_cnt=" UINT64_FORMAT ","
+  st->print_cr("_java_thread_list_alloc_cnt=" UINT64_FORMAT ", "
+               "_java_thread_list_free_cnt=" UINT64_FORMAT ", "
                "_java_thread_list_max=%u, "
                "_nested_thread_list_max=%u",
                _java_thread_list_alloc_cnt,
--- a/src/hotspot/share/runtime/threadSMR.hpp	Wed May 02 11:21:27 2018 -0700
+++ b/src/hotspot/share/runtime/threadSMR.hpp	Wed May 02 16:47:40 2018 -0400
@@ -28,6 +28,10 @@
 #include "memory/allocation.hpp"
 #include "runtime/timer.hpp"
 
+class JavaThread;
+class Monitor;
+class outputStream;
+class Thread;
 class ThreadClosure;
 
 // Thread Safe Memory Reclamation (Thread-SMR) support.
@@ -82,6 +86,8 @@
 // SMR Support for the Threads class.
 //
 class ThreadsSMRSupport : AllStatic {
+  friend class SafeThreadsListPtr;  // for _nested_thread_list_max, delete_notify(), release_stable_list_wake_up() access
+
   // The coordination between ThreadsSMRSupport::release_stable_list() and
   // ThreadsSMRSupport::smr_delete() uses the delete_lock in order to
   // reduce the traffic on the Threads_lock.
@@ -122,24 +128,20 @@
   static void inc_java_thread_list_alloc_cnt();
   static void inc_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 release_stable_list_wake_up(bool is_nested);
   static void set_delete_notify();
   static void threads_do(ThreadClosure *tc);
   static void threads_do(ThreadClosure *tc, ThreadsList *list);
   static void update_deleted_thread_time_max(uint new_value);
   static void update_java_thread_list_max(uint new_value);
   static void update_tlh_time_max(uint new_value);
-  static void verify_hazard_pointer_scanned(Thread *self, ThreadsList *threads);
+  static void verify_hazard_ptr_scanned(Thread *self, ThreadsList *threads);
   static ThreadsList* xchg_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_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_tlh_stats(uint millis);
@@ -148,16 +150,19 @@
   static void log_statistics();
   static void print_info_elements_on(outputStream* st, ThreadsList* t_list);
   static void print_info_on(outputStream* st);
+  static void print_info_on(const Thread* thread, outputStream* st);
 };
 
 // A fast list of JavaThreads.
 //
 class ThreadsList : public CHeapObj<mtThread> {
-  friend class ThreadsSMRSupport;  // for next_list(), set_next_list() access
+  friend class SafeThreadsListPtr;  // for {dec,inc}_nested_handle_cnt() access
+  friend class ThreadsSMRSupport;  // for _nested_handle_cnt, {add,remove}_thread(), {,set_}next_list() access
 
   const uint _length;
   ThreadsList* _next_list;
   JavaThread *const *const _threads;
+  volatile intx _nested_handle_cnt;
 
   template <class T>
   void threads_do_dispatch(T *cl, JavaThread *const thread) const;
@@ -165,6 +170,9 @@
   ThreadsList *next_list() const        { return _next_list; }
   void set_next_list(ThreadsList *list) { _next_list = list; }
 
+  void inc_nested_handle_cnt();
+  void dec_nested_handle_cnt();
+
   static ThreadsList* add_thread(ThreadsList* list, JavaThread* java_thread);
   static ThreadsList* remove_thread(ThreadsList* list, JavaThread* java_thread);
 
@@ -187,20 +195,60 @@
   bool includes(const JavaThread * const p) const;
 };
 
-// Linked list of ThreadsLists to support nested ThreadsListHandles.
-class NestedThreadsList : public CHeapObj<mtThread> {
-  ThreadsList*const _t_list;
-  NestedThreadsList* _next;
+// An abstract safe ptr to a ThreadsList comprising either a stable hazard ptr
+// for leaves, or a retained reference count for nested uses. The user of this
+// API does not need to know which mechanism is providing the safety.
+class SafeThreadsListPtr {
+  friend class ThreadsListSetter;
+
+  SafeThreadsListPtr* _previous;
+  Thread*                 _thread;
+  ThreadsList*            _list;
+  bool                    _has_ref_count;
+  bool                    _needs_release;
+
+  void acquire_stable_list();
+  void acquire_stable_list_fast_path();
+  void acquire_stable_list_nested_path();
+
+  void release_stable_list();
+
+  void verify_hazard_ptr_scanned();
 
 public:
-  NestedThreadsList(ThreadsList* t_list) : _t_list(t_list) {
-    assert(Threads_lock->owned_by_self(),
-           "must own Threads_lock for saved t_list to be valid.");
+  // Constructor that attaches the list onto a thread.
+  SafeThreadsListPtr(Thread *thread, bool acquire) :
+    _previous(NULL),
+    _thread(thread),
+    _list(NULL),
+    _has_ref_count(false),
+    _needs_release(false)
+  {
+    if (acquire) {
+      acquire_stable_list();
+    }
   }
 
-  ThreadsList* t_list() { return _t_list; }
-  NestedThreadsList* next() { return _next; }
-  void set_next(NestedThreadsList* value) { _next = value; }
+  // Constructor that transfers ownership of the pointer.
+  SafeThreadsListPtr(SafeThreadsListPtr& other) :
+    _previous(other._previous),
+    _thread(other._thread),
+    _list(other._list),
+    _has_ref_count(other._has_ref_count),
+    _needs_release(other._needs_release)
+  {
+    other._needs_release = false;
+  }
+
+  ~SafeThreadsListPtr() {
+    if (_needs_release) {
+      release_stable_list();
+    }
+  }
+
+  ThreadsList* list() const { return _list; }
+  SafeThreadsListPtr* previous() const { return _previous; }
+  void print_on(outputStream* st);
 };
 
 // A helper to optionally set the hazard ptr in ourself. This helper can
@@ -209,24 +257,20 @@
 //
 class ThreadsListSetter : public StackObj {
 private:
-  bool _target_needs_release;  // needs release only when set()
-  Thread * _target;
+  SafeThreadsListPtr _list_ptr;
 
 public:
-  ThreadsListSetter() : _target_needs_release(false), _target(Thread::current()) {
-  }
-  ~ThreadsListSetter();
-  ThreadsList* list();
-  void set();
-  bool target_needs_release() { return _target_needs_release; }
+  ThreadsListSetter() : _list_ptr(Thread::current(), /* acquire */ false) {}
+  ThreadsList* list() { return _list_ptr.list(); }
+  void set() { _list_ptr.acquire_stable_list(); }
+  bool is_set() { return _list_ptr._needs_release; }
 };
 
 // This stack allocated ThreadsListHandle keeps all JavaThreads in the
 // ThreadsList from being deleted until it is safe.
 //
 class ThreadsListHandle : public StackObj {
-  ThreadsList * _list;
-  Thread *const _self;
+  SafeThreadsListPtr _list_ptr;
   elapsedTimer _timer;  // Enabled via -XX:+EnableThreadSMRStatistics.
 
 public:
@@ -234,22 +278,22 @@
   ~ThreadsListHandle();
 
   ThreadsList *list() const {
-    return _list;
+    return _list_ptr.list();
   }
 
   template <class T>
   void threads_do(T *cl) const {
-    return _list->threads_do(cl);
+    return list()->threads_do(cl);
   }
 
   bool cv_internal_thread_to_JavaThread(jobject jthread, JavaThread ** jt_pp, oop * thread_oop_p);
 
   bool includes(JavaThread* p) {
-    return _list->includes(p);
+    return list()->includes(p);
   }
 
   uint length() const {
-    return _list->length();
+    return list()->length();
   }
 };
 
--- a/src/hotspot/share/runtime/threadSMR.inline.hpp	Wed May 02 11:21:27 2018 -0700
+++ b/src/hotspot/share/runtime/threadSMR.inline.hpp	Wed May 02 16:47:40 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -77,14 +77,6 @@
   }
 }
 
-
-inline ThreadsList* ThreadsListSetter::list() {
-  ThreadsList *ret = _target->get_threads_hazard_ptr();
-  assert(ret != NULL, "hazard ptr should be set");
-  assert(!Thread::is_hazard_ptr_tagged(ret), "hazard ptr should be validated");
-  return ret;
-}
-
 inline ThreadsList* ThreadsSMRSupport::get_java_thread_list() {
   return (ThreadsList*)OrderAccess::load_acquire(&_java_thread_list);
 }
--- a/src/hotspot/share/services/threadService.hpp	Wed May 02 11:21:27 2018 -0700
+++ b/src/hotspot/share/services/threadService.hpp	Wed May 02 16:47:40 2018 -0400
@@ -377,7 +377,7 @@
   ThreadSnapshot*      snapshots()                      { return _snapshots; }
   void                 set_t_list()                     { _setter.set(); }
   ThreadsList*         t_list();
-  bool                 t_list_has_been_set()            { return _setter.target_needs_release(); }
+  bool                 t_list_has_been_set()            { return _setter.is_set(); }
   void                 oops_do(OopClosure* f);
   void                 metadata_do(void f(Metadata*));
 };
--- a/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java	Wed May 02 11:21:27 2018 -0700
+++ b/test/hotspot/jtreg/runtime/ErrorHandling/NestedThreadsListHandleInErrorHandlingTest.java	Wed May 02 16:47:40 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -85,14 +85,14 @@
     Pattern [] pattern = new Pattern[] {
         // The "Current thread" line should show a hazard ptr and
         // a nested hazard ptr:
-        Pattern.compile("Current thread .* _threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*, _nested_threads_hazard_ptr_cnt=1, _nested_threads_hazard_ptrs=0x.*"),
+        Pattern.compile("Current thread .* _threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*, _nested_threads_hazard_ptr_cnt=1, _nested_threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*.*"),
         // We should have a section of Threads class SMR info:
         Pattern.compile("Threads class SMR info:"),
         // We should have one nested ThreadsListHandle:
         Pattern.compile(".*, _nested_thread_list_max=1"),
         // The current thread (marked with '=>') in the threads list
-        // should show a hazard ptr:
-        Pattern.compile("=>.* JavaThread \"main\" .*_threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*, _nested_threads_hazard_ptr_cnt=1, _nested_threads_hazard_ptrs=0x.*"),
+        // should show a hazard ptr and a nested hazard ptr:
+        Pattern.compile("=>.* JavaThread \"main\" .* _threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*, _nested_threads_hazard_ptr_cnt=1, _nested_threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*.*"),
     };
     int currentPattern = 0;
 
--- a/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java	Wed May 02 11:21:27 2018 -0700
+++ b/test/hotspot/jtreg/runtime/ErrorHandling/ThreadsListHandleInErrorHandlingTest.java	Wed May 02 16:47:40 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -83,13 +83,14 @@
     String line = null;
 
     Pattern [] pattern = new Pattern[] {
-        // The "Current thread" line should show a hazard ptr:
-        Pattern.compile("Current thread .* _threads_hazard_ptr=0x.*"),
+        // The "Current thread" line should show a hazard ptr
+        // and no nested hazard ptrs:
+        Pattern.compile("Current thread .* _threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*, _nested_threads_hazard_ptr_cnt=0.*"),
         // We should have a section of Threads class SMR info:
         Pattern.compile("Threads class SMR info:"),
         // The current thread (marked with '=>') in the threads list
-        // should show a hazard ptr:
-        Pattern.compile("=>.* JavaThread \"main\" .*_threads_hazard_ptr=0x.*"),
+        // should show a hazard ptr and no nested hazard ptrs:
+        Pattern.compile("=>.* JavaThread \"main\" .* _threads_hazard_ptr=0x[0-9A-Fa-f][0-9A-Fa-f]*, _nested_threads_hazard_ptr_cnt=0.*"),
     };
     int currentPattern = 0;