Merge stuefe-new-metaspace-branch
authorstuefe
Wed, 18 Sep 2019 07:46:02 +0200
branchstuefe-new-metaspace-branch
changeset 58199 595fcbebaa77
parent 58107 69c38b90014c (current diff)
parent 58196 cea6839598e8 (diff)
child 58227 0e7d9a23261e
Merge
src/hotspot/share/classfile/classLoaderData.cpp
src/hotspot/share/gc/shared/collectedHeap.cpp
src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
src/hotspot/share/gc/z/zCollectedHeap.cpp
src/hotspot/share/gc/z/zUtils.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.cpp
src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.hpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp
src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/memory/universe.cpp
src/hotspot/share/oops/access.cpp
src/hotspot/share/runtime/globals.hpp
src/hotspot/share/runtime/os.hpp
--- a/make/autoconf/toolchain_windows.m4	Thu Sep 12 15:04:00 2019 +0200
+++ b/make/autoconf/toolchain_windows.m4	Wed Sep 18 07:46:02 2019 +0200
@@ -808,7 +808,7 @@
   if test "x$USE_UCRT" = "xtrue"; then
     AC_MSG_CHECKING([for UCRT DLL dir])
     if test "x$with_ucrt_dll_dir" != x; then
-      if test -z "$(ls -d $with_ucrt_dll_dir/*.dll 2> /dev/null)"; then
+      if test -z "$(ls -d "$with_ucrt_dll_dir/"*.dll 2> /dev/null)"; then
         AC_MSG_RESULT([no])
         AC_MSG_ERROR([Could not find any dlls in $with_ucrt_dll_dir])
       else
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/posix/gc/z/zUtils_posix.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "precompiled.hpp"
+#include "gc/z/zUtils.hpp"
+#include "utilities/debug.hpp"
+
+#include <stdlib.h>
+
+uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) {
+  void* res = NULL;
+
+  if (posix_memalign(&res, alignment, size) != 0) {
+    fatal("posix_memalign() failed");
+  }
+
+  memset(res, 0, size);
+
+  return (uintptr_t)res;
+}
--- a/src/hotspot/os/posix/os_posix.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/os/posix/os_posix.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -640,61 +640,6 @@
   return;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// interrupt support
-
-void os::interrupt(Thread* thread) {
-  debug_only(Thread::check_for_dangling_thread_pointer(thread);)
-  assert(thread->is_Java_thread(), "invariant");
-  JavaThread* jt = (JavaThread*) thread;
-  OSThread* osthread = thread->osthread();
-
-  if (!osthread->interrupted()) {
-    osthread->set_interrupted(true);
-    // More than one thread can get here with the same value of osthread,
-    // resulting in multiple notifications.  We do, however, want the store
-    // to interrupted() to be visible to other threads before we execute unpark().
-    OrderAccess::fence();
-    ParkEvent * const slp = jt->_SleepEvent ;
-    if (slp != NULL) slp->unpark() ;
-  }
-
-  // For JSR166. Unpark even if interrupt status already was set
-  jt->parker()->unpark();
-
-  ParkEvent * ev = thread->_ParkEvent ;
-  if (ev != NULL) ev->unpark() ;
-}
-
-bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
-  debug_only(Thread::check_for_dangling_thread_pointer(thread);)
-
-  OSThread* osthread = thread->osthread();
-
-  bool interrupted = osthread->interrupted();
-
-  // NOTE that since there is no "lock" around the interrupt and
-  // is_interrupted operations, there is the possibility that the
-  // interrupted flag (in osThread) will be "false" but that the
-  // low-level events will be in the signaled state. This is
-  // intentional. The effect of this is that Object.wait() and
-  // LockSupport.park() will appear to have a spurious wakeup, which
-  // is allowed and not harmful, and the possibility is so rare that
-  // it is not worth the added complexity to add yet another lock.
-  // For the sleep event an explicit reset is performed on entry
-  // to JavaThread::sleep, so there is no early return. It has also been
-  // recommended not to put the interrupted flag into the "event"
-  // structure because it hides the issue.
-  if (interrupted && clear_interrupted) {
-    osthread->set_interrupted(false);
-    // consider thread->_SleepEvent->reset() ... optional optimization
-  }
-
-  return interrupted;
-}
-
-
-
 static const struct {
   int sig; const char* name;
 }
@@ -2107,7 +2052,7 @@
 
   // Optional optimization -- avoid state transitions if there's
   // an interrupt pending.
-  if (Thread::is_interrupted(thread, false)) {
+  if (jt->is_interrupted(false)) {
     return;
   }
 
@@ -2130,7 +2075,7 @@
 
   // Don't wait if cannot get lock since interference arises from
   // unparking. Also re-check interrupt before trying wait.
-  if (Thread::is_interrupted(thread, false) ||
+  if (jt->is_interrupted(false) ||
       pthread_mutex_trylock(_mutex) != 0) {
     return;
   }
--- a/src/hotspot/os/solaris/os_solaris.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/os/solaris/os_solaris.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -5063,7 +5063,7 @@
   Thread* thread = Thread::current();
   assert(thread->is_Java_thread(), "Must be JavaThread");
   JavaThread *jt = (JavaThread *)thread;
-  if (Thread::is_interrupted(thread, false)) {
+  if (jt->is_interrupted(false)) {
     return;
   }
 
@@ -5088,7 +5088,7 @@
 
   // Don't wait if cannot get lock since interference arises from
   // unblocking.  Also. check interrupt before trying wait
-  if (Thread::is_interrupted(thread, false) ||
+  if (jt->is_interrupted(false) ||
       os::Solaris::mutex_trylock(_mutex) != 0) {
     return;
   }
--- a/src/hotspot/os/windows/osThread_windows.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/os/windows/osThread_windows.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, 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,12 +23,9 @@
  */
 
 // no precompiled headers
-#include "runtime/handles.inline.hpp"
-#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.hpp"
 #include "runtime/os.hpp"
 #include "runtime/osThread.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/vmThread.hpp"
 
 void OSThread::pd_initialize() {
   set_thread_handle(NULL);
@@ -36,8 +33,34 @@
   set_interrupt_event(NULL);
 }
 
-// TODO: this is not well encapsulated; creation and deletion of the
-// interrupt_event are done in os_win32.cpp, create_thread and
-// free_thread. Should follow pattern of Linux/Solaris code here.
 void OSThread::pd_destroy() {
+  if (_interrupt_event != NULL) {
+    CloseHandle(_interrupt_event);
+  }
 }
+
+// We need to specialize these to interact with the _interrupt_event.
+
+volatile bool OSThread::interrupted() {
+  return _interrupted != 0 &&
+    (WaitForSingleObject(_interrupt_event, 0) == WAIT_OBJECT_0);
+}
+
+void OSThread::set_interrupted(bool z) {
+  if (z) {
+    _interrupted = 1;
+    // More than one thread can get here with the same value of osthread,
+    // resulting in multiple notifications.  We do, however, want the store
+    // to interrupted() to be visible to other threads before we post
+    // the interrupt event.
+    OrderAccess::release();
+    SetEvent(_interrupt_event);
+  }
+  else {
+    // We should only ever clear the interrupt if we are in fact interrupted,
+    // and this can only be done by the current thread on itself.
+    assert(_interrupted == 1, "invariant for clearing interrupt state");
+    _interrupted = 0;
+    ResetEvent(_interrupt_event);
+  }
+}
--- a/src/hotspot/os/windows/osThread_windows.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/os/windows/osThread_windows.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -32,7 +32,8 @@
  private:
   // Win32-specific thread information
   HANDLE _thread_handle;        // Win32 thread handle
-  HANDLE _interrupt_event;      // Event signalled on thread interrupt
+  HANDLE _interrupt_event;      // Event signalled on thread interrupt for use by
+                                // Process.waitFor().
   ThreadState _last_state;
 
  public:
@@ -42,6 +43,11 @@
   void set_thread_handle(HANDLE handle)            { _thread_handle = handle; }
   HANDLE interrupt_event() const                   { return _interrupt_event; }
   void set_interrupt_event(HANDLE interrupt_event) { _interrupt_event = interrupt_event; }
+  // These are specialized on Windows to interact with the _interrupt_event.
+  // Also note that Windows does not skip these calls if we are interrupted - see
+  // LibraryCallKit::inline_native_isInterrupted
+  volatile bool interrupted();
+  void set_interrupted(bool z);
 
 #ifndef PRODUCT
   // Used for debugging, return a unique integer for each thread.
@@ -54,7 +60,6 @@
     return false;
   }
 #endif // ASSERT
-  bool is_try_mutex_enter()                        { return false; }
 
   // This is a temporary fix for the thread states during
   // suspend/resume until we throw away OSThread completely.
--- a/src/hotspot/os/windows/os_windows.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/os/windows/os_windows.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -612,7 +612,9 @@
     return false;
   }
   osthread->set_interrupt_event(interrupt_event);
-  osthread->set_interrupted(false);
+  // We don't call set_interrupted(false) as it will trip the assert in there
+  // as we are not operating on the current thread. We don't need to call it
+  // because the initial state is already correct.
 
   thread->set_osthread(osthread);
 
@@ -684,7 +686,6 @@
 
   if (thread_handle == NULL) {
     // Need to clean up stuff we've allocated so far
-    CloseHandle(osthread->interrupt_event());
     thread->set_osthread(NULL);
     delete osthread;
     return false;
@@ -714,7 +715,6 @@
          "os::free_thread but not current thread");
 
   CloseHandle(osthread->thread_handle());
-  CloseHandle(osthread->interrupt_event());
   delete osthread;
 }
 
@@ -3485,7 +3485,6 @@
 }
 
 
-
 // Short sleep, direct OS call.
 //
 // ms = 0, means allow others (if any) to run.
@@ -3593,49 +3592,6 @@
   return OS_OK;
 }
 
-void os::interrupt(Thread* thread) {
-  debug_only(Thread::check_for_dangling_thread_pointer(thread);)
-  assert(thread->is_Java_thread(), "invariant");
-  JavaThread* jt = (JavaThread*) thread;
-  OSThread* osthread = thread->osthread();
-  osthread->set_interrupted(true);
-  // More than one thread can get here with the same value of osthread,
-  // resulting in multiple notifications.  We do, however, want the store
-  // to interrupted() to be visible to other threads before we post
-  // the interrupt event.
-  OrderAccess::release();
-  SetEvent(osthread->interrupt_event());
-  // For JSR166:  unpark after setting status
-  jt->parker()->unpark();
-
-  ParkEvent * ev = thread->_ParkEvent;
-  if (ev != NULL) ev->unpark();
-
-  ev = jt->_SleepEvent;
-  if (ev != NULL) ev->unpark();
-}
-
-
-bool os::is_interrupted(Thread* thread, bool clear_interrupted) {
-  debug_only(Thread::check_for_dangling_thread_pointer(thread);)
-
-  OSThread* osthread = thread->osthread();
-  // There is no synchronization between the setting of the interrupt
-  // and it being cleared here. It is critical - see 6535709 - that
-  // we only clear the interrupt state, and reset the interrupt event,
-  // if we are going to report that we were indeed interrupted - else
-  // an interrupt can be "lost", leading to spurious wakeups or lost wakeups
-  // depending on the timing. By checking thread interrupt event to see
-  // if the thread gets real interrupt thus prevent spurious wakeup.
-  bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0);
-  if (interrupted && clear_interrupted) {
-    osthread->set_interrupted(false);
-    ResetEvent(osthread->interrupt_event());
-  } // Otherwise leave the interrupted state alone
-
-  return interrupted;
-}
-
 // GetCurrentThreadId() returns DWORD
 intx os::current_thread_id()  { return GetCurrentThreadId(); }
 
@@ -5346,7 +5302,7 @@
   JavaThread* thread = JavaThread::current();
 
   // Don't wait if interrupted or already triggered
-  if (Thread::is_interrupted(thread, false) ||
+  if (thread->is_interrupted(false) ||
       WaitForSingleObject(_ParkEvent, 0) == WAIT_OBJECT_0) {
     ResetEvent(_ParkEvent);
     return;
--- a/src/hotspot/share/ci/ciEnv.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/ci/ciEnv.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -539,7 +539,7 @@
     // Calculate accessibility the hard way.
     if (!k->is_loaded()) {
       is_accessible = false;
-    } else if (!oopDesc::equals(k->loader(), accessor->loader()) &&
+    } else if (k->loader() != accessor->loader() &&
                get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) {
       // Loaded only remotely.  Not linked yet.
       is_accessible = false;
@@ -590,7 +590,7 @@
     index = cpool->object_to_cp_index(cache_index);
     oop obj = cpool->resolved_references()->obj_at(cache_index);
     if (obj != NULL) {
-      if (oopDesc::equals(obj, Universe::the_null_sentinel())) {
+      if (obj == Universe::the_null_sentinel()) {
         return ciConstant(T_OBJECT, get_object(NULL));
       }
       BasicType bt = T_OBJECT;
--- a/src/hotspot/share/ci/ciObjectFactory.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/ci/ciObjectFactory.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -250,7 +250,7 @@
   // into the cache.
   Handle keyHandle(Thread::current(), key);
   ciObject* new_object = create_new_object(keyHandle());
-  assert(oopDesc::equals(keyHandle(), new_object->get_oop()), "must be properly recorded");
+  assert(keyHandle() == new_object->get_oop(), "must be properly recorded");
   init_ident_of(new_object);
   assert(Universe::heap()->is_in(new_object->get_oop()), "must be");
 
@@ -469,8 +469,8 @@
   for (int i=0; i<_unloaded_klasses->length(); i++) {
     ciKlass* entry = _unloaded_klasses->at(i);
     if (entry->name()->equals(name) &&
-        oopDesc::equals(entry->loader(), loader) &&
-        oopDesc::equals(entry->protection_domain(), domain)) {
+        entry->loader() == loader &&
+        entry->protection_domain() == domain) {
       // We've found a match.
       return entry;
     }
--- a/src/hotspot/share/ci/ciObjectFactory.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/ci/ciObjectFactory.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -74,7 +74,7 @@
   ciMetadata* create_new_metadata(Metadata* o);
 
   static bool is_equal(NonPermObject* p, oop key) {
-    return oopDesc::equals(p->object()->get_oop(), key);
+    return p->object()->get_oop() == key;
   }
 
   NonPermObject* &find_non_perm(oop key);
--- a/src/hotspot/share/classfile/classLoader.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/classLoader.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1325,7 +1325,7 @@
                                                            THREAD);
   if (HAS_PENDING_EXCEPTION) {
     if (DumpSharedSpaces) {
-      tty->print_cr("Preload Error: Failed to load %s", class_name);
+      log_error(cds)("Preload Error: Failed to load %s", class_name);
     }
     return NULL;
   }
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -236,7 +236,7 @@
   VerifyContainsOopClosure(oop target) : _target(target), _found(false) {}
 
   void do_oop(oop* p) {
-    if (p != NULL && oopDesc::equals(NativeAccess<AS_NO_KEEPALIVE>::oop_load(p), _target)) {
+    if (p != NULL && NativeAccess<AS_NO_KEEPALIVE>::oop_load(p) == _target) {
       _found = true;
     }
   }
@@ -437,7 +437,7 @@
 
     // Just return if this dependency is to a class with the same or a parent
     // class_loader.
-    if (oopDesc::equals(from, to) || java_lang_ClassLoader::isAncestor(from, to)) {
+    if (from == to || java_lang_ClassLoader::isAncestor(from, to)) {
       return; // this class loader is in the parent list, no need to add it.
     }
   }
--- a/src/hotspot/share/classfile/classLoaderExt.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -32,6 +32,7 @@
 #include "classfile/modules.hpp"
 #include "classfile/systemDictionaryShared.hpp"
 #include "classfile/vmSymbols.hpp"
+#include "logging/log.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/filemap.hpp"
 #include "memory/resourceArea.hpp"
@@ -146,7 +147,7 @@
       if (found != NULL) {
         // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java
         // If duplicated entries are found, the last one is used.
-        tty->print_cr("Warning: Duplicate name in Manifest: %s.\n"
+        log_warning(cds)("Warning: Duplicate name in Manifest: %s.\n"
                       "Ensure that the manifest does not have duplicate entries, and\n"
                       "that blank lines separate individual sections in both your\n"
                       "manifest and in the META-INF/MANIFEST.MF entry in the jar file:\n%s\n", tag, jar_path);
@@ -276,7 +277,7 @@
   }
 
   if (NULL == stream) {
-    tty->print_cr("Preload Warning: Cannot find %s", class_name);
+    log_warning(cds)("Preload Warning: Cannot find %s", class_name);
     return NULL;
   }
 
@@ -295,7 +296,7 @@
                                                            THREAD);
 
   if (HAS_PENDING_EXCEPTION) {
-    tty->print_cr("Preload Error: Failed to load %s", class_name);
+    log_error(cds)("Preload Error: Failed to load %s", class_name);
     return NULL;
   }
   return result;
--- a/src/hotspot/share/classfile/classLoaderStats.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/classLoaderStats.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -98,7 +98,7 @@
 class ClassLoaderStatsClosure : public CLDClosure {
 protected:
   static bool oop_equals(oop const& s1, oop const& s2) {
-    return oopDesc::equals(s1, s2);
+    return s1 == s2;
   }
 
   static unsigned oop_hash(oop const& s1) {
--- a/src/hotspot/share/classfile/dictionary.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/dictionary.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -153,13 +153,13 @@
   // a Dictionary entry, which can be moved if the Dictionary is resized.
   MutexLocker ml(ProtectionDomainSet_lock, Mutex::_no_safepoint_check_flag);
 #ifdef ASSERT
-  if (oopDesc::equals(protection_domain, instance_klass()->protection_domain())) {
+  if (protection_domain == instance_klass()->protection_domain()) {
     // Ensure this doesn't show up in the pd_set (invariant)
     bool in_pd_set = false;
     for (ProtectionDomainEntry* current = pd_set();
                                 current != NULL;
                                 current = current->next()) {
-      if (oopDesc::equals(current->object_no_keepalive(), protection_domain)) {
+      if (current->object_no_keepalive() == protection_domain) {
         in_pd_set = true;
         break;
       }
@@ -171,7 +171,7 @@
   }
 #endif /* ASSERT */
 
-  if (oopDesc::equals(protection_domain, instance_klass()->protection_domain())) {
+  if (protection_domain == instance_klass()->protection_domain()) {
     // Succeeds trivially
     return true;
   }
@@ -179,7 +179,7 @@
   for (ProtectionDomainEntry* current = pd_set();
                               current != NULL;
                               current = current->next()) {
-    if (oopDesc::equals(current->object_no_keepalive(), protection_domain)) return true;
+    if (current->object_no_keepalive() == protection_domain) return true;
   }
   return false;
 }
--- a/src/hotspot/share/classfile/javaClasses.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -878,7 +878,7 @@
   } else {
     assert(Universe::is_module_initialized() ||
            (ModuleEntryTable::javabase_defined() &&
-            (oopDesc::equals(module(), ModuleEntryTable::javabase_moduleEntry()->module()))),
+            (module() == ModuleEntryTable::javabase_moduleEntry()->module())),
            "Incorrect java.lang.Module specification while creating mirror");
     set_module(mirror(), module());
   }
@@ -955,7 +955,7 @@
     }
 
     // set the classLoader field in the java_lang_Class instance
-    assert(oopDesc::equals(class_loader(), k->class_loader()), "should be same");
+    assert(class_loader() == k->class_loader(), "should be same");
     set_class_loader(mirror(), class_loader());
 
     // Setup indirection from klass->mirror
@@ -1510,9 +1510,9 @@
     // Note: create_basic_type_mirror above initializes ak to a non-null value.
     type = ArrayKlass::cast(ak)->element_type();
   } else {
-    assert(oopDesc::equals(java_class, Universe::void_mirror()), "only valid non-array primitive");
+    assert(java_class == Universe::void_mirror(), "only valid non-array primitive");
   }
-  assert(oopDesc::equals(Universe::java_mirror(type), java_class), "must be consistent");
+  assert(Universe::java_mirror(type) == java_class, "must be consistent");
   return type;
 }
 
@@ -3712,14 +3712,14 @@
 }
 
 bool java_lang_invoke_MethodType::equals(oop mt1, oop mt2) {
-  if (oopDesc::equals(mt1, mt2))
+  if (mt1 == mt2)
     return true;
-  if (!oopDesc::equals(rtype(mt1), rtype(mt2)))
+  if (rtype(mt1) != rtype(mt2))
     return false;
   if (ptype_count(mt1) != ptype_count(mt2))
     return false;
   for (int i = ptype_count(mt1) - 1; i >= 0; i--) {
-    if (!oopDesc::equals(ptype(mt1, i), ptype(mt2, i)))
+    if (ptype(mt1, i) != ptype(mt2, i))
       return false;
   }
   return true;
@@ -3933,7 +3933,7 @@
   // This loop taken verbatim from ClassLoader.java:
   do {
     acl = parent(acl);
-    if (oopDesc::equals(cl, acl)) {
+    if (cl == acl) {
       return true;
     }
     assert(++loop_count > 0, "loop_count overflow");
@@ -3963,7 +3963,7 @@
 
   oop cl = SystemDictionary::java_system_loader();
   while(cl != NULL) {
-    if (oopDesc::equals(cl, loader)) return true;
+    if (cl == loader) return true;
     cl = parent(cl);
   }
   return false;
--- a/src/hotspot/share/classfile/javaClasses.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/javaClasses.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -52,7 +52,7 @@
 
 // Accessors
 bool java_lang_String::value_equals(typeArrayOop str_value1, typeArrayOop str_value2) {
-  return (oopDesc::equals(str_value1, str_value2) ||
+  return ((str_value1 == str_value2) ||
           (str_value1->length() == str_value2->length() &&
            (!memcmp(str_value1->base(T_BYTE),
                     str_value2->base(T_BYTE),
--- a/src/hotspot/share/classfile/modules.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/modules.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -306,7 +306,7 @@
 
   oop loader = java_lang_Module::loader(module_handle());
   // Make sure loader is not the jdk.internal.reflect.DelegatingClassLoader.
-  if (!oopDesc::equals(loader, java_lang_ClassLoader::non_reflection_class_loader(loader))) {
+  if (loader != java_lang_ClassLoader::non_reflection_class_loader(loader)) {
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
               "Class loader is an invalid delegating class loader");
   }
--- a/src/hotspot/share/classfile/protectionDomainCache.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/protectionDomainCache.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -160,7 +160,7 @@
 ProtectionDomainCacheEntry* ProtectionDomainCacheTable::find_entry(int index, Handle protection_domain) {
   assert_locked_or_safepoint(SystemDictionary_lock);
   for (ProtectionDomainCacheEntry* e = bucket(index); e != NULL; e = e->next()) {
-    if (oopDesc::equals(e->object_no_keepalive(), protection_domain())) {
+    if (e->object_no_keepalive() == protection_domain()) {
       return e;
     }
   }
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -177,7 +177,7 @@
     return false;
   }
   return (class_loader->klass() == SystemDictionary::jdk_internal_loader_ClassLoaders_AppClassLoader_klass() ||
-         oopDesc::equals(class_loader, _java_system_loader));
+         class_loader == _java_system_loader);
 }
 
 // Returns true if the passed class loader is the platform class loader.
@@ -393,7 +393,7 @@
     if ((childk != NULL ) && (is_superclass) &&
         ((quicksuperk = childk->java_super()) != NULL) &&
          ((quicksuperk->name() == super_name) &&
-            (oopDesc::equals(quicksuperk->class_loader(), class_loader())))) {
+            (quicksuperk->class_loader() == class_loader()))) {
            return quicksuperk;
     } else {
       PlaceholderEntry* probe = placeholders()->get_entry(p_index, p_hash, child_name, loader_data);
@@ -542,7 +542,7 @@
   bool calledholdinglock
       = ObjectSynchronizer::current_thread_holds_lock((JavaThread*)THREAD, lockObject);
   assert(calledholdinglock,"must hold lock for notify");
-  assert((!oopDesc::equals(lockObject(), _system_loader_lock_obj) && !is_parallelCapable(lockObject)), "unexpected double_lock_wait");
+  assert((lockObject() != _system_loader_lock_obj && !is_parallelCapable(lockObject)), "unexpected double_lock_wait");
   ObjectSynchronizer::notifyall(lockObject, THREAD);
   intptr_t recursions =  ObjectSynchronizer::complete_exit(lockObject, THREAD);
   SystemDictionary_lock->wait();
@@ -850,7 +850,7 @@
       // If everything was OK (no exceptions, no null return value), and
       // class_loader is NOT the defining loader, do a little more bookkeeping.
       if (!HAS_PENDING_EXCEPTION && k != NULL &&
-        !oopDesc::equals(k->class_loader(), class_loader())) {
+        k->class_loader() != class_loader()) {
 
         check_constraints(d_hash, k, class_loader, false, THREAD);
 
@@ -1003,7 +1003,7 @@
   if (unsafe_anonymous_host != NULL) {
     // Create a new CLD for an unsafe anonymous class, that uses the same class loader
     // as the unsafe_anonymous_host
-    guarantee(oopDesc::equals(unsafe_anonymous_host->class_loader(), class_loader()), "should be the same");
+    guarantee(unsafe_anonymous_host->class_loader() == class_loader(), "should be the same");
     loader_data = ClassLoaderData::unsafe_anonymous_class_loader_data(class_loader);
   } else {
     loader_data = ClassLoaderData::class_loader_data(class_loader());
@@ -1729,7 +1729,7 @@
       == ObjectSynchronizer::owner_other) {
     // contention will likely happen, so increment the corresponding
     // contention counter.
-    if (oopDesc::equals(loader_lock(), _system_loader_lock_obj)) {
+    if (loader_lock() == _system_loader_lock_obj) {
       ClassLoader::sync_systemLoaderLockContentionRate()->inc();
     } else {
       ClassLoader::sync_nonSystemLoaderLockContentionRate()->inc();
@@ -2150,7 +2150,7 @@
       // cleared if revocation occurs too often for this type
       // NOTE that we must only do this when the class is initally
       // defined, not each time it is referenced from a new class loader
-      if (oopDesc::equals(k->class_loader(), class_loader())) {
+      if (k->class_loader() == class_loader()) {
         k->set_prototype_header(markWord::biased_locking_prototype());
       }
     }
@@ -2343,7 +2343,7 @@
                                                Handle loader1, Handle loader2,
                                                bool is_method, TRAPS)  {
   // Nothing to do if loaders are the same.
-  if (oopDesc::equals(loader1(), loader2())) {
+  if (loader1() == loader2()) {
     return NULL;
   }
 
--- a/src/hotspot/share/code/dependencies.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/code/dependencies.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1813,12 +1813,12 @@
 
   if (changes == NULL) {
     // Validate all CallSites
-    if (!oopDesc::equals(java_lang_invoke_CallSite::target(call_site), method_handle))
+    if (java_lang_invoke_CallSite::target(call_site) != method_handle)
       return call_site->klass();  // assertion failed
   } else {
     // Validate the given CallSite
-    if (oopDesc::equals(call_site, changes->call_site()) && !oopDesc::equals(java_lang_invoke_CallSite::target(call_site), changes->method_handle())) {
-      assert(!oopDesc::equals(method_handle, changes->method_handle()), "must be");
+    if (call_site == changes->call_site() && java_lang_invoke_CallSite::target(call_site) != changes->method_handle()) {
+      assert(method_handle != changes->method_handle(), "must be");
       return call_site->klass();  // assertion failed
     }
   }
--- a/src/hotspot/share/compiler/compileBroker.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/compiler/compileBroker.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -316,7 +316,7 @@
   // We only allow the last compiler thread of each type to get removed.
   jobject last_compiler = c1 ? CompileBroker::compiler1_object(compiler_count - 1)
                              : CompileBroker::compiler2_object(compiler_count - 1);
-  if (oopDesc::equals(ct->threadObj(), JNIHandles::resolve_non_null(last_compiler))) {
+  if (ct->threadObj() == JNIHandles::resolve_non_null(last_compiler)) {
     if (do_it) {
       assert_locked_or_safepoint(CompileThread_lock); // Update must be consistent.
       compiler->set_num_compiler_threads(compiler_count - 1);
@@ -557,8 +557,14 @@
 }
 
 void CompileQueue::print_tty() {
-  ttyLocker ttyl;
-  print(tty);
+  ResourceMark rm;
+  stringStream ss;
+  // Dump the compile queue into a buffer before locking the tty
+  print(&ss);
+  {
+    ttyLocker ttyl;
+    tty->print("%s", ss.as_string());
+  }
 }
 
 CompilerCounters::CompilerCounters() {
@@ -1687,7 +1693,7 @@
   int compiler_number = 0;
   bool found = false;
   for (; compiler_number < count; compiler_number++) {
-    if (oopDesc::equals(JNIHandles::resolve_non_null(compiler_objects[compiler_number]), compiler_obj)) {
+    if (JNIHandles::resolve_non_null(compiler_objects[compiler_number]) == compiler_obj) {
       found = true;
       break;
     }
--- a/src/hotspot/share/gc/shared/barrierSet.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shared/barrierSet.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -144,10 +144,6 @@
 
   virtual void make_parsable(JavaThread* thread) {}
 
-#ifdef CHECK_UNHANDLED_OOPS
-  virtual bool oop_equals_operator_allowed() { return true; }
-#endif
-
 public:
   // Print a description of the memory for the barrier set
   virtual void print_on(outputStream* st) const = 0;
@@ -318,10 +314,6 @@
     static oop resolve(oop obj) {
       return Raw::resolve(obj);
     }
-
-    static bool equals(oop o1, oop o2) {
-      return Raw::equals(o1, o2);
-    }
   };
 };
 
--- a/src/hotspot/share/gc/shared/collectedHeap.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shared/collectedHeap.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -175,7 +175,7 @@
 }
 
 bool CollectedHeap::is_oop(oop object) const {
-  if (!check_obj_alignment(object)) {
+  if (!is_object_aligned(object)) {
     return false;
   }
 
@@ -345,7 +345,7 @@
 #endif // PRODUCT
 
 void CollectedHeap::check_oop_location(void* addr) const {
-  assert(check_obj_alignment(addr), "address is not aligned");
+  assert(is_object_aligned(addr), "address is not aligned");
   assert(_reserved.contains(addr),  "address is not in reserved heap");
 }
 
--- a/src/hotspot/share/gc/shared/referenceProcessor.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -282,7 +282,7 @@
 
   // First _prev_next ref actually points into DiscoveredList (gross).
   oop new_next;
-  if (oopDesc::equals_raw(_next_discovered, _current_discovered)) {
+  if (_next_discovered == _current_discovered) {
     // At the end of the list, we should make _prev point to itself.
     // If _ref is the first ref, then _prev_next will be in the DiscoveredList,
     // and _prev will be NULL.
@@ -472,7 +472,7 @@
 ReferenceProcessor::clear_discovered_references(DiscoveredList& refs_list) {
   oop obj = NULL;
   oop next = refs_list.head();
-  while (!oopDesc::equals_raw(next, obj)) {
+  while (next != obj) {
     obj = next;
     next = java_lang_ref_Reference::discovered(obj);
     java_lang_ref_Reference::set_discovered_raw(obj, NULL);
@@ -744,7 +744,7 @@
         ref_lists[to_idx].inc_length(refs_to_move);
 
         // Remove the chain from the from list.
-        if (oopDesc::equals_raw(move_tail, new_head)) {
+        if (move_tail == new_head) {
           // We found the end of the from list.
           ref_lists[from_idx].set_head(NULL);
         } else {
--- a/src/hotspot/share/gc/shared/referenceProcessor.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -143,13 +143,13 @@
   inline size_t removed() const { return _removed; }
 
   inline void move_to_next() {
-    if (oopDesc::equals_raw(_current_discovered, _next_discovered)) {
+    if (_current_discovered == _next_discovered) {
       // End of the list.
       _current_discovered = NULL;
     } else {
       _current_discovered = _next_discovered;
     }
-    assert(!oopDesc::equals_raw(_current_discovered, _first_seen), "cyclic ref_list found");
+    assert(_current_discovered != _first_seen, "cyclic ref_list found");
     _processed++;
   }
 };
--- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -363,7 +363,7 @@
   }
 
   typeArrayOop existing_value = lookup_or_add(value, latin1, hash);
-  if (oopDesc::equals_raw(existing_value, value)) {
+  if (existing_value == value) {
     // Same value, already known
     stat->inc_known();
     return;
--- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -142,7 +142,7 @@
   if (level >= _safe_oop) {
     oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
     msg.append("Forwardee:\n");
-    if (!oopDesc::equals_raw(obj, fwd)) {
+    if (obj != fwd) {
       if (level >= _safe_oop_fwd) {
         print_obj(msg, fwd);
       } else {
@@ -157,7 +157,7 @@
   if (level >= _safe_oop_fwd) {
     oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
     oop fwd2 = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(fwd);
-    if (!oopDesc::equals_raw(fwd, fwd2)) {
+    if (fwd != fwd2) {
       msg.append("Second forwardee:\n");
       print_obj_safe(msg, fwd2);
       msg.append("\n");
@@ -203,7 +203,7 @@
 
   oop fwd = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(obj));
 
-  if (!oopDesc::equals_raw(obj, fwd)) {
+  if (obj != fwd) {
     // When Full GC moves the objects, we cannot trust fwdptrs. If we got here, it means something
     // tries fwdptr manipulation when Full GC is running. The only exception is using the fwdptr
     // that still points to the object itself.
@@ -235,7 +235,7 @@
 
     // Step 4. Check for multiple forwardings
     oop fwd2 = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(fwd));
-    if (!oopDesc::equals_raw(fwd, fwd2)) {
+    if (fwd != fwd2) {
       print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_correct failed",
                     "Multiple forwardings",
                     file, line);
@@ -278,7 +278,7 @@
   assert_correct(interior_loc, obj, file, line);
   oop fwd = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(obj));
 
-  if (oopDesc::equals_raw(obj, fwd)) {
+  if (obj == fwd) {
     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_forwarded failed",
                   "Object should be forwarded",
                   file, line);
@@ -289,7 +289,7 @@
   assert_correct(interior_loc, obj, file, line);
   oop fwd = oop(ShenandoahForwarding::get_forwardee_raw_unchecked(obj));
 
-  if (!oopDesc::equals_raw(obj, fwd)) {
+  if (obj != fwd) {
     print_failure(_safe_all, obj, interior_loc, NULL, "Shenandoah assert_not_forwarded failed",
                   "Object should not be forwarded",
                   file, line);
--- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -238,7 +238,7 @@
   shenandoah_assert_in_cset(NULL, obj);
 
   oop fwd = resolve_forwarded_not_null(obj);
-  if (oopDesc::equals_raw(obj, fwd)) {
+  if (obj == fwd) {
     ShenandoahEvacOOMScope oom_evac_scope;
 
     Thread* thread = Thread::current();
@@ -267,7 +267,7 @@
       size_t count = 0;
       while ((cur < r->top()) && ctx->is_marked(oop(cur)) && (count++ < max)) {
         oop cur_oop = oop(cur);
-        if (oopDesc::equals_raw(cur_oop, resolve_forwarded_not_null(cur_oop))) {
+        if (cur_oop == resolve_forwarded_not_null(cur_oop)) {
           _heap->evacuate_object(cur_oop, thread);
         }
         cur = cur + cur_oop->size();
@@ -286,7 +286,7 @@
     oop fwd = resolve_forwarded_not_null(obj);
     if (evac_in_progress &&
         _heap->in_collection_set(obj) &&
-        oopDesc::equals_raw(obj, fwd)) {
+        obj == fwd) {
       Thread *t = Thread::current();
       if (t->is_GC_task_thread()) {
         return _heap->evacuate_object(obj, t);
--- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -103,7 +103,7 @@
     compare_value = expected;
     res = Raw::oop_atomic_cmpxchg(new_value, addr, compare_value);
     expected = res;
-  } while ((! oopDesc::equals_raw(compare_value, expected)) && oopDesc::equals_raw(resolve_forwarded(compare_value), resolve_forwarded(expected)));
+  } while ((compare_value != expected) && (resolve_forwarded(compare_value) == resolve_forwarded(expected)));
   if (res != NULL) {
     return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(res);
   } else {
@@ -118,7 +118,7 @@
   oop result = oop_atomic_cmpxchg_not_in_heap(new_value, addr, compare_value);
   const bool keep_alive = (decorators & AS_NO_KEEPALIVE) == 0;
   if (keep_alive && ShenandoahSATBBarrier && !CompressedOops::is_null(result) &&
-      oopDesc::equals_raw(result, compare_value) &&
+      (result == compare_value) &&
       ShenandoahHeap::heap()->is_concurrent_mark_in_progress()) {
     ShenandoahBarrierSet::barrier_set()->enqueue(result);
   }
@@ -307,7 +307,7 @@
     case EVAC_BARRIER:
       if (_heap->in_collection_set(obj)) {
         oop forw = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
-        if (oopDesc::equals_raw(forw, obj)) {
+        if (forw == obj) {
           forw = _heap->evacuate_object(forw, thread);
         }
         obj = forw;
--- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -92,7 +92,7 @@
     if (_heap->in_collection_set(obj)) {
       shenandoah_assert_marked(p, obj);
       oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
-      if (oopDesc::equals_raw(resolved, obj)) {
+      if (resolved == obj) {
         resolved = _heap->evacuate_object(obj, _thread);
       }
       RawAccess<IS_NOT_NULL>::oop_store(p, resolved);
@@ -119,7 +119,7 @@
     if (_heap->in_collection_set(obj)) {
       shenandoah_assert_marked(p, obj);
       oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
-      if (oopDesc::equals_raw(resolved, obj)) {
+      if (resolved == obj) {
         resolved = _heap->evacuate_object(obj, _thread);
       }
 
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1922,7 +1922,7 @@
     else if (prev == CANCELLED) return false;
     assert(ShenandoahSuspendibleWorkers, "should not get here when not using suspendible workers");
     assert(prev == NOT_CANCELLED, "must be NOT_CANCELLED");
-    {
+    if (Thread::current()->is_Java_thread()) {
       // We need to provide a safepoint here, otherwise we might
       // spin forever if a SP is pending.
       ThreadBlockInVM sp(JavaThread::current());
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -113,11 +113,11 @@
     oop heap_oop = CompressedOops::decode_not_null(o);
     if (in_collection_set(heap_oop)) {
       oop forwarded_oop = ShenandoahBarrierSet::resolve_forwarded_not_null(heap_oop);
-      if (oopDesc::equals_raw(forwarded_oop, heap_oop)) {
+      if (forwarded_oop == heap_oop) {
         forwarded_oop = evacuate_object(heap_oop, Thread::current());
       }
       oop prev = cas_oop(forwarded_oop, p, heap_oop);
-      if (oopDesc::equals_raw(prev, heap_oop)) {
+      if (prev == heap_oop) {
         return forwarded_oop;
       } else {
         return NULL;
@@ -146,7 +146,7 @@
 
   if (in_collection_set(heap_oop)) {
     oop forwarded_oop = ShenandoahBarrierSet::resolve_forwarded_not_null(heap_oop);
-    if (oopDesc::equals_raw(forwarded_oop, heap_oop)) {
+    if (forwarded_oop == heap_oop) {
       // E.g. during evacuation.
       return forwarded_oop;
     }
@@ -159,7 +159,7 @@
     // reference be updated later.
     oop witness = cas_oop(forwarded_oop, p, heap_oop);
 
-    if (!oopDesc::equals_raw(witness, heap_oop)) {
+    if (witness != heap_oop) {
       // CAS failed, someone had beat us to it. Normally, we would return the failure witness,
       // because that would be the proper write of to-space object, enforced by strong barriers.
       // However, there is a corner case with arraycopy. It can happen that a Java thread
@@ -279,7 +279,7 @@
   // Try to install the new forwarding pointer.
   oop copy_val = oop(copy);
   oop result = ShenandoahForwarding::try_update_forwardee(p, copy_val);
-  if (oopDesc::equals_raw(result, copy_val)) {
+  if (result == copy_val) {
     // Successfully evacuated. Our copy is now the public one!
     shenandoah_assert_correct(NULL, copy_val);
     return copy_val;
--- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -141,11 +141,11 @@
 
 public:
   ObjArrayChunkedTask(oop o = NULL) {
-    assert(oopDesc::equals_raw(decode_oop(encode_oop(o)), o), "oop can be encoded: " PTR_FORMAT, p2i(o));
+    assert(decode_oop(encode_oop(o)) ==  o, "oop can be encoded: " PTR_FORMAT, p2i(o));
     _obj = encode_oop(o);
   }
   ObjArrayChunkedTask(oop o, int chunk, int pow) {
-    assert(oopDesc::equals_raw(decode_oop(encode_oop(o)), o), "oop can be encoded: " PTR_FORMAT, p2i(o));
+    assert(decode_oop(encode_oop(o)) == o, "oop can be encoded: " PTR_FORMAT, p2i(o));
     assert(decode_chunk(encode_chunk(chunk)) == chunk, "chunk can be encoded: %d", chunk);
     assert(decode_pow(encode_pow(pow)) == pow, "pow can be encoded: %d", pow);
     _obj = encode_oop(o) | encode_chunk(chunk) | encode_pow(pow);
--- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -672,7 +672,7 @@
     if (!CompressedOops::is_null(o)) {
       oop obj = CompressedOops::decode_not_null(o);
       oop forw = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
-      if (!oopDesc::equals_raw(obj, forw)) {
+      if (obj != forw) {
         RawAccess<IS_NOT_NULL>::oop_store(p, forw);
       }
     }
--- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -42,14 +42,14 @@
     oop obj = CompressedOops::decode_not_null(o);
     if (DEGEN) {
       oop forw = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
-      if (!oopDesc::equals_raw(obj, forw)) {
+      if (obj != forw) {
         // Update reference.
         RawAccess<IS_NOT_NULL>::oop_store(p, forw);
       }
       obj = forw;
     } else if (_heap->in_collection_set(obj)) {
       oop forw = ShenandoahBarrierSet::resolve_forwarded_not_null(obj);
-      if (oopDesc::equals_raw(obj, forw)) {
+      if (obj == forw) {
         forw = _heap->evacuate_object(obj, thread);
       }
       shenandoah_assert_forwarded_except(p, obj, _heap->cancelled_gc());
--- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -35,6 +35,7 @@
 #include "memory/iterator.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/compressedOops.inline.hpp"
+#include "utilities/align.hpp"
 
 // Avoid name collision on verify_oop (defined in macroAssembler_arm.hpp)
 #ifdef verify_oop
@@ -98,7 +99,7 @@
 
     check(ShenandoahAsserts::_safe_unknown, obj, _heap->is_in(obj),
               "oop must be in heap");
-    check(ShenandoahAsserts::_safe_unknown, obj, check_obj_alignment(obj),
+    check(ShenandoahAsserts::_safe_unknown, obj, is_object_aligned(obj),
               "oop must be aligned");
 
     ShenandoahHeapRegion *obj_reg = _heap->heap_region_containing(obj);
@@ -153,12 +154,12 @@
 
     ShenandoahHeapRegion* fwd_reg = NULL;
 
-    if (!oopDesc::equals_raw(obj, fwd)) {
+    if (obj != fwd) {
       check(ShenandoahAsserts::_safe_oop, obj, _heap->is_in(fwd),
              "Forwardee must be in heap");
       check(ShenandoahAsserts::_safe_oop, obj, !CompressedOops::is_null(fwd),
              "Forwardee is set");
-      check(ShenandoahAsserts::_safe_oop, obj, check_obj_alignment(fwd),
+      check(ShenandoahAsserts::_safe_oop, obj, is_object_aligned(fwd),
              "Forwardee must be aligned");
 
       // Do this before touching fwd->size()
@@ -183,7 +184,7 @@
              "Forwardee end should be within the region");
 
       oop fwd2 = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(fwd);
-      check(ShenandoahAsserts::_safe_oop, obj, oopDesc::equals_raw(fwd, fwd2),
+      check(ShenandoahAsserts::_safe_oop, obj, (fwd == fwd2),
              "Double forwarding");
     } else {
       fwd_reg = obj_reg;
@@ -212,12 +213,12 @@
         // skip
         break;
       case ShenandoahVerifier::_verify_forwarded_none: {
-        check(ShenandoahAsserts::_safe_all, obj, oopDesc::equals_raw(obj, fwd),
+        check(ShenandoahAsserts::_safe_all, obj, (obj == fwd),
                "Should not be forwarded");
         break;
       }
       case ShenandoahVerifier::_verify_forwarded_allow: {
-        if (!oopDesc::equals_raw(obj, fwd)) {
+        if (obj != fwd) {
           check(ShenandoahAsserts::_safe_all, obj, obj_reg != fwd_reg,
                  "Forwardee should be in another region");
         }
@@ -237,7 +238,7 @@
         break;
       case ShenandoahVerifier::_verify_cset_forwarded:
         if (_heap->in_collection_set(obj)) {
-          check(ShenandoahAsserts::_safe_all, obj, !oopDesc::equals_raw(obj, fwd),
+          check(ShenandoahAsserts::_safe_all, obj, (obj != fwd),
                  "Object in collection set, should have forwardee");
         }
         break;
@@ -952,7 +953,7 @@
     if (!CompressedOops::is_null(o)) {
       oop obj = CompressedOops::decode_not_null(o);
       oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
-      if (!oopDesc::equals_raw(obj, fwd)) {
+      if (obj != fwd) {
         ShenandoahAsserts::print_failure(ShenandoahAsserts::_safe_all, obj, p, NULL,
                                          "Verify Roots", "Should not be forwarded", __FILE__, __LINE__);
       }
@@ -984,7 +985,7 @@
       }
 
       oop fwd = (oop) ShenandoahForwarding::get_forwardee_raw_unchecked(obj);
-      if (!oopDesc::equals_raw(obj, fwd)) {
+      if (obj != fwd) {
         ShenandoahAsserts::print_failure(ShenandoahAsserts::_safe_all, obj, p, NULL,
                 "Verify Roots In To-Space", "Should not be forwarded", __FILE__, __LINE__);
       }
--- a/src/hotspot/share/gc/z/zCPU.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zCPU.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -33,8 +33,8 @@
 #define ZCPU_UNKNOWN_SELF     (Thread*)-2;
 
 PaddedEnd<ZCPU::ZCPUAffinity>* ZCPU::_affinity = NULL;
-__thread Thread*  ZCPU::_self                  = ZCPU_UNKNOWN_SELF;
-__thread uint32_t ZCPU::_cpu                   = 0;
+THREAD_LOCAL Thread*           ZCPU::_self     = ZCPU_UNKNOWN_SELF;
+THREAD_LOCAL uint32_t          ZCPU::_cpu      = 0;
 
 void ZCPU::initialize() {
   assert(_affinity == NULL, "Already initialized");
--- a/src/hotspot/share/gc/z/zCPU.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zCPU.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -26,6 +26,7 @@
 
 #include "memory/allocation.hpp"
 #include "memory/padded.hpp"
+#include "utilities/globalDefinitions.hpp"
 
 class Thread;
 
@@ -36,8 +37,8 @@
   };
 
   static PaddedEnd<ZCPUAffinity>* _affinity;
-  static __thread Thread*         _self;
-  static __thread uint32_t        _cpu;
+  static THREAD_LOCAL Thread*     _self;
+  static THREAD_LOCAL uint32_t    _cpu;
 
 public:
   static void initialize();
--- a/src/hotspot/share/gc/z/zCollectedHeap.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -37,6 +37,7 @@
 #include "memory/metaspace/metaspaceEnums.hpp"
 #include "memory/universe.hpp"
 #include "runtime/mutexLocker.hpp"
+#include "utilities/align.hpp"
 
 ZCollectedHeap* ZCollectedHeap::heap() {
   CollectedHeap* heap = Universe::heap();
@@ -371,7 +372,7 @@
 }
 
 void ZCollectedHeap::check_oop_location(void* addr) const {
-  assert(check_obj_alignment(addr), "address is not aligned");
+  assert(is_object_aligned(addr), "address is not aligned");
 
   const uintptr_t addr_int = reinterpret_cast<uintptr_t>(addr);
   assert(addr_int >= ZAddressSpaceStart, "address is outside of the heap");
--- a/src/hotspot/share/gc/z/zLock.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zLock.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,16 +25,13 @@
 #define SHARE_GC_Z_ZLOCK_HPP
 
 #include "memory/allocation.hpp"
-#include <pthread.h>
+#include "runtime/os.hpp"
 
 class ZLock {
 private:
-  pthread_mutex_t _lock;
+  os::PlatformMutex _lock;
 
 public:
-  ZLock();
-  ~ZLock();
-
   void lock();
   bool try_lock();
   void unlock();
--- a/src/hotspot/share/gc/z/zLock.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zLock.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -26,27 +26,20 @@
 
 #include "gc/z/zLock.hpp"
 #include "runtime/atomic.hpp"
+#include "runtime/os.inline.hpp"
 #include "runtime/thread.hpp"
 #include "utilities/debug.hpp"
 
-inline ZLock::ZLock() {
-  pthread_mutex_init(&_lock, NULL);
-}
-
-inline ZLock::~ZLock() {
-  pthread_mutex_destroy(&_lock);
-}
-
 inline void ZLock::lock() {
-  pthread_mutex_lock(&_lock);
+  _lock.lock();
 }
 
 inline bool ZLock::try_lock() {
-  return pthread_mutex_trylock(&_lock) == 0;
+  return _lock.try_lock();
 }
 
 inline void ZLock::unlock() {
-  pthread_mutex_unlock(&_lock);
+  _lock.unlock();
 }
 
 inline ZReentrantLock::ZReentrantLock() :
--- a/src/hotspot/share/gc/z/zStat.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zStat.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -755,7 +755,7 @@
 //
 // Stat timer
 //
-__thread uint32_t ZStatTimerDisable::_active = 0;
+THREAD_LOCAL uint32_t ZStatTimerDisable::_active = 0;
 
 //
 // Stat sample/inc
--- a/src/hotspot/share/gc/z/zStat.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zStat.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -29,6 +29,7 @@
 #include "gc/z/zMetronome.hpp"
 #include "logging/logHandle.hpp"
 #include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
 #include "utilities/numberSeq.hpp"
 #include "utilities/ticks.hpp"
 
@@ -271,7 +272,7 @@
 //
 class ZStatTimerDisable : public StackObj {
 private:
-  static __thread uint32_t _active;
+  static THREAD_LOCAL uint32_t _active;
 
 public:
   ZStatTimerDisable() {
--- a/src/hotspot/share/gc/z/zThread.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zThread.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -26,13 +26,13 @@
 #include "runtime/thread.hpp"
 #include "utilities/debug.hpp"
 
-__thread bool      ZThread::_initialized;
-__thread uintptr_t ZThread::_id;
-__thread bool      ZThread::_is_vm;
-__thread bool      ZThread::_is_java;
-__thread bool      ZThread::_is_worker;
-__thread bool      ZThread::_is_runtime_worker;
-__thread uint      ZThread::_worker_id;
+THREAD_LOCAL bool      ZThread::_initialized;
+THREAD_LOCAL uintptr_t ZThread::_id;
+THREAD_LOCAL bool      ZThread::_is_vm;
+THREAD_LOCAL bool      ZThread::_is_java;
+THREAD_LOCAL bool      ZThread::_is_worker;
+THREAD_LOCAL bool      ZThread::_is_runtime_worker;
+THREAD_LOCAL uint      ZThread::_worker_id;
 
 void ZThread::initialize() {
   assert(!_initialized, "Already initialized");
--- a/src/hotspot/share/gc/z/zThread.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/gc/z/zThread.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,6 +25,7 @@
 #define SHARE_GC_Z_ZTHREAD_HPP
 
 #include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
 #include "utilities/debug.hpp"
 
 class ZThread : public AllStatic {
@@ -33,13 +34,13 @@
   friend class ZRuntimeWorkersInitializeTask;
 
 private:
-  static __thread bool      _initialized;
-  static __thread uintptr_t _id;
-  static __thread bool      _is_vm;
-  static __thread bool      _is_java;
-  static __thread bool      _is_worker;
-  static __thread bool      _is_runtime_worker;
-  static __thread uint      _worker_id;
+  static THREAD_LOCAL bool      _initialized;
+  static THREAD_LOCAL uintptr_t _id;
+  static THREAD_LOCAL bool      _is_vm;
+  static THREAD_LOCAL bool      _is_java;
+  static THREAD_LOCAL bool      _is_worker;
+  static THREAD_LOCAL bool      _is_runtime_worker;
+  static THREAD_LOCAL uint      _worker_id;
 
   static void initialize();
 
--- a/src/hotspot/share/gc/z/zUtils.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-#include "precompiled.hpp"
-#include "gc/z/zUtils.inline.hpp"
-#include "utilities/debug.hpp"
-
-#include <stdlib.h>
-
-uintptr_t ZUtils::alloc_aligned(size_t alignment, size_t size) {
-  void* res = NULL;
-
-  if (posix_memalign(&res, alignment, size) != 0) {
-    fatal("posix_memalign() failed");
-  }
-
-  memset(res, 0, size);
-
-  return (uintptr_t)res;
-}
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -2436,7 +2436,7 @@
                   handle_exception);
           result = THREAD->vm_result();
         }
-        if (oopDesc::equals(result, Universe::the_null_sentinel()))
+        if (result == Universe::the_null_sentinel())
           result = NULL;
 
         VERIFY_OOP(result);
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -206,7 +206,7 @@
     if (rindex >= 0) {
       oop coop = m->constants()->resolved_references()->obj_at(rindex);
       oop roop = (result == NULL ? Universe::the_null_sentinel() : result);
-      assert(oopDesc::equals(roop, coop), "expected result for assembly code");
+      assert(roop == coop, "expected result for assembly code");
     }
   }
 #endif
--- a/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/instrumentation/jfrEventClassTransformer.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -44,7 +44,6 @@
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/array.hpp"
-#include "oops/constantPool.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
@@ -1522,7 +1521,7 @@
     assert(new_method != NULL, "invariant");
     assert(new_method->name() == old_method->name(), "invariant");
     assert(new_method->signature() == old_method->signature(), "invariant");
-    *new_method->trace_flags_addr() = old_method->trace_flags();
+    new_method->set_trace_flags(old_method->trace_flags());
     assert(new_method->trace_flags() == old_method->trace_flags(), "invariant");
   }
 }
--- a/src/hotspot/share/jfr/jfr.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/jfr.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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
@@ -84,7 +84,9 @@
 }
 
 void Jfr::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
-  LeakProfiler::oops_do(is_alive, f);
+  if (LeakProfiler::is_running()) {
+    LeakProfiler::oops_do(is_alive, f);
+  }
 }
 
 bool Jfr::on_flight_recorder_option(const JavaVMOption** option, char* delimiter) {
--- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -55,18 +55,23 @@
   return !_edges->has_entries();
 }
 
-void EdgeStore::assign_id(EdgeEntry* entry) {
+void EdgeStore::on_link(EdgeEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->id() == 0, "invariant");
   entry->set_id(++_edge_id_counter);
 }
 
-bool EdgeStore::equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry) {
+bool EdgeStore::on_equals(uintptr_t hash, const EdgeEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return true;
 }
 
+void EdgeStore::on_unlink(EdgeEntry* entry) {
+  assert(entry != NULL, "invariant");
+  // nothing
+}
+
 #ifdef ASSERT
 bool EdgeStore::contains(const oop* reference) const {
   return get(reference) != NULL;
@@ -75,22 +80,21 @@
 
 StoredEdge* EdgeStore::get(const oop* reference) const {
   assert(reference != NULL, "invariant");
-  const StoredEdge e(NULL, reference);
-  EdgeEntry* const entry = _edges->lookup_only(e, (uintptr_t)reference);
+  EdgeEntry* const entry = _edges->lookup_only((uintptr_t)reference);
   return entry != NULL ? entry->literal_addr() : NULL;
 }
 
 StoredEdge* EdgeStore::put(const oop* reference) {
   assert(reference != NULL, "invariant");
   const StoredEdge e(NULL, reference);
-  assert(NULL == _edges->lookup_only(e, (uintptr_t)reference), "invariant");
-  EdgeEntry& entry = _edges->put(e, (uintptr_t)reference);
+  assert(NULL == _edges->lookup_only((uintptr_t)reference), "invariant");
+  EdgeEntry& entry = _edges->put((uintptr_t)reference, e);
   return entry.literal_addr();
 }
 
 traceid EdgeStore::get_id(const Edge* edge) const {
   assert(edge != NULL, "invariant");
-  EdgeEntry* const entry = _edges->lookup_only(*edge, (uintptr_t)edge->reference());
+  EdgeEntry* const entry = _edges->lookup_only((uintptr_t)edge->reference());
   assert(entry != NULL, "invariant");
   return entry->id();
 }
--- a/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/chains/edgeStore.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -58,7 +58,7 @@
 };
 
 class EdgeStore : public CHeapObj<mtTracing> {
-  typedef HashTableHost<StoredEdge, traceid, Entry, EdgeStore> EdgeHashTable;
+  typedef HashTableHost<StoredEdge, traceid, JfrHashtableEntry, EdgeStore> EdgeHashTable;
   typedef EdgeHashTable::HashEntry EdgeEntry;
   template <typename,
             typename,
@@ -74,8 +74,9 @@
   EdgeHashTable* _edges;
 
   // Hash table callbacks
-  void assign_id(EdgeEntry* entry);
-  bool equals(const Edge& query, uintptr_t hash, const EdgeEntry* entry);
+  void on_link(EdgeEntry* entry);
+  bool on_equals(uintptr_t hash, const EdgeEntry* entry);
+  void on_unlink(EdgeEntry* entry);
 
   StoredEdge* get(const oop* reference) const;
   StoredEdge* put(const oop* reference);
--- a/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/chains/pathToGcRootsOperation.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -43,7 +43,6 @@
 #include "jfr/leakprofiler/utilities/granularTimer.hpp"
 #include "logging/log.hpp"
 #include "memory/universe.hpp"
-#include "oops/markWord.hpp"
 #include "oops/oop.inline.hpp"
 #include "runtime/safepoint.hpp"
 #include "utilities/globalDefinitions.hpp"
@@ -101,7 +100,7 @@
   // Save the original markWord for the potential leak objects,
   // to be restored on function exit
   ObjectSampleMarker marker;
-  if (ObjectSampleCheckpoint::mark(_sampler, marker, _emit_all) == 0) {
+  if (ObjectSampleCheckpoint::save_mark_words(_sampler, marker, _emit_all) == 0) {
     // no valid samples to process
     return;
   }
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -24,10 +24,6 @@
 
 #include "precompiled.hpp"
 #include "jfr/jfrEvents.hpp"
-#include "jfr/recorder/jfrRecorder.hpp"
-#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
-#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
 #include "jfr/leakprofiler/chains/edgeStore.hpp"
 #include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
@@ -35,14 +31,101 @@
 #include "jfr/leakprofiler/leakProfiler.hpp"
 #include "jfr/leakprofiler/sampling/objectSample.hpp"
 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
-#include "jfr/leakprofiler/utilities/rootType.hpp"
-#include "jfr/metadata/jfrSerializer.hpp"
-#include "runtime/interfaceSupport.inline.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/thread.inline.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/service/jfrOptionSet.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
+#include "jfr/utilities/jfrHashtable.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/thread.hpp"
+#include "utilities/growableArray.hpp"
+
+static bool predicate(GrowableArray<traceid>* set, traceid id) {
+  assert(set != NULL, "invariant");
+  bool found = false;
+  set->find_sorted<traceid, compare_traceid>(id, found);
+  return found;
+}
+
+static bool mutable_predicate(GrowableArray<traceid>* set, traceid id) {
+  assert(set != NULL, "invariant");
+  bool found = false;
+  const int location = set->find_sorted<traceid, compare_traceid>(id, found);
+  if (!found) {
+    set->insert_before(location, id);
+  }
+  return found;
+}
+
+static bool add(GrowableArray<traceid>* set, traceid id) {
+  assert(set != NULL, "invariant");
+  return mutable_predicate(set, id);
+}
+
+const int initial_array_size = 64;
+
+template <typename T>
+static GrowableArray<T>* c_heap_allocate_array(int size = initial_array_size) {
+  return new (ResourceObj::C_HEAP, mtTracing) GrowableArray<T>(size, true, mtTracing);
+}
+
+static GrowableArray<traceid>* unloaded_thread_id_set = NULL;
 
-template <typename SampleProcessor>
-static void do_samples(ObjectSample* sample, const ObjectSample* const end, SampleProcessor& processor) {
+class ThreadIdExclusiveAccess : public StackObj {
+ private:
+  static Semaphore _mutex_semaphore;
+ public:
+  ThreadIdExclusiveAccess() { _mutex_semaphore.wait(); }
+  ~ThreadIdExclusiveAccess() { _mutex_semaphore.signal(); }
+};
+
+Semaphore ThreadIdExclusiveAccess::_mutex_semaphore(1);
+
+static bool has_thread_exited(traceid tid) {
+  assert(tid != 0, "invariant");
+  return unloaded_thread_id_set != NULL && predicate(unloaded_thread_id_set, tid);
+}
+
+static void add_to_unloaded_thread_set(traceid tid) {
+  ThreadIdExclusiveAccess lock;
+  if (unloaded_thread_id_set == NULL) {
+    unloaded_thread_id_set = c_heap_allocate_array<traceid>();
+  }
+  add(unloaded_thread_id_set, tid);
+}
+
+void ObjectSampleCheckpoint::on_thread_exit(JavaThread* jt) {
+  assert(jt != NULL, "invariant");
+  if (LeakProfiler::is_running()) {
+    add_to_unloaded_thread_set(jt->jfr_thread_local()->thread_id());
+  }
+}
+
+// Track the set of unloaded klasses during a chunk / epoch.
+// Methods in stacktraces belonging to unloaded klasses must not be accessed.
+static GrowableArray<traceid>* unloaded_klass_set = NULL;
+
+static void add_to_unloaded_klass_set(traceid klass_id) {
+  if (unloaded_klass_set == NULL) {
+    unloaded_klass_set = c_heap_allocate_array<traceid>();
+  }
+  unloaded_klass_set->append(klass_id);
+}
+
+static void sort_unloaded_klass_set() {
+  if (unloaded_klass_set != NULL && unloaded_klass_set->length() > 1) {
+    unloaded_klass_set->sort(sort_traceid);
+  }
+}
+
+void ObjectSampleCheckpoint::on_klass_unload(const Klass* k) {
+  assert(k != NULL, "invariant");
+  add_to_unloaded_klass_set(TRACE_ID(k));
+}
+
+template <typename Processor>
+static void do_samples(ObjectSample* sample, const ObjectSample* end, Processor& processor) {
   assert(sample != NULL, "invariant");
   while (sample != end) {
     processor.sample_do(sample);
@@ -50,244 +133,339 @@
   }
 }
 
-class RootSystemType : public JfrSerializer {
- public:
-  void serialize(JfrCheckpointWriter& writer) {
-    const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
-    writer.write_count(nof_root_systems);
-    for (u4 i = 0; i < nof_root_systems; ++i) {
-      writer.write_key(i);
-      writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
-    }
-  }
-};
+template <typename Processor>
+static void iterate_samples(Processor& processor, bool all = false) {
+  ObjectSampler* const sampler = ObjectSampler::sampler();
+  assert(sampler != NULL, "invariant");
+  ObjectSample* const last = sampler->last();
+  assert(last != NULL, "invariant");
+  do_samples(last, all ? NULL : sampler->last_resolved(), processor);
+}
 
-class RootType : public JfrSerializer {
+class SampleMarker {
+ private:
+  ObjectSampleMarker& _marker;
+  jlong _last_sweep;
+  int _count;
  public:
-  void serialize(JfrCheckpointWriter& writer) {
-    const u4 nof_root_types = OldObjectRoot::_number_of_types;
-    writer.write_count(nof_root_types);
-    for (u4 i = 0; i < nof_root_types; ++i) {
-      writer.write_key(i);
-      writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
-    }
-  }
-};
-
-class CheckpointInstall {
- private:
-  const JfrCheckpointBlobHandle& _cp;
- public:
-  CheckpointInstall(const JfrCheckpointBlobHandle& cp) : _cp(cp) {}
+  SampleMarker(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker), _last_sweep(last_sweep), _count(0) {}
   void sample_do(ObjectSample* sample) {
-    assert(sample != NULL, "invariant");
-    if (!sample->is_dead()) {
-      sample->set_klass_checkpoint(_cp);
+    if (sample->is_alive_and_older_than(_last_sweep)) {
+      _marker.mark(sample->object());
+      ++_count;
     }
   }
-};
-
-class CheckpointWrite {
- private:
-  JfrCheckpointWriter& _writer;
-  const jlong _last_sweep;
- public:
-  CheckpointWrite(JfrCheckpointWriter& writer, jlong last_sweep) : _writer(writer), _last_sweep(last_sweep) {}
-  void sample_do(ObjectSample* sample) {
-    assert(sample != NULL, "invariant");
-    if (sample->is_alive_and_older_than(_last_sweep)) {
-      if (sample->has_thread_checkpoint()) {
-        const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
-        thread_cp->exclusive_write(_writer);
-      }
-      if (sample->has_klass_checkpoint()) {
-        const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
-        klass_cp->exclusive_write(_writer);
-      }
-    }
-  }
-};
-
-class CheckpointStateReset {
- private:
-  const jlong _last_sweep;
- public:
-  CheckpointStateReset(jlong last_sweep) : _last_sweep(last_sweep) {}
-  void sample_do(ObjectSample* sample) {
-    assert(sample != NULL, "invariant");
-    if (sample->is_alive_and_older_than(_last_sweep)) {
-      if (sample->has_thread_checkpoint()) {
-        const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
-        thread_cp->reset_write_state();
-      }
-      if (sample->has_klass_checkpoint()) {
-        const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
-        klass_cp->reset_write_state();
-      }
-    }
-  }
-};
-
-class StackTraceWrite {
- private:
-  JfrStackTraceRepository& _stack_trace_repo;
-  JfrCheckpointWriter& _writer;
-  int _count;
- public:
-  StackTraceWrite(JfrStackTraceRepository& stack_trace_repo, JfrCheckpointWriter& writer) :
-    _stack_trace_repo(stack_trace_repo), _writer(writer), _count(0) {
-    JfrStacktrace_lock->lock_without_safepoint_check();
-  }
-  ~StackTraceWrite() {
-    assert(JfrStacktrace_lock->owned_by_self(), "invariant");
-    JfrStacktrace_lock->unlock();
-  }
-
-  void sample_do(ObjectSample* sample) {
-    assert(sample != NULL, "invariant");
-    if (!sample->is_dead()) {
-      if (sample->has_stack_trace()) {
-        JfrTraceId::use(sample->klass(), true);
-        _stack_trace_repo.write(_writer, sample->stack_trace_id(), sample->stack_trace_hash());
-        ++_count;
-      }
-    }
-  }
-
   int count() const {
     return _count;
   }
 };
 
-class SampleMark {
+int ObjectSampleCheckpoint::save_mark_words(const ObjectSampler* sampler, ObjectSampleMarker& marker, bool emit_all) {
+  assert(sampler != NULL, "invariant");
+  if (sampler->last() == NULL) {
+    return 0;
+  }
+  SampleMarker sample_marker(marker, emit_all ? max_jlong : sampler->last_sweep().value());
+  iterate_samples(sample_marker, true);
+  return sample_marker.count();
+}
+
+class BlobCache {
+  typedef HashTableHost<JfrBlobHandle, traceid, JfrHashtableEntry, BlobCache> BlobTable;
+  typedef BlobTable::HashEntry BlobEntry;
  private:
-  ObjectSampleMarker& _marker;
-  jlong _last_sweep;
-  int _count;
+  BlobTable _table;
+  traceid _lookup_id;
  public:
-  SampleMark(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker),
-                                                             _last_sweep(last_sweep),
-                                                             _count(0) {}
+  BlobCache(size_t size) : _table(this, size), _lookup_id(0) {}
+  JfrBlobHandle get(const ObjectSample* sample);
+  void put(const ObjectSample* sample, const JfrBlobHandle& blob);
+  // Hash table callbacks
+  void on_link(const BlobEntry* entry) const;
+  bool on_equals(uintptr_t hash, const BlobEntry* entry) const;
+  void on_unlink(BlobEntry* entry) const;
+};
+
+JfrBlobHandle BlobCache::get(const ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  _lookup_id = sample->stack_trace_id();
+  assert(_lookup_id != 0, "invariant");
+  BlobEntry* const entry = _table.lookup_only(sample->stack_trace_hash());
+  return entry != NULL ? entry->literal() : JfrBlobHandle();
+}
+
+void BlobCache::put(const ObjectSample* sample, const JfrBlobHandle& blob) {
+  assert(sample != NULL, "invariant");
+  assert(_table.lookup_only(sample->stack_trace_hash()) == NULL, "invariant");
+  _lookup_id = sample->stack_trace_id();
+  assert(_lookup_id != 0, "invariant");
+  _table.put(sample->stack_trace_hash(), blob);
+}
+
+inline void BlobCache::on_link(const BlobEntry* entry) const {
+  assert(entry != NULL, "invariant");
+  assert(entry->id() == 0, "invariant");
+  entry->set_id(_lookup_id);
+}
+
+inline bool BlobCache::on_equals(uintptr_t hash, const BlobEntry* entry) const {
+  assert(entry != NULL, "invariant");
+  assert(entry->hash() == hash, "invariant");
+  return entry->id() == _lookup_id;
+}
+
+inline void BlobCache::on_unlink(BlobEntry* entry) const {
+  assert(entry != NULL, "invariant");
+}
+
+static GrowableArray<traceid>* id_set = NULL;
+
+static void prepare_for_resolution() {
+  id_set = new GrowableArray<traceid>(JfrOptionSet::old_object_queue_size());
+  sort_unloaded_klass_set();
+}
+
+static bool stack_trace_precondition(const ObjectSample* sample) {
+  assert(sample != NULL, "invariant");
+  return sample->has_stack_trace_id() && !sample->is_dead();
+}
+
+class StackTraceBlobInstaller {
+ private:
+  const JfrStackTraceRepository& _stack_trace_repo;
+  BlobCache _cache;
+  const JfrStackTrace* resolve(const ObjectSample* sample);
+  void install(ObjectSample* sample);
+ public:
+  StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo);
   void sample_do(ObjectSample* sample) {
-    assert(sample != NULL, "invariant");
-    if (sample->is_alive_and_older_than(_last_sweep)) {
-      _marker.mark(sample->object());
-      ++_count;
+    if (stack_trace_precondition(sample)) {
+      install(sample);
     }
   }
-
-  int count() const {
-    return _count;
-  }
 };
 
-void ObjectSampleCheckpoint::install(JfrCheckpointWriter& writer, bool class_unload, bool type_set) {
-  if (!writer.has_data()) {
+StackTraceBlobInstaller::StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo) :
+  _stack_trace_repo(stack_trace_repo), _cache(JfrOptionSet::old_object_queue_size()) {
+  prepare_for_resolution();
+}
+
+const JfrStackTrace* StackTraceBlobInstaller::resolve(const ObjectSample* sample) {
+  return _stack_trace_repo.lookup(sample->stack_trace_hash(), sample->stack_trace_id());
+}
+
+#ifdef ASSERT
+static void validate_stack_trace(const ObjectSample* sample, const JfrStackTrace* stack_trace) {
+  assert(!sample->has_stacktrace(), "invariant");
+  assert(stack_trace != NULL, "invariant");
+  assert(stack_trace->hash() == sample->stack_trace_hash(), "invariant");
+  assert(stack_trace->id() == sample->stack_trace_id(), "invariant");
+}
+#endif
+
+void StackTraceBlobInstaller::install(ObjectSample* sample) {
+  JfrBlobHandle blob = _cache.get(sample);
+  if (blob.valid()) {
+    sample->set_stacktrace(blob);
     return;
   }
-
-  assert(writer.has_data(), "invariant");
-  const JfrCheckpointBlobHandle h_cp = writer.checkpoint_blob();
-  CheckpointInstall install(h_cp);
-
-  // Class unload implies a safepoint.
-  // Not class unload implies the object sampler is locked, because it was claimed exclusively earlier.
-  // Therefore: direct access the object sampler instance is safe.
-  ObjectSampler* const object_sampler = ObjectSampler::sampler();
-  assert(object_sampler != NULL, "invariant");
+  const JfrStackTrace* const stack_trace = resolve(sample);
+  DEBUG_ONLY(validate_stack_trace(sample, stack_trace));
+  JfrCheckpointWriter writer(false, true, Thread::current());
+  writer.write_type(TYPE_STACKTRACE);
+  writer.write_count(1);
+  ObjectSampleCheckpoint::write_stacktrace(stack_trace, writer);
+  blob = writer.move();
+  _cache.put(sample, blob);
+  sample->set_stacktrace(blob);
+}
 
-  ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
-  const ObjectSample* const last_resolved = object_sampler->last_resolved();
-
-  // install only to new samples since last resolved checkpoint
-  if (last != last_resolved) {
-    do_samples(last, last_resolved, install);
-    if (class_unload) {
-      return;
-    }
-    if (type_set) {
-      object_sampler->set_last_resolved(last);
-    }
+static void install_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
+  assert(sampler != NULL, "invariant");
+  const ObjectSample* const last = sampler->last();
+  if (last != sampler->last_resolved()) {
+    StackTraceBlobInstaller installer(stack_trace_repo);
+    iterate_samples(installer);
   }
 }
 
-void ObjectSampleCheckpoint::write(ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) {
+// caller needs ResourceMark
+void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
+  assert(sampler != NULL, "invariant");
+  assert(LeakProfiler::is_running(), "invariant");
+  install_stack_traces(sampler, stack_trace_repo);
+}
+
+static traceid get_klass_id(traceid method_id) {
+  assert(method_id != 0, "invariant");
+  return method_id >> TRACE_ID_SHIFT;
+}
+
+static bool is_klass_unloaded(traceid method_id) {
+  return unloaded_klass_set != NULL && predicate(unloaded_klass_set, get_klass_id(method_id));
+}
+
+static bool is_processed(traceid id) {
+  assert(id != 0, "invariant");
+  assert(id_set != NULL, "invariant");
+  return mutable_predicate(id_set, id);
+}
+
+void ObjectSampleCheckpoint::add_to_leakp_set(const Method* method, traceid method_id) {
+  if (is_processed(method_id) || is_klass_unloaded(method_id)) {
+    return;
+  }
+  JfrTraceId::set_leakp(method);
+}
+
+void ObjectSampleCheckpoint::write_stacktrace(const JfrStackTrace* trace, JfrCheckpointWriter& writer) {
+  assert(trace != NULL, "invariant");
+  // JfrStackTrace
+  writer.write(trace->id());
+  writer.write((u1)!trace->_reached_root);
+  writer.write(trace->_nr_of_frames);
+  // JfrStackFrames
+  for (u4 i = 0; i < trace->_nr_of_frames; ++i) {
+    const JfrStackFrame& frame = trace->_frames[i];
+    frame.write(writer);
+    add_to_leakp_set(frame._method, frame._methodid);
+  }
+}
+
+static void write_blob(const JfrBlobHandle& blob, JfrCheckpointWriter& writer, bool reset) {
+  if (reset) {
+    blob->reset_write_state();
+    return;
+  }
+  blob->exclusive_write(writer);
+}
+
+static void write_type_set_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
+  if (sample->has_type_set()) {
+    write_blob(sample->type_set(), writer, reset);
+  }
+}
+
+static void write_thread_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
+  assert(sample->has_thread(), "invariant");
+  if (has_thread_exited(sample->thread_id())) {
+    write_blob(sample->thread(), writer, reset);
+  }
+}
+
+static void write_stacktrace_blob(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
+  if (sample->has_stacktrace()) {
+    write_blob(sample->stacktrace(), writer, reset);
+  }
+}
+
+static void write_blobs(const ObjectSample* sample, JfrCheckpointWriter& writer, bool reset) {
+  assert(sample != NULL, "invariant");
+  write_stacktrace_blob(sample, writer, reset);
+  write_thread_blob(sample, writer, reset);
+  write_type_set_blob(sample, writer, reset);
+}
+
+class BlobWriter {
+ private:
+  const ObjectSampler* _sampler;
+  JfrCheckpointWriter& _writer;
+  const jlong _last_sweep;
+  bool _reset;
+ public:
+  BlobWriter(const ObjectSampler* sampler, JfrCheckpointWriter& writer, jlong last_sweep) :
+    _sampler(sampler), _writer(writer), _last_sweep(last_sweep), _reset(false)  {}
+  void sample_do(ObjectSample* sample) {
+    if (sample->is_alive_and_older_than(_last_sweep)) {
+      write_blobs(sample, _writer, _reset);
+    }
+  }
+  void set_reset() {
+    _reset = true;
+  }
+};
+
+static void write_sample_blobs(const ObjectSampler* sampler, bool emit_all, Thread* thread) {
+  // sample set is predicated on time of last sweep
+  const jlong last_sweep = emit_all ? max_jlong : sampler->last_sweep().value();
+  JfrCheckpointWriter writer(false, false, thread);
+  BlobWriter cbw(sampler, writer, last_sweep);
+  iterate_samples(cbw, true);
+  // reset blob write states
+  cbw.set_reset();
+  iterate_samples(cbw, true);
+}
+
+void ObjectSampleCheckpoint::write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) {
   assert(sampler != NULL, "invariant");
   assert(edge_store != NULL, "invariant");
   assert(thread != NULL, "invariant");
-
-  static bool types_registered = false;
-  if (!types_registered) {
-    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
-    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
-    types_registered = true;
-  }
-
-  const jlong last_sweep = emit_all ? max_jlong : sampler->last_sweep().value();
-  ObjectSample* const last = const_cast<ObjectSample*>(sampler->last());
-  {
-    JfrCheckpointWriter writer(false, false, thread);
-    CheckpointWrite checkpoint_write(writer, last_sweep);
-    do_samples(last, NULL, checkpoint_write);
-  }
-
-  CheckpointStateReset state_reset(last_sweep);
-  do_samples(last, NULL, state_reset);
-
+  write_sample_blobs(sampler, emit_all, thread);
+  // write reference chains
   if (!edge_store->is_empty()) {
-    // java object and chain representations
     JfrCheckpointWriter writer(false, true, thread);
     ObjectSampleWriter osw(writer, edge_store);
     edge_store->iterate(osw);
   }
 }
 
-int ObjectSampleCheckpoint::mark(ObjectSampler* object_sampler, ObjectSampleMarker& marker, bool emit_all) {
-  assert(object_sampler != NULL, "invariant");
-  ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
-  if (last == NULL) {
-    return 0;
+static void clear_unloaded_klass_set() {
+  if (unloaded_klass_set != NULL && unloaded_klass_set->is_nonempty()) {
+    unloaded_klass_set->clear();
   }
-  const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
-  SampleMark mark(marker, last_sweep);
-  do_samples(last, NULL, mark);
-  return mark.count();
+}
+
+// A linked list of saved type set blobs for the epoch.
+// The link consist of a reference counted handle.
+static JfrBlobHandle saved_type_set_blobs;
+
+static void release_state_for_previous_epoch() {
+  // decrements the reference count and the list is reinitialized
+  saved_type_set_blobs = JfrBlobHandle();
+  clear_unloaded_klass_set();
 }
 
-WriteObjectSampleStacktrace::WriteObjectSampleStacktrace(ObjectSampler* sampler, JfrStackTraceRepository& repo) :
-  _sampler(sampler), _stack_trace_repo(repo) {}
-
-bool WriteObjectSampleStacktrace::process() {
-  assert(LeakProfiler::is_running(), "invariant");
-  assert(_sampler != NULL, "invariant");
+class BlobInstaller {
+ public:
+  ~BlobInstaller() {
+    release_state_for_previous_epoch();
+  }
+  void sample_do(ObjectSample* sample) {
+    if (!sample->is_dead()) {
+      sample->set_type_set(saved_type_set_blobs);
+    }
+  }
+};
 
-  ObjectSample* const last = const_cast<ObjectSample*>(_sampler->last());
-  const ObjectSample* const last_resolved = _sampler->last_resolved();
-  if (last == last_resolved) {
-    return true;
-  }
-
-  JfrCheckpointWriter writer(false, true, Thread::current());
-  const JfrCheckpointContext ctx = writer.context();
-
-  writer.write_type(TYPE_STACKTRACE);
-  const jlong count_offset = writer.reserve(sizeof(u4));
+static void install_type_set_blobs() {
+  BlobInstaller installer;
+  iterate_samples(installer);
+}
 
-  int count = 0;
-  {
-    StackTraceWrite stack_trace_write(_stack_trace_repo, writer); // JfrStacktrace_lock
-    do_samples(last, last_resolved, stack_trace_write);
-    count = stack_trace_write.count();
+static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) {
+  assert(writer.has_data(), "invariant");
+  const JfrBlobHandle blob = copy ? writer.copy() : writer.move();
+  if (saved_type_set_blobs.valid()) {
+    saved_type_set_blobs->set_next(blob);
+  } else {
+    saved_type_set_blobs = blob;
   }
-  if (count == 0) {
-    writer.set_context(ctx);
-    return true;
+}
+
+void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
+  assert(LeakProfiler::is_running(), "invariant");
+  const ObjectSample* last = ObjectSampler::sampler()->last();
+  if (writer.has_data() && last != NULL) {
+    save_type_set_blob(writer);
+    install_type_set_blobs();
+    ObjectSampler::sampler()->set_last_resolved(last);
   }
-  assert(count > 0, "invariant");
-  writer.write_count((u4)count, count_offset);
-  JfrStackTraceRepository::write_metadata(writer);
+}
 
-  // install the stacktrace checkpoint information to the candidates
-  ObjectSampleCheckpoint::install(writer, false, false);
-  return true;
+void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
+  assert(SafepointSynchronize::is_at_safepoint(), "invariant");
+  assert(LeakProfiler::is_running(), "invariant");
+  if (writer.has_data() && ObjectSampler::sampler()->last() != NULL) {
+    save_type_set_blob(writer, true);
+  }
 }
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -26,27 +26,35 @@
 #define SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
 
 #include "memory/allocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
 
 class EdgeStore;
+class JavaThread;
 class JfrCheckpointWriter;
+class JfrStackTrace;
 class JfrStackTraceRepository;
+class Klass;
+class Method;
+class ObjectSample;
 class ObjectSampleMarker;
 class ObjectSampler;
+class Thread;
 
 class ObjectSampleCheckpoint : AllStatic {
+  friend class EventEmitter;
+  friend class PathToGcRootsOperation;
+  friend class StackTraceBlobInstaller;
+ private:
+  static void add_to_leakp_set(const Method* method, traceid method_id);
+  static int save_mark_words(const ObjectSampler* sampler, ObjectSampleMarker& marker, bool emit_all);
+  static void write_stacktrace(const JfrStackTrace* trace, JfrCheckpointWriter& writer);
+  static void write(const ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread);
  public:
-  static void install(JfrCheckpointWriter& writer, bool class_unload, bool type_set);
-  static void write(ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread);
-  static int mark(ObjectSampler* sampler, ObjectSampleMarker& marker, bool emit_all);
-};
-
-class WriteObjectSampleStacktrace : public StackObj {
- private:
-  ObjectSampler* const _sampler;
-  JfrStackTraceRepository& _stack_trace_repo;
- public:
-  WriteObjectSampleStacktrace(ObjectSampler* sampler, JfrStackTraceRepository& repo);
-  bool process();
+  static void on_klass_unload(const Klass* k);
+  static void on_type_set(JfrCheckpointWriter& writer);
+  static void on_type_set_unload(JfrCheckpointWriter& writer);
+  static void on_thread_exit(JavaThread* jt);
+  static void on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& repo);
 };
 
 #endif // SHARE_JFR_LEAKPROFILER_CHECKPOINT_OBJECTSAMPLECHECKPOINT_HPP
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleWriter.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -33,8 +33,8 @@
 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
 #include "jfr/leakprofiler/utilities/rootType.hpp"
 #include "jfr/leakprofiler/utilities/unifiedOop.hpp"
-#include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
-#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"
+#include "jfr/metadata/jfrSerializer.hpp"
+#include "jfr/writers/jfrTypeWriterHost.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "utilities/growableArray.hpp"
@@ -137,30 +137,33 @@
             typename,
             size_t>
   friend class HashTableHost;
-  typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, Entry, FieldTable, 109> FieldInfoTable;
+  typedef HashTableHost<const ObjectSampleFieldInfo*, traceid, JfrHashtableEntry, FieldTable, 109> FieldInfoTable;
  public:
   typedef FieldInfoTable::HashEntry FieldInfoEntry;
 
  private:
   static traceid _field_id_counter;
   FieldInfoTable* _table;
+  const ObjectSampleFieldInfo* _lookup;
 
-  void assign_id(FieldInfoEntry* entry) {
+  void on_link(FieldInfoEntry* entry) {
     assert(entry != NULL, "invariant");
     entry->set_id(++_field_id_counter);
   }
 
-  bool equals(const ObjectSampleFieldInfo* query, uintptr_t hash, const FieldInfoEntry* entry) {
+  bool on_equals(uintptr_t hash, const FieldInfoEntry* entry) {
     assert(hash == entry->hash(), "invariant");
-    assert(query != NULL, "invariant");
-    const ObjectSampleFieldInfo* stored = entry->literal();
-    assert(stored != NULL, "invariant");
-    assert(stored->_field_name_symbol->identity_hash() == query->_field_name_symbol->identity_hash(), "invariant");
-    return stored->_field_modifiers == query->_field_modifiers;
+    assert(_lookup != NULL, "invariant");
+    return entry->literal()->_field_modifiers == _lookup->_field_modifiers;
+  }
+
+  void on_unlink(FieldInfoEntry* entry) {
+    assert(entry != NULL, "invariant");
+    // nothing
   }
 
  public:
-  FieldTable() : _table(new FieldInfoTable(this)) {}
+  FieldTable() : _table(new FieldInfoTable(this)), _lookup(NULL) {}
   ~FieldTable() {
     assert(_table != NULL, "invariant");
     delete _table;
@@ -168,8 +171,8 @@
 
   traceid store(const ObjectSampleFieldInfo* field_info) {
     assert(field_info != NULL, "invariant");
-    const FieldInfoEntry& entry =_table->lookup_put(field_info,
-                                                    field_info->_field_name_symbol->identity_hash());
+    _lookup = field_info;
+    const FieldInfoEntry& entry = _table->lookup_put(field_info->_field_name_symbol->identity_hash(), field_info);
     return entry.id();
   }
 
@@ -196,7 +199,7 @@
 static FieldTable* field_infos = NULL;
 static RootDescriptionInfo* root_infos = NULL;
 
-int __write_sample_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* si) {
+int __write_sample_info__(JfrCheckpointWriter* writer, const void* si) {
   assert(writer != NULL, "invariant");
   assert(si != NULL, "invariant");
   const OldObjectSampleInfo* const oosi = (const OldObjectSampleInfo*)si;
@@ -211,17 +214,17 @@
   return 1;
 }
 
-typedef JfrArtifactWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
-typedef JfrArtifactWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
+typedef JfrTypeWriterImplHost<const OldObjectSampleInfo*, __write_sample_info__> SampleWriterImpl;
+typedef JfrTypeWriterHost<SampleWriterImpl, TYPE_OLDOBJECT> SampleWriter;
 
 static void write_sample_infos(JfrCheckpointWriter& writer) {
   if (sample_infos != NULL) {
-    SampleWriter sw(&writer, NULL, false);
+    SampleWriter sw(&writer);
     sample_infos->iterate(sw);
   }
 }
 
-int __write_reference_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ri) {
+int __write_reference_info__(JfrCheckpointWriter* writer, const void* ri) {
   assert(writer != NULL, "invariant");
   assert(ri != NULL, "invariant");
   const ReferenceInfo* const ref_info = (const ReferenceInfo*)ri;
@@ -233,17 +236,17 @@
   return 1;
 }
 
-typedef JfrArtifactWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
-typedef JfrArtifactWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
+typedef JfrTypeWriterImplHost<const ReferenceInfo*, __write_reference_info__> ReferenceWriterImpl;
+typedef JfrTypeWriterHost<ReferenceWriterImpl, TYPE_REFERENCE> ReferenceWriter;
 
 static void write_reference_infos(JfrCheckpointWriter& writer) {
   if (ref_infos != NULL) {
-    ReferenceWriter rw(&writer, NULL, false);
+    ReferenceWriter rw(&writer);
     ref_infos->iterate(rw);
   }
 }
 
-int __write_array_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* ai) {
+int __write_array_info__(JfrCheckpointWriter* writer, const void* ai) {
   assert(writer != NULL, "invariant");
   assert(ai != NULL, "invariant");
   const ObjectSampleArrayInfo* const osai = (const ObjectSampleArrayInfo*)ai;
@@ -270,17 +273,17 @@
   return array_infos->store(osai);
 }
 
-typedef JfrArtifactWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
-typedef JfrArtifactWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
+typedef JfrTypeWriterImplHost<const ObjectSampleArrayInfo*, __write_array_info__> ArrayWriterImpl;
+typedef JfrTypeWriterHost<ArrayWriterImpl, TYPE_OLDOBJECTARRAY> ArrayWriter;
 
 static void write_array_infos(JfrCheckpointWriter& writer) {
   if (array_infos != NULL) {
-    ArrayWriter aw(&writer, NULL, false);
+    ArrayWriter aw(&writer);
     array_infos->iterate(aw);
   }
 }
 
-int __write_field_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* fi) {
+int __write_field_info__(JfrCheckpointWriter* writer, const void* fi) {
   assert(writer != NULL, "invariant");
   assert(fi != NULL, "invariant");
   const FieldTable::FieldInfoEntry* field_info_entry = (const FieldTable::FieldInfoEntry*)fi;
@@ -314,12 +317,12 @@
   return field_infos->store(osfi);
 }
 
-typedef JfrArtifactWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
-typedef JfrArtifactWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
+typedef JfrTypeWriterImplHost<const FieldTable::FieldInfoEntry*, __write_field_info__> FieldWriterImpl;
+typedef JfrTypeWriterHost<FieldWriterImpl, TYPE_OLDOBJECTFIELD> FieldWriter;
 
 static void write_field_infos(JfrCheckpointWriter& writer) {
   if (field_infos != NULL) {
-    FieldWriter fw(&writer, NULL, false);
+    FieldWriter fw(&writer);
     field_infos->iterate(fw);
   }
 }
@@ -339,7 +342,7 @@
   return description.description();
 }
 
-int __write_root_description_info__(JfrCheckpointWriter* writer, JfrArtifactSet* unused, const void* di) {
+int __write_root_description_info__(JfrCheckpointWriter* writer, const void* di) {
   assert(writer != NULL, "invariant");
   assert(di != NULL, "invariant");
   const ObjectSampleRootDescriptionInfo* const osdi = (const ObjectSampleRootDescriptionInfo*)di;
@@ -366,8 +369,8 @@
   return root_infos->store(oodi);
 }
 
-typedef JfrArtifactWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
-typedef JfrArtifactWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
+typedef JfrTypeWriterImplHost<const ObjectSampleRootDescriptionInfo*, __write_root_description_info__> RootDescriptionWriterImpl;
+typedef JfrTypeWriterHost<RootDescriptionWriterImpl, TYPE_OLDOBJECTGCROOT> RootDescriptionWriter;
 
 
 int _edge_reference_compare_(uintptr_t lhs, uintptr_t rhs) {
@@ -513,7 +516,7 @@
     RootResolutionSet rrs(root_infos);
     RootResolver::resolve(rrs);
     // write roots
-    RootDescriptionWriter rw(&writer, NULL, false);
+    RootDescriptionWriter rw(&writer);
     root_infos->iterate(rw);
   }
 }
@@ -576,11 +579,45 @@
   }
 }
 
+class RootSystemType : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer) {
+    const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
+    writer.write_count(nof_root_systems);
+    for (u4 i = 0; i < nof_root_systems; ++i) {
+      writer.write_key(i);
+      writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
+    }
+  }
+};
+
+class RootType : public JfrSerializer {
+ public:
+  void serialize(JfrCheckpointWriter& writer) {
+    const u4 nof_root_types = OldObjectRoot::_number_of_types;
+    writer.write_count(nof_root_types);
+    for (u4 i = 0; i < nof_root_types; ++i) {
+      writer.write_key(i);
+      writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
+    }
+  }
+};
+
+static void register_serializers() {
+  static bool is_registered = false;
+  if (!is_registered) {
+    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
+    JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
+    is_registered = true;
+  }
+}
+
 ObjectSampleWriter::ObjectSampleWriter(JfrCheckpointWriter& writer, EdgeStore* store) :
   _writer(writer),
   _store(store) {
   assert(store != NULL, "invariant");
   assert(!store->is_empty(), "invariant");
+  register_serializers();
   sample_infos = NULL;
   ref_infos = NULL;
   array_infos = NULL;
--- a/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/checkpoint/rootResolver.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -32,7 +32,6 @@
 #include "memory/iterator.hpp"
 #include "memory/universe.hpp"
 #include "oops/klass.hpp"
-#include "oops/markWord.hpp"
 #include "oops/oop.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/frame.inline.hpp"
--- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSample.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,13 +25,14 @@
 #ifndef SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
 #define SHARE_JFR_LEAKPROFILER_SAMPLING_OBJECTSAMPLE_HPP
 
-#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
 #include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrBlob.hpp"
 #include "jfr/utilities/jfrTime.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "memory/allocation.hpp"
 #include "oops/oop.hpp"
 #include "utilities/ticks.hpp"
+
 /*
  * Handle for diagnosing Java memory leaks.
  *
@@ -44,8 +45,9 @@
  private:
   ObjectSample* _next;
   ObjectSample* _previous;
-  JfrCheckpointBlobHandle _thread_cp;
-  JfrCheckpointBlobHandle _klass_cp;
+  JfrBlobHandle _stacktrace;
+  JfrBlobHandle _thread;
+  JfrBlobHandle _type_set;
   oop _object;
   Ticks _allocation_time;
   traceid _stack_trace_id;
@@ -62,17 +64,14 @@
   }
 
   void release_references() {
-    if (_thread_cp.valid()) {
-      _thread_cp.~JfrCheckpointBlobHandle();
-    }
-    if (_klass_cp.valid()) {
-      _klass_cp.~JfrCheckpointBlobHandle();
-    }
+    _stacktrace.~JfrBlobHandle();
+    _thread.~JfrBlobHandle();
+    _type_set.~JfrBlobHandle();
   }
 
   void reset() {
     set_stack_trace_id(0);
-    set_stack_trace_hash(0),
+    set_stack_trace_hash(0);
     release_references();
     _dead = false;
   }
@@ -80,8 +79,9 @@
  public:
   ObjectSample() : _next(NULL),
                    _previous(NULL),
-                   _thread_cp(),
-                   _klass_cp(),
+                   _stacktrace(),
+                   _thread(),
+                   _type_set(),
                    _object(NULL),
                    _allocation_time(),
                    _stack_trace_id(0),
@@ -174,7 +174,7 @@
     return _heap_used_at_last_gc;
   }
 
-  bool has_stack_trace() const {
+  bool has_stack_trace_id() const {
     return stack_trace_id() != 0;
   }
 
@@ -194,10 +194,6 @@
     _stack_trace_hash = hash;
   }
 
-  bool has_thread() const {
-    return _thread_id != 0;
-  }
-
   traceid thread_id() const {
     return _thread_id;
   }
@@ -211,37 +207,51 @@
       _allocation_time.ft_value() : _allocation_time.value()) < time_stamp;
   }
 
-  const JfrCheckpointBlobHandle& thread_checkpoint() const {
-    return _thread_cp;
+  const JfrBlobHandle& stacktrace() const {
+    return _stacktrace;
   }
 
-  bool has_thread_checkpoint() const {
-    return _thread_cp.valid();
+  bool has_stacktrace() const {
+    return _stacktrace.valid();
   }
 
-  // JfrCheckpointBlobHandle assignment operator
+  // JfrBlobHandle assignment operator
   // maintains proper reference counting
-  void set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) {
-    if (_thread_cp != ref) {
-      _thread_cp = ref;
+  void set_stacktrace(const JfrBlobHandle& ref) {
+    if (_stacktrace != ref) {
+      _stacktrace = ref;
     }
   }
 
-  const JfrCheckpointBlobHandle& klass_checkpoint() const {
-    return _klass_cp;
+  const JfrBlobHandle& thread() const {
+    return _thread;
   }
 
-  bool has_klass_checkpoint() const {
-    return _klass_cp.valid();
+  bool has_thread() const {
+    return _thread.valid();
+  }
+
+  void set_thread(const JfrBlobHandle& ref) {
+    if (_thread != ref) {
+      _thread = ref;
+    }
   }
 
-  void set_klass_checkpoint(const JfrCheckpointBlobHandle& ref) {
-    if (_klass_cp != ref) {
-      if (_klass_cp.valid()) {
-        _klass_cp->set_next(ref);
+  const JfrBlobHandle& type_set() const {
+    return _type_set;
+  }
+
+  bool has_type_set() const {
+    return _type_set.valid();
+  }
+
+  void set_type_set(const JfrBlobHandle& ref) {
+    if (_type_set != ref) {
+      if (_type_set.valid()) {
+        _type_set->set_next(ref);
         return;
       }
-      _klass_cp = ref;
+      _type_set = ref;
     }
   }
 };
--- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -110,63 +110,42 @@
   }
   const JfrThreadLocal* const tl = thread->jfr_thread_local();
   assert(tl != NULL, "invariant");
-  if (!tl->has_thread_checkpoint()) {
-    JfrCheckpointManager::create_thread_checkpoint(thread);
+  if (!tl->has_thread_blob()) {
+    JfrCheckpointManager::create_thread_blob(thread);
   }
-  assert(tl->has_thread_checkpoint(), "invariant");
+  assert(tl->has_thread_blob(), "invariant");
   return tl->thread_id();
 }
 
-// Populates the thread local stack frames, but does not add them
-// to the stacktrace repository (...yet, see stacktrace_id() below)
-//
-void ObjectSampler::fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread) {
-  assert(stacktrace != NULL, "invariant");
+static void record_stacktrace(JavaThread* thread) {
   assert(thread != NULL, "invariant");
   if (JfrEventSetting::has_stacktrace(EventOldObjectSample::eventId)) {
-    JfrStackTraceRepository::fill_stacktrace_for(thread, stacktrace, 0);
+    JfrStackTraceRepository::record_and_cache(thread);
   }
 }
 
-// We were successful in acquiring the try lock and have been selected for adding a sample.
-// Go ahead with installing our previously taken stacktrace into the stacktrace repository.
-//
-traceid ObjectSampler::stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread) {
-  assert(stacktrace != NULL, "invariant");
-  assert(stacktrace->hash() != 0, "invariant");
-  const traceid stacktrace_id = JfrStackTraceRepository::add(stacktrace, thread);
-  thread->jfr_thread_local()->set_cached_stack_trace_id(stacktrace_id, stacktrace->hash());
-  return stacktrace_id;
-}
-
 void ObjectSampler::sample(HeapWord* obj, size_t allocated, JavaThread* thread) {
   assert(thread != NULL, "invariant");
   assert(is_created(), "invariant");
-
   const traceid thread_id = get_thread_id(thread);
   if (thread_id == 0) {
     return;
   }
-
-  const JfrThreadLocal* const tl = thread->jfr_thread_local();
-  JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
-  fill_stacktrace(&stacktrace, thread);
-
+  record_stacktrace(thread);
   // try enter critical section
   JfrTryLock tryLock(&_lock);
   if (!tryLock.has_lock()) {
     log_trace(jfr, oldobject, sampling)("Skipping old object sample due to lock contention");
     return;
   }
-
-  instance().add(obj, allocated, thread_id, &stacktrace, thread);
+  instance().add(obj, allocated, thread_id, thread);
 }
 
-void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread) {
-  assert(stacktrace != NULL, "invariant");
+void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, JavaThread* thread) {
+  assert(obj != NULL, "invariant");
   assert(thread_id != 0, "invariant");
   assert(thread != NULL, "invariant");
-  assert(thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
+  assert(thread->jfr_thread_local()->has_thread_blob(), "invariant");
 
   if (_dead_samples) {
     scavenge();
@@ -190,11 +169,13 @@
 
   assert(sample != NULL, "invariant");
   sample->set_thread_id(thread_id);
-  sample->set_thread_checkpoint(thread->jfr_thread_local()->thread_checkpoint());
+
+  const JfrThreadLocal* const tl = thread->jfr_thread_local();
+  sample->set_thread(tl->thread_blob());
 
-  const unsigned int stacktrace_hash = stacktrace->hash();
+  const unsigned int stacktrace_hash = tl->cached_stack_trace_hash();
   if (stacktrace_hash != 0) {
-    sample->set_stack_trace_id(stacktrace_id(stacktrace, thread));
+    sample->set_stack_trace_id(tl->cached_stack_trace_id());
     sample->set_stack_trace_hash(stacktrace_hash);
   }
 
@@ -253,7 +234,7 @@
   sampler._last_sweep = JfrTicks::now();
 }
 
-const ObjectSample* ObjectSampler::last() const {
+ObjectSample* ObjectSampler::last() const {
   return _list->last();
 }
 
--- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -31,25 +31,19 @@
 typedef u8 traceid;
 
 class BoolObjectClosure;
-class JfrStackTrace;
+class JavaThread;
 class OopClosure;
 class ObjectSample;
-class ObjectSampler;
 class SampleList;
 class SamplePriorityQueue;
-class Thread;
 
 // Class reponsible for holding samples and
 // making sure the samples are evenly distributed as
 // new entries are added and removed.
 class ObjectSampler : public CHeapObj<mtTracing> {
-  friend class EventEmitter;
-  friend class JfrRecorderService;
   friend class LeakProfiler;
   friend class StartOperation;
   friend class StopOperation;
-  friend class ObjectSampleCheckpoint;
-  friend class WriteObjectSampleStacktrace;
  private:
   SamplePriorityQueue* _priority_queue;
   SampleList* _list;
@@ -64,20 +58,11 @@
   ~ObjectSampler();
   static bool create(size_t size);
   static bool is_created();
-  static ObjectSampler* sampler();
   static void destroy();
 
-  // For operations that require exclusive access (non-safepoint)
-  static ObjectSampler* acquire();
-  static void release();
-
-  // Stacktrace
-  static void fill_stacktrace(JfrStackTrace* stacktrace, JavaThread* thread);
-  traceid stacktrace_id(const JfrStackTrace* stacktrace, JavaThread* thread);
-
   // Sampling
   static void sample(HeapWord* object, size_t size, JavaThread* thread);
-  void add(HeapWord* object, size_t size, traceid thread_id, JfrStackTrace* stacktrace, JavaThread* thread);
+  void add(HeapWord* object, size_t size, traceid thread_id, JavaThread* thread);
   void scavenge();
   void remove_dead(ObjectSample* sample);
 
@@ -87,8 +72,15 @@
   const ObjectSample* item_at(int index) const;
   ObjectSample* item_at(int index);
   int item_count() const;
+
+ public:
+  static ObjectSampler* sampler();
+  // For operations that require exclusive access (non-safepoint)
+  static ObjectSampler* acquire();
+  static void release();
+
   const ObjectSample* first() const;
-  const ObjectSample* last() const;
+  ObjectSample* last() const;
   const ObjectSample* last_resolved() const;
   void set_last_resolved(const ObjectSample* sample);
   const JfrTicks& last_sweep() const;
--- a/src/hotspot/share/jfr/leakprofiler/sampling/sampleList.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/sampleList.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -50,12 +50,12 @@
   SampleList(size_t limit, size_t cache_size = 0);
   ~SampleList();
 
-  void set_last_resolved(const ObjectSample* sample);
   ObjectSample* get();
+  ObjectSample* first() const;
   ObjectSample* last() const;
-  ObjectSample* first() const;
+  const ObjectSample* last_resolved() const;
+  void set_last_resolved(const ObjectSample* sample);
   void release(ObjectSample* sample);
-  const ObjectSample* last_resolved() const;
   ObjectSample* reuse(ObjectSample* sample);
   bool is_full() const;
   size_t count() const;
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
-#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
-
-JfrCheckpointBlob::JfrCheckpointBlob(const u1* checkpoint, size_t size) :
-  _checkpoint(JfrCHeapObj::new_array<u1>(size)),
-  _size(size),
-  _next(),
-  _written(false) {
-  assert(checkpoint != NULL, "invariant");
-  assert(_checkpoint != NULL, "invariant");
-  memcpy(const_cast<u1*>(_checkpoint), checkpoint, size);
-}
-
-JfrCheckpointBlob::~JfrCheckpointBlob() {
-  JfrCHeapObj::free(const_cast<u1*>(_checkpoint), _size);
-}
-
-const JfrCheckpointBlobHandle& JfrCheckpointBlob::next() const {
-  return _next;
-}
-
-void JfrCheckpointBlob::write_this(JfrCheckpointWriter& writer) const {
-  writer.bytes(_checkpoint, _size);
-}
-
-void JfrCheckpointBlob::exclusive_write(JfrCheckpointWriter& writer) const {
-  if (!_written) {
-    write_this(writer);
-    _written = true;
-  }
-  if (_next.valid()) {
-    _next->exclusive_write(writer);
-  }
-}
-
-void JfrCheckpointBlob::write(JfrCheckpointWriter& writer) const {
-  write_this(writer);
-  if (_next.valid()) {
-    _next->write(writer);
-  }
-}
-
-void JfrCheckpointBlob::reset_write_state() const {
-  if (_written) {
-    _written = false;
-  }
-  if (_next.valid()) {
-    _next->reset_write_state();
-  }
-}
-
-void JfrCheckpointBlob::set_next(const JfrCheckpointBlobHandle& ref) {
-  if (_next == ref) {
-    return;
-  }
-  assert(_next != ref, "invariant");
-  if (_next.valid()) {
-    _next->set_next(ref);
-    return;
-  }
-  _next = ref;
-}
-
-JfrCheckpointBlobHandle JfrCheckpointBlob::make(const u1* checkpoint, size_t size) {
-  const JfrCheckpointBlob* cp_blob = new JfrCheckpointBlob(checkpoint, size);
-  assert(cp_blob != NULL, "invariant");
-  return JfrCheckpointBlobReference::make(cp_blob);
-}
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointBlob.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTBLOB_HPP
-#define SHARE_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTBLOB_HPP
-
-#include "jfr/utilities/jfrAllocation.hpp"
-#include "jfr/utilities/jfrRefCountPointer.hpp"
-
-class JfrCheckpointBlob;
-class JfrCheckpointWriter;
-
-typedef RefCountPointer<JfrCheckpointBlob, MultiThreadedRefCounter> JfrCheckpointBlobReference;
-typedef RefCountHandle<JfrCheckpointBlobReference> JfrCheckpointBlobHandle;
-
-class JfrCheckpointBlob : public JfrCHeapObj {
-  template <typename, typename>
-  friend class RefCountPointer;
- private:
-  const u1* _checkpoint;
-  const size_t _size;
-  JfrCheckpointBlobHandle _next;
-  mutable bool _written;
-
-  JfrCheckpointBlob(const u1* checkpoint, size_t size);
-  ~JfrCheckpointBlob();
-  const JfrCheckpointBlobHandle& next() const;
-  void write_this(JfrCheckpointWriter& writer) const;
-
- public:
-  void write(JfrCheckpointWriter& writer) const;
-  void exclusive_write(JfrCheckpointWriter& writer) const;
-  void reset_write_state() const;
-  void set_next(const JfrCheckpointBlobHandle& ref);
-  static JfrCheckpointBlobHandle make(const u1* checkpoint, size_t size);
-};
-
-#endif // SHARE_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTBLOB_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -37,6 +37,7 @@
 #include "jfr/utilities/jfrTypes.hpp"
 #include "logging/log.hpp"
 #include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/orderAccess.hpp"
 #include "runtime/os.inline.hpp"
@@ -87,22 +88,18 @@
 static const size_t checkpoint_buffer_cache_count = 2;
 static const size_t checkpoint_buffer_size = 512 * K;
 
-static JfrCheckpointMspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, JfrCheckpointManager* system) {
-  JfrCheckpointMspace* mspace = new JfrCheckpointMspace(buffer_size, limit, cache_count, system);
-  if (mspace != NULL) {
-    mspace->initialize();
-  }
-  return mspace;
+static JfrCheckpointMspace* allocate_mspace(size_t size, size_t limit, size_t cache_count, JfrCheckpointManager* mgr) {
+  return create_mspace<JfrCheckpointMspace, JfrCheckpointManager>(size, limit, cache_count, mgr);
 }
 
 bool JfrCheckpointManager::initialize() {
   assert(_free_list_mspace == NULL, "invariant");
-  _free_list_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
+  _free_list_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
   if (_free_list_mspace == NULL) {
     return false;
   }
   assert(_epoch_transition_mspace == NULL, "invariant");
-  _epoch_transition_mspace = create_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
+  _epoch_transition_mspace = allocate_mspace(checkpoint_buffer_size, unlimited_mspace_size, checkpoint_buffer_cache_count, this);
   if (_epoch_transition_mspace == NULL) {
     return false;
   }
@@ -114,22 +111,6 @@
   return JfrTypeManager::initialize();
 }
 
-bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const {
-  return _service_thread != thread && OrderAccess::load_acquire(&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch();
-}
-
-void JfrCheckpointManager::synchronize_epoch() {
-  assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant");
-  OrderAccess::storestore();
-  _checkpoint_epoch_state = JfrTraceIdEpoch::epoch();
-}
-
-void JfrCheckpointManager::shift_epoch() {
-  debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();)
-  JfrTraceIdEpoch::shift_epoch();
-  assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
-}
-
 void JfrCheckpointManager::register_service_thread(const Thread* thread) {
   _service_thread = thread;
 }
@@ -151,7 +132,6 @@
 }
 
 #ifdef ASSERT
-
 bool JfrCheckpointManager::is_locked() const {
   return _lock->owned_by_self();
 }
@@ -167,7 +147,6 @@
   assert(buffer->lease(), "invariant");
   assert(buffer->acquired_by_self(), "invariant");
 }
-
 #endif // ASSERT
 
 static BufferPtr lease_free(size_t size, JfrCheckpointMspace* mspace, size_t retry_count, Thread* thread) {
@@ -185,6 +164,10 @@
   return buffer;
 }
 
+bool JfrCheckpointManager::use_epoch_transition_mspace(const Thread* thread) const {
+  return _service_thread != thread && OrderAccess::load_acquire(&_checkpoint_epoch_state) != JfrTraceIdEpoch::epoch();
+}
+
 static const size_t lease_retry = 10;
 
 BufferPtr JfrCheckpointManager::lease_buffer(Thread* thread, size_t size /* 0 */) {
@@ -256,33 +239,33 @@
   return read_data<juint>(data + types_offset);
 }
 
-static void write_checkpoint_header(JfrChunkWriter& cw, intptr_t offset_prev_cp_event, const u1* data) {
+static void write_checkpoint_header(JfrChunkWriter& cw, int64_t offset_prev_cp_event, const u1* data) {
   cw.reserve(sizeof(u4));
-  cw.write((u8)EVENT_CHECKPOINT);
+  cw.write<u8>(EVENT_CHECKPOINT);
   cw.write(starttime(data));
   cw.write(duration(data));
-  cw.write((jlong)offset_prev_cp_event);
+  cw.write(offset_prev_cp_event);
   cw.write(is_flushpoint(data));
   cw.write(number_of_types(data));
 }
 
 static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) {
   assert(data != NULL, "invariant");
-  cw.write_unbuffered(data + payload_offset, size);
+  cw.write_unbuffered(data + payload_offset, size - sizeof(JfrCheckpointEntry));
 }
 
 static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) {
   assert(data != NULL, "invariant");
-  const intptr_t previous_checkpoint_event = cw.previous_checkpoint_offset();
-  const intptr_t event_begin = cw.current_offset();
-  const intptr_t offset_to_previous_checkpoint_event = 0 == previous_checkpoint_event ? 0 : previous_checkpoint_event - event_begin;
-  const jlong total_checkpoint_size = total_size(data);
-  write_checkpoint_header(cw, offset_to_previous_checkpoint_event, data);
-  write_checkpoint_content(cw, data, total_checkpoint_size - sizeof(JfrCheckpointEntry));
-  const jlong checkpoint_event_size = cw.current_offset() - event_begin;
-  cw.write_padded_at_offset<u4>(checkpoint_event_size, event_begin);
-  cw.set_previous_checkpoint_offset(event_begin);
-  return (size_t)total_checkpoint_size;
+  const int64_t event_begin = cw.current_offset();
+  const int64_t last_checkpoint_event = cw.last_checkpoint_offset();
+  const int64_t delta = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin;
+  const int64_t checkpoint_size = total_size(data);
+  write_checkpoint_header(cw, delta, data);
+  write_checkpoint_content(cw, data, checkpoint_size);
+  const int64_t event_size = cw.current_offset() - event_begin;
+  cw.write_padded_at_offset<u4>(event_size, event_begin);
+  cw.set_last_checkpoint_offset(event_begin);
+  return (size_t)checkpoint_size;
 }
 
 static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) {
@@ -290,14 +273,14 @@
   assert(data != NULL, "invariant");
   assert(size > 0, "invariant");
   const u1* const limit = data + size;
-  const u1* next_entry = data;
+  const u1* next = data;
   size_t processed = 0;
-  while (next_entry < limit) {
-    const size_t checkpoint_size = write_checkpoint_event(cw, next_entry);
+  while (next < limit) {
+    const size_t checkpoint_size = write_checkpoint_event(cw, next);
     processed += checkpoint_size;
-    next_entry += checkpoint_size;
+    next += checkpoint_size;
   }
-  assert(next_entry == limit, "invariant");
+  assert(next == limit, "invariant");
   return processed;
 }
 
@@ -331,6 +314,12 @@
   return wo.processed();
 }
 
+void JfrCheckpointManager::synchronize_epoch() {
+  assert(_checkpoint_epoch_state != JfrTraceIdEpoch::epoch(), "invariant");
+  OrderAccess::storestore();
+  _checkpoint_epoch_state = JfrTraceIdEpoch::epoch();
+}
+
 size_t JfrCheckpointManager::write() {
   const size_t processed = write_mspace<MutexedWriteOp, CompositeOperation>(_free_list_mspace, _chunkwriter);
   synchronize_epoch();
@@ -372,10 +361,16 @@
   JfrTypeManager::write_type_set_for_unloaded_classes();
 }
 
-void JfrCheckpointManager::create_thread_checkpoint(JavaThread* jt) {
-  JfrTypeManager::create_thread_checkpoint(jt);
+void JfrCheckpointManager::create_thread_blob(JavaThread* jt) {
+  JfrTypeManager::create_thread_blob(jt);
 }
 
 void JfrCheckpointManager::write_thread_checkpoint(JavaThread* jt) {
   JfrTypeManager::write_thread_checkpoint(jt);
 }
+
+void JfrCheckpointManager::shift_epoch() {
+  debug_only(const u1 current_epoch = JfrTraceIdEpoch::current();)
+  JfrTraceIdEpoch::shift_epoch();
+  assert(current_epoch != JfrTraceIdEpoch::current(), "invariant");
+}
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -92,7 +92,7 @@
  public:
   void register_service_thread(const Thread* t);
   static void write_type_set_for_unloaded_classes();
-  static void create_thread_checkpoint(JavaThread* jt);
+  static void create_thread_blob(JavaThread* jt);
   static void write_thread_checkpoint(JavaThread* jt);
 
   friend class JfrRecorder;
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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 @@
 #include "precompiled.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/utilities/jfrBlob.hpp"
 #include "jfr/writers/jfrBigEndianWriter.hpp"
 
 JfrCheckpointFlush::JfrCheckpointFlush(Type* old, size_t used, size_t requested, Thread* t) :
@@ -126,7 +127,7 @@
   write_padded_at_offset(nof_entries, offset);
 }
 
-const u1* JfrCheckpointWriter::session_data(size_t* size, const JfrCheckpointContext* ctx /* 0 */) {
+const u1* JfrCheckpointWriter::session_data(size_t* size, bool move /* false */, const JfrCheckpointContext* ctx /* 0 */) {
   assert(this->is_acquired(), "wrong state!");
   if (!this->is_valid()) {
     *size = 0;
@@ -140,8 +141,10 @@
   *size = this->used_size();
   assert(this->start_pos() + *size == this->current_pos(), "invariant");
   write_checkpoint_header(const_cast<u1*>(this->start_pos()), this->used_offset(), _time, is_flushpoint(), count());
-  this->seek(_offset + (_header ? sizeof(JfrCheckpointEntry) : 0));
-  set_count(0);
+  _header = false; // the header was just written
+  if (move) {
+    this->seek(_offset);
+  }
   return this->start_pos();
 }
 
@@ -160,26 +163,19 @@
   return this->used_size() > sizeof(JfrCheckpointEntry);
 }
 
-JfrCheckpointBlobHandle JfrCheckpointWriter::checkpoint_blob() {
+JfrBlobHandle JfrCheckpointWriter::copy(const JfrCheckpointContext* ctx /* 0 */) {
   size_t size = 0;
-  const u1* data = session_data(&size);
-  return JfrCheckpointBlob::make(data, size);
+  const u1* data = session_data(&size, false, ctx);
+  return JfrBlob::make(data, size);
 }
 
-JfrCheckpointBlobHandle JfrCheckpointWriter::copy(const JfrCheckpointContext* ctx /* 0 */) {
-  if (ctx == NULL) {
-    return checkpoint_blob();
-  }
+JfrBlobHandle JfrCheckpointWriter::move(const JfrCheckpointContext* ctx /* 0 */) {
   size_t size = 0;
-  const u1* data = session_data(&size, ctx);
-  return JfrCheckpointBlob::make(data, size);
-}
-
-JfrCheckpointBlobHandle JfrCheckpointWriter::move(const JfrCheckpointContext* ctx /* 0 */) {
-  JfrCheckpointBlobHandle data = copy(ctx);
+  const u1* data = session_data(&size, true, ctx);
+  JfrBlobHandle blob = JfrBlob::make(data, size);
   if (ctx != NULL) {
     const_cast<JfrCheckpointContext*>(ctx)->count = 0;
     set_context(*ctx);
   }
-  return data;
+  return blob;
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,8 +25,8 @@
 #ifndef SHARE_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
 #define SHARE_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
 
-#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
 #include "jfr/recorder/storage/jfrBuffer.hpp"
+#include "jfr/utilities/jfrBlob.hpp"
 #include "jfr/utilities/jfrTime.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 #include "jfr/writers/jfrEventWriterHost.inline.hpp"
@@ -67,9 +67,8 @@
   void increment();
   void set_flushpoint(bool flushpoint);
   bool is_flushpoint() const;
-  const u1* session_data(size_t* size, const JfrCheckpointContext* ctx = NULL);
+  const u1* session_data(size_t* size, bool move = false, const JfrCheckpointContext* ctx = NULL);
   void release();
-
  public:
   JfrCheckpointWriter(bool flushpoint, bool header, Thread* thread);
   ~JfrCheckpointWriter();
@@ -80,9 +79,8 @@
   const JfrCheckpointContext context() const;
   void set_context(const JfrCheckpointContext ctx);
   bool has_data() const;
-  JfrCheckpointBlobHandle checkpoint_blob();
-  JfrCheckpointBlobHandle copy(const JfrCheckpointContext* ctx = NULL);
-  JfrCheckpointBlobHandle move(const JfrCheckpointContext* ctx = NULL);
+  JfrBlobHandle copy(const JfrCheckpointContext* ctx = NULL);
+  JfrBlobHandle move(const JfrCheckpointContext* ctx = NULL);
 };
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_JFRCHECKPOINTWRITER_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -30,7 +30,6 @@
 #include "gc/shared/gcName.hpp"
 #include "gc/shared/gcTrace.hpp"
 #include "gc/shared/gcWhen.hpp"
-#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
 #include "jfr/leakprofiler/leakProfiler.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
 #include "jfr/recorder/checkpoint/types/jfrType.hpp"
@@ -275,34 +274,26 @@
 
 class TypeSetSerialization {
  private:
+  JfrCheckpointWriter* _leakp_writer;
   bool _class_unload;
  public:
-  explicit TypeSetSerialization(bool class_unload) : _class_unload(class_unload) {}
-  void write(JfrCheckpointWriter& writer, JfrCheckpointWriter* leakp_writer) {
-    JfrTypeSet::serialize(&writer, leakp_writer, _class_unload);
+  TypeSetSerialization(bool class_unload, JfrCheckpointWriter* leakp_writer = NULL) :
+    _leakp_writer(leakp_writer), _class_unload(class_unload) {}
+  void write(JfrCheckpointWriter& writer) {
+    JfrTypeSet::serialize(&writer, _leakp_writer, _class_unload);
   }
 };
 
 void ClassUnloadTypeSet::serialize(JfrCheckpointWriter& writer) {
   TypeSetSerialization type_set(true);
-  if (LeakProfiler::is_running()) {
-    JfrCheckpointWriter leakp_writer(false, true, Thread::current());
-    type_set.write(writer, &leakp_writer);
-    ObjectSampleCheckpoint::install(leakp_writer, true, true);
-    return;
-  }
-  type_set.write(writer, NULL);
+  type_set.write(writer);
 };
 
+TypeSet::TypeSet(JfrCheckpointWriter* leakp_writer) : _leakp_writer(leakp_writer) {}
+
 void TypeSet::serialize(JfrCheckpointWriter& writer) {
-  TypeSetSerialization type_set(false);
-  if (LeakProfiler::is_running()) {
-    JfrCheckpointWriter leakp_writer(false, true, Thread::current());
-    type_set.write(writer, &leakp_writer);
-    ObjectSampleCheckpoint::install(leakp_writer, false, true);
-    return;
-  }
-  type_set.write(writer, NULL);
+  TypeSetSerialization type_set(false, _leakp_writer);
+  type_set.write(writer);
 };
 
 void ThreadStateConstant::serialize(JfrCheckpointWriter& writer) {
@@ -313,7 +304,6 @@
   assert(_thread != NULL, "invariant");
   assert(_thread == Thread::current(), "invariant");
   assert(_thread->is_Java_thread(), "invariant");
-  assert(!_thread->jfr_thread_local()->has_thread_checkpoint(), "invariant");
   ResourceMark rm(_thread);
   const oop threadObj = _thread->threadObj();
   assert(threadObj != NULL, "invariant");
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -108,7 +108,10 @@
 };
 
 class TypeSet : public JfrSerializer {
+ private:
+  JfrCheckpointWriter* _leakp_writer;
  public:
+  explicit TypeSet(JfrCheckpointWriter* leakp_writer = NULL);
   void serialize(JfrCheckpointWriter& writer);
 };
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -23,12 +23,17 @@
  */
 
 #include "precompiled.hpp"
+#include "jfr/jfr.hpp"
+#include "jfr/leakprofiler/leakProfiler.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
 #include "jfr/metadata/jfrSerializer.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
 #include "jfr/recorder/checkpoint/types/jfrType.hpp"
 #include "jfr/recorder/checkpoint/types/jfrTypeManager.hpp"
 #include "jfr/utilities/jfrDoublyLinkedList.hpp"
 #include "jfr/utilities/jfrIterator.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/thread.inline.hpp"
 #include "utilities/exceptions.hpp"
@@ -39,7 +44,7 @@
   JfrSerializerRegistration* _next;
   JfrSerializerRegistration* _prev;
   JfrSerializer* _serializer;
-  mutable JfrCheckpointBlobHandle _cache;
+  mutable JfrBlobHandle _cache;
   JfrTypeId _id;
   bool _permit_cache;
 
@@ -148,45 +153,59 @@
 }
 
 void JfrTypeManager::write_type_set() {
-  // can safepoint here because of Module_lock
-  MutexLocker cld_lock(SafepointSynchronize::is_at_safepoint() ? NULL : ClassLoaderDataGraph_lock);
-  MutexLocker lock(SafepointSynchronize::is_at_safepoint() ? NULL : Module_lock);
-
-  JfrCheckpointWriter writer(true, true, Thread::current());
-  TypeSet set;
+  assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
+  // can safepoint here
+  MutexLocker cld_lock(ClassLoaderDataGraph_lock);
+  MutexLocker module_lock(Module_lock);
+  if (!LeakProfiler::is_running()) {
+    JfrCheckpointWriter writer(true, true, Thread::current());
+    TypeSet set;
+    set.serialize(writer);
+    return;
+  }
+  JfrCheckpointWriter leakp_writer(false, true, Thread::current());
+  JfrCheckpointWriter writer(false, true, Thread::current());
+  TypeSet set(&leakp_writer);
   set.serialize(writer);
+  ObjectSampleCheckpoint::on_type_set(leakp_writer);
 }
 
 void JfrTypeManager::write_type_set_for_unloaded_classes() {
   assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
   JfrCheckpointWriter writer(false, true, Thread::current());
+  const JfrCheckpointContext ctx = writer.context();
   ClassUnloadTypeSet class_unload_set;
   class_unload_set.serialize(writer);
+  if (LeakProfiler::is_running()) {
+    ObjectSampleCheckpoint::on_type_set_unload(writer);
+  }
+  if (!Jfr::is_recording()) {
+    // discard anything written
+    writer.set_context(ctx);
+  }
 }
 
-void JfrTypeManager::create_thread_checkpoint(JavaThread* jt) {
+void JfrTypeManager::create_thread_blob(JavaThread* jt) {
   assert(jt != NULL, "invariant");
+  ResourceMark rm(jt);
+  HandleMark hm(jt);
   JfrThreadConstant type_thread(jt);
   JfrCheckpointWriter writer(false, true, jt);
   writer.write_type(TYPE_THREAD);
   type_thread.serialize(writer);
   // create and install a checkpoint blob
-  jt->jfr_thread_local()->set_thread_checkpoint(writer.checkpoint_blob());
-  assert(jt->jfr_thread_local()->has_thread_checkpoint(), "invariant");
+  jt->jfr_thread_local()->set_thread_blob(writer.move());
+  assert(jt->jfr_thread_local()->has_thread_blob(), "invariant");
 }
 
 void JfrTypeManager::write_thread_checkpoint(JavaThread* jt) {
   assert(jt != NULL, "JavaThread is NULL!");
   ResourceMark rm(jt);
-  if (jt->jfr_thread_local()->has_thread_checkpoint()) {
-    JfrCheckpointWriter writer(false, false, jt);
-    jt->jfr_thread_local()->thread_checkpoint()->write(writer);
-  } else {
-    JfrThreadConstant type_thread(jt);
-    JfrCheckpointWriter writer(false, true, jt);
-    writer.write_type(TYPE_THREAD);
-    type_thread.serialize(writer);
-  }
+  HandleMark hm(jt);
+  JfrThreadConstant type_thread(jt);
+  JfrCheckpointWriter writer(false, true, jt);
+  writer.write_type(TYPE_THREAD);
+  type_thread.serialize(writer);
 }
 
 #ifdef ASSERT
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeManager.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -37,7 +37,7 @@
   static void write_safepoint_types(JfrCheckpointWriter& writer);
   static void write_type_set();
   static void write_type_set_for_unloaded_classes();
-  static void create_thread_checkpoint(JavaThread* jt);
+  static void create_thread_blob(JavaThread* jt);
   static void write_thread_checkpoint(JavaThread* jt);
 };
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,32 +28,22 @@
 #include "classfile/moduleEntry.hpp"
 #include "classfile/packageEntry.hpp"
 #include "classfile/symbolTable.hpp"
-#include "classfile/systemDictionary.hpp"
 #include "jfr/jfr.hpp"
 #include "jfr/jni/jfrGetAllEventClasses.hpp"
-#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
 #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp"
 #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp"
-#include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp"
 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
-#include "jfr/recorder/storage/jfrBuffer.hpp"
 #include "jfr/utilities/jfrHashtable.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
+#include "jfr/writers/jfrTypeWriterHost.hpp"
 #include "memory/iterator.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/oop.inline.hpp"
-#include "memory/resourceArea.hpp"
 #include "utilities/accessFlags.hpp"
 
-// incremented on each checkpoint
-static u8 checkpoint_id = 0;
-
-// creates a unique id by combining a checkpoint relative symbol id (2^24)
-// with the current checkpoint id (2^40)
-#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id)))
-
 typedef const Klass* KlassPtr;
 typedef const PackageEntry* PkgPtr;
 typedef const ModuleEntry* ModPtr;
@@ -63,57 +53,112 @@
 typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr;
 typedef const JfrSymbolId::CStringEntry* CStringEntryPtr;
 
-static traceid module_id(PkgPtr pkg) {
-  assert(pkg != NULL, "invariant");
-  ModPtr module_entry = pkg->module();
-  return module_entry != NULL && module_entry->is_named() ? TRACE_ID(module_entry) : 0;
+static JfrCheckpointWriter* _writer = NULL;
+static JfrCheckpointWriter* _leakp_writer = NULL;
+static JfrArtifactSet* _artifacts = NULL;
+static JfrArtifactClosure* _subsystem_callback = NULL;
+static bool _class_unload = false;
+static bool _flushpoint = false;
+
+// incremented on each rotation
+static u8 checkpoint_id = 1;
+
+// creates a unique id by combining a checkpoint relative symbol id (2^24)
+// with the current checkpoint id (2^40)
+#define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id)))
+
+static traceid create_symbol_id(traceid artifact_id) {
+  return artifact_id != 0 ? CREATE_SYMBOL_ID(artifact_id) : 0;
+}
+
+static bool current_epoch() {
+  return _class_unload;
 }
 
-static traceid package_id(KlassPtr klass) {
-  assert(klass != NULL, "invariant");
-  PkgPtr pkg_entry = klass->package();
-  return pkg_entry == NULL ? 0 : TRACE_ID(pkg_entry);
+static bool previous_epoch() {
+  return !current_epoch();
+}
+
+static bool is_complete() {
+  return !_artifacts->has_klass_entries() && current_epoch();
+}
+
+static traceid mark_symbol(KlassPtr klass, bool leakp) {
+  return klass != NULL ? create_symbol_id(_artifacts->mark(klass, leakp)) : 0;
 }
 
-static traceid cld_id(CldPtr cld) {
-  assert(cld != NULL, "invariant");
-  return cld->is_unsafe_anonymous() ? 0 : TRACE_ID(cld);
+static traceid mark_symbol(Symbol* symbol, bool leakp) {
+  return symbol != NULL ? create_symbol_id(_artifacts->mark(symbol, leakp)) : 0;
+}
+
+static traceid get_bootstrap_name(bool leakp) {
+  return create_symbol_id(_artifacts->bootstrap_name(leakp));
+}
+
+template <typename T>
+static traceid artifact_id(const T* ptr) {
+  assert(ptr != NULL, "invariant");
+  return TRACE_ID(ptr);
 }
 
-static void tag_leakp_klass_artifacts(KlassPtr k, bool class_unload) {
-  assert(k != NULL, "invariant");
-  PkgPtr pkg = k->package();
-  if (pkg != NULL) {
-    tag_leakp_artifact(pkg, class_unload);
-    ModPtr module = pkg->module();
-    if (module != NULL) {
-      tag_leakp_artifact(module, class_unload);
-    }
+static traceid package_id(KlassPtr klass, bool leakp) {
+  assert(klass != NULL, "invariant");
+  PkgPtr pkg_entry = klass->package();
+  if (pkg_entry == NULL) {
+    return 0;
+  }
+  if (leakp) {
+    SET_LEAKP(pkg_entry);
   }
-  CldPtr cld = k->class_loader_data();
-  assert(cld != NULL, "invariant");
-  if (!cld->is_unsafe_anonymous()) {
-    tag_leakp_artifact(cld, class_unload);
+  // package implicitly tagged already
+  return artifact_id(pkg_entry);
+}
+
+static traceid module_id(PkgPtr pkg, bool leakp) {
+  assert(pkg != NULL, "invariant");
+  ModPtr module_entry = pkg->module();
+  if (module_entry == NULL || !module_entry->is_named()) {
+    return 0;
   }
+  if (leakp) {
+    SET_LEAKP(module_entry);
+  } else {
+    SET_TRANSIENT(module_entry);
+  }
+  return artifact_id(module_entry);
 }
 
-class TagLeakpKlassArtifact {
-  bool _class_unload;
- public:
-  TagLeakpKlassArtifact(bool class_unload) : _class_unload(class_unload) {}
-  bool operator()(KlassPtr klass) {
-    if (_class_unload) {
-      if (LEAKP_USED_THIS_EPOCH(klass)) {
-        tag_leakp_klass_artifacts(klass, _class_unload);
-      }
-    } else {
-      if (LEAKP_USED_PREV_EPOCH(klass)) {
-        tag_leakp_klass_artifacts(klass, _class_unload);
-      }
-    }
-    return true;
+static traceid method_id(KlassPtr klass, MethodPtr method) {
+  assert(klass != NULL, "invariant");
+  assert(method != NULL, "invariant");
+  return METHOD_ID(klass, method);
+}
+
+static traceid cld_id(CldPtr cld, bool leakp) {
+  assert(cld != NULL, "invariant");
+  if (cld->is_unsafe_anonymous()) {
+    return 0;
+  }
+  if (leakp) {
+    SET_LEAKP(cld);
+  } else {
+    SET_TRANSIENT(cld);
   }
-};
+  return artifact_id(cld);
+}
+
+template <typename T>
+static s4 get_flags(const T* ptr) {
+  assert(ptr != NULL, "invariant");
+  return ptr->access_flags().get_flags();
+}
+
+template <typename T>
+static void set_serialized(const T* ptr) {
+  assert(ptr != NULL, "invariant");
+  SET_SERIALIZED(ptr);
+  assert(IS_SERIALIZED(ptr), "invariant");
+}
 
 /*
  * In C++03, functions used as template parameters must have external linkage;
@@ -123,11 +168,10 @@
  * The weird naming is an effort to decrease the risk of name clashes.
  */
 
-int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
+static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp) {
   assert(writer != NULL, "invariant");
-  assert(artifacts != NULL, "invariant");
-  assert(k != NULL, "invariant");
-  KlassPtr klass = (KlassPtr)k;
+  assert(_artifacts != NULL, "invariant");
+  assert(klass != NULL, "invariant");
   traceid pkg_id = 0;
   KlassPtr theklass = klass;
   if (theklass->is_objArray_klass()) {
@@ -135,445 +179,167 @@
     theklass = obj_arr_klass->bottom_klass();
   }
   if (theklass->is_instance_klass()) {
-    pkg_id = package_id(theklass);
+    pkg_id = package_id(theklass, leakp);
   } else {
     assert(theklass->is_typeArray_klass(), "invariant");
   }
-  const traceid symbol_id = artifacts->mark(klass);
-  assert(symbol_id > 0, "need to have an address for symbol!");
-  writer->write(TRACE_ID(klass));
-  writer->write(cld_id(klass->class_loader_data()));
-  writer->write((traceid)CREATE_SYMBOL_ID(symbol_id));
+  writer->write(artifact_id(klass));
+  writer->write(cld_id(klass->class_loader_data(), leakp));
+  writer->write(mark_symbol(klass, leakp));
   writer->write(pkg_id);
-  writer->write((s4)klass->access_flags().get_flags());
+  writer->write(get_flags(klass));
   return 1;
 }
 
-typedef LeakPredicate<KlassPtr> LeakKlassPredicate;
-typedef JfrPredicatedArtifactWriterImplHost<KlassPtr, LeakKlassPredicate, write__artifact__klass> LeakKlassWriterImpl;
-typedef JfrArtifactWriterHost<LeakKlassWriterImpl, TYPE_CLASS> LeakKlassWriter;
-typedef JfrArtifactWriterImplHost<KlassPtr, write__artifact__klass> KlassWriterImpl;
-typedef JfrArtifactWriterHost<KlassWriterImpl, TYPE_CLASS> KlassWriter;
+int write__klass(JfrCheckpointWriter* writer, const void* k) {
+  assert(k != NULL, "invariant");
+  KlassPtr klass = (KlassPtr)k;
+  set_serialized(klass);
+  return write_klass(writer, klass, false);
+}
+
+int write__klass__leakp(JfrCheckpointWriter* writer, const void* k) {
+  assert(k != NULL, "invariant");
+  KlassPtr klass = (KlassPtr)k;
+  return write_klass(writer, klass, true);
+}
+
+static void do_implied(Klass* klass) {
+  assert(klass != NULL, "invariant");
+  if (klass->is_subclass_of(SystemDictionary::ClassLoader_klass()) || klass == SystemDictionary::Object_klass()) {
+    if (_leakp_writer != NULL) {
+      SET_LEAKP(klass);
+    }
+    _subsystem_callback->do_artifact(klass);
+  }
+}
 
-int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
-  assert(writer != NULL, "invariant");
-  assert(artifacts != NULL, "invariant");
-  assert(m != NULL, "invariant");
-  MethodPtr method = (MethodPtr)m;
-  const traceid method_name_symbol_id = artifacts->mark(method->name());
-  assert(method_name_symbol_id > 0, "invariant");
-  const traceid method_sig_symbol_id = artifacts->mark(method->signature());
-  assert(method_sig_symbol_id > 0, "invariant");
-  KlassPtr klass = method->method_holder();
+static void do_unloaded_klass(Klass* klass) {
+  assert(klass != NULL, "invariant");
+  assert(_subsystem_callback != NULL, "invariant");
+  if (IS_JDK_JFR_EVENT_SUBKLASS(klass)) {
+    JfrEventClasses::increment_unloaded_event_class();
+  }
+  if (USED_THIS_EPOCH(klass)) {
+    ObjectSampleCheckpoint::on_klass_unload(klass);
+    _subsystem_callback->do_artifact(klass);
+    return;
+  }
+  do_implied(klass);
+}
+
+static void do_klass(Klass* klass) {
   assert(klass != NULL, "invariant");
-  assert(METHOD_USED_ANY_EPOCH(klass), "invariant");
-  writer->write((u8)METHOD_ID(klass, method));
-  writer->write((u8)TRACE_ID(klass));
-  writer->write((u8)CREATE_SYMBOL_ID(method_name_symbol_id));
-  writer->write((u8)CREATE_SYMBOL_ID(method_sig_symbol_id));
-  writer->write((u2)method->access_flags().get_flags());
-  writer->write(const_cast<Method*>(method)->is_hidden() ? (u1)1 : (u1)0);
-  return 1;
+  assert(_subsystem_callback != NULL, "invariant");
+  if (current_epoch()) {
+    if (USED_THIS_EPOCH(klass)) {
+      _subsystem_callback->do_artifact(klass);
+      return;
+    }
+  } else {
+    if (USED_PREV_EPOCH(klass)) {
+      _subsystem_callback->do_artifact(klass);
+      return;
+    }
+  }
+  do_implied(klass);
+}
+
+static void do_klasses() {
+  if (_class_unload) {
+    ClassLoaderDataGraph::classes_unloading_do(&do_unloaded_klass);
+    return;
+  }
+  ClassLoaderDataGraph::classes_do(&do_klass);
 }
 
-typedef JfrArtifactWriterImplHost<MethodPtr, write__artifact__method> MethodWriterImplTarget;
-typedef JfrArtifactWriterHost<MethodWriterImplTarget, TYPE_METHOD> MethodWriterImpl;
+typedef SerializePredicate<KlassPtr> KlassPredicate;
+typedef JfrPredicatedTypeWriterImplHost<KlassPtr, KlassPredicate, write__klass> KlassWriterImpl;
+typedef JfrTypeWriterHost<KlassWriterImpl, TYPE_CLASS> KlassWriter;
+typedef CompositeFunctor<KlassPtr, KlassWriter, KlassArtifactRegistrator> KlassWriterRegistration;
+typedef JfrArtifactCallbackHost<KlassPtr, KlassWriterRegistration> KlassCallback;
+
+typedef LeakPredicate<KlassPtr> LeakKlassPredicate;
+typedef JfrPredicatedTypeWriterImplHost<KlassPtr, LeakKlassPredicate, write__klass__leakp> LeakKlassWriterImpl;
+typedef JfrTypeWriterHost<LeakKlassWriterImpl, TYPE_CLASS> LeakKlassWriter;
+
+typedef CompositeFunctor<KlassPtr, LeakKlassWriter, KlassWriter> CompositeKlassWriter;
+typedef CompositeFunctor<KlassPtr, CompositeKlassWriter, KlassArtifactRegistrator> CompositeKlassWriterRegistration;
+typedef JfrArtifactCallbackHost<KlassPtr, CompositeKlassWriterRegistration> CompositeKlassCallback;
 
-int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
+static bool write_klasses() {
+  assert(!_artifacts->has_klass_entries(), "invariant");
+  assert(_writer != NULL, "invariant");
+  KlassArtifactRegistrator reg(_artifacts);
+  KlassWriter kw(_writer, _class_unload);
+  KlassWriterRegistration kwr(&kw, &reg);
+  if (_leakp_writer == NULL) {
+    KlassCallback callback(&kwr);
+    _subsystem_callback = &callback;
+    do_klasses();
+  } else {
+    LeakKlassWriter lkw(_leakp_writer, _artifacts, _class_unload);
+    CompositeKlassWriter ckw(&lkw, &kw);
+    CompositeKlassWriterRegistration ckwr(&ckw, &reg);
+    CompositeKlassCallback callback(&ckwr);
+    _subsystem_callback = &callback;
+    do_klasses();
+  }
+  if (is_complete()) {
+    return false;
+  }
+  _artifacts->tally(kw);
+  return true;
+}
+
+template <typename T>
+static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) {
+  assert(callback != NULL, "invariant");
+  assert(value != NULL, "invariant");
+  if (USED_PREV_EPOCH(value)) {
+    callback->do_artifact(value);
+    assert(IS_NOT_SERIALIZED(value), "invariant");
+    return;
+  }
+  if (IS_SERIALIZED(value)) {
+    CLEAR_SERIALIZED(value);
+  }
+  assert(IS_NOT_SERIALIZED(value), "invariant");
+}
+
+static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) {
   assert(writer != NULL, "invariant");
-  assert(artifacts != NULL, "invariant");
-  assert(p != NULL, "invariant");
-  PkgPtr pkg = (PkgPtr)p;
-  Symbol* const pkg_name = pkg->name();
-  const traceid package_name_symbol_id = pkg_name != NULL ? artifacts->mark(pkg_name) : 0;
-  assert(package_name_symbol_id > 0, "invariant");
-  writer->write((traceid)TRACE_ID(pkg));
-  writer->write((traceid)CREATE_SYMBOL_ID(package_name_symbol_id));
-  writer->write(module_id(pkg));
+  assert(_artifacts != NULL, "invariant");
+  assert(pkg != NULL, "invariant");
+  writer->write(artifact_id(pkg));
+  writer->write(mark_symbol(pkg->name(), leakp));
+  writer->write(module_id(pkg, leakp));
   writer->write((bool)pkg->is_exported());
   return 1;
 }
 
-typedef LeakPredicate<PkgPtr> LeakPackagePredicate;
-int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
-typedef UniquePredicate<PkgPtr, _compare_pkg_ptr_> PackagePredicate;
-typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, LeakPackagePredicate, write__artifact__package> LeakPackageWriterImpl;
-typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, PackagePredicate, write__artifact__package> PackageWriterImpl;
-typedef JfrArtifactWriterHost<LeakPackageWriterImpl, TYPE_PACKAGE> LeakPackageWriter;
-typedef JfrArtifactWriterHost<PackageWriterImpl, TYPE_PACKAGE> PackageWriter;
-
-int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) {
-  assert( m != NULL, "invariant");
-  ModPtr entry = (ModPtr)m;
-  Symbol* const module_name = entry->name();
-  const traceid module_name_symbol_id = module_name != NULL ? artifacts->mark(module_name) : 0;
-  Symbol* const module_version = entry->version();
-  const traceid module_version_symbol_id = module_version != NULL ? artifacts->mark(module_version) : 0;
-  Symbol* const module_location = entry->location();
-  const traceid module_location_symbol_id = module_location != NULL ? artifacts->mark(module_location) : 0;
-  writer->write((traceid)TRACE_ID(entry));
-  writer->write(module_name_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_name_symbol_id));
-  writer->write(module_version_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_version_symbol_id));
-  writer->write(module_location_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_location_symbol_id));
-  writer->write(cld_id(entry->loader_data()));
-  return 1;
-}
-
-typedef LeakPredicate<ModPtr> LeakModulePredicate;
-int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
-typedef UniquePredicate<ModPtr, _compare_mod_ptr_> ModulePredicate;
-typedef JfrPredicatedArtifactWriterImplHost<ModPtr, LeakModulePredicate, write__artifact__module> LeakModuleWriterImpl;
-typedef JfrPredicatedArtifactWriterImplHost<ModPtr, ModulePredicate, write__artifact__module> ModuleWriterImpl;
-typedef JfrArtifactWriterHost<LeakModuleWriterImpl, TYPE_MODULE> LeakModuleWriter;
-typedef JfrArtifactWriterHost<ModuleWriterImpl, TYPE_MODULE> ModuleWriter;
-
-int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) {
-  assert(c != NULL, "invariant");
-  CldPtr cld = (CldPtr)c;
-  assert(!cld->is_unsafe_anonymous(), "invariant");
-  const traceid cld_id = TRACE_ID(cld);
-  // class loader type
-  const Klass* class_loader_klass = cld->class_loader_klass();
-  if (class_loader_klass == NULL) {
-    // (primordial) boot class loader
-    writer->write(cld_id); // class loader instance id
-    writer->write((traceid)0);  // class loader type id (absence of)
-    writer->write((traceid)CREATE_SYMBOL_ID(1)); // 1 maps to synthetic name -> "bootstrap"
-  } else {
-    Symbol* symbol_name = cld->name();
-    const traceid symbol_name_id = symbol_name != NULL ? artifacts->mark(symbol_name) : 0;
-    writer->write(cld_id); // class loader instance id
-    writer->write(TRACE_ID(class_loader_klass)); // class loader type id
-    writer->write(symbol_name_id == 0 ? (traceid)0 :
-      (traceid)CREATE_SYMBOL_ID(symbol_name_id)); // class loader instance name
-  }
-  return 1;
-}
-
-typedef LeakPredicate<CldPtr> LeakCldPredicate;
-int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
-typedef UniquePredicate<CldPtr, _compare_cld_ptr_> CldPredicate;
-typedef JfrPredicatedArtifactWriterImplHost<CldPtr, LeakCldPredicate, write__artifact__classloader> LeakCldWriterImpl;
-typedef JfrPredicatedArtifactWriterImplHost<CldPtr, CldPredicate, write__artifact__classloader> CldWriterImpl;
-typedef JfrArtifactWriterHost<LeakCldWriterImpl, TYPE_CLASSLOADER> LeakCldWriter;
-typedef JfrArtifactWriterHost<CldWriterImpl, TYPE_CLASSLOADER> CldWriter;
-
-typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr;
-
-static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer,
-                                            SymbolEntryPtr entry) {
-  assert(writer != NULL, "invariant");
-  assert(entry != NULL, "invariant");
-  ResourceMark rm;
-  writer->write(CREATE_SYMBOL_ID(entry->id()));
-  writer->write(entry->value()->as_C_string());
-  return 1;
-}
-
-int write__artifact__symbol__entry(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* e) {
-  assert(e != NULL, "invariant");
-  return write__artifact__symbol__entry__(writer, (SymbolEntryPtr)e);
-}
-
-typedef JfrArtifactWriterImplHost<SymbolEntryPtr, write__artifact__symbol__entry> SymbolEntryWriterImpl;
-typedef JfrArtifactWriterHost<SymbolEntryWriterImpl, TYPE_SYMBOL> SymbolEntryWriter;
-
-typedef const JfrSymbolId::CStringEntry* CStringEntryPtr;
-
-static int write__artifact__cstring__entry__(JfrCheckpointWriter* writer, CStringEntryPtr entry) {
-  assert(writer != NULL, "invariant");
-  assert(entry != NULL, "invariant");
-  writer->write(CREATE_SYMBOL_ID(entry->id()));
-  writer->write(entry->value());
-  return 1;
-}
-
-int write__artifact__cstring__entry(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* e) {
-  assert(e != NULL, "invariant");
-  return write__artifact__cstring__entry__(writer, (CStringEntryPtr)e);
-}
-
-typedef JfrArtifactWriterImplHost<CStringEntryPtr, write__artifact__cstring__entry> CStringEntryWriterImpl;
-typedef JfrArtifactWriterHost<CStringEntryWriterImpl, TYPE_SYMBOL> CStringEntryWriter;
-
-int write__artifact__klass__symbol(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) {
-  assert(writer != NULL, "invariant");
-  assert(artifacts != NULL, "invaiant");
-  assert(k != NULL, "invariant");
-  const InstanceKlass* const ik = (const InstanceKlass*)k;
-  if (ik->is_unsafe_anonymous()) {
-    CStringEntryPtr entry =
-      artifacts->map_cstring(JfrSymbolId::unsafe_anonymous_klass_name_hash_code(ik));
-    assert(entry != NULL, "invariant");
-    return write__artifact__cstring__entry__(writer, entry);
-  }
-
-  SymbolEntryPtr entry = artifacts->map_symbol(JfrSymbolId::regular_klass_name_hash_code(ik));
-  return write__artifact__symbol__entry__(writer, entry);
-}
-
-int _compare_traceid_(const traceid& lhs, const traceid& rhs) {
-  return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
+int write__package(JfrCheckpointWriter* writer, const void* p) {
+  assert(p != NULL, "invariant");
+  PkgPtr pkg = (PkgPtr)p;
+  set_serialized(pkg);
+  return write_package(writer, pkg, false);
 }
 
-template <template <typename> class Predicate>
-class KlassSymbolWriterImpl {
- private:
-  JfrCheckpointWriter* _writer;
-  JfrArtifactSet* _artifacts;
-  Predicate<KlassPtr> _predicate;
-  MethodUsedPredicate<true> _method_used_predicate;
-  MethodFlagPredicate _method_flag_predicate;
-  UniquePredicate<traceid, _compare_traceid_> _unique_predicate;
-
-  int klass_symbols(KlassPtr klass);
-  int package_symbols(PkgPtr pkg);
-  int module_symbols(ModPtr module);
-  int class_loader_symbols(CldPtr cld);
-  int method_symbols(KlassPtr klass);
-
- public:
-  typedef KlassPtr Type;
-  KlassSymbolWriterImpl(JfrCheckpointWriter* writer,
-                        JfrArtifactSet* artifacts,
-                        bool class_unload) : _writer(writer),
-                                             _artifacts(artifacts),
-                                             _predicate(class_unload),
-                                             _method_used_predicate(class_unload),
-                                             _method_flag_predicate(class_unload),
-                                             _unique_predicate(class_unload) {}
-
-  int operator()(KlassPtr klass) {
-    assert(klass != NULL, "invariant");
-    int count = 0;
-    if (_predicate(klass)) {
-      count += klass_symbols(klass);
-      PkgPtr pkg = klass->package();
-      if (pkg != NULL) {
-        count += package_symbols(pkg);
-        ModPtr module = pkg->module();
-        if (module != NULL && module->is_named()) {
-          count += module_symbols(module);
-        }
-      }
-      CldPtr cld = klass->class_loader_data();
-      assert(cld != NULL, "invariant");
-      if (!cld->is_unsafe_anonymous()) {
-        count += class_loader_symbols(cld);
-      }
-      if (_method_used_predicate(klass)) {
-        count += method_symbols(klass);
-      }
-    }
-    return count;
-  }
-};
-
-template <template <typename> class Predicate>
-int KlassSymbolWriterImpl<Predicate>::klass_symbols(KlassPtr klass) {
-  assert(klass != NULL, "invariant");
-  assert(_predicate(klass), "invariant");
-  const InstanceKlass* const ik = (const InstanceKlass*)klass;
-  if (ik->is_unsafe_anonymous()) {
-    CStringEntryPtr entry =
-      this->_artifacts->map_cstring(JfrSymbolId::unsafe_anonymous_klass_name_hash_code(ik));
-    assert(entry != NULL, "invariant");
-    return _unique_predicate(entry->id()) ? write__artifact__cstring__entry__(this->_writer, entry) : 0;
-  }
-  SymbolEntryPtr entry = this->_artifacts->map_symbol(ik->name());
-  assert(entry != NULL, "invariant");
-  return _unique_predicate(entry->id()) ? write__artifact__symbol__entry__(this->_writer, entry) : 0;
-}
-
-template <template <typename> class Predicate>
-int KlassSymbolWriterImpl<Predicate>::package_symbols(PkgPtr pkg) {
-  assert(pkg != NULL, "invariant");
-  SymbolPtr pkg_name = pkg->name();
-  assert(pkg_name != NULL, "invariant");
-  SymbolEntryPtr package_symbol = this->_artifacts->map_symbol(pkg_name);
-  assert(package_symbol != NULL, "invariant");
-  return _unique_predicate(package_symbol->id()) ?
-    write__artifact__symbol__entry__(this->_writer, package_symbol) : 0;
-}
-
-template <template <typename> class Predicate>
-int KlassSymbolWriterImpl<Predicate>::module_symbols(ModPtr module) {
-  assert(module != NULL, "invariant");
-  assert(module->is_named(), "invariant");
-  int count = 0;
-  SymbolPtr sym = module->name();
-  SymbolEntryPtr entry = NULL;
-  if (sym != NULL) {
-    entry = this->_artifacts->map_symbol(sym);
-    assert(entry != NULL, "invariant");
-    if (_unique_predicate(entry->id())) {
-      count += write__artifact__symbol__entry__(this->_writer, entry);
-    }
-  }
-  sym = module->version();
-  if (sym != NULL) {
-    entry = this->_artifacts->map_symbol(sym);
-    assert(entry != NULL, "invariant");
-    if (_unique_predicate(entry->id())) {
-      count += write__artifact__symbol__entry__(this->_writer, entry);
-    }
-  }
-  sym = module->location();
-  if (sym != NULL) {
-    entry = this->_artifacts->map_symbol(sym);
-    assert(entry != NULL, "invariant");
-    if (_unique_predicate(entry->id())) {
-      count += write__artifact__symbol__entry__(this->_writer, entry);
-    }
-  }
-  return count;
+int write__package__leakp(JfrCheckpointWriter* writer, const void* p) {
+  assert(p != NULL, "invariant");
+  PkgPtr pkg = (PkgPtr)p;
+  CLEAR_LEAKP(pkg);
+  return write_package(writer, pkg, true);
 }
 
-template <template <typename> class Predicate>
-int KlassSymbolWriterImpl<Predicate>::class_loader_symbols(CldPtr cld) {
-  assert(cld != NULL, "invariant");
-  assert(!cld->is_unsafe_anonymous(), "invariant");
-  int count = 0;
-  // class loader type
-  const Klass* class_loader_klass = cld->class_loader_klass();
-  if (class_loader_klass == NULL) {
-    // (primordial) boot class loader
-    CStringEntryPtr entry = this->_artifacts->map_cstring(0);
-    assert(entry != NULL, "invariant");
-    assert(strncmp(entry->literal(),
-      BOOTSTRAP_LOADER_NAME,
-      BOOTSTRAP_LOADER_NAME_LEN) == 0, "invariant");
-    if (_unique_predicate(entry->id())) {
-      count += write__artifact__cstring__entry__(this->_writer, entry);
-    }
-  } else {
-    const Symbol* class_loader_name = cld->name();
-    if (class_loader_name != NULL) {
-      SymbolEntryPtr entry = this->_artifacts->map_symbol(class_loader_name);
-      assert(entry != NULL, "invariant");
-      if (_unique_predicate(entry->id())) {
-        count += write__artifact__symbol__entry__(this->_writer, entry);
-      }
-    }
-  }
-  return count;
-}
-
-template <template <typename> class Predicate>
-int KlassSymbolWriterImpl<Predicate>::method_symbols(KlassPtr klass) {
-  assert(_predicate(klass), "invariant");
-  assert(_method_used_predicate(klass), "invariant");
-  assert(METHOD_AND_CLASS_USED_ANY_EPOCH(klass), "invariant");
-  int count = 0;
-  const InstanceKlass* const ik = InstanceKlass::cast(klass);
-  const int len = ik->methods()->length();
-  for (int i = 0; i < len; ++i) {
-    MethodPtr method = ik->methods()->at(i);
-    if (_method_flag_predicate(method)) {
-      SymbolEntryPtr entry = this->_artifacts->map_symbol(method->name());
-      assert(entry != NULL, "invariant");
-      if (_unique_predicate(entry->id())) {
-        count += write__artifact__symbol__entry__(this->_writer, entry);
-      }
-      entry = this->_artifacts->map_symbol(method->signature());
-      assert(entry != NULL, "invariant");
-      if (_unique_predicate(entry->id())) {
-        count += write__artifact__symbol__entry__(this->_writer, entry);
-      }
-    }
-  }
-  return count;
+static void do_package(PackageEntry* entry) {
+  do_previous_epoch_artifact(_subsystem_callback, entry);
 }
 
-typedef KlassSymbolWriterImpl<LeakPredicate> LeakKlassSymbolWriterImpl;
-typedef JfrArtifactWriterHost<LeakKlassSymbolWriterImpl, TYPE_SYMBOL> LeakKlassSymbolWriter;
-
-class ClearKlassAndMethods {
- private:
-  ClearArtifact<KlassPtr> _clear_klass_tag_bits;
-  ClearArtifact<MethodPtr> _clear_method_flag;
-  MethodUsedPredicate<false> _method_used_predicate;
-
- public:
-  ClearKlassAndMethods(bool class_unload) : _clear_klass_tag_bits(class_unload),
-                                            _clear_method_flag(class_unload),
-                                            _method_used_predicate(class_unload) {}
-  bool operator()(KlassPtr klass) {
-    if (_method_used_predicate(klass)) {
-      const InstanceKlass* ik = InstanceKlass::cast(klass);
-      const int len = ik->methods()->length();
-      for (int i = 0; i < len; ++i) {
-        MethodPtr method = ik->methods()->at(i);
-        _clear_method_flag(method);
-      }
-    }
-    _clear_klass_tag_bits(klass);
-    return true;
-  }
-};
-
-typedef CompositeFunctor<KlassPtr,
-                         TagLeakpKlassArtifact,
-                         LeakKlassWriter> LeakpKlassArtifactTagging;
-
-typedef CompositeFunctor<KlassPtr,
-                         LeakpKlassArtifactTagging,
-                         KlassWriter> CompositeKlassWriter;
-
-typedef CompositeFunctor<KlassPtr,
-                         CompositeKlassWriter,
-                         KlassArtifactRegistrator> CompositeKlassWriterRegistration;
-
-typedef CompositeFunctor<KlassPtr,
-                         KlassWriter,
-                         KlassArtifactRegistrator> KlassWriterRegistration;
-
-typedef JfrArtifactCallbackHost<KlassPtr, KlassWriterRegistration> KlassCallback;
-typedef JfrArtifactCallbackHost<KlassPtr, CompositeKlassWriterRegistration> CompositeKlassCallback;
-
-/*
- * Composite operation
- *
- * TagLeakpKlassArtifact ->
- *   LeakpPredicate ->
- *     LeakpKlassWriter ->
- *       KlassPredicate ->
- *         KlassWriter ->
- *           KlassWriterRegistration
- */
-void JfrTypeSet::write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
-  assert(!_artifacts->has_klass_entries(), "invariant");
-  KlassArtifactRegistrator reg(_artifacts);
-  KlassWriter kw(writer, _artifacts, _class_unload);
-  KlassWriterRegistration kwr(&kw, &reg);
-  if (leakp_writer == NULL) {
-    KlassCallback callback(&kwr);
-    _subsystem_callback = &callback;
-    do_klasses();
-    return;
-  }
-  TagLeakpKlassArtifact tagging(_class_unload);
-  LeakKlassWriter lkw(leakp_writer, _artifacts, _class_unload);
-  LeakpKlassArtifactTagging lpkat(&tagging, &lkw);
-  CompositeKlassWriter ckw(&lpkat, &kw);
-  CompositeKlassWriterRegistration ckwr(&ckw, &reg);
-  CompositeKlassCallback callback(&ckwr);
-  _subsystem_callback = &callback;
-  do_klasses();
+static void do_packages() {
+  ClassLoaderDataGraph::packages_do(&do_package);
 }
 
-typedef CompositeFunctor<PkgPtr,
-                         PackageWriter,
-                         ClearArtifact<PkgPtr> > PackageWriterWithClear;
-
-typedef CompositeFunctor<PkgPtr,
-                         LeakPackageWriter,
-                         PackageWriter> CompositePackageWriter;
-
-typedef CompositeFunctor<PkgPtr,
-                         CompositePackageWriter,
-                         ClearArtifact<PkgPtr> > CompositePackageWriterWithClear;
-
 class PackageFieldSelector {
  public:
   typedef PkgPtr TypePtr;
@@ -583,60 +349,86 @@
   }
 };
 
-typedef KlassToFieldEnvelope<PackageFieldSelector,
-                             PackageWriterWithClear> KlassPackageWriterWithClear;
+typedef SerializePredicate<PkgPtr> PackagePredicate;
+typedef JfrPredicatedTypeWriterImplHost<PkgPtr, PackagePredicate, write__package> PackageWriterImpl;
+typedef JfrTypeWriterHost<PackageWriterImpl, TYPE_PACKAGE> PackageWriter;
+typedef CompositeFunctor<PkgPtr, PackageWriter, ClearArtifact<PkgPtr> > PackageWriterWithClear;
+typedef KlassToFieldEnvelope<PackageFieldSelector, PackageWriter> KlassPackageWriter;
+typedef JfrArtifactCallbackHost<PkgPtr, PackageWriterWithClear> PackageCallback;
 
-typedef KlassToFieldEnvelope<PackageFieldSelector,
-                             CompositePackageWriterWithClear> KlassCompositePackageWriterWithClear;
+typedef LeakPredicate<PkgPtr> LeakPackagePredicate;
+typedef JfrPredicatedTypeWriterImplHost<PkgPtr, LeakPackagePredicate, write__package__leakp> LeakPackageWriterImpl;
+typedef JfrTypeWriterHost<LeakPackageWriterImpl, TYPE_PACKAGE> LeakPackageWriter;
 
-typedef JfrArtifactCallbackHost<PkgPtr, PackageWriterWithClear> PackageCallback;
+typedef CompositeFunctor<PkgPtr, LeakPackageWriter, PackageWriter> CompositePackageWriter;
+typedef KlassToFieldEnvelope<PackageFieldSelector, CompositePackageWriter> KlassCompositePackageWriter;
+typedef KlassToFieldEnvelope<PackageFieldSelector, PackageWriterWithClear> KlassPackageWriterWithClear;
+typedef CompositeFunctor<PkgPtr, CompositePackageWriter, ClearArtifact<PkgPtr> > CompositePackageWriterWithClear;
 typedef JfrArtifactCallbackHost<PkgPtr, CompositePackageWriterWithClear> CompositePackageCallback;
 
-/*
- * Composite operation
- *
- * LeakpPackageWriter ->
- *   PackageWriter ->
- *     ClearArtifact<PackageEntry>
- *
- */
-void JfrTypeSet::write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
-  assert(_artifacts->has_klass_entries(), "invariant");
-  ClearArtifact<PkgPtr> clear(_class_unload);
-  PackageWriter pw(writer, _artifacts, _class_unload);
-  if (leakp_writer == NULL) {
+static void write_packages() {
+  assert(_writer != NULL, "invariant");
+  PackageWriter pw(_writer, _class_unload);
+  KlassPackageWriter kpw(&pw);
+  if (current_epoch()) {
+    _artifacts->iterate_klasses(kpw);
+    _artifacts->tally(pw);
+    return;
+  }
+  assert(previous_epoch(), "invariant");
+  if (_leakp_writer == NULL) {
+    _artifacts->iterate_klasses(kpw);
+    ClearArtifact<PkgPtr> clear;
     PackageWriterWithClear pwwc(&pw, &clear);
-    KlassPackageWriterWithClear kpwwc(&pwwc);
-    _artifacts->iterate_klasses(kpwwc);
     PackageCallback callback(&pwwc);
     _subsystem_callback = &callback;
     do_packages();
-    return;
+  } else {
+    LeakPackageWriter lpw(_leakp_writer, _class_unload);
+    CompositePackageWriter cpw(&lpw, &pw);
+    KlassCompositePackageWriter kcpw(&cpw);
+    _artifacts->iterate_klasses(kcpw);
+    ClearArtifact<PkgPtr> clear;
+    CompositePackageWriterWithClear cpwwc(&cpw, &clear);
+    CompositePackageCallback callback(&cpwwc);
+    _subsystem_callback = &callback;
+    do_packages();
   }
-  LeakPackageWriter lpw(leakp_writer, _artifacts, _class_unload);
-  CompositePackageWriter cpw(&lpw, &pw);
-  CompositePackageWriterWithClear cpwwc(&cpw, &clear);
-  KlassCompositePackageWriterWithClear ckpw(&cpwwc);
-  _artifacts->iterate_klasses(ckpw);
-  CompositePackageCallback callback(&cpwwc);
-  _subsystem_callback = &callback;
-  do_packages();
+  _artifacts->tally(pw);
 }
 
-typedef CompositeFunctor<ModPtr,
-                         ModuleWriter,
-                         ClearArtifact<ModPtr> > ModuleWriterWithClear;
+static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) {
+  assert(mod != NULL, "invariant");
+  assert(_artifacts != NULL, "invariant");
+  writer->write(artifact_id(mod));
+  writer->write(mark_symbol(mod->name(), leakp));
+  writer->write(mark_symbol(mod->version(), leakp));
+  writer->write(mark_symbol(mod->location(), leakp));
+  writer->write(cld_id(mod->loader_data(), leakp));
+  return 1;
+}
 
-typedef CompositeFunctor<ModPtr,
-                         LeakModuleWriter,
-                         ModuleWriter> CompositeModuleWriter;
+int write__module(JfrCheckpointWriter* writer, const void* m) {
+  assert(m != NULL, "invariant");
+  ModPtr mod = (ModPtr)m;
+  set_serialized(mod);
+  return write_module(writer, mod, false);
+}
 
-typedef CompositeFunctor<ModPtr,
-                         CompositeModuleWriter,
-                         ClearArtifact<ModPtr> > CompositeModuleWriterWithClear;
+int write__module__leakp(JfrCheckpointWriter* writer, const void* m) {
+  assert(m != NULL, "invariant");
+  ModPtr mod = (ModPtr)m;
+  CLEAR_LEAKP(mod);
+  return write_module(writer, mod, true);
+}
 
-typedef JfrArtifactCallbackHost<ModPtr, ModuleWriterWithClear> ModuleCallback;
-typedef JfrArtifactCallbackHost<ModPtr, CompositeModuleWriterWithClear> CompositeModuleCallback;
+static void do_module(ModuleEntry* entry) {
+  do_previous_epoch_artifact(_subsystem_callback, entry);
+}
+
+static void do_modules() {
+  ClassLoaderDataGraph::modules_do(&do_module);
+}
 
 class ModuleFieldSelector {
  public:
@@ -648,47 +440,88 @@
   }
 };
 
-typedef KlassToFieldEnvelope<ModuleFieldSelector,
-                             ModuleWriterWithClear> KlassModuleWriterWithClear;
+typedef SerializePredicate<ModPtr> ModulePredicate;
+typedef JfrPredicatedTypeWriterImplHost<ModPtr, ModulePredicate, write__module> ModuleWriterImpl;
+typedef JfrTypeWriterHost<ModuleWriterImpl, TYPE_MODULE> ModuleWriter;
+typedef CompositeFunctor<ModPtr, ModuleWriter, ClearArtifact<ModPtr> > ModuleWriterWithClear;
+typedef JfrArtifactCallbackHost<ModPtr, ModuleWriterWithClear> ModuleCallback;
+typedef KlassToFieldEnvelope<ModuleFieldSelector, ModuleWriter> KlassModuleWriter;
 
-typedef KlassToFieldEnvelope<ModuleFieldSelector,
-                             CompositeModuleWriterWithClear> KlassCompositeModuleWriterWithClear;
+typedef LeakPredicate<ModPtr> LeakModulePredicate;
+typedef JfrPredicatedTypeWriterImplHost<ModPtr, LeakModulePredicate, write__module__leakp> LeakModuleWriterImpl;
+typedef JfrTypeWriterHost<LeakModuleWriterImpl, TYPE_MODULE> LeakModuleWriter;
 
-/*
- * Composite operation
- *
- * LeakpModuleWriter ->
- *   ModuleWriter ->
- *     ClearArtifact<ModuleEntry>
- */
-void JfrTypeSet::write_module_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
-  assert(_artifacts->has_klass_entries(), "invariant");
-  ClearArtifact<ModPtr> clear(_class_unload);
-  ModuleWriter mw(writer, _artifacts, _class_unload);
-  if (leakp_writer == NULL) {
+typedef CompositeFunctor<ModPtr, LeakModuleWriter, ModuleWriter> CompositeModuleWriter;
+typedef KlassToFieldEnvelope<ModuleFieldSelector, CompositeModuleWriter> KlassCompositeModuleWriter;
+typedef CompositeFunctor<ModPtr, CompositeModuleWriter, ClearArtifact<ModPtr> > CompositeModuleWriterWithClear;
+typedef JfrArtifactCallbackHost<ModPtr, CompositeModuleWriterWithClear> CompositeModuleCallback;
+
+static void write_modules() {
+  assert(_writer != NULL, "invariant");
+  ModuleWriter mw(_writer, _class_unload);
+  KlassModuleWriter kmw(&mw);
+  if (current_epoch()) {
+    _artifacts->iterate_klasses(kmw);
+    _artifacts->tally(mw);
+    return;
+  }
+  assert(previous_epoch(), "invariant");
+  if (_leakp_writer == NULL) {
+    _artifacts->iterate_klasses(kmw);
+    ClearArtifact<ModPtr> clear;
     ModuleWriterWithClear mwwc(&mw, &clear);
-    KlassModuleWriterWithClear kmwwc(&mwwc);
-    _artifacts->iterate_klasses(kmwwc);
     ModuleCallback callback(&mwwc);
     _subsystem_callback = &callback;
     do_modules();
-    return;
+  } else {
+    LeakModuleWriter lmw(_leakp_writer, _class_unload);
+    CompositeModuleWriter cmw(&lmw, &mw);
+    KlassCompositeModuleWriter kcpw(&cmw);
+    _artifacts->iterate_klasses(kcpw);
+    ClearArtifact<ModPtr> clear;
+    CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
+    CompositeModuleCallback callback(&cmwwc);
+    _subsystem_callback = &callback;
+    do_modules();
   }
-  LeakModuleWriter lmw(leakp_writer, _artifacts, _class_unload);
-  CompositeModuleWriter cmw(&lmw, &mw);
-  CompositeModuleWriterWithClear cmwwc(&cmw, &clear);
-  KlassCompositeModuleWriterWithClear kmwwc(&cmwwc);
-  _artifacts->iterate_klasses(kmwwc);
-  CompositeModuleCallback callback(&cmwwc);
-  _subsystem_callback = &callback;
-  do_modules();
+  _artifacts->tally(mw);
 }
 
-typedef CompositeFunctor<CldPtr, CldWriter, ClearArtifact<CldPtr> > CldWriterWithClear;
-typedef CompositeFunctor<CldPtr, LeakCldWriter, CldWriter> CompositeCldWriter;
-typedef CompositeFunctor<CldPtr, CompositeCldWriter, ClearArtifact<CldPtr> > CompositeCldWriterWithClear;
-typedef JfrArtifactCallbackHost<CldPtr, CldWriterWithClear> CldCallback;
-typedef JfrArtifactCallbackHost<CldPtr, CompositeCldWriterWithClear> CompositeCldCallback;
+static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) {
+  assert(cld != NULL, "invariant");
+  assert(!cld->is_unsafe_anonymous(), "invariant");
+  // class loader type
+  const Klass* class_loader_klass = cld->class_loader_klass();
+  if (class_loader_klass == NULL) {
+    // (primordial) boot class loader
+    writer->write(artifact_id(cld)); // class loader instance id
+    writer->write((traceid)0);  // class loader type id (absence of)
+    writer->write(get_bootstrap_name(leakp)); // maps to synthetic name -> "bootstrap"
+  } else {
+    writer->write(artifact_id(cld)); // class loader instance id
+    writer->write(artifact_id(class_loader_klass)); // class loader type id
+    writer->write(mark_symbol(cld->name(), leakp)); // class loader instance name
+  }
+  return 1;
+}
+
+int write__classloader(JfrCheckpointWriter* writer, const void* c) {
+  assert(c != NULL, "invariant");
+  CldPtr cld = (CldPtr)c;
+  set_serialized(cld);
+  return write_classloader(writer, cld, false);
+}
+
+int write__classloader__leakp(JfrCheckpointWriter* writer, const void* c) {
+  assert(c != NULL, "invariant");
+  CldPtr cld = (CldPtr)c;
+  CLEAR_LEAKP(cld);
+  return write_classloader(writer, cld, true);
+}
+
+static void do_class_loader_data(ClassLoaderData* cld) {
+  do_previous_epoch_artifact(_subsystem_callback, cld);
+}
 
 class CldFieldSelector {
  public:
@@ -700,289 +533,328 @@
   }
 };
 
-typedef KlassToFieldEnvelope<CldFieldSelector, CldWriterWithClear> KlassCldWriterWithClear;
-typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriterWithClear> KlassCompositeCldWriterWithClear;
+class CLDCallback : public CLDClosure {
+ public:
+  CLDCallback() {}
+  void do_cld(ClassLoaderData* cld) {
+    assert(cld != NULL, "invariant");
+    if (cld->is_unsafe_anonymous()) {
+      return;
+    }
+    do_class_loader_data(cld);
+  }
+};
+
+static void do_class_loaders() {
+  CLDCallback cld_cb;
+  ClassLoaderDataGraph::loaded_cld_do(&cld_cb);
+}
+
+typedef SerializePredicate<CldPtr> CldPredicate;
+typedef JfrPredicatedTypeWriterImplHost<CldPtr, CldPredicate, write__classloader> CldWriterImpl;
+typedef JfrTypeWriterHost<CldWriterImpl, TYPE_CLASSLOADER> CldWriter;
+typedef CompositeFunctor<CldPtr, CldWriter, ClearArtifact<CldPtr> > CldWriterWithClear;
+typedef JfrArtifactCallbackHost<CldPtr, CldWriterWithClear> CldCallback;
+typedef KlassToFieldEnvelope<CldFieldSelector, CldWriter> KlassCldWriter;
 
-/*
- * Composite operation
- *
- * LeakpClassLoaderWriter ->
- *   ClassLoaderWriter ->
- *     ClearArtifact<ClassLoaderData>
- */
-void JfrTypeSet::write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
-  assert(_artifacts->has_klass_entries(), "invariant");
-  ClearArtifact<CldPtr> clear(_class_unload);
-  CldWriter cldw(writer, _artifacts, _class_unload);
-  if (leakp_writer == NULL) {
+typedef LeakPredicate<CldPtr> LeakCldPredicate;
+typedef JfrPredicatedTypeWriterImplHost<CldPtr, LeakCldPredicate, write__classloader__leakp> LeakCldWriterImpl;
+typedef JfrTypeWriterHost<LeakCldWriterImpl, TYPE_CLASSLOADER> LeakCldWriter;
+
+typedef CompositeFunctor<CldPtr, LeakCldWriter, CldWriter> CompositeCldWriter;
+typedef KlassToFieldEnvelope<CldFieldSelector, CompositeCldWriter> KlassCompositeCldWriter;
+typedef CompositeFunctor<CldPtr, CompositeCldWriter, ClearArtifact<CldPtr> > CompositeCldWriterWithClear;
+typedef JfrArtifactCallbackHost<CldPtr, CompositeCldWriterWithClear> CompositeCldCallback;
+
+static void write_classloaders() {
+  assert(_writer != NULL, "invariant");
+  CldWriter cldw(_writer, _class_unload);
+  KlassCldWriter kcw(&cldw);
+  if (current_epoch()) {
+    _artifacts->iterate_klasses(kcw);
+    _artifacts->tally(cldw);
+    return;
+  }
+  assert(previous_epoch(), "invariant");
+  if (_leakp_writer == NULL) {
+    _artifacts->iterate_klasses(kcw);
+    ClearArtifact<CldPtr> clear;
     CldWriterWithClear cldwwc(&cldw, &clear);
-    KlassCldWriterWithClear kcldwwc(&cldwwc);
-    _artifacts->iterate_klasses(kcldwwc);
     CldCallback callback(&cldwwc);
     _subsystem_callback = &callback;
     do_class_loaders();
-    return;
+  } else {
+    LeakCldWriter lcldw(_leakp_writer, _class_unload);
+    CompositeCldWriter ccldw(&lcldw, &cldw);
+    KlassCompositeCldWriter kccldw(&ccldw);
+    _artifacts->iterate_klasses(kccldw);
+    ClearArtifact<CldPtr> clear;
+    CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
+    CompositeCldCallback callback(&ccldwwc);
+    _subsystem_callback = &callback;
+    do_class_loaders();
   }
-  LeakCldWriter lcldw(leakp_writer, _artifacts, _class_unload);
-  CompositeCldWriter ccldw(&lcldw, &cldw);
-  CompositeCldWriterWithClear ccldwwc(&ccldw, &clear);
-  KlassCompositeCldWriterWithClear kcclwwc(&ccldwwc);
-  _artifacts->iterate_klasses(kcclwwc);
-  CompositeCldCallback callback(&ccldwwc);
-  _subsystem_callback = &callback;
-  do_class_loaders();
+  _artifacts->tally(cldw);
+}
+
+static u1 get_visibility(MethodPtr method) {
+  assert(method != NULL, "invariant");
+  return const_cast<Method*>(method)->is_hidden() ? (u1)1 : (u1)0;
+}
+
+template <>
+void set_serialized<Method>(MethodPtr method) {
+  assert(method != NULL, "invariant");
+  SET_METHOD_SERIALIZED(method);
+  assert(IS_METHOD_SERIALIZED(method), "invariant");
 }
 
-template <bool predicate_bool, typename MethodFunctor>
+static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leakp) {
+  assert(writer != NULL, "invariant");
+  assert(method != NULL, "invariant");
+  assert(_artifacts != NULL, "invariant");
+  KlassPtr klass = method->method_holder();
+  assert(klass != NULL, "invariant");
+  writer->write(method_id(klass, method));
+  writer->write(artifact_id(klass));
+  writer->write(mark_symbol(method->name(), leakp));
+  writer->write(mark_symbol(method->signature(), leakp));
+  writer->write((u2)get_flags(method));
+  writer->write(get_visibility(method));
+  return 1;
+}
+
+int write__method(JfrCheckpointWriter* writer, const void* m) {
+  assert(m != NULL, "invariant");
+  MethodPtr method = (MethodPtr)m;
+  set_serialized(method);
+  return write_method(writer, method, false);
+}
+
+int write__method__leakp(JfrCheckpointWriter* writer, const void* m) {
+  assert(m != NULL, "invariant");
+  MethodPtr method = (MethodPtr)m;
+  return write_method(writer, method, true);
+}
+
+template <typename MethodCallback, typename KlassCallback, bool leakp>
 class MethodIteratorHost {
  private:
-  MethodFunctor _method_functor;
-  MethodUsedPredicate<predicate_bool> _method_used_predicate;
-  MethodFlagPredicate _method_flag_predicate;
-
+  MethodCallback _method_cb;
+  KlassCallback _klass_cb;
+  MethodUsedPredicate<leakp> _method_used_predicate;
+  MethodFlagPredicate<leakp> _method_flag_predicate;
  public:
   MethodIteratorHost(JfrCheckpointWriter* writer,
-                     JfrArtifactSet* artifacts,
-                     bool class_unload,
+                     bool current_epoch = false,
+                     bool class_unload = false,
                      bool skip_header = false) :
-    _method_functor(writer, artifacts, class_unload, skip_header),
-    _method_used_predicate(class_unload),
-    _method_flag_predicate(class_unload) {}
+    _method_cb(writer, class_unload, skip_header),
+    _klass_cb(writer, class_unload, skip_header),
+    _method_used_predicate(current_epoch),
+    _method_flag_predicate(current_epoch) {}
 
   bool operator()(KlassPtr klass) {
     if (_method_used_predicate(klass)) {
-      assert(METHOD_AND_CLASS_USED_ANY_EPOCH(klass), "invariant");
-      const InstanceKlass* ik = InstanceKlass::cast(klass);
+      const InstanceKlass* const ik = InstanceKlass::cast(klass);
       const int len = ik->methods()->length();
       for (int i = 0; i < len; ++i) {
         MethodPtr method = ik->methods()->at(i);
         if (_method_flag_predicate(method)) {
-          _method_functor(method);
+          _method_cb(method);
         }
       }
     }
-    return true;
+    return _klass_cb(klass);
   }
 
-  int count() const { return _method_functor.count(); }
-  void add(int count) { _method_functor.add(count); }
+  int count() const { return _method_cb.count(); }
+  void add(int count) { _method_cb.add(count); }
 };
 
-typedef MethodIteratorHost<true /*leakp */,  MethodWriterImpl> LeakMethodWriter;
-typedef MethodIteratorHost<false, MethodWriterImpl> MethodWriter;
-typedef CompositeFunctor<KlassPtr, LeakMethodWriter, MethodWriter> CompositeMethodWriter;
-
-/*
- * Composite operation
- *
- * LeakpMethodWriter ->
- *   MethodWriter
- */
-void JfrTypeSet::write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
-  assert(_artifacts->has_klass_entries(), "invariant");
-  MethodWriter mw(writer, _artifacts, _class_unload);
-  if (leakp_writer == NULL) {
-    _artifacts->iterate_klasses(mw);
-    return;
-  }
-  LeakMethodWriter lpmw(leakp_writer, _artifacts, _class_unload);
-  CompositeMethodWriter cmw(&lpmw, &mw);
-  _artifacts->iterate_klasses(cmw);
-}
-static void write_symbols_leakp(JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool class_unload) {
-  assert(leakp_writer != NULL, "invariant");
-  assert(artifacts != NULL, "invariant");
-  LeakKlassSymbolWriter lpksw(leakp_writer, artifacts, class_unload);
-  artifacts->iterate_klasses(lpksw);
-}
-static void write_symbols(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, JfrArtifactSet* artifacts, bool class_unload) {
-  assert(writer != NULL, "invariant");
-  assert(artifacts != NULL, "invariant");
-  if (leakp_writer != NULL) {
-    write_symbols_leakp(leakp_writer, artifacts, class_unload);
-  }
-  // iterate all registered symbols
-  SymbolEntryWriter symbol_writer(writer, artifacts, class_unload);
-  artifacts->iterate_symbols(symbol_writer);
-  CStringEntryWriter cstring_writer(writer, artifacts, class_unload, true); // skip header
-  artifacts->iterate_cstrings(cstring_writer);
-  symbol_writer.add(cstring_writer.count());
-}
-
-bool JfrTypeSet::_class_unload = false;
-JfrArtifactSet* JfrTypeSet::_artifacts = NULL;
-JfrArtifactClosure* JfrTypeSet::_subsystem_callback = NULL;
-
-void JfrTypeSet::write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
-  assert(writer != NULL, "invariant");
-  assert(_artifacts->has_klass_entries(), "invariant");
-  write_symbols(writer, leakp_writer, _artifacts, _class_unload);
-}
-
-void JfrTypeSet::do_unloaded_klass(Klass* klass) {
-  assert(klass != NULL, "invariant");
-  assert(_subsystem_callback != NULL, "invariant");
-  if (IS_JDK_JFR_EVENT_SUBKLASS(klass)) {
-    JfrEventClasses::increment_unloaded_event_class();
-  }
-  if (USED_THIS_EPOCH(klass)) { // includes leakp subset
-    _subsystem_callback->do_artifact(klass);
-    return;
-  }
-  if (klass->is_subclass_of(SystemDictionary::ClassLoader_klass()) || klass == SystemDictionary::Object_klass()) {
-    SET_LEAKP_USED_THIS_EPOCH(klass); // tag leakp "safe byte" for subset inclusion
-    _subsystem_callback->do_artifact(klass);
-  }
-}
-
-void JfrTypeSet::do_klass(Klass* klass) {
-  assert(klass != NULL, "invariant");
-  assert(_subsystem_callback != NULL, "invariant");
-  if (USED_PREV_EPOCH(klass)) { // includes leakp subset
-    _subsystem_callback->do_artifact(klass);
-    return;
-  }
-  if (klass->is_subclass_of(SystemDictionary::ClassLoader_klass()) || klass == SystemDictionary::Object_klass()) {
-    SET_LEAKP_USED_PREV_EPOCH(klass); // tag leakp "safe byte" for subset inclusion
-    _subsystem_callback->do_artifact(klass);
-  }
-}
-
-void JfrTypeSet::do_klasses() {
-  if (_class_unload) {
-    ClassLoaderDataGraph::classes_unloading_do(&do_unloaded_klass);
-    return;
-  }
-  ClassLoaderDataGraph::classes_do(&do_klass);
-}
-
-void JfrTypeSet::do_unloaded_package(PackageEntry* entry) {
-  assert(entry != NULL, "invariant");
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_THIS_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
-}
-
-void JfrTypeSet::do_package(PackageEntry* entry) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_PREV_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
-}
-
-void JfrTypeSet::do_packages() {
-  if (_class_unload) {
-    ClassLoaderDataGraph::packages_unloading_do(&do_unloaded_package);
-    return;
-  }
-  ClassLoaderDataGraph::packages_do(&do_package);
-}
-void JfrTypeSet::do_unloaded_module(ModuleEntry* entry) {
-  assert(entry != NULL, "invariant");
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_THIS_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
-}
-
-void JfrTypeSet::do_module(ModuleEntry* entry) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_PREV_EPOCH(entry)) { // includes leakp subset
-    _subsystem_callback->do_artifact(entry);
-  }
-}
-
-void JfrTypeSet::do_modules() {
-  if (_class_unload) {
-    ClassLoaderDataGraph::modules_unloading_do(&do_unloaded_module);
-    return;
-  }
-  ClassLoaderDataGraph::modules_do(&do_module);
-}
-
-void JfrTypeSet::do_unloaded_class_loader_data(ClassLoaderData* cld) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_THIS_EPOCH(cld)) { // includes leakp subset
-    _subsystem_callback->do_artifact(cld);
-  }
-}
-
-void JfrTypeSet::do_class_loader_data(ClassLoaderData* cld) {
-  assert(_subsystem_callback != NULL, "invariant");
-  if (ANY_USED_PREV_EPOCH(cld)) { // includes leakp subset
-    _subsystem_callback->do_artifact(cld);
-  }
-}
-
-class CLDCallback : public CLDClosure {
- private:
-  bool _class_unload;
+template <typename T, template <typename> class Impl>
+class Wrapper {
+  Impl<T> _t;
  public:
-  CLDCallback(bool class_unload) : _class_unload(class_unload) {}
-  void do_cld(ClassLoaderData* cld) {
-     assert(cld != NULL, "invariant");
-    if (cld->is_unsafe_anonymous()) {
-      return;
-    }
-    if (_class_unload) {
-      JfrTypeSet::do_unloaded_class_loader_data(cld);
-      return;
-    }
-    JfrTypeSet::do_class_loader_data(cld);
+  Wrapper(JfrCheckpointWriter*, bool, bool) : _t() {}
+  bool operator()(T const& value) {
+    return _t(value);
   }
 };
 
-void JfrTypeSet::do_class_loaders() {
-  CLDCallback cld_cb(_class_unload);
-  if (_class_unload) {
-    ClassLoaderDataGraph::cld_unloading_do(&cld_cb);
-    return;
+typedef SerializePredicate<MethodPtr> MethodPredicate;
+typedef JfrPredicatedTypeWriterImplHost<MethodPtr, MethodPredicate, write__method> MethodWriterImplTarget;
+typedef Wrapper<KlassPtr, Stub> KlassCallbackStub;
+typedef JfrTypeWriterHost<MethodWriterImplTarget, TYPE_METHOD> MethodWriterImpl;
+typedef MethodIteratorHost<MethodWriterImpl, KlassCallbackStub, false> MethodWriter;
+
+typedef LeakPredicate<MethodPtr> LeakMethodPredicate;
+typedef JfrPredicatedTypeWriterImplHost<MethodPtr, LeakMethodPredicate, write__method__leakp> LeakMethodWriterImplTarget;
+typedef JfrTypeWriterHost<LeakMethodWriterImplTarget, TYPE_METHOD> LeakMethodWriterImpl;
+typedef MethodIteratorHost<LeakMethodWriterImpl, KlassCallbackStub, true> LeakMethodWriter;
+typedef CompositeFunctor<KlassPtr, LeakMethodWriter, MethodWriter> CompositeMethodWriter;
+
+static void write_methods() {
+  assert(_writer != NULL, "invariant");
+  MethodWriter mw(_writer, current_epoch(), _class_unload);
+  if (_leakp_writer == NULL) {
+    _artifacts->iterate_klasses(mw);
+  } else {
+    LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload);
+    CompositeMethodWriter cmw(&lpmw, &mw);
+    _artifacts->iterate_klasses(cmw);
   }
-  ClassLoaderDataGraph::loaded_cld_do(&cld_cb);
+  _artifacts->tally(mw);
+}
+
+template <>
+void set_serialized<JfrSymbolId::SymbolEntry>(SymbolEntryPtr ptr) {
+  assert(ptr != NULL, "invariant");
+  ptr->set_serialized();
+  assert(ptr->is_serialized(), "invariant");
+}
+
+template <>
+void set_serialized<JfrSymbolId::CStringEntry>(CStringEntryPtr ptr) {
+  assert(ptr != NULL, "invariant");
+  ptr->set_serialized();
+  assert(ptr->is_serialized(), "invariant");
+}
+
+static int write_symbol(JfrCheckpointWriter* writer, SymbolEntryPtr entry, bool leakp) {
+  assert(writer != NULL, "invariant");
+  assert(entry != NULL, "invariant");
+  ResourceMark rm;
+  writer->write(create_symbol_id(entry->id()));
+  writer->write(entry->value()->as_C_string());
+  return 1;
+}
+
+int write__symbol(JfrCheckpointWriter* writer, const void* e) {
+  assert(e != NULL, "invariant");
+  SymbolEntryPtr entry = (SymbolEntryPtr)e;
+  set_serialized(entry);
+  return write_symbol(writer, entry, false);
+}
+
+int write__symbol__leakp(JfrCheckpointWriter* writer, const void* e) {
+  assert(e != NULL, "invariant");
+  SymbolEntryPtr entry = (SymbolEntryPtr)e;
+  return write_symbol(writer, entry, true);
+}
+
+static int write_cstring(JfrCheckpointWriter* writer, CStringEntryPtr entry, bool leakp) {
+  assert(writer != NULL, "invariant");
+  assert(entry != NULL, "invariant");
+  writer->write(create_symbol_id(entry->id()));
+  writer->write(entry->value());
+  return 1;
+}
+
+int write__cstring(JfrCheckpointWriter* writer, const void* e) {
+  assert(e != NULL, "invariant");
+  CStringEntryPtr entry = (CStringEntryPtr)e;
+  set_serialized(entry);
+  return write_cstring(writer, entry, false);
 }
 
-static void clear_artifacts(JfrArtifactSet* artifacts,
-                            bool class_unload) {
-  assert(artifacts != NULL, "invariant");
-  assert(artifacts->has_klass_entries(), "invariant");
+int write__cstring__leakp(JfrCheckpointWriter* writer, const void* e) {
+  assert(e != NULL, "invariant");
+  CStringEntryPtr entry = (CStringEntryPtr)e;
+  return write_cstring(writer, entry, true);
+}
+
+typedef SymbolPredicate<SymbolEntryPtr, false> SymPredicate;
+typedef JfrPredicatedTypeWriterImplHost<SymbolEntryPtr, SymPredicate, write__symbol> SymbolEntryWriterImpl;
+typedef JfrTypeWriterHost<SymbolEntryWriterImpl, TYPE_SYMBOL> SymbolEntryWriter;
+typedef SymbolPredicate<CStringEntryPtr, false> CStringPredicate;
+typedef JfrPredicatedTypeWriterImplHost<CStringEntryPtr, CStringPredicate, write__cstring> CStringEntryWriterImpl;
+typedef JfrTypeWriterHost<CStringEntryWriterImpl, TYPE_SYMBOL> CStringEntryWriter;
+
+typedef SymbolPredicate<SymbolEntryPtr, true> LeakSymPredicate;
+typedef JfrPredicatedTypeWriterImplHost<SymbolEntryPtr, LeakSymPredicate, write__symbol__leakp> LeakSymbolEntryWriterImpl;
+typedef JfrTypeWriterHost<LeakSymbolEntryWriterImpl, TYPE_SYMBOL> LeakSymbolEntryWriter;
+typedef CompositeFunctor<SymbolEntryPtr, LeakSymbolEntryWriter, SymbolEntryWriter> CompositeSymbolWriter;
+typedef SymbolPredicate<CStringEntryPtr, true> LeakCStringPredicate;
+typedef JfrPredicatedTypeWriterImplHost<CStringEntryPtr, LeakCStringPredicate, write__cstring__leakp> LeakCStringEntryWriterImpl;
+typedef JfrTypeWriterHost<LeakCStringEntryWriterImpl, TYPE_SYMBOL> LeakCStringEntryWriter;
+typedef CompositeFunctor<CStringEntryPtr, LeakCStringEntryWriter, CStringEntryWriter> CompositeCStringWriter;
+
+static void write_symbols_with_leakp() {
+  assert(_leakp_writer != NULL, "invariant");
+  SymbolEntryWriter sw(_writer, _class_unload);
+  LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload);
+  CompositeSymbolWriter csw(&lsw, &sw);
+  _artifacts->iterate_symbols(csw);
+  CStringEntryWriter ccsw(_writer, _class_unload, true); // skip header
+  LeakCStringEntryWriter lccsw(_leakp_writer, _class_unload, true); // skip header
+  CompositeCStringWriter cccsw(&lccsw, &ccsw);
+  _artifacts->iterate_cstrings(cccsw);
+  sw.add(ccsw.count());
+  lsw.add(lccsw.count());
+  _artifacts->tally(sw);
+}
 
-  // untag
-  ClearKlassAndMethods clear(class_unload);
-  artifacts->iterate_klasses(clear);
-  artifacts->clear();
+static void write_symbols() {
+  assert(_writer != NULL, "invariant");
+  if (_leakp_writer != NULL) {
+    write_symbols_with_leakp();
+    return;
+  }
+  SymbolEntryWriter sw(_writer, _class_unload);
+  _artifacts->iterate_symbols(sw);
+  CStringEntryWriter csw(_writer, _class_unload, true); // skip header
+  _artifacts->iterate_cstrings(csw);
+  sw.add(csw.count());
+  _artifacts->tally(sw);
+}
+
+typedef Wrapper<KlassPtr, ClearArtifact> ClearKlassBits;
+typedef Wrapper<MethodPtr, ClearArtifact> ClearMethodFlag;
+typedef MethodIteratorHost<ClearMethodFlag, ClearKlassBits, false> ClearKlassAndMethods;
+
+static size_t teardown() {
+  assert(_artifacts != NULL, "invariant");
+  const size_t total_count = _artifacts->total_count();
+  if (previous_epoch()) {
+    assert(_writer != NULL, "invariant");
+    ClearKlassAndMethods clear(_writer);
+    _artifacts->iterate_klasses(clear);
+    _artifacts->clear();
+    ++checkpoint_id;
+  }
+  return total_count;
+}
+
+static void setup(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload) {
+  _writer = writer;
+  _leakp_writer = leakp_writer;
+  _class_unload = class_unload;
+  if (_artifacts == NULL) {
+    _artifacts = new JfrArtifactSet(class_unload);
+  } else {
+    _artifacts->initialize(class_unload);
+  }
+  assert(_artifacts != NULL, "invariant");
+  assert(!_artifacts->has_klass_entries(), "invariant");
 }
 
 /**
  * Write all "tagged" (in-use) constant artifacts and their dependencies.
  */
-void JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload) {
+size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload) {
   assert(writer != NULL, "invariant");
   ResourceMark rm;
-  // initialization begin
-  _class_unload = class_unload;
-  ++checkpoint_id;
-  if (_artifacts == NULL) {
-    _artifacts = new JfrArtifactSet(class_unload);
-    _subsystem_callback = NULL;
-  } else {
-    _artifacts->initialize(class_unload);
-    _subsystem_callback = NULL;
-  }
-  assert(_artifacts != NULL, "invariant");
-  assert(!_artifacts->has_klass_entries(), "invariant");
-  assert(_subsystem_callback == NULL, "invariant");
-  // initialization complete
-
+  setup(writer, leakp_writer, class_unload);
   // write order is important because an individual write step
   // might tag an artifact to be written in a subsequent step
-  write_klass_constants(writer, leakp_writer);
-  if (_artifacts->has_klass_entries()) {
-    write_package_constants(writer, leakp_writer);
-    write_module_constants(writer, leakp_writer);
-    write_class_loader_constants(writer, leakp_writer);
-    write_method_constants(writer, leakp_writer);
-    write_symbol_constants(writer, leakp_writer);
-    clear_artifacts(_artifacts, class_unload);
+  if (!write_klasses()) {
+    return 0;
   }
+  write_packages();
+  write_modules();
+  write_classloaders();
+  write_methods();
+  write_symbols();
+  return teardown();
 }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -27,47 +27,11 @@
 
 #include "jfr/utilities/jfrAllocation.hpp"
 
-class ClassLoaderData;
-class JfrArtifactClosure;
-class JfrArtifactSet;
 class JfrCheckpointWriter;
-class Klass;
-
-class ModuleEntry;
-class PackageEntry;
 
 class JfrTypeSet : AllStatic {
-  friend class CLDCallback;
-  friend class JfrTypeManager;
-  friend class TypeSetSerialization;
- private:
-  static JfrArtifactSet* _artifacts;
-  static JfrArtifactClosure* _subsystem_callback;
-  static bool _class_unload;
-
-  static void do_klass(Klass* k);
-  static void do_unloaded_klass(Klass* k);
-  static void do_klasses();
-
-  static void do_package(PackageEntry* entry);
-  static void do_unloaded_package(PackageEntry* entry);
-  static void do_packages();
-
-  static void do_module(ModuleEntry* entry);
-  static void do_unloaded_module(ModuleEntry* entry);
-  static void do_modules();
-
-  static void do_class_loader_data(ClassLoaderData* cld);
-  static void do_unloaded_class_loader_data(ClassLoaderData* cld);
-  static void do_class_loaders();
-
-  static void write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void write_module_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
-  static void serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload);
+ public:
+  static size_t serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer, bool class_unload);
 };
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESET_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,15 +28,28 @@
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 
-JfrSymbolId::JfrSymbolId() : _sym_table(new SymbolTable(this)), _cstring_table(new CStringTable(this)), _symbol_id_counter(0) {
+static JfrSymbolId::CStringEntry* bootstrap = NULL;
+
+JfrSymbolId::JfrSymbolId() :
+  _sym_table(new SymbolTable(this)),
+  _cstring_table(new CStringTable(this)),
+  _sym_list(NULL),
+  _cstring_list(NULL),
+  _symbol_id_counter(1),
+  _class_unload(false) {
   assert(_sym_table != NULL, "invariant");
   assert(_cstring_table != NULL, "invariant");
-  initialize();
+  bootstrap = new CStringEntry(0, (const char*)&BOOTSTRAP_LOADER_NAME);
+  assert(bootstrap != NULL, "invariant");
+  bootstrap->set_id(1);
+  _cstring_list = bootstrap;
 }
 
-void JfrSymbolId::initialize() {
+JfrSymbolId::~JfrSymbolId() {
   clear();
-  assert(_symbol_id_counter == 0, "invariant");
+  delete _sym_table;
+  delete _cstring_table;
+  delete bootstrap;
 }
 
 void JfrSymbolId::clear() {
@@ -51,106 +64,115 @@
     _cstring_table->clear_entries();
   }
   assert(!_cstring_table->has_entries(), "invariant");
-  _symbol_id_counter = 0;
-}
 
-JfrSymbolId::~JfrSymbolId() {
-  delete _sym_table;
-  delete _cstring_table;
+  _sym_list = NULL;
+  _cstring_list = NULL;
+  _symbol_id_counter = 1;
+
+  assert(bootstrap != NULL, "invariant");
+  bootstrap->reset();
+  _cstring_list = bootstrap;
 }
 
-traceid JfrSymbolId::mark_unsafe_anonymous_klass_name(const Klass* k) {
-  assert(k != NULL, "invariant");
-  assert(k->is_instance_klass(), "invariant");
-  assert(is_unsafe_anonymous_klass(k), "invariant");
-
-  uintptr_t anonymous_symbol_hash_code = 0;
-  const char* const anonymous_symbol =
-    create_unsafe_anonymous_klass_symbol((const InstanceKlass*)k, anonymous_symbol_hash_code);
-
-  if (anonymous_symbol == NULL) {
-    return 0;
-  }
-
-  assert(anonymous_symbol_hash_code != 0, "invariant");
-  traceid symbol_id = mark(anonymous_symbol, anonymous_symbol_hash_code);
-  assert(mark(anonymous_symbol, anonymous_symbol_hash_code) == symbol_id, "invariant");
-  return symbol_id;
+void JfrSymbolId::set_class_unload(bool class_unload) {
+  _class_unload = class_unload;
 }
 
-const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(const Symbol* symbol) const {
-  return _sym_table->lookup_only(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash());
-}
-
-const JfrSymbolId::SymbolEntry* JfrSymbolId::map_symbol(uintptr_t hash) const {
-  return _sym_table->lookup_only(NULL, hash);
+void JfrSymbolId::on_link(const SymbolEntry* entry) {
+  assert(entry != NULL, "invariant");
+  const_cast<Symbol*>(entry->literal())->increment_refcount();
+  assert(entry->id() == 0, "invariant");
+  entry->set_id(++_symbol_id_counter);
+  entry->set_list_next(_sym_list);
+  _sym_list = entry;
 }
 
-const JfrSymbolId::CStringEntry* JfrSymbolId::map_cstring(uintptr_t hash) const {
-  return _cstring_table->lookup_only(NULL, hash);
-}
-
-void JfrSymbolId::assign_id(SymbolEntry* entry) {
-  assert(entry != NULL, "invariant");
-  assert(entry->id() == 0, "invariant");
-  entry->set_id(++_symbol_id_counter);
-}
-
-bool JfrSymbolId::equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry) {
+bool JfrSymbolId::on_equals(uintptr_t hash, const SymbolEntry* entry) {
   // query might be NULL
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return true;
 }
 
-void JfrSymbolId::assign_id(CStringEntry* entry) {
+void JfrSymbolId::on_unlink(const SymbolEntry* entry) {
+  assert(entry != NULL, "invariant");
+  const_cast<Symbol*>(entry->literal())->decrement_refcount();
+}
+
+void JfrSymbolId::on_link(const CStringEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->id() == 0, "invariant");
   entry->set_id(++_symbol_id_counter);
+  entry->set_list_next(_cstring_list);
+  _cstring_list = entry;
 }
 
-bool JfrSymbolId::equals(const char* query, uintptr_t hash, const CStringEntry* entry) {
-  // query might be NULL
+bool JfrSymbolId::on_equals(uintptr_t hash, const CStringEntry* entry) {
   assert(entry != NULL, "invariant");
   assert(entry->hash() == hash, "invariant");
   return true;
 }
 
-traceid JfrSymbolId::mark(const Klass* k) {
-  assert(k != NULL, "invariant");
-  traceid symbol_id = 0;
-  if (is_unsafe_anonymous_klass(k)) {
-    symbol_id = mark_unsafe_anonymous_klass_name(k);
+void JfrSymbolId::on_unlink(const CStringEntry* entry) {
+  assert(entry != NULL, "invariant");
+  JfrCHeapObj::free(const_cast<char*>(entry->literal()), strlen(entry->literal() + 1));
+}
+
+traceid JfrSymbolId::bootstrap_name(bool leakp) {
+  assert(bootstrap != NULL, "invariant");
+  if (leakp) {
+    bootstrap->set_leakp();
   }
-  if (0 == symbol_id) {
-    const Symbol* const sym = k->name();
-    if (sym != NULL) {
-      symbol_id = mark(sym);
-    }
-  }
-  assert(symbol_id > 0, "a symbol handler must mark the symbol for writing");
-  return symbol_id;
+  return 1;
+}
+
+traceid JfrSymbolId::mark(const Symbol* symbol, bool leakp) {
+  assert(symbol != NULL, "invariant");
+  return mark((uintptr_t)symbol->identity_hash(), symbol, leakp);
 }
 
-traceid JfrSymbolId::mark(const Symbol* symbol) {
-  assert(symbol != NULL, "invariant");
-  return mark(symbol, (uintptr_t)const_cast<Symbol*>(symbol)->identity_hash());
-}
+static unsigned int last_symbol_hash = 0;
+static traceid last_symbol_id = 0;
 
-traceid JfrSymbolId::mark(const Symbol* data, uintptr_t hash) {
+traceid JfrSymbolId::mark(uintptr_t hash, const Symbol* data, bool leakp) {
   assert(data != NULL, "invariant");
   assert(_sym_table != NULL, "invariant");
-  return _sym_table->id(data, hash);
+  if (hash == last_symbol_hash) {
+    assert(last_symbol_id != 0, "invariant");
+    return last_symbol_id;
+  }
+  const SymbolEntry& entry = _sym_table->lookup_put(hash, data);
+  if (_class_unload) {
+    entry.set_unloading();
+  }
+  if (leakp) {
+    entry.set_leakp();
+  }
+  last_symbol_hash = hash;
+  last_symbol_id = entry.id();
+  return last_symbol_id;
 }
 
-traceid JfrSymbolId::mark(const char* str, uintptr_t hash) {
+static unsigned int last_cstring_hash = 0;
+static traceid last_cstring_id = 0;
+
+traceid JfrSymbolId::mark(uintptr_t hash, const char* str, bool leakp) {
   assert(str != NULL, "invariant");
-  return _cstring_table->id(str, hash);
-}
-
-bool JfrSymbolId::is_unsafe_anonymous_klass(const Klass* k) {
-  assert(k != NULL, "invariant");
-  return k->is_instance_klass() && ((const InstanceKlass*)k)->is_unsafe_anonymous();
+  assert(_cstring_table != NULL, "invariant");
+  if (hash == last_cstring_hash) {
+    assert(last_cstring_id != 0, "invariant");
+    return last_cstring_id;
+  }
+  const CStringEntry& entry = _cstring_table->lookup_put(hash, str);
+  if (_class_unload) {
+    entry.set_unloading();
+  }
+  if (leakp) {
+    entry.set_leakp();
+  }
+  last_cstring_hash = hash;
+  last_cstring_id = entry.id();
+  return last_cstring_id;
 }
 
 /*
@@ -161,7 +183,7 @@
 * caller needs ResourceMark
 */
 
-uintptr_t JfrSymbolId::unsafe_anonymous_klass_name_hash_code(const InstanceKlass* ik) {
+uintptr_t JfrSymbolId::unsafe_anonymous_klass_name_hash(const InstanceKlass* ik) {
   assert(ik != NULL, "invariant");
   assert(ik->is_unsafe_anonymous(), "invariant");
   const oop mirror = ik->java_mirror_no_keepalive();
@@ -169,19 +191,18 @@
   return (uintptr_t)mirror->identity_hash();
 }
 
-const char* JfrSymbolId::create_unsafe_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode) {
+static const char* create_unsafe_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t hash) {
   assert(ik != NULL, "invariant");
   assert(ik->is_unsafe_anonymous(), "invariant");
-  assert(0 == hashcode, "invariant");
+  assert(hash != 0, "invariant");
   char* anonymous_symbol = NULL;
   const oop mirror = ik->java_mirror_no_keepalive();
   assert(mirror != NULL, "invariant");
   char hash_buf[40];
-  hashcode = unsafe_anonymous_klass_name_hash_code(ik);
-  sprintf(hash_buf, "/" UINTX_FORMAT, hashcode);
+  sprintf(hash_buf, "/" UINTX_FORMAT, hash);
   const size_t hash_len = strlen(hash_buf);
   const size_t result_len = ik->name()->utf8_length();
-  anonymous_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1);
+  anonymous_symbol = JfrCHeapObj::new_array<char>(result_len + hash_len + 1);
   ik->name()->as_klass_external_name(anonymous_symbol, (int)result_len + 1);
   assert(strlen(anonymous_symbol) == result_len, "invariant");
   strcpy(anonymous_symbol + result_len, hash_buf);
@@ -189,70 +210,102 @@
   return anonymous_symbol;
 }
 
-uintptr_t JfrSymbolId::regular_klass_name_hash_code(const Klass* k) {
+bool JfrSymbolId::is_unsafe_anonymous_klass(const Klass* k) {
   assert(k != NULL, "invariant");
-  const Symbol* const sym = k->name();
-  assert(sym != NULL, "invariant");
-  return (uintptr_t)const_cast<Symbol*>(sym)->identity_hash();
+  return k->is_instance_klass() && ((const InstanceKlass*)k)->is_unsafe_anonymous();
+}
+
+static unsigned int last_anonymous_hash = 0;
+static traceid last_anonymous_id = 0;
+
+traceid JfrSymbolId::mark_unsafe_anonymous_klass_name(const InstanceKlass* ik, bool leakp) {
+  assert(ik != NULL, "invariant");
+  assert(ik->is_unsafe_anonymous(), "invariant");
+  const uintptr_t hash = unsafe_anonymous_klass_name_hash(ik);
+  if (hash == last_anonymous_hash) {
+    assert(last_anonymous_id != 0, "invariant");
+    return last_anonymous_id;
+  }
+  last_anonymous_hash = hash;
+  const CStringEntry* const entry = _cstring_table->lookup_only(hash);
+  last_anonymous_id = entry != NULL ? entry->id() : mark(hash, create_unsafe_anonymous_klass_symbol(ik, hash), leakp);
+  return last_anonymous_id;
+}
+
+traceid JfrSymbolId::mark(const Klass* k, bool leakp) {
+  assert(k != NULL, "invariant");
+  traceid symbol_id = 0;
+  if (is_unsafe_anonymous_klass(k)) {
+    assert(k->is_instance_klass(), "invariant");
+    symbol_id = mark_unsafe_anonymous_klass_name((const InstanceKlass*)k, leakp);
+  }
+  if (0 == symbol_id) {
+    Symbol* const sym = k->name();
+    if (sym != NULL) {
+      symbol_id = mark(sym, leakp);
+    }
+  }
+  assert(symbol_id > 0, "a symbol handler must mark the symbol for writing");
+  return symbol_id;
+}
+
+static void reset_symbol_caches() {
+  last_anonymous_hash = 0;
+  last_symbol_hash = 0;
+  last_cstring_hash = 0;
 }
 
 JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_id(new JfrSymbolId()),
-                                                    _klass_list(NULL),
-                                                    _class_unload(class_unload) {
+                                                     _klass_list(NULL),
+                                                     _total_count(0) {
   initialize(class_unload);
   assert(_klass_list != NULL, "invariant");
 }
 
 static const size_t initial_class_list_size = 200;
+
 void JfrArtifactSet::initialize(bool class_unload) {
   assert(_symbol_id != NULL, "invariant");
-  _symbol_id->initialize();
-  assert(!_symbol_id->has_entries(), "invariant");
-  _symbol_id->mark(BOOTSTRAP_LOADER_NAME, 0); // pre-load "bootstrap"
-  _class_unload = class_unload;
+  _symbol_id->set_class_unload(class_unload);
+  _total_count = 0;
   // resource allocation
   _klass_list = new GrowableArray<const Klass*>(initial_class_list_size, false, mtTracing);
 }
 
 JfrArtifactSet::~JfrArtifactSet() {
   clear();
+  delete _symbol_id;
 }
 
 void JfrArtifactSet::clear() {
+  reset_symbol_caches();
   _symbol_id->clear();
   // _klass_list will be cleared by a ResourceMark
 }
 
-traceid JfrArtifactSet::mark_unsafe_anonymous_klass_name(const Klass* klass) {
-  return _symbol_id->mark_unsafe_anonymous_klass_name(klass);
+traceid JfrArtifactSet::bootstrap_name(bool leakp) {
+  return _symbol_id->bootstrap_name(leakp);
 }
 
-traceid JfrArtifactSet::mark(const Symbol* sym, uintptr_t hash) {
-  return _symbol_id->mark(sym, hash);
-}
-
-traceid JfrArtifactSet::mark(const Klass* klass) {
-  return _symbol_id->mark(klass);
+traceid JfrArtifactSet::mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp) {
+  assert(klass->is_instance_klass(), "invariant");
+  return _symbol_id->mark_unsafe_anonymous_klass_name((const InstanceKlass*)klass, leakp);
 }
 
-traceid JfrArtifactSet::mark(const Symbol* symbol) {
-  return _symbol_id->mark(symbol);
-}
-
-traceid JfrArtifactSet::mark(const char* const str, uintptr_t hash) {
-  return _symbol_id->mark(str, hash);
+traceid JfrArtifactSet::mark(uintptr_t hash, const Symbol* sym, bool leakp) {
+  return _symbol_id->mark(hash, sym, leakp);
 }
 
-const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(const Symbol* symbol) const {
-  return _symbol_id->map_symbol(symbol);
+traceid JfrArtifactSet::mark(const Klass* klass, bool leakp) {
+  return _symbol_id->mark(klass, leakp);
 }
 
-const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(uintptr_t hash) const {
-  return _symbol_id->map_symbol(hash);
+traceid JfrArtifactSet::mark(const Symbol* symbol, bool leakp) {
+  return _symbol_id->mark(symbol, leakp);
 }
 
-const JfrSymbolId::CStringEntry* JfrArtifactSet::map_cstring(uintptr_t hash) const {
-  return _symbol_id->map_cstring(hash);
+traceid JfrArtifactSet::mark(uintptr_t hash, const char* const str, bool leakp) {
+  return _symbol_id->mark(hash, str, leakp);
 }
 
 bool JfrArtifactSet::has_klass_entries() const {
@@ -269,3 +322,7 @@
   assert(_klass_list->find(k) == -1, "invariant");
   _klass_list->append(k);
 }
+
+size_t JfrArtifactSet::total_count() const {
+  return _total_count;
+}
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -76,223 +76,203 @@
 };
 
 template <typename T>
-void tag_leakp_artifact(T const& value, bool class_unload) {
-  assert(value != NULL, "invariant");
-  if (class_unload) {
-    SET_LEAKP_USED_THIS_EPOCH(value);
-    assert(LEAKP_USED_THIS_EPOCH(value), "invariant");
-  } else {
-    SET_LEAKP_USED_PREV_EPOCH(value);
-    assert(LEAKP_USED_PREV_EPOCH(value), "invariant");
-  }
-}
-
-template <typename T>
-class LeakpClearArtifact {
-  bool _class_unload;
+class ClearArtifact {
  public:
-  LeakpClearArtifact(bool class_unload) : _class_unload(class_unload) {}
   bool operator()(T const& value) {
-    if (_class_unload) {
-      if (LEAKP_USED_THIS_EPOCH(value)) {
-        LEAKP_UNUSE_THIS_EPOCH(value);
-      }
-    } else {
-      if (LEAKP_USED_PREV_EPOCH(value)) {
-        LEAKP_UNUSE_PREV_EPOCH(value);
-      }
-    }
-    return true;
-  }
-};
-
-template <typename T>
-class ClearArtifact {
-  bool _class_unload;
- public:
-  ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
-  bool operator()(T const& value) {
-    if (_class_unload) {
-      if (LEAKP_USED_THIS_EPOCH(value)) {
-        LEAKP_UNUSE_THIS_EPOCH(value);
-      }
-      if (USED_THIS_EPOCH(value)) {
-        UNUSE_THIS_EPOCH(value);
-      }
-      if (METHOD_USED_THIS_EPOCH(value)) {
-        UNUSE_METHOD_THIS_EPOCH(value);
-      }
-    } else {
-      if (LEAKP_USED_PREV_EPOCH(value)) {
-        LEAKP_UNUSE_PREV_EPOCH(value);
-      }
-      if (USED_PREV_EPOCH(value)) {
-        UNUSE_PREV_EPOCH(value);
-      }
-      if (METHOD_USED_PREV_EPOCH(value)) {
-        UNUSE_METHOD_PREV_EPOCH(value);
-      }
-    }
+    CLEAR_METHOD_AND_CLASS_PREV_EPOCH(value);
+    CLEAR_SERIALIZED(value);
+    assert(IS_NOT_SERIALIZED(value), "invariant");
     return true;
   }
 };
 
 template <>
 class ClearArtifact<const Method*> {
+ public:
+  bool operator()(const Method* method) {
+    assert(METHOD_FLAG_USED_PREV_EPOCH(method), "invariant");
+    CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
+    CLEAR_METHOD_SERIALIZED(method);
+    assert(METHOD_NOT_SERIALIZED(method), "invariant");
+    return true;
+  }
+};
+
+template <typename T>
+class Stub {
+ public:
+  bool operator()(T const& value) { return true; }
+};
+
+template <typename T>
+class SerializePredicate {
+  bool _class_unload;
+ public:
+  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(T const& value) {
+    assert(value != NULL, "invariant");
+    return _class_unload ? true : IS_NOT_SERIALIZED(value);
+  }
+};
+
+template <>
+class SerializePredicate<const Method*> {
   bool _class_unload;
  public:
-  ClearArtifact(bool class_unload) : _class_unload(class_unload) {}
+  SerializePredicate(bool class_unload) : _class_unload(class_unload) {}
   bool operator()(const Method* method) {
+    assert(method != NULL, "invariant");
+    return _class_unload ? true : METHOD_NOT_SERIALIZED(method);
+  }
+};
+
+template <typename T, bool leakp>
+class SymbolPredicate {
+  bool _class_unload;
+ public:
+  SymbolPredicate(bool class_unload) : _class_unload(class_unload) {}
+  bool operator()(T const& value) {
+    assert(value != NULL, "invariant");
     if (_class_unload) {
-      if (METHOD_FLAG_USED_THIS_EPOCH(method)) {
-        CLEAR_METHOD_FLAG_USED_THIS_EPOCH(method);
-      }
-    } else {
-      if (METHOD_FLAG_USED_PREV_EPOCH(method)) {
-        CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method);
-      }
+      return leakp ? value->is_leakp() : value->is_unloading();
+    }
+    return leakp ? value->is_leakp() : !value->is_serialized();
+  }
+};
+
+template <bool leakp>
+class MethodUsedPredicate {
+  bool _current_epoch;
+public:
+  MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
+  bool operator()(const Klass* klass) {
+    if (_current_epoch) {
+      return leakp ? IS_LEAKP(klass) : METHOD_USED_THIS_EPOCH(klass);
     }
-    return true;
+    return  leakp ? IS_LEAKP(klass) : METHOD_USED_PREV_EPOCH(klass);
+  }
+};
+
+template <bool leakp>
+class MethodFlagPredicate {
+  bool _current_epoch;
+ public:
+  MethodFlagPredicate(bool current_epoch) : _current_epoch(current_epoch) {}
+  bool operator()(const Method* method) {
+    if (_current_epoch) {
+      return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_THIS_EPOCH(method);
+    }
+    return leakp ? IS_METHOD_LEAKP_USED(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
   }
 };
 
 template <typename T>
 class LeakPredicate {
-  bool _class_unload;
  public:
-  LeakPredicate(bool class_unload) : _class_unload(class_unload) {}
+  LeakPredicate(bool class_unload) {}
   bool operator()(T const& value) {
-    return _class_unload ? LEAKP_USED_THIS_EPOCH(value) : LEAKP_USED_PREV_EPOCH(value);
+    return IS_LEAKP(value);
   }
 };
 
-template <typename T>
-class UsedPredicate {
-  bool _class_unload;
+template <>
+class LeakPredicate<const Method*> {
  public:
-  UsedPredicate(bool class_unload) : _class_unload(class_unload) {}
-  bool operator()(T const& value) {
-    return _class_unload ? USED_THIS_EPOCH(value) : USED_PREV_EPOCH(value);
+  LeakPredicate(bool class_unload) {}
+  bool operator()(const Method* method) {
+    assert(method != NULL, "invariant");
+    return IS_METHOD_LEAKP_USED(method);
   }
 };
 
-template <typename T, int compare(const T&, const T&)>
-class UniquePredicate {
- private:
-  GrowableArray<T> _seen;
+template <typename T, typename IdType>
+class ListEntry : public JfrHashtableEntry<T, IdType> {
  public:
-  UniquePredicate(bool) : _seen() {}
-  bool operator()(T const& value) {
-    bool not_unique;
-    _seen.template find_sorted<T, compare>(value, not_unique);
-    if (not_unique) {
-      return false;
-    }
-    _seen.template insert_sorted<compare>(value);
-    return true;
+  ListEntry(uintptr_t hash, const T& data) : JfrHashtableEntry<T, IdType>(hash, data),
+    _list_next(NULL), _serialized(false), _unloading(false), _leakp(false) {}
+  const ListEntry<T, IdType>* list_next() const { return _list_next; }
+  void reset() const {
+    _list_next = NULL; _serialized = false; _unloading = false; _leakp = false;
   }
-};
-
-class MethodFlagPredicate {
-  bool _class_unload;
- public:
-  MethodFlagPredicate(bool class_unload) : _class_unload(class_unload) {}
-  bool operator()(const Method* method) {
-    return _class_unload ? METHOD_FLAG_USED_THIS_EPOCH(method) : METHOD_FLAG_USED_PREV_EPOCH(method);
-  }
-};
-
-template <bool leakp>
-class MethodUsedPredicate {
-  bool _class_unload;
- public:
-  MethodUsedPredicate(bool class_unload) : _class_unload(class_unload) {}
-  bool operator()(const Klass* klass) {
-    assert(ANY_USED(klass), "invariant");
-    if (_class_unload) {
-      return leakp ? LEAKP_METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_THIS_EPOCH(klass);
-    }
-    return leakp ? LEAKP_METHOD_USED_PREV_EPOCH(klass) : METHOD_USED_PREV_EPOCH(klass);
-  }
+  void set_list_next(const ListEntry<T, IdType>* next) const { _list_next = next; }
+  bool is_serialized() const { return _serialized; }
+  void set_serialized() const { _serialized = true; }
+  bool is_unloading() const { return _unloading; }
+  void set_unloading() const { _unloading = true; }
+  bool is_leakp() const { return _leakp; }
+  void set_leakp() const { _leakp = true; }
+ private:
+  mutable const ListEntry<T, IdType>* _list_next;
+  mutable bool _serialized;
+  mutable bool _unloading;
+  mutable bool _leakp;
 };
 
 class JfrSymbolId : public JfrCHeapObj {
   template <typename, typename, template<typename, typename> class, typename, size_t>
   friend class HashTableHost;
-  typedef HashTableHost<const Symbol*, traceid, Entry, JfrSymbolId> SymbolTable;
-  typedef HashTableHost<const char*, traceid, Entry, JfrSymbolId> CStringTable;
+  typedef HashTableHost<const Symbol*, traceid, ListEntry, JfrSymbolId> SymbolTable;
+  typedef HashTableHost<const char*, traceid, ListEntry, JfrSymbolId> CStringTable;
+  friend class JfrArtifactSet;
  public:
   typedef SymbolTable::HashEntry SymbolEntry;
   typedef CStringTable::HashEntry CStringEntry;
  private:
   SymbolTable* _sym_table;
   CStringTable* _cstring_table;
+  const SymbolEntry* _sym_list;
+  const CStringEntry* _cstring_list;
   traceid _symbol_id_counter;
+  bool _class_unload;
 
   // hashtable(s) callbacks
-  void assign_id(SymbolEntry* entry);
-  bool equals(const Symbol* query, uintptr_t hash, const SymbolEntry* entry);
-  void assign_id(CStringEntry* entry);
-  bool equals(const char* query, uintptr_t hash, const CStringEntry* entry);
+  void on_link(const SymbolEntry* entry);
+  bool on_equals(uintptr_t hash, const SymbolEntry* entry);
+  void on_unlink(const SymbolEntry* entry);
+  void on_link(const CStringEntry* entry);
+  bool on_equals(uintptr_t hash, const CStringEntry* entry);
+  void on_unlink(const CStringEntry* entry);
+
+  template <typename Functor, typename T>
+  void iterate(Functor& functor, const T* list) {
+    const T* symbol = list;
+    while (symbol != NULL) {
+      const T* next = symbol->list_next();
+      functor(symbol);
+      symbol = next;
+    }
+  }
+
+  traceid mark_unsafe_anonymous_klass_name(const InstanceKlass* k, bool leakp);
+  bool is_unsafe_anonymous_klass(const Klass* k);
+  uintptr_t unsafe_anonymous_klass_name_hash(const InstanceKlass* ik);
 
  public:
-  static bool is_unsafe_anonymous_klass(const Klass* k);
-  static const char* create_unsafe_anonymous_klass_symbol(const InstanceKlass* ik, uintptr_t& hashcode);
-  static uintptr_t unsafe_anonymous_klass_name_hash_code(const InstanceKlass* ik);
-  static uintptr_t regular_klass_name_hash_code(const Klass* k);
-
   JfrSymbolId();
   ~JfrSymbolId();
 
-  void initialize();
   void clear();
-
-  traceid mark_unsafe_anonymous_klass_name(const Klass* k);
-  traceid mark(const Symbol* sym, uintptr_t hash);
-  traceid mark(const Klass* k);
-  traceid mark(const Symbol* symbol);
-  traceid mark(const char* str, uintptr_t hash);
+  void set_class_unload(bool class_unload);
 
-  const SymbolEntry* map_symbol(const Symbol* symbol) const;
-  const SymbolEntry* map_symbol(uintptr_t hash) const;
-  const CStringEntry* map_cstring(uintptr_t hash) const;
+  traceid mark(uintptr_t hash, const Symbol* sym, bool leakp);
+  traceid mark(const Klass* k, bool leakp);
+  traceid mark(const Symbol* symbol, bool leakp);
+  traceid mark(uintptr_t hash, const char* str, bool leakp);
+  traceid bootstrap_name(bool leakp);
 
-  template <typename T>
-  void symbol(T& functor, const Klass* k) {
-    if (is_unsafe_anonymous_klass(k)) {
-      return;
-    }
-    functor(map_symbol(regular_klass_name_hash_code(k)));
+  template <typename Functor>
+  void iterate_symbols(Functor& functor) {
+    iterate(functor, _sym_list);
   }
 
-  template <typename T>
-  void symbol(T& functor, const Method* method) {
-    assert(method != NULL, "invariant");
-    functor(map_symbol((uintptr_t)method->name()->identity_hash()));
-    functor(map_symbol((uintptr_t)method->signature()->identity_hash()));
-  }
-
-  template <typename T>
-  void cstring(T& functor, const Klass* k) {
-    if (!is_unsafe_anonymous_klass(k)) {
-      return;
-    }
-    functor(map_cstring(unsafe_anonymous_klass_name_hash_code((const InstanceKlass*)k)));
-  }
-
-  template <typename T>
-  void iterate_symbols(T& functor) {
-    _sym_table->iterate_entry(functor);
-  }
-
-  template <typename T>
-  void iterate_cstrings(T& functor) {
-    _cstring_table->iterate_entry(functor);
+  template <typename Functor>
+  void iterate_cstrings(Functor& functor) {
+    iterate(functor, _cstring_list);
   }
 
   bool has_entries() const { return has_symbol_entries() || has_cstring_entries(); }
-  bool has_symbol_entries() const { return _sym_table->has_entries(); }
-  bool has_cstring_entries() const { return _cstring_table->has_entries(); }
+  bool has_symbol_entries() const { return _sym_list != NULL; }
+  bool has_cstring_entries() const { return _cstring_list != NULL; }
 };
 
 /**
@@ -313,7 +293,7 @@
  private:
   JfrSymbolId* _symbol_id;
   GrowableArray<const Klass*>* _klass_list;
-  bool _class_unload;
+  size_t _total_count;
 
  public:
   JfrArtifactSet(bool class_unload);
@@ -323,11 +303,13 @@
   void initialize(bool class_unload);
   void clear();
 
-  traceid mark(const Symbol* sym, uintptr_t hash);
-  traceid mark(const Klass* klass);
-  traceid mark(const Symbol* symbol);
-  traceid mark(const char* const str, uintptr_t hash);
-  traceid mark_unsafe_anonymous_klass_name(const Klass* klass);
+
+  traceid mark(uintptr_t hash, const Symbol* sym, bool leakp);
+  traceid mark(const Klass* klass, bool leakp);
+  traceid mark(const Symbol* symbol, bool leakp);
+  traceid mark(uintptr_t hash, const char* const str, bool leakp);
+  traceid mark_unsafe_anonymous_klass_name(const Klass* klass, bool leakp);
+  traceid bootstrap_name(bool leakp);
 
   const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;
   const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const;
@@ -335,6 +317,7 @@
 
   bool has_klass_entries() const;
   int entries() const;
+  size_t total_count() const;
   void register_klass(const Klass* k);
 
   template <typename Functor>
@@ -355,6 +338,12 @@
   void iterate_cstrings(T& functor) {
     _symbol_id->iterate_cstrings(functor);
   }
+
+  template <typename Writer>
+  void tally(Writer& writer) {
+    _total_count += writer.count();
+  }
+
 };
 
 class KlassArtifactRegistrator {
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETWRITER_HPP
-#define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETWRITER_HPP
-
-#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
-#include "jfr/utilities/jfrTypes.hpp"
-#include "memory/allocation.hpp"
-
-template <typename WriterImpl, u4 ID>
-class JfrArtifactWriterHost : public StackObj {
- private:
-  WriterImpl _impl;
-  JfrCheckpointWriter* _writer;
-  JfrCheckpointContext _ctx;
-  int64_t _count_offset;
-  int _count;
-  bool _skip_header;
- public:
-  JfrArtifactWriterHost(JfrCheckpointWriter* writer,
-                        JfrArtifactSet* artifacts,
-                        bool class_unload,
-                        bool skip_header = false) : _impl(writer, artifacts, class_unload),
-                                                    _writer(writer),
-                                                    _ctx(writer->context()),
-                                                    _count(0),
-                                                    _skip_header(skip_header) {
-    assert(_writer != NULL, "invariant");
-    if (!_skip_header) {
-      _writer->write_type((JfrTypeId)ID);
-      _count_offset = _writer->reserve(sizeof(u4)); // Don't know how many yet
-    }
-  }
-
-  ~JfrArtifactWriterHost() {
-    if (_count == 0) {
-      // nothing written, restore context for rewind
-      _writer->set_context(_ctx);
-      return;
-    }
-    assert(_count > 0, "invariant");
-    if (!_skip_header) {
-      _writer->write_count(_count, _count_offset);
-    }
-  }
-
-  bool operator()(typename WriterImpl::Type const & value) {
-    this->_count += _impl(value);
-    return true;
-  }
-
-  int count() const   { return _count; }
-  void add(int count) { _count += count; }
-};
-
-typedef int(*artifact_write_operation)(JfrCheckpointWriter*, JfrArtifactSet*, const void*);
-
-template <typename T, artifact_write_operation op>
-class JfrArtifactWriterImplHost {
- private:
-  JfrCheckpointWriter* _writer;
-  JfrArtifactSet* _artifacts;
-  bool _class_unload;
- public:
-  typedef T Type;
-  JfrArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool class_unload) :
-    _writer(writer), _artifacts(artifacts), _class_unload(class_unload) {}
-  int operator()(T const& value) {
-    return op(this->_writer, this->_artifacts, value);
-  }
-};
-
-template <typename T, typename Predicate, artifact_write_operation op>
-class JfrPredicatedArtifactWriterImplHost : public JfrArtifactWriterImplHost<T, op> {
- private:
-  Predicate _predicate;
-  typedef JfrArtifactWriterImplHost<T, op> Parent;
- public:
-  JfrPredicatedArtifactWriterImplHost(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, bool class_unload) :
-    Parent(writer, artifacts, class_unload), _predicate(class_unload) {}
-  int operator()(T const& value) {
-    return _predicate(value) ? Parent::operator()(value) : 0;
-  }
-};
-
-#endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_JFRTYPESETWRITER_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -159,7 +159,7 @@
   // This mechanism will retain the event specific flags
   // in the archive, allowing for event flag restoration
   // when renewing the traceid on klass revival.
-  k->set_trace_id(EVENT_FLAGS_MASK(k));
+  k->set_trace_id(EVENT_KLASS_MASK(k));
 }
 
 // used by CDS / APPCDS as part of "restore_unshareable_info"
@@ -181,12 +181,12 @@
   return get(java_lang_Class::as_Klass(my_oop));
 }
 
-traceid JfrTraceId::use(jclass jc, bool leakp /* false */) {
+traceid JfrTraceId::use(jclass jc) {
   assert(jc != NULL, "invariant");
   assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_vm, "invariant");
   const oop my_oop = JNIHandles::resolve(jc);
   assert(my_oop != NULL, "invariant");
-  return use(java_lang_Class::as_Klass(my_oop), leakp);
+  return use(java_lang_Class::as_Klass(my_oop));
 }
 
 bool JfrTraceId::in_visible_set(const jclass jc) {
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -90,12 +90,16 @@
   static traceid get(const Thread* thread);
 
   // tag construct as used, returns pre-tagged traceid
-  static traceid use(const Klass* klass, bool leakp = false);
-  static traceid use(jclass jc, bool leakp = false);
-  static traceid use(const Method* method, bool leakp = false);
-  static traceid use(const ModuleEntry* module, bool leakp = false);
-  static traceid use(const PackageEntry* package, bool leakp = false);
-  static traceid use(const ClassLoaderData* cld, bool leakp = false);
+  static traceid use(const Klass* klass);
+  static traceid use(jclass jc);
+  static traceid use(const Method* method);
+  static traceid use(const Klass* klass, const Method* method);
+  static traceid use(const ModuleEntry* module);
+  static traceid use(const PackageEntry* package);
+  static traceid use(const ClassLoaderData* cld);
+
+  // leak profiler
+  static void set_leakp(const Method* method);
 
   static void remove(const Klass* klass);
   static void restore(const Klass* klass);
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -28,8 +28,11 @@
 #include "classfile/classLoaderData.hpp"
 #include "classfile/moduleEntry.hpp"
 #include "classfile/packageEntry.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
+#include "jfr/support/jfrKlassExtension.hpp"
 #include "oops/arrayKlass.hpp"
 #include "oops/klass.hpp"
 #include "oops/instanceKlass.hpp"
@@ -38,21 +41,11 @@
 #include "utilities/debug.hpp"
 
 template <typename T>
-inline traceid set_used_and_get(const T* type, bool leakp) {
+inline traceid set_used_and_get(const T* type) {
   assert(type != NULL, "invariant");
-  if (leakp) {
-    SET_LEAKP_USED_THIS_EPOCH(type);
-    assert(LEAKP_USED_THIS_EPOCH(type), "invariant");
-  }
   SET_USED_THIS_EPOCH(type);
   assert(USED_THIS_EPOCH(type), "invariant");
-  return TRACE_ID_MASKED_PTR(type);
-}
-
-template <typename T>
-inline traceid set_used_and_get_shifted(const T* type, bool leakp) {
-  assert(type != NULL, "invariant");
-  return set_used_and_get(type, leakp) >> TRACE_ID_SHIFT;
+  return TRACE_ID(type);
 }
 
 inline traceid JfrTraceId::get(const Klass* klass) {
@@ -65,38 +58,49 @@
   return TRACE_ID_RAW(t->jfr_thread_local());
 }
 
-inline traceid JfrTraceId::use(const Klass* klass, bool leakp /* false */) {
+inline traceid JfrTraceId::use(const Klass* klass) {
   assert(klass != NULL, "invariant");
-  return set_used_and_get_shifted(klass, leakp);
+  return set_used_and_get(klass);
 }
 
-inline traceid JfrTraceId::use(const Method* method, bool leakp /* false */) {
+inline traceid JfrTraceId::use(const Method* method) {
+  assert(method != NULL, "invariant");
+  return use(method->method_holder(), method);
+}
+
+inline traceid JfrTraceId::use(const Klass* klass, const Method* method) {
+  assert(klass != NULL, "invariant");
   assert(method != NULL, "invariant");
   SET_METHOD_FLAG_USED_THIS_EPOCH(method);
-  const Klass* const klass = method->method_holder();
-  assert(klass != NULL, "invariant");
-  if (leakp) {
-    SET_LEAKP_USED_THIS_EPOCH(klass);
-    assert(LEAKP_USED_THIS_EPOCH(klass), "invariant");
-  }
+
   SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass);
   assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
   return (METHOD_ID(klass, method));
 }
 
-inline traceid JfrTraceId::use(const ModuleEntry* module, bool leakp /* false */) {
+inline traceid JfrTraceId::use(const ModuleEntry* module) {
   assert(module != NULL, "invariant");
-  return set_used_and_get_shifted(module, leakp);
+  return set_used_and_get(module);
+}
+
+inline traceid JfrTraceId::use(const PackageEntry* package) {
+  assert(package != NULL, "invariant");
+  return set_used_and_get(package);
 }
 
-inline traceid JfrTraceId::use(const PackageEntry* package, bool leakp /* false */) {
-  assert(package != NULL, "invariant");
-  return set_used_and_get_shifted(package, leakp);
+inline traceid JfrTraceId::use(const ClassLoaderData* cld) {
+  assert(cld != NULL, "invariant");
+  return cld->is_unsafe_anonymous() ? 0 : set_used_and_get(cld);
 }
 
-inline traceid JfrTraceId::use(const ClassLoaderData* cld, bool leakp /* false */) {
-  assert(cld != NULL, "invariant");
-  return cld->is_unsafe_anonymous() ? 0 : set_used_and_get_shifted(cld, leakp);
+inline void JfrTraceId::set_leakp(const Method* method) {
+  assert(method != NULL, "invariant");
+  const Klass* const klass = method->method_holder();
+  assert(klass != NULL, "invariant");
+  assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant");
+  assert(METHOD_FLAG_USED_THIS_EPOCH(method), "invariant");
+  SET_LEAKP(klass);
+  SET_METHOD_LEAKP(method);
 }
 
 inline bool JfrTraceId::in_visible_set(const Klass* klass) {
@@ -112,7 +116,7 @@
 
 inline void JfrTraceId::tag_as_jdk_jfr_event(const Klass* klass) {
   assert(klass != NULL, "invariant");
-  SET_TAG(klass, JDK_JFR_EVENT_KLASS);
+  SET_JDK_JFR_EVENT_KLASS(klass);
   assert(IS_JDK_JFR_EVENT_KLASS(klass), "invariant");
 }
 
@@ -124,7 +128,7 @@
 inline void JfrTraceId::tag_as_jdk_jfr_event_sub(const Klass* k) {
   assert(k != NULL, "invariant");
   if (IS_NOT_AN_EVENT_SUB_KLASS(k)) {
-    SET_TAG(k, JDK_JFR_EVENT_SUBKLASS);
+    SET_JDK_JFR_EVENT_SUBKLASS(k);
   }
   assert(IS_JDK_JFR_EVENT_SUBKLASS(k), "invariant");
 }
@@ -145,7 +149,7 @@
 
 inline void JfrTraceId::tag_as_event_host(const Klass* k) {
   assert(k != NULL, "invariant");
-  SET_TAG(k, EVENT_HOST_KLASS);
+  SET_EVENT_HOST_KLASS(k);
   assert(IS_EVENT_HOST_KLASS(k), "invariant");
 }
 
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -27,20 +27,22 @@
 
 #include "jfr/utilities/jfrTypes.hpp"
 #include "runtime/atomic.hpp"
+#include "runtime/orderAccess.hpp"
 #include "utilities/macros.hpp"
 
 #ifdef VM_LITTLE_ENDIAN
 static const int low_offset = 0;
-static const int leakp_offset = low_offset + 1;
+static const int meta_offset = low_offset + 1;
 #else
 static const int low_offset = 7;
-static const int leakp_offset = low_offset - 1;
+static const int meta_offset = low_offset - 1;
 #endif
 
 inline void set_bits(jbyte bits, jbyte* const dest) {
   assert(dest != NULL, "invariant");
   if (bits != (*dest & bits)) {
     *dest |= bits;
+    OrderAccess::storestore();
   }
 }
 
@@ -92,16 +94,28 @@
   set_mask(mask, ((jbyte*)dest) + low_offset);
 }
 
-inline void set_leakp_traceid_bits(jbyte bits, traceid* dest) {
-  set_bits(bits, ((jbyte*)dest) + leakp_offset);
+inline void set_meta_bits(jbyte bits, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  *dest |= bits;
+}
+
+inline void set_traceid_meta_bits(jbyte bits, traceid* dest) {
+  set_meta_bits(bits, ((jbyte*)dest) + meta_offset);
 }
 
-inline void set_leakp_traceid_bits_cas(jbyte bits, traceid* dest) {
-  set_bits_cas(bits, ((jbyte*)dest) + leakp_offset);
+inline void set_meta_mask(jbyte mask, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  *dest &= mask;
 }
 
-inline void set_leakp_traceid_mask(jbyte mask, traceid* dest) {
-  set_mask(mask, ((jbyte*)dest) + leakp_offset);
+inline void set_traceid_meta_mask(jbyte mask, traceid* dest) {
+  set_meta_mask(mask, ((jbyte*)dest) + meta_offset);
+}
+
+// only used by a single thread with no visibility requirements
+inline void clear_meta_bits(jbyte bits, jbyte* const dest) {
+  assert(dest != NULL, "invariant");
+  *dest ^= bits;
 }
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDBITS_INLINE_HPP
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -32,12 +32,8 @@
 #define METHOD_USED_BIT (USED_BIT << 2)
 #define EPOCH_1_SHIFT 0
 #define EPOCH_2_SHIFT 1
-#define LEAKP_SHIFT 8
-
 #define USED_EPOCH_1_BIT (USED_BIT << EPOCH_1_SHIFT)
 #define USED_EPOCH_2_BIT (USED_BIT << EPOCH_2_SHIFT)
-#define LEAKP_USED_EPOCH_1_BIT (USED_EPOCH_1_BIT << LEAKP_SHIFT)
-#define LEAKP_USED_EPOCH_2_BIT (USED_EPOCH_2_BIT << LEAKP_SHIFT)
 #define METHOD_USED_EPOCH_1_BIT (METHOD_USED_BIT << EPOCH_1_SHIFT)
 #define METHOD_USED_EPOCH_2_BIT (METHOD_USED_BIT << EPOCH_2_SHIFT)
 #define METHOD_AND_CLASS_IN_USE_BITS (METHOD_USED_BIT | USED_BIT)
@@ -75,14 +71,6 @@
     return _epoch_state ? USED_EPOCH_1_BIT : USED_EPOCH_2_BIT;
   }
 
-  static traceid leakp_in_use_this_epoch_bit() {
-    return _epoch_state ? LEAKP_USED_EPOCH_2_BIT : LEAKP_USED_EPOCH_1_BIT;
-  }
-
-  static traceid leakp_in_use_prev_epoch_bit() {
-    return _epoch_state ? LEAKP_USED_EPOCH_1_BIT : LEAKP_USED_EPOCH_2_BIT;
-  }
-
   static traceid method_in_use_this_epoch_bit() {
     return _epoch_state ? METHOD_USED_EPOCH_2_BIT : METHOD_USED_EPOCH_1_BIT;
   }
--- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,163 +25,117 @@
 #ifndef SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
 #define SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
 
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp"
-#include "jfr/support/jfrKlassExtension.hpp"
-#include "utilities/globalDefinitions.hpp"
-
 /**
  *
  * If a traceid is used, depending on epoch, either the first or the second bit is tagged.
  * If a class member (method) is used, either the third or fourth bit is tagged.
  * Which bit to set is a function of the epoch. This allows for concurrent tagging.
  *
- * LeakProfiler subsystem gets its own byte and uses the same tagging scheme but is shifted up 8.
- *
- * We also tag the individual method by using the TraceFlag field,
+ * We also tag individual methods by using the _trace_flags field,
  * (see jfr/support/jfrTraceIdExtension.hpp for details)
  *
  */
 
-// these are defined in jfr/support/jfrKlassExtension.hpp
+// the following are defined in jfr/support/jfrKlassExtension.hpp
 //
-// #define JDK_JFR_EVENT_SUBKLASS  16
-// #define JDK_JFR_EVENT_KLASS     32
-// #define EVENT_HOST_KLASS        64
-
-#define IS_JDK_JFR_EVENT_SUBKLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_SUBKLASS)) != 0)
+// #define JDK_JFR_EVENT_SUBKLASS                 16
+// #define JDK_JFR_EVENT_KLASS                    32
+// #define EVENT_HOST_KLASS                       64
 
-#define ANY_USED_BITS (USED_EPOCH_2_BIT         | \
-                       USED_EPOCH_1_BIT         | \
-                       METHOD_USED_EPOCH_2_BIT  | \
-                       METHOD_USED_EPOCH_1_BIT  | \
-                       LEAKP_USED_EPOCH_2_BIT   | \
-                       LEAKP_USED_EPOCH_1_BIT)
-
-#define TRACE_ID_META_BITS (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS | ANY_USED_BITS)
-
-#define ANY_EVENT                       (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)
-#define IS_JDK_JFR_EVENT_KLASS(ptr)     (((ptr)->trace_id() & JDK_JFR_EVENT_KLASS) != 0)
-#define IS_EVENT_HOST_KLASS(ptr)        (((ptr)->trace_id() & EVENT_HOST_KLASS) != 0)
-#define IS_NOT_AN_EVENT_KLASS(ptr)      (!IS_EVENT_KLASS(ptr))
-#define IS_NOT_AN_EVENT_SUB_KLASS(ptr)  (!IS_JDK_JFR_EVENT_SUBKLASS(ptr))
-#define IS_NOT_JDK_JFR_EVENT_KLASS(ptr) (!IS_JDK_JFR_EVENT_KLASS(ptr))
-#define EVENT_FLAGS_MASK(ptr)           (((ptr)->trace_id() & ANY_EVENT) != 0)
-#define UNEVENT(ptr)                    ((ptr)->set_trace_id(((ptr)->trace_id()) & ~ANY_EVENT))
-
-#define TRACE_ID_SHIFT 16
+// static bits
+#define META_SHIFT                                8
+#define LEAKP_META_BIT                            USED_BIT
+#define LEAKP_BIT                                 (LEAKP_META_BIT << META_SHIFT)
+#define TRANSIENT_META_BIT                        (USED_BIT << 1)
+#define TRANSIENT_BIT                             (TRANSIENT_META_BIT << META_SHIFT)
+#define SERIALIZED_META_BIT                       (USED_BIT << 2)
+#define SERIALIZED_BIT                            (SERIALIZED_META_BIT << META_SHIFT)
+#define TRACE_ID_SHIFT                            16
+#define METHOD_ID_NUM_MASK                        ((1 << TRACE_ID_SHIFT) - 1)
+#define META_BITS                                 (SERIALIZED_BIT | TRANSIENT_BIT | LEAKP_BIT)
+#define EVENT_BITS                                (EVENT_HOST_KLASS | JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)
+#define USED_BITS                                 (METHOD_USED_EPOCH_2_BIT | METHOD_USED_EPOCH_1_BIT | USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)
+#define ALL_BITS                                  (META_BITS | EVENT_BITS | USED_BITS)
+#define ALL_BITS_MASK                             (~(ALL_BITS))
 
-#define TRACE_ID_MASKED(id)             (id & ~TRACE_ID_META_BITS)
-#define TRACE_ID_VALUE(id)              (TRACE_ID_MASKED(id) >> TRACE_ID_SHIFT)
-#define TRACE_ID_MASKED_PTR(ptr)        (TRACE_ID_MASKED((ptr)->trace_id()))
-#define TRACE_ID_RAW(ptr)               ((ptr)->trace_id())
-#define TRACE_ID(ptr)                   (TRACE_ID_MASKED_PTR(ptr) >> TRACE_ID_SHIFT)
-#define METHOD_ID(kls, meth)            (TRACE_ID_MASKED_PTR(kls) | (meth)->method_idnum())
-#define SET_TAG(ptr, tag)               (set_traceid_bits(tag, (ptr)->trace_id_addr()))
-#define SET_LEAKP_TAG(ptr, tag)         (set_leakp_traceid_bits(tag, (ptr)->trace_id_addr()))
-#define SET_TAG_CAS(ptr, tag)           (set_traceid_bits_cas(tag, (ptr)->trace_id_addr()))
-#define SET_LEAKP_TAG_CAS(ptr, tag)     (set_leakp_traceid_bits_cas(tag, (ptr)->trace_id_addr()))
-
-#define IN_USE_THIS_EPOCH_BIT           (JfrTraceIdEpoch::in_use_this_epoch_bit())
-#define IN_USE_PREV_EPOCH_BIT           (JfrTraceIdEpoch::in_use_prev_epoch_bit())
-#define LEAKP_IN_USE_THIS_EPOCH_BIT     (JfrTraceIdEpoch::leakp_in_use_this_epoch_bit())
-#define LEAKP_IN_USE_PREV_EPOCH_BIT     (JfrTraceIdEpoch::leakp_in_use_prev_epoch_bit())
+// epoch relative bits
+#define IN_USE_THIS_EPOCH_BIT                     (JfrTraceIdEpoch::in_use_this_epoch_bit())
+#define IN_USE_PREV_EPOCH_BIT                     (JfrTraceIdEpoch::in_use_prev_epoch_bit())
+#define METHOD_IN_USE_THIS_EPOCH_BIT              (JfrTraceIdEpoch::method_in_use_this_epoch_bit())
+#define METHOD_IN_USE_PREV_EPOCH_BIT              (JfrTraceIdEpoch::method_in_use_prev_epoch_bit())
+#define METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS   (JfrTraceIdEpoch::method_and_class_in_use_this_epoch_bits())
+#define METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS   (JfrTraceIdEpoch::method_and_class_in_use_prev_epoch_bits())
+#define METHOD_FLAG_IN_USE_THIS_EPOCH_BIT         ((jbyte)IN_USE_THIS_EPOCH_BIT)
+#define METHOD_FLAG_IN_USE_PREV_EPOCH_BIT         ((jbyte)IN_USE_PREV_EPOCH_BIT)
 
-#define METHOD_IN_USE_THIS_EPOCH_BIT    (JfrTraceIdEpoch::method_in_use_this_epoch_bit())
-#define METHOD_IN_USE_PREV_EPOCH_BIT    (JfrTraceIdEpoch::method_in_use_prev_epoch_bit())
-#define METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_this_epoch_bits())
-#define METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS (JfrTraceIdEpoch::method_and_class_in_use_prev_epoch_bits())
-
-#define UNUSE_THIS_EPOCH_MASK           (~(IN_USE_THIS_EPOCH_BIT))
-#define UNUSE_PREV_EPOCH_MASK           (~(IN_USE_PREV_EPOCH_BIT))
-#define LEAKP_UNUSE_THIS_EPOCH_MASK     UNUSE_THIS_EPOCH_MASK
-#define LEAKP_UNUSE_PREV_EPOCH_MASK     UNUSE_PREV_EPOCH_MASK
-
-#define UNUSE_METHOD_THIS_EPOCH_MASK    (~(METHOD_IN_USE_THIS_EPOCH_BIT))
-#define UNUSE_METHOD_PREV_EPOCH_MASK    (~(METHOD_IN_USE_PREV_EPOCH_BIT))
-#define LEAKP_UNUSE_METHOD_THIS_EPOCH_MASK (~(UNUSE_METHOD_THIS_EPOCH_MASK))
-#define LEAKP_UNUSE_METHOD_PREV_EPOCH_MASK (~UNUSE_METHOD_PREV_EPOCH_MASK))
-
-#define UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK (~(METHOD_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT))
-#define UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK (~(METHOD_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT))
-
-#define SET_USED_THIS_EPOCH(ptr)        (SET_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
-#define SET_USED_PREV_EPOCH(ptr)        (SET_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT))
-#define SET_LEAKP_USED_THIS_EPOCH(ptr)  (SET_LEAKP_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
-#define SET_LEAKP_USED_PREV_EPOCH(ptr)  (SET_LEAKP_TAG_CAS(ptr, IN_USE_PREV_EPOCH_BIT))
-#define SET_METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (SET_TAG(kls, METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS))
+// operators
+#define TRACE_ID_RAW(ptr)                         ((ptr)->trace_id())
+#define TRACE_ID(ptr)                             (TRACE_ID_RAW(ptr) >> TRACE_ID_SHIFT)
+#define TRACE_ID_MASKED(ptr)                      (TRACE_ID_RAW(ptr) & ALL_BITS_MASK)
+#define TRACE_ID_PREDICATE(ptr, bits)             ((TRACE_ID_RAW(ptr) & bits) != 0)
+#define TRACE_ID_TAG(ptr, bits)                   (set_traceid_bits(bits, (ptr)->trace_id_addr()))
+#define TRACE_ID_TAG_CAS(ptr, bits)               (set_traceid_bits_cas(bits, (ptr)->trace_id_addr()))
+#define TRACE_ID_CLEAR(ptr, bits)                 (set_traceid_mask(bits, (ptr)->trace_id_addr()))
+#define TRACE_ID_META_TAG(ptr, bits)              (set_traceid_meta_bits(bits, (ptr)->trace_id_addr()))
+#define TRACE_ID_META_CLEAR(ptr, bits)            (set_traceid_meta_mask(bits, (ptr)->trace_id_addr()))
+#define METHOD_ID(kls, method)                    (TRACE_ID_MASKED(kls) | (method)->orig_method_idnum())
+#define METHOD_FLAG_PREDICATE(method, bits)       ((method)->is_trace_flag_set(bits))
+#define METHOD_FLAG_TAG(method, bits)             (set_bits(bits, (method)->trace_flags_addr()))
+#define METHOD_META_TAG(method, bits)             (set_meta_bits(bits, (method)->trace_meta_addr()))
+#define METHOD_FLAG_CLEAR(method, bits)           (clear_bits_cas(bits, (method)->trace_flags_addr()))
+#define METHOD_META_CLEAR(method, bits)           (set_meta_mask(bits, (method)->trace_meta_addr()))
 
-#define USED_THIS_EPOCH(ptr)            (((ptr)->trace_id() & IN_USE_THIS_EPOCH_BIT) != 0)
-#define NOT_USED_THIS_EPOCH(ptr)        (!USED_THIS_EPOCH(ptr))
-#define USED_PREV_EPOCH(ptr)            (((ptr)->trace_id() & IN_USE_PREV_EPOCH_BIT) != 0)
-#define NOT_USED_PREV_EPOCH(ptr)        (!USED_PREV_EPOCH(ptr))
-#define USED_ANY_EPOCH(ptr)             (((ptr)->trace_id() & (USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)) != 0)
-#define NOT_USED_ANY_EPOCH(ptr)         (!USED_ANY_EPOCH(ptr))
-
-#define LEAKP_USED_THIS_EPOCH(ptr)      (((ptr)->trace_id() & LEAKP_IN_USE_THIS_EPOCH_BIT) != 0)
-#define LEAKP_NOT_USED_THIS_EPOCH(ptr)  (!LEAKP_USED_THIS_EPOCH(ptr))
-#define LEAKP_USED_PREV_EPOCH(ptr)      (((ptr)->trace_id() & LEAKP_IN_USE_PREV_EPOCH_BIT) != 0)
-#define LEAKP_NOT_USED_PREV_EPOCH(ptr)  (!LEAKP_USED_PREV_EPOCH(ptr))
-#define LEAKP_USED_ANY_EPOCH(ptr)       (((ptr)->trace_id() & (LEAKP_USED_EPOCH_2_BIT | LEAKP_USED_EPOCH_1_BIT)) != 0)
-#define LEAKP_NOT_USED_ANY_EPOCH(ptr)   (!LEAKP_USED_ANY_EPOCH(ptr))
+// predicates
+#define USED_THIS_EPOCH(ptr)                      (TRACE_ID_PREDICATE(ptr, (TRANSIENT_BIT | IN_USE_THIS_EPOCH_BIT)))
+#define NOT_USED_THIS_EPOCH(ptr)                  (!(USED_THIS_EPOCH(ptr)))
+#define USED_PREV_EPOCH(ptr)                      (TRACE_ID_PREDICATE(ptr, (TRANSIENT_BIT | IN_USE_PREV_EPOCH_BIT)))
+#define USED_ANY_EPOCH(ptr)                       (TRACE_ID_PREDICATE(ptr, (TRANSIENT_BIT | USED_EPOCH_2_BIT | USED_EPOCH_1_BIT)))
+#define METHOD_USED_THIS_EPOCH(kls)               (TRACE_ID_PREDICATE(kls, (METHOD_IN_USE_THIS_EPOCH_BIT)))
+#define METHOD_NOT_USED_THIS_EPOCH(kls)           (!(METHOD_USED_THIS_EPOCH(kls)))
+#define METHOD_USED_PREV_EPOCH(kls)               (TRACE_ID_PREDICATE(kls, (METHOD_IN_USE_PREV_EPOCH_BIT)))
+#define METHOD_USED_ANY_EPOCH(kls)                (TRACE_ID_PREDICATE(kls, (METHOD_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)))
+#define METHOD_AND_CLASS_USED_THIS_EPOCH(kls)     (TRACE_ID_PREDICATE(kls, (METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS)))
+#define METHOD_AND_CLASS_USED_PREV_EPOCH(kls)     (TRACE_ID_PREDICATE(kls, (METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS)))
+#define METHOD_AND_CLASS_USED_ANY_EPOCH(kls)      (METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls))
+#define METHOD_FLAG_USED_THIS_EPOCH(method)       (METHOD_FLAG_PREDICATE(method, (METHOD_FLAG_IN_USE_THIS_EPOCH_BIT)))
+#define METHOD_FLAG_NOT_USED_THIS_EPOCH(method)   (!(METHOD_FLAG_USED_THIS_EPOCH(method)))
+#define METHOD_FLAG_USED_PREV_EPOCH(method)       (METHOD_FLAG_PREDICATE(method, (METHOD_FLAG_IN_USE_PREV_EPOCH_BIT)))
 
-#define ANY_USED_THIS_EPOCH(ptr)        (((ptr)->trace_id() & (LEAKP_IN_USE_THIS_EPOCH_BIT | IN_USE_THIS_EPOCH_BIT)) != 0)
-#define ANY_NOT_USED_THIS_EPOCH(ptr)    (!ANY_USED_THIS_EPOCH(ptr))
-#define ANY_USED_PREV_EPOCH(ptr)        (((ptr)->trace_id() & (LEAKP_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT)) != 0)
-#define ANY_NOT_USED_PREV_EPOCH(ptr)    (!ANY_USED_PREV_EPOCH(ptr))
-
-#define METHOD_USED_THIS_EPOCH(kls)     (((kls)->trace_id() & METHOD_IN_USE_THIS_EPOCH_BIT) != 0)
-#define METHOD_NOT_USED_THIS_EPOCH(kls) (!METHOD_USED_THIS_EPOCH(kls))
-#define METHOD_USED_PREV_EPOCH(kls)     (((kls)->trace_id() & METHOD_IN_USE_PREV_EPOCH_BIT) != 0)
-#define METHOD_NOT_USED_PREV_EPOCH(kls) (!METHOD_USED_PREV_EPOCH(kls))
-#define METHOD_USED_ANY_EPOCH(kls)      (((kls)->trace_id() & (METHOD_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)) != 0)
-
-#define METHOD_NOT_USED_ANY_EPOCH(kls)  (!METHOD_USED_ANY_EPOCH(kls))
-
-#define METHOD_AND_CLASS_USED_THIS_EPOCH(kls) ((((kls)->trace_id() & METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS) == \
-                                                                     METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS) != 0)
-
-#define METHOD_AND_CLASS_USED_PREV_EPOCH(kls) ((((kls)->trace_id() & METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS) == \
-                                                                     METHOD_AND_CLASS_IN_USE_PREV_EPOCH_BITS) != 0)
-
-#define METHOD_AND_CLASS_USED_ANY_EPOCH(kls)     ((METHOD_USED_ANY_EPOCH(kls) && USED_ANY_EPOCH(kls)) != 0)
-#define METHOD_AND_CLASS_NOT_USED_ANY_EPOCH(kls) (!METHOD_AND_CLASS_USED_ANY_EPOCH(kls))
+// setters
+#define SET_USED_THIS_EPOCH(ptr)                  (TRACE_ID_TAG(ptr, IN_USE_THIS_EPOCH_BIT))
+#define SET_METHOD_AND_CLASS_USED_THIS_EPOCH(kls) (TRACE_ID_TAG(kls, METHOD_AND_CLASS_IN_USE_THIS_EPOCH_BITS))
+#define SET_METHOD_FLAG_USED_THIS_EPOCH(method)   (METHOD_FLAG_TAG(method, METHOD_FLAG_IN_USE_THIS_EPOCH_BIT))
+#define CLEAR_METHOD_AND_CLASS_PREV_EPOCH_MASK    (~(METHOD_IN_USE_PREV_EPOCH_BIT | IN_USE_PREV_EPOCH_BIT))
+#define CLEAR_METHOD_AND_CLASS_PREV_EPOCH(kls)    (TRACE_ID_CLEAR(kls, CLEAR_METHOD_AND_CLASS_PREV_EPOCH_MASK))
+#define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(method) (METHOD_FLAG_CLEAR(method, METHOD_FLAG_IN_USE_PREV_EPOCH_BIT))
 
-#define LEAKP_METHOD_IN_USE_THIS_EPOCH  (LEAKP_IN_USE_THIS_EPOCH_BIT | METHOD_IN_USE_THIS_EPOCH_BIT)
-#define LEAKP_METHOD_IN_USE_PREV_EPOCH  (LEAKP_IN_USE_PREV_EPOCH_BIT | METHOD_IN_USE_PREV_EPOCH_BIT)
-#define LEAKP_METHOD_USED_THIS_EPOCH(ptr)  ((((ptr)->trace_id() & LEAKP_METHOD_IN_USE_THIS_EPOCH) == \
-                                                                  LEAKP_METHOD_IN_USE_THIS_EPOCH) != 0)
-#define LEAKP_METHOD_NOT_USED_THIS_EPOCH(kls) (!LEAKP_METHOD_USED_THIS_EPOCH(kls))
-#define LEAKP_METHOD_USED_PREV_EPOCH(ptr)  ((((ptr)->trace_id() & LEAKP_METHOD_IN_USE_PREV_EPOCH) == \
-                                                                  LEAKP_METHOD_IN_USE_PREV_EPOCH) != 0)
-#define LEAKP_METHOD_NOT_USED_PREV_EPOCH(kls) (!LEAKP_METHOD_USED_PREV_EPOCH(kls))
-
-#define UNUSE_THIS_EPOCH(ptr)           (set_traceid_mask(UNUSE_THIS_EPOCH_MASK, (ptr)->trace_id_addr()))
-#define UNUSE_PREV_EPOCH(ptr)           (set_traceid_mask(UNUSE_PREV_EPOCH_MASK, (ptr)->trace_id_addr()))
-#define UNUSE_METHOD_THIS_EPOCH(kls)    (set_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
-#define UNUSE_METHOD_PREV_EPOCH(kls)    (set_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
+// types
+#define IS_JDK_JFR_EVENT_KLASS(kls)               (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_KLASS))
+#define IS_JDK_JFR_EVENT_SUBKLASS(kls)            (TRACE_ID_PREDICATE(kls, JDK_JFR_EVENT_SUBKLASS))
+#define IS_NOT_AN_EVENT_SUB_KLASS(kls)            (!(IS_JDK_JFR_EVENT_SUBKLASS(kls)))
+#define IS_EVENT_HOST_KLASS(kls)                  (TRACE_ID_PREDICATE(kls, EVENT_HOST_KLASS))
+#define SET_JDK_JFR_EVENT_KLASS(kls)              (TRACE_ID_TAG(kls, JDK_JFR_EVENT_KLASS))
+#define SET_JDK_JFR_EVENT_SUBKLASS(kls)           (TRACE_ID_TAG(kls, JDK_JFR_EVENT_SUBKLASS))
+#define SET_EVENT_HOST_KLASS(kls)                 (TRACE_ID_TAG(kls, EVENT_HOST_KLASS))
+#define EVENT_KLASS_MASK(kls)                     (TRACE_ID_RAW(kls) & EVENT_BITS)
 
-#define LEAKP_UNUSE_THIS_EPOCH(ptr)     (set_leakp_traceid_mask(UNUSE_THIS_EPOCH_MASK, (ptr)->trace_id_addr()))
-#define LEAKP_UNUSE_PREV_EPOCH(ptr)     (set_leakp_traceid_mask(UNUSE_PREV_EPOCH_MASK, (ptr)->trace_id_addr()))
-#define LEAKP_UNUSE_METHOD_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
-#define LEAKP_UNUSE_METHOD_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
-
-#define ANY_USED(ptr)                   (((ptr)->trace_id() & ANY_USED_BITS) != 0)
-#define ANY_NOT_USED(ptr)               (!ANY_USED(ptr))
-
-#define UNUSE_METHOD_AND_CLASS_THIS_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
-#define LEAKP_UNUSE_METHOD_AND_CLASS_THIS_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_THIS_EPOCH_MASK, (kls)->trace_id_addr()))
-#define UNUSE_METHOD_AND_CLASS_PREV_EPOCH(kls) (set_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
-#define LEAKP_UNUSE_METHODS_AND_CLASS_PREV_EPOCH(kls) (set_leakp_traceid_mask(UNUSE_METHOD_AND_CLASS_PREV_EPOCH_MASK, (kls)->trace_id_addr()))
-
-#define METHOD_FLAG_USED_THIS_EPOCH(m)       ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
-#define METHOD_FLAG_NOT_USED_THIS_EPOCH(m)   (!METHOD_FLAG_USED_THIS_EPOCH(m))
-#define SET_METHOD_FLAG_USED_THIS_EPOCH(m)   ((m)->set_trace_flag((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit()))
-#define METHOD_FLAG_USED_PREV_EPOCH(m)       ((m)->is_trace_flag_set((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit()))
-#define METHOD_FLAG_NOT_USED_PREV_EPOCH(m)   (!METHOD_FLAG_USED_PREV_EPOCH(m))
-#define METHOD_FLAG_USED_ANY_EPOCH(m)        ((METHOD_FLAG_USED_THIS_EPOCH(m) || METHOD_FLAG_USED_PREV_EPOCH(m)) != 0)
-#define METHOD_FLAG_NOT_USED_ANY_EPOCH(m)    ((METHOD_FLAG_NOT_USED_THIS_EPOCH(m) && METHOD_FLAG_NOT_USED_PREV_EPOCH(m)) != 0)
-#define CLEAR_METHOD_FLAG_USED_THIS_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_this_epoch_bit(), (m)->trace_flags_addr()))
-#define CLEAR_METHOD_FLAG_USED_PREV_EPOCH(m) (clear_bits_cas((jbyte)JfrTraceIdEpoch::in_use_prev_epoch_bit(), (m)->trace_flags_addr()))
+// meta
+#define META_MASK                                 (~(SERIALIZED_META_BIT | TRANSIENT_META_BIT | LEAKP_META_BIT))
+#define SET_LEAKP(ptr)                            (TRACE_ID_META_TAG(ptr, LEAKP_META_BIT))
+#define IS_LEAKP(ptr)                             (TRACE_ID_PREDICATE(ptr, LEAKP_BIT))
+#define SET_TRANSIENT(ptr)                        (TRACE_ID_META_TAG(ptr, TRANSIENT_META_BIT))
+#define IS_SERIALIZED(ptr)                        (TRACE_ID_PREDICATE(ptr, SERIALIZED_BIT))
+#define IS_NOT_SERIALIZED(ptr)                    (!(IS_SERIALIZED(ptr)))
+#define SHOULD_TAG(ptr)                           (NOT_USED_THIS_EPOCH(ptr))
+#define SHOULD_TAG_KLASS_METHOD(ptr)              (METHOD_NOT_USED_THIS_EPOCH(ptr))
+#define SET_SERIALIZED(ptr)                       (TRACE_ID_META_TAG(ptr, SERIALIZED_META_BIT))
+#define CLEAR_SERIALIZED(ptr)                     (TRACE_ID_META_CLEAR(ptr, META_MASK))
+#define IS_METHOD_SERIALIZED(method)              (METHOD_FLAG_PREDICATE(method, SERIALIZED_BIT))
+#define IS_METHOD_LEAKP_USED(method)              (METHOD_FLAG_PREDICATE(method, LEAKP_BIT))
+#define METHOD_NOT_SERIALIZED(method)             (!(IS_METHOD_SERIALIZED(method)))
+#define SET_METHOD_LEAKP(method)                  (METHOD_META_TAG(method, LEAKP_META_BIT))
+#define SET_METHOD_SERIALIZED(method)             (METHOD_META_TAG(method, SERIALIZED_META_BIT))
+#define CLEAR_METHOD_SERIALIZED(method)           (METHOD_META_CLEAR(method, META_MASK))
+#define CLEAR_LEAKP(ptr)                          (TRACE_ID_META_CLEAR(ptr, (~(LEAKP_META_BIT))))
 
 #endif // SHARE_JFR_RECORDER_CHECKPOINT_TYPES_TRACEID_JFRTRACEIDMACROS_HPP
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkState.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -39,7 +39,7 @@
   _start_nanos(0),
   _previous_start_ticks(0),
   _previous_start_nanos(0),
-  _previous_checkpoint_offset(0) {}
+  _last_checkpoint_offset(0) {}
 
 JfrChunkState::~JfrChunkState() {
   reset();
@@ -50,15 +50,15 @@
     JfrCHeapObj::free(_path, strlen(_path) + 1);
     _path = NULL;
   }
-  set_previous_checkpoint_offset(0);
+  set_last_checkpoint_offset(0);
 }
 
-void JfrChunkState::set_previous_checkpoint_offset(int64_t offset) {
-  _previous_checkpoint_offset = offset;
+void JfrChunkState::set_last_checkpoint_offset(int64_t offset) {
+  _last_checkpoint_offset = offset;
 }
 
-int64_t JfrChunkState::previous_checkpoint_offset() const {
-  return _previous_checkpoint_offset;
+int64_t JfrChunkState::last_checkpoint_offset() const {
+  return _last_checkpoint_offset;
 }
 
 int64_t JfrChunkState::previous_start_ticks() const {
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkState.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -36,7 +36,7 @@
   int64_t _start_nanos;
   int64_t _previous_start_ticks;
   int64_t _previous_start_nanos;
-  int64_t _previous_checkpoint_offset;
+  int64_t _last_checkpoint_offset;
 
   void update_start_ticks();
   void update_start_nanos();
@@ -46,8 +46,8 @@
   JfrChunkState();
   ~JfrChunkState();
   void reset();
-  int64_t previous_checkpoint_offset() const;
-  void set_previous_checkpoint_offset(int64_t offset);
+  int64_t last_checkpoint_offset() const;
+  void set_last_checkpoint_offset(int64_t offset);
   int64_t previous_start_ticks() const;
   int64_t previous_start_nanos() const;
   int64_t last_chunk_duration() const;
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -86,7 +86,7 @@
   // Chunk size
   this->write_be_at_offset(size_written(), CHUNK_SIZE_OFFSET);
   // initial checkpoint event offset
-  this->write_be_at_offset(_chunkstate->previous_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE));
+  this->write_be_at_offset(_chunkstate->last_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE));
   // metadata event offset
   this->write_be_at_offset(metadata_offset, CHUNK_SIZE_OFFSET + (2 * FILEHEADER_SLOT_SIZE));
   // start of chunk in nanos since epoch
@@ -105,12 +105,12 @@
   return this->is_valid() ? this->current_offset() : 0;
 }
 
-int64_t JfrChunkWriter::previous_checkpoint_offset() const {
-  return _chunkstate->previous_checkpoint_offset();
+int64_t JfrChunkWriter::last_checkpoint_offset() const {
+  return _chunkstate->last_checkpoint_offset();
 }
 
-void JfrChunkWriter::set_previous_checkpoint_offset(int64_t offset) {
-  _chunkstate->set_previous_checkpoint_offset(offset);
+void JfrChunkWriter::set_last_checkpoint_offset(int64_t offset) {
+  _chunkstate->set_last_checkpoint_offset(offset);
 }
 
 void JfrChunkWriter::time_stamp_chunk_now() {
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -49,8 +49,8 @@
   JfrChunkWriter();
   bool initialize();
   int64_t size_written() const;
-  int64_t previous_checkpoint_offset() const;
-  void set_previous_checkpoint_offset(int64_t offset);
+  int64_t last_checkpoint_offset() const;
+  void set_last_checkpoint_offset(int64_t offset);
   void time_stamp_chunk_now();
 };
 
--- a/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/service/jfrRecorderService.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -133,13 +133,13 @@
 };
 
 static int64_t write_checkpoint_event_prologue(JfrChunkWriter& cw, u8 type_id) {
-  const int64_t prev_cp_offset = cw.previous_checkpoint_offset();
-  const int64_t prev_cp_relative_offset = 0 == prev_cp_offset ? 0 : prev_cp_offset - cw.current_offset();
+  const int64_t last_cp_offset = cw.last_checkpoint_offset();
+  const int64_t delta_to_last_checkpoint = 0 == last_cp_offset ? 0 : last_cp_offset - cw.current_offset();
   cw.reserve(sizeof(u4));
   cw.write<u8>(EVENT_CHECKPOINT);
   cw.write(JfrTicks::now());
-  cw.write((int64_t)0);
-  cw.write(prev_cp_relative_offset); // write previous checkpoint offset delta
+  cw.write((int64_t)0); // duration
+  cw.write(delta_to_last_checkpoint);
   cw.write<bool>(false); // flushpoint
   cw.write((u4)1); // nof types in this checkpoint
   cw.write(type_id);
@@ -178,7 +178,7 @@
     _cw.write_padded_at_offset<u4>(number_of_elements, num_elements_offset);
     _cw.write_padded_at_offset<u4>((u4)_cw.current_offset() - current_cp_offset, current_cp_offset);
     // update writer with last checkpoint position
-    _cw.set_previous_checkpoint_offset(current_cp_offset);
+    _cw.set_last_checkpoint_offset(current_cp_offset);
     return true;
   }
 };
@@ -317,19 +317,16 @@
     vm_error = true;
     prepare_for_vm_error_rotation();
   }
+  if (!_storage.control().to_disk()) {
+    in_memory_rotation();
+  } else if (vm_error) {
+    vm_error_rotation();
+  } else {
+    chunk_rotation();
+  }
   if (msgs & (MSGBIT(MSG_STOP))) {
     stop();
   }
-  // action determined by chunkwriter state
-  if (!_chunkwriter.is_valid()) {
-    in_memory_rotation();
-    return;
-  }
-  if (vm_error) {
-    vm_error_rotation();
-    return;
-  }
-  chunk_rotation();
 }
 
 void JfrRecorderService::prepare_for_vm_error_rotation() {
@@ -400,12 +397,6 @@
   WriteStackTraceCheckpoint write_stack_trace_checkpoint(chunkwriter, TYPE_STACKTRACE, write_stacktrace_repo);
   write_stack_trace_checkpoint.process();
 }
-
-static void write_object_sample_stacktrace(ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repository) {
-  WriteObjectSampleStacktrace object_sample_stacktrace(sampler, stack_trace_repository);
-  object_sample_stacktrace.process();
-}
-
 static void write_stringpool_checkpoint(JfrStringPool& string_pool, JfrChunkWriter& chunkwriter) {
   WriteStringPool write_string_pool(string_pool);
   WriteStringPoolCheckpoint write_string_pool_checkpoint(chunkwriter, TYPE_STRING, write_string_pool);
@@ -440,9 +431,7 @@
   if (LeakProfiler::is_running()) {
     // Exclusive access to the object sampler instance.
     // The sampler is released (unlocked) later in post_safepoint_write.
-    ObjectSampler* const sampler = ObjectSampler::acquire();
-    assert(sampler != NULL, "invariant");
-    write_object_sample_stacktrace(sampler, _stack_trace_repository);
+    ObjectSampleCheckpoint::on_rotation(ObjectSampler::acquire(), _stack_trace_repository);
   }
   _storage.write();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/stacktrace/jfrStackTrace.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/vframe.inline.hpp"
+
+static void copy_frames(JfrStackFrame** lhs_frames, u4 length, const JfrStackFrame* rhs_frames) {
+  assert(lhs_frames != NULL, "invariant");
+  assert(rhs_frames != NULL, "invariant");
+  if (length > 0) {
+    *lhs_frames = NEW_C_HEAP_ARRAY(JfrStackFrame, length, mtTracing);
+    memcpy(*lhs_frames, rhs_frames, length * sizeof(JfrStackFrame));
+  }
+}
+
+JfrStackFrame::JfrStackFrame(const traceid& id, int bci, int type, const Method* method) :
+  _method(method), _methodid(id), _line(0), _bci(bci), _type(type) {}
+
+JfrStackFrame::JfrStackFrame(const traceid& id, int bci, int type, int lineno) :
+  _method(NULL), _methodid(id), _line(lineno), _bci(bci), _type(type) {}
+
+JfrStackTrace::JfrStackTrace(JfrStackFrame* frames, u4 max_frames) :
+  _next(NULL),
+  _frames(frames),
+  _id(0),
+  _hash(0),
+  _nr_of_frames(0),
+  _max_frames(max_frames),
+  _frames_ownership(false),
+  _reached_root(false),
+  _lineno(false),
+  _written(false) {}
+
+JfrStackTrace::JfrStackTrace(traceid id, const JfrStackTrace& trace, const JfrStackTrace* next) :
+  _next(next),
+  _frames(NULL),
+  _id(id),
+  _hash(trace._hash),
+  _nr_of_frames(trace._nr_of_frames),
+  _max_frames(trace._max_frames),
+  _frames_ownership(true),
+  _reached_root(trace._reached_root),
+  _lineno(trace._lineno),
+  _written(false) {
+  copy_frames(&_frames, trace._nr_of_frames, trace._frames);
+}
+
+JfrStackTrace::~JfrStackTrace() {
+  if (_frames_ownership) {
+    FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
+  }
+}
+
+template <typename Writer>
+static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
+  w.write((u8)id);
+  w.write((u1)!reached_root);
+  w.write(nr_of_frames);
+  for (u4 i = 0; i < nr_of_frames; ++i) {
+    frames[i].write(w);
+  }
+}
+
+void JfrStackTrace::write(JfrChunkWriter& sw) const {
+  assert(!_written, "invariant");
+  write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
+  _written = true;
+}
+
+void JfrStackTrace::write(JfrCheckpointWriter& cpw) const {
+  write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
+}
+
+bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
+  return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
+}
+
+bool JfrStackTrace::equals(const JfrStackTrace& rhs) const {
+  if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
+    return false;
+  }
+  for (u4 i = 0; i < _nr_of_frames; ++i) {
+    if (!_frames[i].equals(rhs._frames[i])) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template <typename Writer>
+static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
+  w.write((u8)methodid);
+  w.write((u4)line);
+  w.write((u4)bci);
+  w.write((u8)type);
+}
+
+void JfrStackFrame::write(JfrChunkWriter& cw) const {
+  write_frame(cw, _methodid, _line, _bci, _type);
+}
+
+void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
+  write_frame(cpw, _methodid, _line, _bci, _type);
+}
+
+class vframeStreamSamples : public vframeStreamCommon {
+ public:
+  // constructor that starts with sender of frame fr (top_frame)
+  vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
+    _stop_at_java_call_stub = stop_at_java_call_stub;
+    _frame = fr;
+
+    // We must always have a valid frame to start filling
+    bool filled_in = fill_from_frame();
+    assert(filled_in, "invariant");
+  }
+  void samples_next();
+  void stop() {}
+};
+
+// Solaris SPARC Compiler1 needs an additional check on the grandparent
+// of the top_frame when the parent of the top_frame is interpreted and
+// the grandparent is compiled. However, in this method we do not know
+// the relationship of the current _frame relative to the top_frame so
+// we implement a more broad sanity check. When the previous callee is
+// interpreted and the current sender is compiled, we verify that the
+// current sender is also walkable. If it is not walkable, then we mark
+// the current vframeStream as at the end.
+void vframeStreamSamples::samples_next() {
+  // handle frames with inlining
+  if (_mode == compiled_mode &&
+    vframeStreamCommon::fill_in_compiled_inlined_sender()) {
+    return;
+  }
+
+  // handle general case
+  u4 loop_count = 0;
+  u4 loop_max = MAX_STACK_DEPTH * 2;
+  do {
+    loop_count++;
+    // By the time we get here we should never see unsafe but better safe then segv'd
+    if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
+      _mode = at_end_mode;
+      return;
+    }
+    _frame = _frame.sender(&_reg_map);
+  } while (!fill_from_frame());
+}
+
+bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
+  vframeStreamSamples st(&thread, frame, false);
+  u4 count = 0;
+  _reached_root = true;
+
+  while (!st.at_end()) {
+    if (count >= _max_frames) {
+      _reached_root = false;
+      break;
+    }
+    const Method* method = st.method();
+    if (!Method::is_valid_method(method)) {
+      // we throw away everything we've gathered in this sample since
+      // none of it is safe
+      return false;
+    }
+    const traceid mid = JfrTraceId::use(method);
+    int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
+    int bci = 0;
+    if (method->is_native()) {
+      type = JfrStackFrame::FRAME_NATIVE;
+    } else {
+      bci = st.bci();
+    }
+    const int lineno = method->line_number_from_bci(bci);
+    // Can we determine if it's inlined?
+    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
+    _frames[count] = JfrStackFrame(mid, bci, type, method);
+    st.samples_next();
+    count++;
+  }
+
+  _lineno = true;
+  _nr_of_frames = count;
+  return true;
+}
+
+void JfrStackFrame::resolve_lineno() const {
+  assert(_method, "no method pointer");
+  assert(_line == 0, "already have linenumber");
+  _line = _method->line_number_from_bci(_bci);
+}
+
+void JfrStackTrace::resolve_linenos() const {
+  for (unsigned int i = 0; i < _nr_of_frames; i++) {
+    _frames[i].resolve_lineno();
+  }
+  _lineno = true;
+}
+
+bool JfrStackTrace::record_safe(JavaThread* thread, int skip) {
+  assert(thread == Thread::current(), "Thread stack needs to be walkable");
+  vframeStream vfs(thread);
+  u4 count = 0;
+  _reached_root = true;
+  for (int i = 0; i < skip; i++) {
+    if (vfs.at_end()) {
+      break;
+    }
+    vfs.next();
+  }
+
+  while (!vfs.at_end()) {
+    if (count >= _max_frames) {
+      _reached_root = false;
+      break;
+    }
+    const Method* method = vfs.method();
+    const traceid mid = JfrTraceId::use(method);
+    int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
+    int bci = 0;
+    if (method->is_native()) {
+      type = JfrStackFrame::FRAME_NATIVE;
+    }
+    else {
+      bci = vfs.bci();
+    }
+    // Can we determine if it's inlined?
+    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
+    _frames[count] = JfrStackFrame(mid, bci, type, method);
+    vfs.next();
+    count++;
+  }
+
+  _nr_of_frames = count;
+  return true;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTrace.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACE_HPP
+#define SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACE_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+
+class frame;
+class JavaThread;
+class JfrCheckpointWriter;
+class JfrChunkWriter;
+class Method;
+
+class JfrStackFrame {
+  friend class ObjectSampleCheckpoint;
+ private:
+  const Method* _method;
+  traceid _methodid;
+  mutable int _line;
+  int _bci;
+  u1 _type;
+
+ public:
+  JfrStackFrame(const traceid& id, int bci, int type, const Method* method);
+  JfrStackFrame(const traceid& id, int bci, int type, int lineno);
+
+  bool equals(const JfrStackFrame& rhs) const;
+  void write(JfrChunkWriter& cw) const;
+  void write(JfrCheckpointWriter& cpw) const;
+  void resolve_lineno() const;
+
+  enum {
+    FRAME_INTERPRETER = 0,
+    FRAME_JIT,
+    FRAME_INLINE,
+    FRAME_NATIVE,
+    NUM_FRAME_TYPES
+  };
+};
+
+class JfrStackTrace : public JfrCHeapObj {
+  friend class JfrNativeSamplerCallback;
+  friend class JfrStackTraceRepository;
+  friend class ObjectSampleCheckpoint;
+  friend class ObjectSampler;
+  friend class OSThreadSampler;
+  friend class StackTraceResolver;
+ private:
+  const JfrStackTrace* _next;
+  JfrStackFrame* _frames;
+  traceid _id;
+  unsigned int _hash;
+  u4 _nr_of_frames;
+  u4 _max_frames;
+  bool _frames_ownership;
+  bool _reached_root;
+  mutable bool _lineno;
+  mutable bool _written;
+
+  const JfrStackTrace* next() const { return _next; }
+
+  bool should_write() const { return !_written; }
+  void write(JfrChunkWriter& cw) const;
+  void write(JfrCheckpointWriter& cpw) const;
+  bool equals(const JfrStackTrace& rhs) const;
+
+  void set_id(traceid id) { _id = id; }
+  void set_nr_of_frames(u4 nr_of_frames) { _nr_of_frames = nr_of_frames; }
+  void set_hash(unsigned int hash) { _hash = hash; }
+  void set_reached_root(bool reached_root) { _reached_root = reached_root; }
+  void resolve_linenos() const;
+
+  bool record_thread(JavaThread& thread, frame& frame);
+  bool record_safe(JavaThread* thread, int skip);
+
+  bool have_lineno() const { return _lineno; }
+  bool full_stacktrace() const { return _reached_root; }
+
+  JfrStackTrace(traceid id, const JfrStackTrace& trace, const JfrStackTrace* next);
+  JfrStackTrace(JfrStackFrame* frames, u4 max_frames);
+  ~JfrStackTrace();
+
+ public:
+  unsigned int hash() const { return _hash; }
+  traceid id() const { return _id; }
+};
+
+#endif // SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACE_HPP
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -24,66 +24,18 @@
 
 #include "precompiled.hpp"
 #include "jfr/metadata/jfrSerializer.hpp"
-#include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
-#include "jfr/recorder/service/jfrOptionSet.hpp"
 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
-#include "jfr/utilities/jfrTypes.hpp"
-#include "memory/allocation.inline.hpp"
+#include "jfr/support/jfrThreadLocal.hpp"
 #include "runtime/mutexLocker.hpp"
-#include "runtime/os.inline.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/task.hpp"
-#include "runtime/vframe.inline.hpp"
-
-class vframeStreamSamples : public vframeStreamCommon {
- public:
-  // constructor that starts with sender of frame fr (top_frame)
-  vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub);
-  void samples_next();
-  void stop() {}
-};
-
-vframeStreamSamples::vframeStreamSamples(JavaThread *jt, frame fr, bool stop_at_java_call_stub) : vframeStreamCommon(jt) {
-  _stop_at_java_call_stub = stop_at_java_call_stub;
-  _frame = fr;
-
-  // We must always have a valid frame to start filling
-  bool filled_in = fill_from_frame();
-  assert(filled_in, "invariant");
-}
-
-// Solaris SPARC Compiler1 needs an additional check on the grandparent
-// of the top_frame when the parent of the top_frame is interpreted and
-// the grandparent is compiled. However, in this method we do not know
-// the relationship of the current _frame relative to the top_frame so
-// we implement a more broad sanity check. When the previous callee is
-// interpreted and the current sender is compiled, we verify that the
-// current sender is also walkable. If it is not walkable, then we mark
-// the current vframeStream as at the end.
-void vframeStreamSamples::samples_next() {
-  // handle frames with inlining
-  if (_mode == compiled_mode &&
-      vframeStreamCommon::fill_in_compiled_inlined_sender()) {
-    return;
-  }
-
-  // handle general case
-  u4 loop_count = 0;
-  u4 loop_max = MAX_STACK_DEPTH * 2;
-  do {
-    loop_count++;
-    // By the time we get here we should never see unsafe but better safe then segv'd
-    if (loop_count > loop_max || !_frame.safe_for_sender(_thread)) {
-      _mode = at_end_mode;
-      return;
-    }
-    _frame = _frame.sender(&_reg_map);
-  } while (!fill_from_frame());
-}
 
 static JfrStackTraceRepository* _instance = NULL;
 
+JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
+  memset(_table, 0, sizeof(_table));
+}
+
 JfrStackTraceRepository& JfrStackTraceRepository::instance() {
   return *_instance;
 }
@@ -94,15 +46,6 @@
   return _instance;
 }
 
-void JfrStackTraceRepository::destroy() {
-  assert(_instance != NULL, "invarinat");
-  delete _instance;
-  _instance = NULL;
-}
-
-JfrStackTraceRepository::JfrStackTraceRepository() : _next_id(0), _entries(0) {
-  memset(_table, 0, sizeof(_table));
-}
 class JfrFrameType : public JfrSerializer {
  public:
   void serialize(JfrCheckpointWriter& writer) {
@@ -122,100 +65,10 @@
   return JfrSerializer::register_serializer(TYPE_FRAMETYPE, false, true, new JfrFrameType());
 }
 
-size_t JfrStackTraceRepository::clear() {
-  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
-  if (_entries == 0) {
-    return 0;
-  }
-  for (u4 i = 0; i < TABLE_SIZE; ++i) {
-    JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
-    while (stacktrace != NULL) {
-      JfrStackTraceRepository::StackTrace* next = stacktrace->next();
-      delete stacktrace;
-      stacktrace = next;
-    }
-  }
-  memset(_table, 0, sizeof(_table));
-  const size_t processed = _entries;
-  _entries = 0;
-  return processed;
-}
-
-traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
-  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
-  const size_t index = stacktrace._hash % TABLE_SIZE;
-  const StackTrace* table_entry = _table[index];
-
-  while (table_entry != NULL) {
-    if (table_entry->equals(stacktrace)) {
-      return table_entry->id();
-    }
-    table_entry = table_entry->next();
-  }
-
-  if (!stacktrace.have_lineno()) {
-    return 0;
-  }
-
-  traceid id = ++_next_id;
-  _table[index] = new StackTrace(id, stacktrace, _table[index]);
-  ++_entries;
-  return id;
-}
-
-traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
-  traceid tid = instance().add_trace(stacktrace);
-  if (tid == 0) {
-    stacktrace.resolve_linenos();
-    tid = instance().add_trace(stacktrace);
-  }
-  assert(tid != 0, "invariant");
-  return tid;
-}
-
-traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
-  assert(thread == Thread::current(), "invariant");
-  JfrThreadLocal* const tl = thread->jfr_thread_local();
-  assert(tl != NULL, "invariant");
-  if (tl->has_cached_stack_trace()) {
-    return tl->cached_stack_trace_id();
-  }
-  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
-    return 0;
-  }
-  JfrStackFrame* frames = tl->stackframes();
-  if (frames == NULL) {
-    // pending oom
-    return 0;
-  }
-  assert(frames != NULL, "invariant");
-  assert(tl->stackframes() == frames, "invariant");
-  return instance().record_for((JavaThread*)thread, skip,frames, tl->stackdepth());
-}
-
-traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
-  JfrStackTrace stacktrace(frames, max_frames);
-  return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
-}
-
-traceid JfrStackTraceRepository::add(const JfrStackTrace* stacktrace, JavaThread* thread) {
-  assert(stacktrace != NULL, "invariant");
-  assert(thread != NULL, "invariant");
-  assert(stacktrace->hash() != 0, "invariant");
-  return add(*stacktrace);
-}
-
-bool JfrStackTraceRepository::fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip) {
-  assert(thread == Thread::current(), "invariant");
-  assert(stacktrace != NULL, "invariant");
-  JfrThreadLocal* const tl = thread->jfr_thread_local();
-  assert(tl != NULL, "invariant");
-  const unsigned int cached_stacktrace_hash = tl->cached_stack_trace_hash();
-  if (cached_stacktrace_hash != 0) {
-    stacktrace->set_hash(cached_stacktrace_hash);
-    return true;
-  }
-  return stacktrace->record_safe(thread, skip, true);
+void JfrStackTraceRepository::destroy() {
+  assert(_instance != NULL, "invarinat");
+  delete _instance;
+  _instance = NULL;
 }
 
 size_t JfrStackTraceRepository::write_impl(JfrChunkWriter& sw, bool clear) {
@@ -223,9 +76,9 @@
   assert(_entries > 0, "invariant");
   int count = 0;
   for (u4 i = 0; i < TABLE_SIZE; ++i) {
-    JfrStackTraceRepository::StackTrace* stacktrace = _table[i];
+    JfrStackTrace* stacktrace = _table[i];
     while (stacktrace != NULL) {
-      JfrStackTraceRepository::StackTrace* next = stacktrace->next();
+      JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
       if (stacktrace->should_write()) {
         stacktrace->write(sw);
         ++count;
@@ -249,7 +102,7 @@
 
 traceid JfrStackTraceRepository::write(JfrCheckpointWriter& writer, traceid id, unsigned int hash) {
   assert(JfrStacktrace_lock->owned_by_self(), "invariant");
-  const StackTrace* const trace = resolve_entry(hash, id);
+  const JfrStackTrace* const trace = lookup(hash, id);
   assert(trace != NULL, "invariant");
   assert(trace->hash() == hash, "invariant");
   assert(trace->id() == id, "invariant");
@@ -257,82 +110,105 @@
   return id;
 }
 
-JfrStackTraceRepository::StackTrace::StackTrace(traceid id, const JfrStackTrace& trace, JfrStackTraceRepository::StackTrace* next) :
-  _next(next),
-  _frames(NULL),
-  _id(id),
-  _nr_of_frames(trace._nr_of_frames),
-  _hash(trace._hash),
-  _reached_root(trace._reached_root),
-  _written(false) {
-  if (_nr_of_frames > 0) {
-    _frames = NEW_C_HEAP_ARRAY(JfrStackFrame, _nr_of_frames, mtTracing);
-    memcpy(_frames, trace._frames, _nr_of_frames * sizeof(JfrStackFrame));
+void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
+  JfrFrameType fct;
+  writer.write_type(TYPE_FRAMETYPE);
+  fct.serialize(writer);
+}
+
+size_t JfrStackTraceRepository::clear() {
+  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  if (_entries == 0) {
+    return 0;
+  }
+  for (u4 i = 0; i < TABLE_SIZE; ++i) {
+    JfrStackTrace* stacktrace = _table[i];
+    while (stacktrace != NULL) {
+      JfrStackTrace* next = const_cast<JfrStackTrace*>(stacktrace->next());
+      delete stacktrace;
+      stacktrace = next;
+    }
+  }
+  memset(_table, 0, sizeof(_table));
+  const size_t processed = _entries;
+  _entries = 0;
+  return processed;
+}
+
+traceid JfrStackTraceRepository::record(Thread* thread, int skip /* 0 */) {
+  assert(thread == Thread::current(), "invariant");
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  assert(tl != NULL, "invariant");
+  if (tl->has_cached_stack_trace()) {
+    return tl->cached_stack_trace_id();
+  }
+  if (!thread->is_Java_thread() || thread->is_hidden_from_external_view()) {
+    return 0;
+  }
+  JfrStackFrame* frames = tl->stackframes();
+  if (frames == NULL) {
+    // pending oom
+    return 0;
+  }
+  assert(frames != NULL, "invariant");
+  assert(tl->stackframes() == frames, "invariant");
+  return instance().record_for((JavaThread*)thread, skip, frames, tl->stackdepth());
+}
+
+traceid JfrStackTraceRepository::record_for(JavaThread* thread, int skip, JfrStackFrame *frames, u4 max_frames) {
+  JfrStackTrace stacktrace(frames, max_frames);
+  return stacktrace.record_safe(thread, skip) ? add(stacktrace) : 0;
+}
+
+traceid JfrStackTraceRepository::add(const JfrStackTrace& stacktrace) {
+  traceid tid = instance().add_trace(stacktrace);
+  if (tid == 0) {
+    stacktrace.resolve_linenos();
+    tid = instance().add_trace(stacktrace);
+  }
+  assert(tid != 0, "invariant");
+  return tid;
+}
+
+void JfrStackTraceRepository::record_and_cache(JavaThread* thread, int skip /* 0 */) {
+  assert(thread != NULL, "invariant");
+  JfrThreadLocal* const tl = thread->jfr_thread_local();
+  assert(tl != NULL, "invariant");
+  assert(!tl->has_cached_stack_trace(), "invariant");
+  JfrStackTrace stacktrace(tl->stackframes(), tl->stackdepth());
+  stacktrace.record_safe(thread, skip);
+  const unsigned int hash = stacktrace.hash();
+  if (hash != 0) {
+    tl->set_cached_stack_trace_id(instance().add(stacktrace), hash);
   }
 }
 
-JfrStackTraceRepository::StackTrace::~StackTrace() {
-  FREE_C_HEAP_ARRAY(JfrStackFrame, _frames);
-}
-
-bool JfrStackTraceRepository::StackTrace::equals(const JfrStackTrace& rhs) const {
-  if (_reached_root != rhs._reached_root || _nr_of_frames != rhs._nr_of_frames || _hash != rhs._hash) {
-    return false;
-  }
-  for (u4 i = 0; i < _nr_of_frames; ++i) {
-    if (!_frames[i].equals(rhs._frames[i])) {
-      return false;
-    }
-  }
-  return true;
-}
-
-template <typename Writer>
-static void write_stacktrace(Writer& w, traceid id, bool reached_root, u4 nr_of_frames, const JfrStackFrame* frames) {
-  w.write((u8)id);
-  w.write((u1)!reached_root);
-  w.write(nr_of_frames);
-  for (u4 i = 0; i < nr_of_frames; ++i) {
-    frames[i].write(w);
-  }
-}
+traceid JfrStackTraceRepository::add_trace(const JfrStackTrace& stacktrace) {
+  MutexLocker lock(JfrStacktrace_lock, Mutex::_no_safepoint_check_flag);
+  const size_t index = stacktrace._hash % TABLE_SIZE;
+  const JfrStackTrace* table_entry = _table[index];
 
-void JfrStackTraceRepository::StackTrace::write(JfrChunkWriter& sw) const {
-  assert(!_written, "invariant");
-  write_stacktrace(sw, _id, _reached_root, _nr_of_frames, _frames);
-  _written = true;
-}
-
-void JfrStackTraceRepository::StackTrace::write(JfrCheckpointWriter& cpw) const {
-  write_stacktrace(cpw, _id, _reached_root, _nr_of_frames, _frames);
-}
-
-// JfrStackFrame
+  while (table_entry != NULL) {
+    if (table_entry->equals(stacktrace)) {
+      return table_entry->id();
+    }
+    table_entry = table_entry->next();
+  }
 
-bool JfrStackFrame::equals(const JfrStackFrame& rhs) const {
-  return _methodid == rhs._methodid && _bci == rhs._bci && _type == rhs._type;
-}
+  if (!stacktrace.have_lineno()) {
+    return 0;
+  }
 
-template <typename Writer>
-static void write_frame(Writer& w, traceid methodid, int line, int bci, u1 type) {
-  w.write((u8)methodid);
-  w.write((u4)line);
-  w.write((u4)bci);
-  w.write((u8)type);
-}
-
-void JfrStackFrame::write(JfrChunkWriter& cw) const {
-  write_frame(cw, _methodid, _line, _bci, _type);
-}
-
-void JfrStackFrame::write(JfrCheckpointWriter& cpw) const {
-  write_frame(cpw, _methodid, _line, _bci, _type);
+  traceid id = ++_next_id;
+  _table[index] = new JfrStackTrace(id, stacktrace, _table[index]);
+  ++_entries;
+  return id;
 }
 
 // invariant is that the entry to be resolved actually exists in the table
-const JfrStackTraceRepository::StackTrace* JfrStackTraceRepository::resolve_entry(unsigned int hash, traceid id) const {
+const JfrStackTrace* JfrStackTraceRepository::lookup(unsigned int hash, traceid id) const {
   const size_t index = (hash % TABLE_SIZE);
-  const StackTrace* trace = _table[index];
+  const JfrStackTrace* trace = _table[index];
   while (trace != NULL && trace->id() != id) {
     trace = trace->next();
   }
@@ -341,102 +217,3 @@
   assert(trace->id() == id, "invariant");
   return trace;
 }
-
-void JfrStackFrame::resolve_lineno() const {
-  assert(_method, "no method pointer");
-  assert(_line == 0, "already have linenumber");
-  _line = _method->line_number_from_bci(_bci);
-  _method = NULL;
-}
-
-void JfrStackTrace::set_frame(u4 frame_pos, JfrStackFrame& frame) {
-  assert(frame_pos < _max_frames, "illegal frame_pos");
-  _frames[frame_pos] = frame;
-}
-
-void JfrStackTrace::resolve_linenos() const {
-  for(unsigned int i = 0; i < _nr_of_frames; i++) {
-    _frames[i].resolve_lineno();
-  }
-  _lineno = true;
-}
-
-bool JfrStackTrace::record_safe(JavaThread* thread, int skip, bool leakp /* false */) {
-  assert(thread == Thread::current(), "Thread stack needs to be walkable");
-  vframeStream vfs(thread);
-  u4 count = 0;
-  _reached_root = true;
-  for(int i = 0; i < skip; i++) {
-    if (vfs.at_end()) {
-      break;
-    }
-    vfs.next();
-  }
-
-  while (!vfs.at_end()) {
-    if (count >= _max_frames) {
-      _reached_root = false;
-      break;
-    }
-    const Method* method = vfs.method();
-    const traceid mid = JfrTraceId::use(method, leakp);
-    int type = vfs.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
-    int bci = 0;
-    if (method->is_native()) {
-      type = JfrStackFrame::FRAME_NATIVE;
-    } else {
-      bci = vfs.bci();
-    }
-    // Can we determine if it's inlined?
-    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
-    _frames[count] = JfrStackFrame(mid, bci, type, method);
-    vfs.next();
-    count++;
-  }
-
-  _nr_of_frames = count;
-  return true;
-}
-
-bool JfrStackTrace::record_thread(JavaThread& thread, frame& frame) {
-  vframeStreamSamples st(&thread, frame, false);
-  u4 count = 0;
-  _reached_root = true;
-
-  while (!st.at_end()) {
-    if (count >= _max_frames) {
-      _reached_root = false;
-      break;
-    }
-    const Method* method = st.method();
-    if (!Method::is_valid_method(method)) {
-      // we throw away everything we've gathered in this sample since
-      // none of it is safe
-      return false;
-    }
-    const traceid mid = JfrTraceId::use(method);
-    int type = st.is_interpreted_frame() ? JfrStackFrame::FRAME_INTERPRETER : JfrStackFrame::FRAME_JIT;
-    int bci = 0;
-    if (method->is_native()) {
-      type = JfrStackFrame::FRAME_NATIVE;
-    } else {
-      bci = st.bci();
-    }
-    const int lineno = method->line_number_from_bci(bci);
-    // Can we determine if it's inlined?
-    _hash = (_hash << 2) + (unsigned int)(((size_t)mid >> 2) + (bci << 4) + type);
-    _frames[count] = JfrStackFrame(mid, bci, type, lineno);
-    st.samples_next();
-    count++;
-  }
-
-  _lineno = true;
-  _nr_of_frames = count;
-  return true;
-}
-
-void JfrStackTraceRepository::write_metadata(JfrCheckpointWriter& writer) {
-  JfrFrameType fct;
-  writer.write_type(TYPE_FRAMETYPE);
-  fct.serialize(writer);
-}
--- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackTraceRepository.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,133 +25,49 @@
 #ifndef SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP
 #define SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP
 
+#include "jfr/recorder/stacktrace/jfrStackTrace.hpp"
 #include "jfr/utilities/jfrAllocation.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 
-class frame;
 class JavaThread;
 class JfrCheckpointWriter;
 class JfrChunkWriter;
-class Method;
-
-class JfrStackFrame {
- private:
-  mutable const Method* _method;
-  traceid _methodid;
-  mutable int _line;
-  int _bci;
-  u1 _type;
-
- public:
-  enum {
-    FRAME_INTERPRETER = 0,
-    FRAME_JIT,
-    FRAME_INLINE,
-    FRAME_NATIVE,
-    NUM_FRAME_TYPES
-  };
-
-  JfrStackFrame(const traceid& id, int bci, int type, const Method* method) :
-    _method(method), _methodid(id), _line(0), _bci(bci), _type(type) {}
-  JfrStackFrame(const traceid& id, int bci, int type, int lineno) :
-    _method(NULL), _methodid(id), _line(lineno), _bci(bci), _type(type) {}
-  bool equals(const JfrStackFrame& rhs) const;
-  void write(JfrChunkWriter& cw) const;
-  void write(JfrCheckpointWriter& cpw) const;
-  void resolve_lineno() const;
-};
-
-class JfrStackTrace : public StackObj {
-  friend class JfrStackTraceRepository;
- private:
-  JfrStackFrame* _frames;
-  traceid _id;
-  u4 _nr_of_frames;
-  unsigned int _hash;
-  const u4 _max_frames;
-  bool _reached_root;
-  mutable bool _lineno;
-
- public:
-  JfrStackTrace(JfrStackFrame* frames, u4 max_frames) : _frames(frames),
-                                                        _id(0),
-                                                        _nr_of_frames(0),
-                                                        _hash(0),
-                                                        _max_frames(max_frames),
-                                                        _reached_root(false),
-                                                        _lineno(false) {}
-  bool record_thread(JavaThread& thread, frame& frame);
-  bool record_safe(JavaThread* thread, int skip, bool leakp = false);
-  void resolve_linenos() const;
-  void set_nr_of_frames(u4 nr_of_frames) { _nr_of_frames = nr_of_frames; }
-  void set_hash(unsigned int hash) { _hash = hash; }
-  unsigned int hash() const { return _hash; }
-  void set_frame(u4 frame_pos, JfrStackFrame& frame);
-  void set_reached_root(bool reached_root) { _reached_root = reached_root; }
-  bool full_stacktrace() const { return _reached_root; }
-  bool have_lineno() const { return _lineno; }
-};
 
 class JfrStackTraceRepository : public JfrCHeapObj {
   friend class JfrRecorder;
   friend class JfrRecorderService;
+  friend class JfrThreadSampleClosure;
+  friend class ObjectSampleCheckpoint;
   friend class ObjectSampler;
-  friend class WriteObjectSampleStacktrace;
-
-  class StackTrace : public JfrCHeapObj {
-    friend class JfrStackTrace;
-    friend class JfrStackTraceRepository;
-   private:
-    StackTrace* _next;
-    JfrStackFrame* _frames;
-    const traceid _id;
-    u4 _nr_of_frames;
-    unsigned int _hash;
-    bool _reached_root;
-    mutable bool _written;
-
-    unsigned int hash() const { return _hash; }
-    bool should_write() const { return !_written; }
-
-   public:
-    StackTrace(traceid id, const JfrStackTrace& trace, StackTrace* next);
-    ~StackTrace();
-    traceid id() const { return _id; }
-    StackTrace* next() const { return _next; }
-    void write(JfrChunkWriter& cw) const;
-    void write(JfrCheckpointWriter& cpw) const;
-    bool equals(const JfrStackTrace& rhs) const;
-  };
+  friend class StackTraceBlobInstaller;
+  friend class WriteStackTraceRepository;
 
  private:
   static const u4 TABLE_SIZE = 2053;
-  StackTrace* _table[TABLE_SIZE];
+  JfrStackTrace* _table[TABLE_SIZE];
   traceid _next_id;
   u4 _entries;
 
-  traceid add_trace(const JfrStackTrace& stacktrace);
-  static traceid add(const JfrStackTrace* stacktrace, JavaThread* thread);
-  traceid record_for(JavaThread* thread, int skip, JfrStackFrame* frames, u4 max_frames);
-
-  size_t write_impl(JfrChunkWriter& cw, bool clear);
-  const StackTrace* resolve_entry(unsigned int hash, traceid id) const;
-  static void write_metadata(JfrCheckpointWriter& cpw);
-
-  static bool fill_stacktrace_for(JavaThread* thread, JfrStackTrace* stacktrace, int skip);
-
   JfrStackTraceRepository();
+  static JfrStackTraceRepository& instance();
   static JfrStackTraceRepository* create();
   bool initialize();
   static void destroy();
 
-  static JfrStackTraceRepository& instance();
-
- public:
-  static traceid add(const JfrStackTrace& stacktrace);
-  static traceid record(Thread* thread, int skip = 0);
+  size_t write_impl(JfrChunkWriter& cw, bool clear);
+  static void write_metadata(JfrCheckpointWriter& cpw);
   traceid write(JfrCheckpointWriter& cpw, traceid id, unsigned int hash);
   size_t write(JfrChunkWriter& cw, bool clear);
   size_t clear();
+
+  traceid add_trace(const JfrStackTrace& stacktrace);
+  static traceid add(const JfrStackTrace& stacktrace);
+  traceid record_for(JavaThread* thread, int skip, JfrStackFrame* frames, u4 max_frames);
+  const JfrStackTrace* lookup(unsigned int hash, traceid id) const;
+
+ public:
+  static traceid record(Thread* thread, int skip = 0);
+  static void record_and_cache(JavaThread* thread, int skip = 0);
 };
 
 #endif // SHARE_JFR_RECORDER_STACKTRACE_JFRSTACKTRACEREPOSITORY_HPP
--- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -27,10 +27,6 @@
 #include "jfr/utilities/jfrAllocation.hpp"
 #include "jfr/utilities/jfrDoublyLinkedList.hpp"
 #include "jfr/utilities/jfrIterator.hpp"
-#include "jfr/utilities/jfrTypes.hpp"
-#include "runtime/os.hpp"
-#include "utilities/globalDefinitions.hpp"
-#include "utilities/macros.hpp"
 
 template <typename T, template <typename> class RetrievalType, typename Callback>
 class JfrMemorySpace : public JfrCHeapObj {
@@ -107,62 +103,4 @@
   debug_only(bool in_free_list(const Type* t) const { return _free.in_list(t); })
 };
 
-// allocations are even multiples of the mspace min size
-inline u8 align_allocation_size(u8 requested_size, size_t min_elem_size) {
-  assert((int)min_elem_size % os::vm_page_size() == 0, "invariant");
-  u8 alloc_size_bytes = min_elem_size;
-  while (requested_size > alloc_size_bytes) {
-    alloc_size_bytes <<= 1;
-  }
-  assert((int)alloc_size_bytes % os::vm_page_size() == 0, "invariant");
-  return alloc_size_bytes;
-}
-
-template <typename T, template <typename> class RetrievalType, typename Callback>
-T* JfrMemorySpace<T, RetrievalType, Callback>::allocate(size_t size) {
-  const u8 aligned_size_bytes = align_allocation_size(size, _min_elem_size);
-  void* const allocation = JfrCHeapObj::new_array<u1>(aligned_size_bytes + sizeof(T));
-  if (allocation == NULL) {
-    return NULL;
-  }
-  T* const t = new (allocation) T;
-  assert(t != NULL, "invariant");
-  if (!t->initialize(sizeof(T), aligned_size_bytes)) {
-    JfrCHeapObj::free(t, aligned_size_bytes + sizeof(T));
-    return NULL;
-  }
-  return t;
-}
-
-template <typename T, template <typename> class RetrievalType, typename Callback>
-void JfrMemorySpace<T, RetrievalType, Callback>::deallocate(T* t) {
-  assert(t != NULL, "invariant");
-  assert(!_free.in_list(t), "invariant");
-  assert(!_full.in_list(t), "invariant");
-  assert(t != NULL, "invariant");
-  JfrCHeapObj::free(t, t->total_size());
-}
-
-template <typename Mspace>
-class MspaceLock {
- private:
-  Mspace* _mspace;
- public:
-  MspaceLock(Mspace* mspace) : _mspace(mspace) { _mspace->lock(); }
-  ~MspaceLock() { _mspace->unlock(); }
-};
-
-template <typename Mspace>
-class ReleaseOp : public StackObj {
- private:
-  Mspace* _mspace;
-  Thread* _thread;
-  bool _release_full;
- public:
-  typedef typename Mspace::Type Type;
-  ReleaseOp(Mspace* mspace, Thread* thread, bool release_full = true) : _mspace(mspace), _thread(thread), _release_full(release_full) {}
-  bool process(Type* t);
-  size_t processed() const { return 0; }
-};
-
 #endif // SHARE_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_HPP
--- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -26,6 +26,7 @@
 #define SHARE_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
 
 #include "jfr/recorder/storage/jfrMemorySpace.hpp"
+#include "runtime/os.hpp"
 
 template <typename T, template <typename> class RetrievalType, typename Callback>
 JfrMemorySpace<T, RetrievalType, Callback>::
@@ -69,6 +70,42 @@
   return true;
 }
 
+// allocations are even multiples of the mspace min size
+static inline size_t align_allocation_size(size_t requested_size, size_t min_elem_size) {
+  assert((int)min_elem_size % os::vm_page_size() == 0, "invariant");
+  u8 alloc_size_bytes = min_elem_size;
+  while (requested_size > alloc_size_bytes) {
+    alloc_size_bytes <<= 1;
+  }
+  assert((int)alloc_size_bytes % os::vm_page_size() == 0, "invariant");
+  return (size_t)alloc_size_bytes;
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+inline T* JfrMemorySpace<T, RetrievalType, Callback>::allocate(size_t size) {
+  const size_t aligned_size_bytes = align_allocation_size(size, _min_elem_size);
+  void* const allocation = JfrCHeapObj::new_array<u1>(aligned_size_bytes + sizeof(T));
+  if (allocation == NULL) {
+    return NULL;
+  }
+  T* const t = new (allocation) T;
+  assert(t != NULL, "invariant");
+  if (!t->initialize(sizeof(T), aligned_size_bytes)) {
+    JfrCHeapObj::free(t, aligned_size_bytes + sizeof(T));
+    return NULL;
+  }
+  return t;
+}
+
+template <typename T, template <typename> class RetrievalType, typename Callback>
+inline void JfrMemorySpace<T, RetrievalType, Callback>::deallocate(T* t) {
+  assert(t != NULL, "invariant");
+  assert(!_free.in_list(t), "invariant");
+  assert(!_full.in_list(t), "invariant");
+  assert(t != NULL, "invariant");
+  JfrCHeapObj::free(t, t->total_size());
+}
+
 template <typename T, template <typename> class RetrievalType, typename Callback>
 inline void JfrMemorySpace<T, RetrievalType, Callback>::release_full(T* t) {
   assert(is_locked(), "invariant");
@@ -122,6 +159,15 @@
   }
 }
 
+template <typename Mspace, typename Callback>
+static inline Mspace* create_mspace(size_t buffer_size, size_t limit, size_t cache_count, Callback* cb) {
+  Mspace* const mspace = new Mspace(buffer_size, limit, cache_count, cb);
+  if (mspace != NULL) {
+    mspace->initialize();
+  }
+  return mspace;
+}
+
 template <typename Mspace>
 inline size_t size_adjustment(size_t size, Mspace* mspace) {
   assert(mspace != NULL, "invariant");
@@ -174,6 +220,15 @@
 }
 
 template <typename Mspace>
+class MspaceLock {
+ private:
+  Mspace* _mspace;
+ public:
+  MspaceLock(Mspace* mspace) : _mspace(mspace) { _mspace->lock(); }
+  ~MspaceLock() { _mspace->unlock(); }
+};
+
+template <typename Mspace>
 inline typename Mspace::Type* mspace_allocate_transient_to_full(size_t size, Mspace* mspace, Thread* thread) {
   typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
   if (t == NULL) return NULL;
@@ -344,6 +399,20 @@
 }
 
 template <typename Mspace>
+class ReleaseOp : public StackObj {
+ private:
+  Mspace* _mspace;
+  Thread* _thread;
+  bool _release_full;
+ public:
+  typedef typename Mspace::Type Type;
+  ReleaseOp(Mspace* mspace, Thread* thread, bool release_full = true) :
+    _mspace(mspace), _thread(thread), _release_full(release_full) {}
+  bool process(Type* t);
+  size_t processed() const { return 0; }
+};
+
+template <typename Mspace>
 inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) {
   assert(t != NULL, "invariant");
   // assumes some means of exclusive access to t
--- a/src/hotspot/share/jfr/support/jfrKlassExtension.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrKlassExtension.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -36,6 +36,7 @@
 #define JDK_JFR_EVENT_SUBKLASS 16
 #define JDK_JFR_EVENT_KLASS    32
 #define EVENT_HOST_KLASS       64
+#define EVENT_RESERVED         128
 #define IS_EVENT_KLASS(ptr) (((ptr)->trace_id() & (JDK_JFR_EVENT_KLASS | JDK_JFR_EVENT_SUBKLASS)) != 0)
 #define ON_KLASS_CREATION(k, p, t) if (IS_EVENT_KLASS(k)) JfrEventClassTransformer::on_klass_creation(k, p, t)
 
--- a/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,13 +25,13 @@
 #include "precompiled.hpp"
 #include "jfr/jfrEvents.hpp"
 #include "jfr/jni/jfrJavaSupport.hpp"
+#include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
 #include "jfr/periodic/jfrThreadCPULoadEvent.hpp"
 #include "jfr/recorder/jfrRecorder.hpp"
 #include "jfr/recorder/checkpoint/jfrCheckpointManager.hpp"
 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
 #include "jfr/recorder/service/jfrOptionSet.hpp"
 #include "jfr/recorder/storage/jfrStorage.hpp"
-#include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
 #include "jfr/support/jfrThreadLocal.hpp"
 #include "memory/allocation.inline.hpp"
 #include "runtime/os.hpp"
@@ -46,7 +46,7 @@
   _shelved_buffer(NULL),
   _stackframes(NULL),
   _trace_id(JfrTraceId::assign_thread_id()),
-  _thread_cp(),
+  _thread(),
   _data_lost(0),
   _stack_trace_id(max_julong),
   _user_time(0),
@@ -62,17 +62,17 @@
   return _data_lost;
 }
 
-bool JfrThreadLocal::has_thread_checkpoint() const {
-  return _thread_cp.valid();
+bool JfrThreadLocal::has_thread_blob() const {
+  return _thread.valid();
 }
 
-void JfrThreadLocal::set_thread_checkpoint(const JfrCheckpointBlobHandle& ref) {
-  assert(!_thread_cp.valid(), "invariant");
-  _thread_cp = ref;
+void JfrThreadLocal::set_thread_blob(const JfrBlobHandle& ref) {
+  assert(!_thread.valid(), "invariant");
+  _thread = ref;
 }
 
-const JfrCheckpointBlobHandle& JfrThreadLocal::thread_checkpoint() const {
-  return _thread_cp;
+const JfrBlobHandle& JfrThreadLocal::thread_blob() const {
+  return _thread;
 }
 
 static void send_java_thread_start_event(JavaThread* jt) {
@@ -95,10 +95,12 @@
   assert(jt != NULL, "invariant");
   assert(Thread::current() == jt, "invariant");
   assert(jt->jfr_thread_local()->trace_id() == id, "invariant");
-  EventThreadEnd event;
-  event.set_thread(id);
-  event.commit();
-  JfrThreadCPULoadEvent::send_event_for_thread(jt);
+  if (JfrRecorder::is_recording()) {
+    EventThreadEnd event;
+    event.set_thread(id);
+    event.commit();
+    JfrThreadCPULoadEvent::send_event_for_thread(jt);
+  }
 }
 
 void JfrThreadLocal::release(JfrThreadLocal* tl, Thread* t) {
@@ -125,10 +127,10 @@
   assert(t != NULL, "invariant");
   JfrThreadLocal * const tl = t->jfr_thread_local();
   assert(!tl->is_dead(), "invariant");
-  if (JfrRecorder::is_recording()) {
-    if (t->is_Java_thread()) {
-      send_java_thread_end_events(tl->thread_id(), (JavaThread*)t);
-    }
+  if (t->is_Java_thread()) {
+    JavaThread* const jt = (JavaThread*)t;
+    ObjectSampleCheckpoint::on_thread_exit(jt);
+    send_java_thread_end_events(tl->thread_id(), jt);
   }
   release(tl, Thread::current()); // because it could be that Thread::current() != t
 }
--- a/src/hotspot/share/jfr/support/jfrThreadLocal.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrThreadLocal.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,7 +25,7 @@
 #ifndef SHARE_JFR_SUPPORT_JFRTHREADLOCAL_HPP
 #define SHARE_JFR_SUPPORT_JFRTHREADLOCAL_HPP
 
-#include "jfr/recorder/checkpoint/jfrCheckpointBlob.hpp"
+#include "jfr/utilities/jfrBlob.hpp"
 #include "jfr/utilities/jfrTypes.hpp"
 
 class JavaThread;
@@ -41,7 +41,7 @@
   JfrBuffer* _shelved_buffer;
   mutable JfrStackFrame* _stackframes;
   mutable traceid _trace_id;
-  JfrCheckpointBlobHandle _thread_cp;
+  JfrBlobHandle _thread;
   u8 _data_lost;
   traceid _stack_trace_id;
   jlong _user_time;
@@ -207,9 +207,9 @@
     return _dead;
   }
 
-  bool has_thread_checkpoint() const;
-  void set_thread_checkpoint(const JfrCheckpointBlobHandle& handle);
-  const JfrCheckpointBlobHandle& thread_checkpoint() const;
+  bool has_thread_blob() const;
+  void set_thread_blob(const JfrBlobHandle& handle);
+  const JfrBlobHandle& thread_blob() const;
 
   static void on_start(Thread* t);
   static void on_exit(Thread* t);
--- a/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/support/jfrTraceIdExtension.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -26,6 +26,7 @@
 #define SHARE_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
 
 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.hpp"
+#include "utilities/macros.hpp"
 
 #define DEFINE_TRACE_ID_FIELD mutable traceid _trace_id
 
@@ -43,39 +44,55 @@
 
 class JfrTraceFlag {
  private:
-  mutable jbyte _flags;
+  mutable jshort _flags;
  public:
   JfrTraceFlag() : _flags(0) {}
-  explicit JfrTraceFlag(jbyte flags) : _flags(flags) {}
-  void set_flag(jbyte flag) const {
-    _flags |= flag;
-  }
-  void clear_flag(jbyte flag) const {
-    _flags &= (~flag);
-  }
-  jbyte flags() const { return _flags; }
-  bool is_set(jbyte flag) const {
+  bool is_set(jshort flag) const {
     return (_flags & flag) != 0;
   }
-  jbyte* const flags_addr() const {
-    return &_flags;
+
+  jshort flags() const {
+    return _flags;
+  }
+
+  void set_flags(jshort flags) const {
+    _flags = flags;
+  }
+
+  jbyte* flags_addr() const {
+#ifdef VM_LITTLE_ENDIAN
+    return (jbyte*)&_flags;
+#else
+    return ((jbyte*)&_flags) + 1;
+#endif
+  }
+
+  jbyte* meta_addr() const {
+#ifdef VM_LITTLE_ENDIAN
+    return (jbyte*)(&_flags) + 1;
+#else
+    return (jbyte*)&_flags;
+#endif
   }
 };
 
 #define DEFINE_TRACE_FLAG mutable JfrTraceFlag _trace_flags
 
 #define DEFINE_TRACE_FLAG_ACCESSOR                 \
-  void set_trace_flag(jbyte flag) const {          \
-    _trace_flags.set_flag(flag);                   \
+  bool is_trace_flag_set(jshort flag) const {      \
+    return _trace_flags.is_set(flag);              \
   }                                                \
-  jbyte trace_flags() const {                      \
+  jshort trace_flags() const {                     \
     return _trace_flags.flags();                   \
   }                                                \
-  bool is_trace_flag_set(jbyte flag) const {       \
-    return _trace_flags.is_set(flag);              \
+  void set_trace_flags(jshort flags) const {       \
+    _trace_flags.set_flags(flags);                 \
   }                                                \
-  jbyte* const trace_flags_addr() const {          \
+  jbyte* trace_flags_addr() const {                \
     return _trace_flags.flags_addr();              \
+  }                                                \
+  jbyte* trace_meta_addr() const {                 \
+    return _trace_flags.meta_addr();               \
   }
 
 #endif // SHARE_JFR_SUPPORT_JFRTRACEIDEXTENSION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrBlob.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jfr/utilities/jfrBlob.hpp"
+
+JfrBlob::JfrBlob(const u1* checkpoint, size_t size) :
+  _data(JfrCHeapObj::new_array<u1>(size)),
+  _next(),
+  _size(size),
+  _written(false) {
+  assert(_data != NULL, "invariant");
+  memcpy(const_cast<u1*>(_data), checkpoint, size);
+}
+
+JfrBlob::~JfrBlob() {
+  JfrCHeapObj::free(const_cast<u1*>(_data), _size);
+}
+
+void JfrBlob::reset_write_state() const {
+  if (!_written) {
+    return;
+  }
+  _written = false;
+  if (_next.valid()) {
+    _next->reset_write_state();
+  }
+}
+
+void JfrBlob::set_next(const JfrBlobHandle& ref) {
+  if (_next == ref) {
+    return;
+  }
+  assert(_next != ref, "invariant");
+  if (_next.valid()) {
+    _next->set_next(ref);
+    return;
+  }
+  _next = ref;
+}
+
+JfrBlobHandle JfrBlob::make(const u1* data, size_t size) {
+  const JfrBlob* const blob = new JfrBlob(data, size);
+  assert(blob != NULL, "invariant");
+  return JfrBlobReference::make(blob);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/utilities/jfrBlob.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_JFR_UTILITIES_JFRBLOB_HPP
+#define SHARE_JFR_UTILITIES_JFRBLOB_HPP
+
+#include "jfr/utilities/jfrAllocation.hpp"
+#include "jfr/utilities/jfrRefCountPointer.hpp"
+
+class JfrBlob;
+typedef RefCountPointer<JfrBlob, MultiThreadedRefCounter> JfrBlobReference;
+typedef RefCountHandle<JfrBlobReference> JfrBlobHandle;
+
+class JfrBlob : public JfrCHeapObj {
+  template <typename, typename>
+  friend class RefCountPointer;
+ private:
+  const u1* const _data;
+  JfrBlobHandle _next;
+  const size_t _size;
+  mutable bool _written;
+
+  JfrBlob(const u1* data, size_t size);
+  ~JfrBlob();
+
+ public:
+  void set_next(const JfrBlobHandle& ref);
+  void reset_write_state() const;
+  static JfrBlobHandle make(const u1* data, size_t size);
+  template <typename Writer>
+  void write(Writer& writer) const {
+    writer.bytes(_data, _size);
+    if (_next.valid()) {
+      _next->write(writer);
+    }
+  }
+  template <typename Writer>
+  void exclusive_write(Writer& writer) const {
+    if (_written) {
+      return;
+    }
+    writer.bytes(_data, _size);
+    _written = true;
+    if (_next.valid()) {
+      _next->exclusive_write(writer);
+    }
+  }
+};
+
+#endif // SHARE_JFR_UTILITIES_JFRBLOB_HPP
--- a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -25,13 +25,13 @@
 #ifndef SHARE_JFR_UTILITIES_JFRHASHTABLE_HPP
 #define SHARE_JFR_UTILITIES_JFRHASHTABLE_HPP
 
-#include "memory/allocation.inline.hpp"
+#include "jfr/utilities/jfrAllocation.hpp"
 #include "runtime/orderAccess.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/macros.hpp"
 
 template <typename T>
-class JfrBasicHashtableEntry {
+class JfrBasicHashtableEntry : public JfrCHeapObj {
  private:
   typedef JfrBasicHashtableEntry<T> Entry;
   Entry* _next;
@@ -39,8 +39,8 @@
   uintptr_t _hash;
 
  public:
+  JfrBasicHashtableEntry(uintptr_t hash, const T& data) : _next(NULL), _literal(data), _hash(hash) {}
   uintptr_t hash() const { return _hash; }
-  void set_hash(uintptr_t hash) { _hash = hash; }
   T literal() const { return _literal; }
   T* literal_addr() { return &_literal; }
   void set_literal(T s) { _literal = s; }
@@ -93,7 +93,6 @@
   }
   void free_buckets() {
     FREE_C_HEAP_ARRAY(Bucket, _buckets);
-    _buckets = NULL;
   }
   TableEntry* bucket(size_t i) { return _buckets[i].get_entry();}
   TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); }
@@ -108,18 +107,18 @@
 };
 
 template <typename IdType, typename Entry, typename T>
-class AscendingId : public CHeapObj<mtTracing>  {
+class AscendingId : public JfrCHeapObj  {
  private:
   IdType _id;
  public:
   AscendingId() : _id(0) {}
   // callbacks
-  void assign_id(Entry* entry) {
+  void on_link(Entry* entry) {
     assert(entry != NULL, "invariant");
     assert(entry->id() == 0, "invariant");
     entry->set_id(++_id);
   }
-  bool equals(const T& data, uintptr_t hash, const Entry* entry) {
+  bool on_equals(uintptr_t hash, const Entry* entry) {
     assert(entry->hash() == hash, "invariant");
     return true;
   }
@@ -127,18 +126,16 @@
 
 // IdType must be scalar
 template <typename T, typename IdType>
-class Entry : public JfrBasicHashtableEntry<T> {
+class JfrHashtableEntry : public JfrBasicHashtableEntry<T> {
  public:
+  JfrHashtableEntry(uintptr_t hash, const T& data) : JfrBasicHashtableEntry<T>(hash, data), _id(0) {}
   typedef IdType ID;
-  void init() { _id = 0; }
   ID id() const { return _id; }
-  void set_id(ID id) { _id = id; }
-  void set_value(const T& value) { this->set_literal(value); }
-  T& value() const { return *const_cast<Entry*>(this)->literal_addr();}
-  const T* value_addr() const { return const_cast<Entry*>(this)->literal_addr(); }
-
+  void set_id(ID id) const { _id = id; }
+  T& value() const { return *const_cast<JfrHashtableEntry*>(this)->literal_addr();}
+  const T* value_addr() const { return const_cast<JfrHashtableEntry*>(this)->literal_addr(); }
  private:
-  ID _id;
+  mutable ID _id;
 };
 
 template <typename T, typename IdType, template <typename, typename> class Entry,
@@ -147,29 +144,28 @@
 class HashTableHost : public JfrBasicHashtable<T> {
  public:
   typedef Entry<T, IdType> HashEntry;
-  HashTableHost() : _callback(new Callback()) {}
-  HashTableHost(Callback* cb) : JfrBasicHashtable<T>(TABLE_SIZE, sizeof(HashEntry)), _callback(cb) {}
+  HashTableHost(size_t size = 0) : JfrBasicHashtable<T>(size == 0 ? TABLE_SIZE : size, sizeof(HashEntry)), _callback(new Callback()) {}
+  HashTableHost(Callback* cb, size_t size = 0) : JfrBasicHashtable<T>(size == 0 ? TABLE_SIZE : size, sizeof(HashEntry)), _callback(cb) {}
   ~HashTableHost() {
     this->clear_entries();
     this->free_buckets();
   }
 
   // direct insert assumes non-existing entry
-  HashEntry& put(const T& data, uintptr_t hash);
+  HashEntry& put(uintptr_t hash, const T& data);
 
   // lookup entry, will put if not found
-  HashEntry& lookup_put(const T& data, uintptr_t hash) {
-    HashEntry* entry = lookup_only(data, hash);
-    return entry == NULL ? put(data, hash) : *entry;
+  HashEntry& lookup_put(uintptr_t hash, const T& data) {
+    HashEntry* entry = lookup_only(hash);
+    return entry == NULL ? put(hash, data) : *entry;
   }
 
-  // read-only lookup
-  HashEntry* lookup_only(const T& query, uintptr_t hash);
+  HashEntry* lookup_only(uintptr_t hash);
 
   // id retrieval
-  IdType id(const T& data, uintptr_t hash) {
+  IdType id(uintptr_t hash, const T& data) {
     assert(data != NULL, "invariant");
-    const HashEntry& entry = lookup_put(data, hash);
+    const HashEntry& entry = lookup_put(hash, data);
     assert(entry.id() > 0, "invariant");
     return entry.id();
   }
@@ -188,34 +184,35 @@
   void free_entry(HashEntry* entry) {
     assert(entry != NULL, "invariant");
     JfrBasicHashtable<T>::unlink_entry(entry);
-    FREE_C_HEAP_ARRAY(char, entry);
+    _callback->on_unlink(entry);
+    delete entry;
   }
 
  private:
   Callback* _callback;
   size_t index_for(uintptr_t hash) { return this->hash_to_index(hash); }
-  HashEntry* new_entry(const T& data, uintptr_t hash);
+  HashEntry* new_entry(uintptr_t hash, const T& data);
   void add_entry(size_t index, HashEntry* new_entry) {
     assert(new_entry != NULL, "invariant");
-    _callback->assign_id(new_entry);
+    _callback->on_link(new_entry);
     assert(new_entry->id() > 0, "invariant");
     JfrBasicHashtable<T>::add_entry(index, new_entry);
   }
 };
 
 template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
-Entry<T, IdType>& HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::put(const T& data, uintptr_t hash) {
-  assert(lookup_only(data, hash) == NULL, "use lookup_put()");
-  HashEntry* const entry = new_entry(data, hash);
+Entry<T, IdType>& HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::put(uintptr_t hash, const T& data) {
+  assert(lookup_only(hash) == NULL, "use lookup_put()");
+  HashEntry* const entry = new_entry(hash, data);
   add_entry(index_for(hash), entry);
   return *entry;
 }
 
 template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
-Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::lookup_only(const T& query, uintptr_t hash) {
+Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::lookup_only(uintptr_t hash) {
   HashEntry* entry = (HashEntry*)this->bucket(index_for(hash));
   while (entry != NULL) {
-    if (entry->hash() == hash && _callback->equals(query, hash, entry)) {
+    if (entry->hash() == hash && _callback->on_equals(hash, entry)) {
       return entry;
     }
     entry = (HashEntry*)entry->next();
@@ -267,13 +264,10 @@
 }
 
 template <typename T, typename IdType, template <typename, typename> class Entry, typename Callback, size_t TABLE_SIZE>
-Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::new_entry(const T& data, uintptr_t hash) {
+Entry<T, IdType>* HashTableHost<T, IdType, Entry, Callback, TABLE_SIZE>::new_entry(uintptr_t hash, const T& data) {
   assert(sizeof(HashEntry) == this->entry_size(), "invariant");
-  HashEntry* const entry = (HashEntry*) NEW_C_HEAP_ARRAY2(char, this->entry_size(), mtTracing, CURRENT_PC);
-  entry->init();
-  entry->set_hash(hash);
-  entry->set_value(data);
-  entry->set_next(NULL);
+  HashEntry* const entry = new HashEntry(hash, data);
+  assert(entry != NULL, "invariant");
   assert(0 == entry->id(), "invariant");
   return entry;
 }
--- a/src/hotspot/share/jfr/utilities/jfrTypes.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/utilities/jfrTypes.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -26,8 +26,6 @@
 #define SHARE_JFR_UTILITIES_JFRTYPES_HPP
 
 #include "jfrfiles/jfrEventIds.hpp"
-#include "memory/allocation.hpp"
-#include "utilities/globalDefinitions.hpp"
 
 typedef u8 traceid;
 typedef int fio_fd;
@@ -37,6 +35,14 @@
 const u4 MIN_STACK_DEPTH = 1;
 const u4 MAX_STACK_DEPTH = 2048;
 
+inline int compare_traceid(const traceid& lhs, const traceid& rhs) {
+  return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0;
+}
+
+inline int sort_traceid(traceid* lhs, traceid* rhs) {
+  return compare_traceid(*lhs, *rhs);
+}
+
 enum EventStartTime {
   UNTIMED,
   TIMED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/jfr/writers/jfrTypeWriterHost.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_JFR_WRITERS_JFRTYPEWRITERHOST_HPP
+#define SHARE_JFR_WRITERS_JFRTYPEWRITERHOST_HPP
+
+#include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
+#include "jfr/utilities/jfrTypes.hpp"
+#include "memory/allocation.hpp"
+
+template <typename WriterImpl, u4 ID>
+class JfrTypeWriterHost : public StackObj {
+ private:
+  WriterImpl _impl;
+  JfrCheckpointWriter* _writer;
+  JfrCheckpointContext _ctx;
+  int64_t _count_offset;
+  int _count;
+  bool _skip_header;
+ public:
+  JfrTypeWriterHost(JfrCheckpointWriter* writer,
+                    bool class_unload = false,
+                    bool skip_header = false) : _impl(writer, class_unload),
+                                                _writer(writer),
+                                                _ctx(writer->context()),
+                                                _count(0),
+                                                _skip_header(skip_header) {
+    assert(_writer != NULL, "invariant");
+    if (!_skip_header) {
+      _writer->write_type((JfrTypeId)ID);
+      _count_offset = _writer->reserve(sizeof(u4)); // Don't know how many yet
+    }
+  }
+
+  ~JfrTypeWriterHost() {
+    if (_count == 0) {
+      // nothing written, restore context for rewind
+      _writer->set_context(_ctx);
+      return;
+    }
+    assert(_count > 0, "invariant");
+    if (!_skip_header) {
+      _writer->write_count(_count, _count_offset);
+    }
+  }
+
+  bool operator()(typename WriterImpl::Type const & value) {
+    this->_count += _impl(value);
+    return true;
+  }
+
+  int count() const   { return _count; }
+  void add(int count) { _count += count; }
+};
+
+typedef int(*type_write_operation)(JfrCheckpointWriter*, const void*);
+
+template <typename T, type_write_operation op>
+class JfrTypeWriterImplHost {
+ private:
+  JfrCheckpointWriter* _writer;
+ public:
+  typedef T Type;
+  JfrTypeWriterImplHost(JfrCheckpointWriter* writer, bool class_unload = false) : _writer(writer) {}
+  int operator()(T const& value) {
+    return op(this->_writer, value);
+  }
+};
+
+template <typename T, typename Predicate, type_write_operation op>
+class JfrPredicatedTypeWriterImplHost : public JfrTypeWriterImplHost<T, op> {
+ private:
+  Predicate _predicate;
+  typedef JfrTypeWriterImplHost<T, op> Parent;
+ public:
+  JfrPredicatedTypeWriterImplHost(JfrCheckpointWriter* writer, bool class_unload = false) :
+    Parent(writer), _predicate(class_unload) {}
+  int operator()(T const& value) {
+    return _predicate(value) ? Parent::operator()(value) : 0;
+  }
+};
+
+#endif // SHARE_JFR_WRITERS_JFRTYPEWRITERHOST_HPP
--- a/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jfr/writers/jfrWriterHost.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -170,7 +170,7 @@
   }
   if (this->available_size() < requested + size_safety_cushion) {
     if (!this->accommodate(this->used_size(), requested + size_safety_cushion)) {
-      this->cancel();
+      assert(!this->is_valid(), "invariant");
       return NULL;
     }
   }
--- a/src/hotspot/share/jvmci/jvmciCompiler.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jvmci/jvmciCompiler.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -123,7 +123,7 @@
     if (excludeModules.not_null()) {
       ModuleEntry* moduleEntry = method->method_holder()->module();
       for (int i = 0; i < excludeModules->length(); i++) {
-        if (oopDesc::equals(excludeModules->obj_at(i), moduleEntry->module())) {
+        if (excludeModules->obj_at(i) == moduleEntry->module()) {
           return true;
         }
       }
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -631,7 +631,7 @@
     // The other thread may exit during this process, which is ok so return false.
     return JNI_FALSE;
   } else {
-    return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0);
+    return (jint) receiverThread->is_interrupted(clear_interrupted != 0);
   }
 JRT_END
 
--- a/src/hotspot/share/memory/filemap.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/memory/filemap.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -460,7 +460,7 @@
     if (e->is_dir()) {
       const char* path = e->name();
       if (!os::dir_is_empty(path)) {
-        tty->print_cr("Error: non-empty directory '%s'", path);
+        log_error(cds)("Error: non-empty directory '%s'", path);
         has_nonempty_dir = true;
       }
     }
--- a/src/hotspot/share/memory/heapShared.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/memory/heapShared.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -125,7 +125,7 @@
   static bool _archive_heap_region_fixed;
 
   static bool oop_equals(oop const& p1, oop const& p2) {
-    return oopDesc::equals(p1, p2);
+    return p1 == p2;
   }
   static unsigned oop_hash(oop const& p);
 
--- a/src/hotspot/share/memory/heapShared.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/memory/heapShared.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -27,6 +27,7 @@
 
 #include "oops/compressedOops.inline.hpp"
 #include "memory/heapShared.hpp"
+#include "utilities/align.hpp"
 #if INCLUDE_G1GC
 #include "gc/g1/g1Allocator.inline.hpp"
 #endif
@@ -40,7 +41,7 @@
 inline oop HeapShared::decode_from_archive(narrowOop v) {
   assert(!CompressedOops::is_null(v), "narrow oop value can never be zero");
   oop result = (oop)(void*)((uintptr_t)_narrow_oop_base + ((uintptr_t)v << _narrow_oop_shift));
-  assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
+  assert(is_object_aligned(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
   return result;
 }
 
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1814,7 +1814,7 @@
       if (klass == NULL &&
           (PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_ClassNotFoundException())) {
         // print a warning only when the pending exception is class not found
-        tty->print_cr("Preload Warning: Cannot find %s", parser.current_class_name());
+        log_warning(cds)("Preload Warning: Cannot find %s", parser.current_class_name());
       }
       CLEAR_PENDING_EXCEPTION;
     }
@@ -1860,7 +1860,7 @@
     ik->link_class(THREAD);
     if (HAS_PENDING_EXCEPTION) {
       ResourceMark rm;
-      tty->print_cr("Preload Warning: Verification failed for %s",
+      log_warning(cds)("Preload Warning: Verification failed for %s",
                     ik->external_name());
       CLEAR_PENDING_EXCEPTION;
       ik->set_in_error_state();
--- a/src/hotspot/share/memory/universe.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/memory/universe.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -571,13 +571,13 @@
   // preallocated errors with backtrace have been consumed. Also need to avoid
   // a potential loop which could happen if an out of memory occurs when attempting
   // to allocate the backtrace.
-  return ((!oopDesc::equals(throwable(), Universe::_out_of_memory_error_java_heap)) &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_metaspace))  &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_class_metaspace))  &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_array_size)) &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_gc_overhead_limit)) &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_realloc_objects)) &&
-          (!oopDesc::equals(throwable(), Universe::_out_of_memory_error_retry)));
+  return ((throwable() != Universe::_out_of_memory_error_java_heap) &&
+          (throwable() != Universe::_out_of_memory_error_metaspace)  &&
+          (throwable() != Universe::_out_of_memory_error_class_metaspace)  &&
+          (throwable() != Universe::_out_of_memory_error_array_size) &&
+          (throwable() != Universe::_out_of_memory_error_gc_overhead_limit) &&
+          (throwable() != Universe::_out_of_memory_error_realloc_objects) &&
+          (throwable() != Universe::_out_of_memory_error_retry));
 }
 
 
--- a/src/hotspot/share/oops/access.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-#include "precompiled.hpp"
-#include "oops/access.inline.hpp"
-#include "oops/accessDecorators.hpp"
-
-// This macro allows instantiating selected accesses to be usable from the
-// access.hpp file, to break dependencies to the access.inline.hpp file.
-#define INSTANTIATE_HPP_ACCESS(decorators, T, barrier_type)  \
-  template struct RuntimeDispatch<DecoratorFixup<decorators>::value, T, barrier_type>
-
-namespace AccessInternal {
-  INSTANTIATE_HPP_ACCESS(DECORATORS_NONE, oop, BARRIER_EQUALS);
-}
--- a/src/hotspot/share/oops/access.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/access.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -58,7 +58,6 @@
 // * arraycopy: Copy data from one heap array to another heap array. The ArrayAccess class has convenience functions for this.
 // * clone: Clone the contents of an object to a newly allocated object.
 // * resolve: Resolve a stable to-space invariant oop that is guaranteed not to relocate its payload until a subsequent thread transition.
-// * equals: Object equality, e.g. when different copies of the same objects are in use (from-space vs. to-space)
 //
 // == IMPLEMENTATION ==
 // Each access goes through the following steps in a template pipeline.
@@ -275,11 +274,6 @@
     verify_decorators<DECORATORS_NONE>();
     return AccessInternal::resolve<decorators>(obj);
   }
-
-  static bool equals(oop o1, oop o2) {
-    verify_decorators<AS_RAW>();
-    return AccessInternal::equals<decorators>(o1, o2);
-  }
 };
 
 // Helper for performing raw accesses (knows only of memory ordering
--- a/src/hotspot/share/oops/access.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/access.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -206,13 +206,6 @@
     }
   };
 
-  template <class GCBarrierType, DecoratorSet decorators>
-  struct PostRuntimeDispatch<GCBarrierType, BARRIER_EQUALS, decorators>: public AllStatic {
-    static bool access_barrier(oop o1, oop o2) {
-      return GCBarrierType::equals(o1, o2);
-    }
-  };
-
   // Resolving accessors with barriers from the barrier set happens in two steps.
   // 1. Expand paths with runtime-decorators, e.g. is UseCompressedOops on or off.
   // 2. Expand paths for each BarrierSet available in the system.
@@ -367,13 +360,6 @@
     _resolve_func = function;
     return function(obj);
   }
-
-  template <DecoratorSet decorators, typename T>
-  bool RuntimeDispatch<decorators, T, BARRIER_EQUALS>::equals_init(oop o1, oop o2) {
-    func_t function = BarrierResolver<decorators, func_t, BARRIER_EQUALS>::resolve_barrier();
-    _equals_func = function;
-    return function(o1, o2);
-  }
 }
 
 #endif // SHARE_OOPS_ACCESS_INLINE_HPP
--- a/src/hotspot/share/oops/accessBackend.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/accessBackend.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -64,8 +64,7 @@
     BARRIER_ATOMIC_XCHG_AT,
     BARRIER_ARRAYCOPY,
     BARRIER_CLONE,
-    BARRIER_RESOLVE,
-    BARRIER_EQUALS
+    BARRIER_RESOLVE
   };
 
   template <DecoratorSet decorators, typename T>
@@ -116,7 +115,6 @@
                                      size_t length);
     typedef void (*clone_func_t)(oop src, oop dst, size_t size);
     typedef oop (*resolve_func_t)(oop obj);
-    typedef bool (*equals_func_t)(oop o1, oop o2);
   };
 
   template <DecoratorSet decorators>
@@ -144,7 +142,6 @@
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_ARRAYCOPY, arraycopy_func_t);
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_CLONE, clone_func_t);
   ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_RESOLVE, resolve_func_t);
-  ACCESS_GENERATE_ACCESS_FUNCTION(BARRIER_EQUALS, equals_func_t);
 #undef ACCESS_GENERATE_ACCESS_FUNCTION
 
   template <DecoratorSet decorators, typename T, BarrierType barrier_type>
@@ -410,8 +407,6 @@
   static void clone(oop src, oop dst, size_t size);
 
   static oop resolve(oop obj) { return obj; }
-
-  static bool equals(oop o1, oop o2) { return (void*)o1 == (void*)o2; }
 };
 
 // Below is the implementation of the first 4 steps of the template pipeline:
@@ -605,18 +600,6 @@
     }
   };
 
-  template <DecoratorSet decorators, typename T>
-  struct RuntimeDispatch<decorators, T, BARRIER_EQUALS>: AllStatic {
-    typedef typename AccessFunction<decorators, T, BARRIER_EQUALS>::type func_t;
-    static func_t _equals_func;
-
-    static bool equals_init(oop o1, oop o2);
-
-    static inline bool equals(oop o1, oop o2) {
-      return _equals_func(o1, o2);
-    }
-  };
-
   // Initialize the function pointers to point to the resolving function.
   template <DecoratorSet decorators, typename T>
   typename AccessFunction<decorators, T, BARRIER_STORE>::type
@@ -662,10 +645,6 @@
   typename AccessFunction<decorators, T, BARRIER_RESOLVE>::type
   RuntimeDispatch<decorators, T, BARRIER_RESOLVE>::_resolve_func = &resolve_init;
 
-  template <DecoratorSet decorators, typename T>
-  typename AccessFunction<decorators, T, BARRIER_EQUALS>::type
-  RuntimeDispatch<decorators, T, BARRIER_EQUALS>::_equals_func = &equals_init;
-
   // Step 3: Pre-runtime dispatching.
   // The PreRuntimeDispatch class is responsible for filtering the barrier strength
   // decorators. That is, for AS_RAW, it hardwires the accesses without a runtime
@@ -996,21 +975,6 @@
     resolve(oop obj) {
       return RuntimeDispatch<decorators, oop, BARRIER_RESOLVE>::resolve(obj);
     }
-
-    template <DecoratorSet decorators>
-    inline static typename EnableIf<
-      HasDecorator<decorators, AS_RAW>::value || HasDecorator<decorators, INTERNAL_BT_TO_SPACE_INVARIANT>::value, bool>::type
-    equals(oop o1, oop o2) {
-      typedef RawAccessBarrier<decorators & RAW_DECORATOR_MASK> Raw;
-      return Raw::equals(o1, o2);
-    }
-
-    template <DecoratorSet decorators>
-    inline static typename EnableIf<
-      !HasDecorator<decorators, AS_RAW>::value && !HasDecorator<decorators, INTERNAL_BT_TO_SPACE_INVARIANT>::value, bool>::type
-    equals(oop o1, oop o2) {
-      return RuntimeDispatch<decorators, oop, BARRIER_EQUALS>::equals(o1, o2);
-    }
   };
 
   // Step 2: Reduce types.
@@ -1309,12 +1273,6 @@
     return PreRuntimeDispatch::resolve<expanded_decorators>(obj);
   }
 
-  template <DecoratorSet decorators>
-  inline bool equals(oop o1, oop o2) {
-    const DecoratorSet expanded_decorators = DecoratorFixup<decorators>::value;
-    return PreRuntimeDispatch::equals<expanded_decorators>(o1, o2);
-  }
-
   // Infer the type that should be returned from an Access::oop_load.
   template <typename P, DecoratorSet decorators>
   class OopLoadProxy: public StackObj {
--- a/src/hotspot/share/oops/compressedOops.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/compressedOops.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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,6 +29,7 @@
 #include "memory/universe.hpp"
 #include "oops/compressedOops.hpp"
 #include "oops/oop.hpp"
+#include "utilities/align.hpp"
 
 // Functions for encoding and decoding compressed oops.
 // If the oops are compressed, the type passed to these overloaded functions
@@ -47,7 +48,7 @@
 inline oop CompressedOops::decode_not_null(narrowOop v) {
   assert(!is_null(v), "narrow oop value can never be zero");
   oop result = decode_raw(v);
-  assert(check_obj_alignment(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
+  assert(is_object_aligned(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result));
   return result;
 }
 
@@ -62,7 +63,7 @@
   assert(OopEncodingHeapMax > pd, "change encoding max if new encoding");
   uint64_t result = pd >> shift();
   assert((result & CONST64(0xffffffff00000000)) == 0, "narrow oop overflow");
-  assert(oopDesc::equals_raw(decode(result), v), "reversibility");
+  assert(decode(result) == v, "reversibility");
   return (narrowOop)result;
 }
 
--- a/src/hotspot/share/oops/constantPool.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/constantPool.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -866,7 +866,7 @@
   if (cache_index >= 0) {
     result_oop = this_cp->resolved_references()->obj_at(cache_index);
     if (result_oop != NULL) {
-      if (oopDesc::equals(result_oop, Universe::the_null_sentinel())) {
+      if (result_oop == Universe::the_null_sentinel()) {
         DEBUG_ONLY(int temp_index = (index >= 0 ? index : this_cp->object_to_cp_index(cache_index)));
         assert(this_cp->tag_at(temp_index).is_dynamic_constant(), "only condy uses the null sentinel");
         result_oop = NULL;
@@ -1096,12 +1096,12 @@
     } else {
       // Return the winning thread's result.  This can be different than
       // the result here for MethodHandles.
-      if (oopDesc::equals(old_result, Universe::the_null_sentinel()))
+      if (old_result == Universe::the_null_sentinel())
         old_result = NULL;
       return old_result;
     }
   } else {
-    assert(!oopDesc::equals(result_oop, Universe::the_null_sentinel()), "");
+    assert(result_oop != Universe::the_null_sentinel(), "");
     return result_oop;
   }
 }
@@ -1154,7 +1154,7 @@
 oop ConstantPool::string_at_impl(const constantPoolHandle& this_cp, int which, int obj_index, TRAPS) {
   // If the string has already been interned, this entry will be non-null
   oop str = this_cp->resolved_references()->obj_at(obj_index);
-  assert(!oopDesc::equals(str, Universe::the_null_sentinel()), "");
+  assert(str != Universe::the_null_sentinel(), "");
   if (str != NULL) return str;
   Symbol* sym = this_cp->unresolved_string_at(which);
   str = StringTable::intern(sym, CHECK_(NULL));
--- a/src/hotspot/share/oops/instanceKlass.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -2717,7 +2717,7 @@
   // and package entries. Both must be the same. This rule
   // applies even to classes that are defined in the unnamed
   // package, they still must have the same class loader.
-  if (oopDesc::equals(classloader1, classloader2) && (classpkg1 == classpkg2)) {
+  if ((classloader1 == classloader2) && (classpkg1 == classpkg2)) {
     return true;
   }
 
@@ -2728,7 +2728,7 @@
 // and classname information is enough to determine a class's package
 bool InstanceKlass::is_same_class_package(oop other_class_loader,
                                           const Symbol* other_class_name) const {
-  if (!oopDesc::equals(class_loader(), other_class_loader)) {
+  if (class_loader() != other_class_loader) {
     return false;
   }
   if (name()->fast_compare(other_class_name) == 0) {
--- a/src/hotspot/share/oops/klassVtable.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/klassVtable.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -491,7 +491,7 @@
           // to link to the first super, and we get all the others.
           Handle super_loader(THREAD, super_klass->class_loader());
 
-          if (!oopDesc::equals(target_loader(), super_loader())) {
+          if (target_loader() != super_loader()) {
             ResourceMark rm(THREAD);
             Symbol* failed_type_symbol =
               SystemDictionary::check_signature_loaders(signature, target_loader,
@@ -1237,7 +1237,7 @@
       // if checkconstraints requested
       if (checkconstraints) {
         Handle method_holder_loader (THREAD, target->method_holder()->class_loader());
-        if (!oopDesc::equals(method_holder_loader(), interface_loader())) {
+        if (method_holder_loader() != interface_loader()) {
           ResourceMark rm(THREAD);
           Symbol* failed_type_symbol =
             SystemDictionary::check_signature_loaders(m->signature(),
--- a/src/hotspot/share/oops/objArrayKlass.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/objArrayKlass.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -212,7 +212,7 @@
 // Either oop or narrowOop depending on UseCompressedOops.
 void ObjArrayKlass::do_copy(arrayOop s, size_t src_offset,
                             arrayOop d, size_t dst_offset, int length, TRAPS) {
-  if (oopDesc::equals(s, d)) {
+  if (s == d) {
     // since source and destination are equal we do not need conversion checks.
     assert(length > 0, "sanity check");
     ArrayAccess<>::oop_arraycopy(s, src_offset, d, dst_offset, length);
--- a/src/hotspot/share/oops/oop.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/oop.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -150,10 +150,6 @@
     }
   }
 
-  inline static bool equals(oop o1, oop o2) { return Access<>::equals(o1, o2); }
-
-  inline static bool equals_raw(oop o1, oop o2) { return RawAccess<>::equals(o1, o2); }
-
   // Access to fields in a instanceOop through these methods.
   template <DecoratorSet decorator>
   oop obj_field_access(int offset) const;
--- a/src/hotspot/share/oops/oopsHierarchy.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/oopsHierarchy.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -23,9 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/shared/barrierSet.hpp"
-#include "gc/shared/collectedHeap.hpp"
-#include "gc/shared/collectedHeap.inline.hpp"
 #include "memory/universe.hpp"
 #include "oops/oopsHierarchy.hpp"
 #include "runtime/thread.inline.hpp"
@@ -56,14 +53,4 @@
   }
 }
 
-bool oop::operator==(const oop o) const {
-  assert(BarrierSet::barrier_set()->oop_equals_operator_allowed(), "Not allowed");
-  return obj() == o.obj();
-}
-
-bool oop::operator!=(const volatile oop o) const {
-  assert(BarrierSet::barrier_set()->oop_equals_operator_allowed(), "Not allowed");
-  return obj() != o.obj();
-}
-
 #endif // CHECK_UNHANDLED_OOPS
--- a/src/hotspot/share/oops/oopsHierarchy.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/oops/oopsHierarchy.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -100,9 +100,9 @@
 
   // General access
   oopDesc*  operator->() const        { return obj(); }
-  bool operator==(const oop o) const;
+  bool operator==(const oop o) const  { return obj() == o.obj(); }
   bool operator==(void *p) const      { return obj() == p; }
-  bool operator!=(const volatile oop o) const;
+  bool operator!=(const volatile oop o) const { return obj() != o.obj(); }
   bool operator!=(void *p) const      { return obj() != p; }
 
   // Assignment
@@ -190,10 +190,6 @@
   return (T)(CHECK_UNHANDLED_OOPS_ONLY((void*))o);
 }
 
-inline bool check_obj_alignment(void* ptr) {
-  return (uintptr_t(ptr) & MinObjAlignmentInBytesMask) == 0;
-}
-
 // The metadata hierarchy is separate from the oop hierarchy
 
 //      class MetaspaceObj
--- a/src/hotspot/share/opto/c2_globals.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/opto/c2_globals.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -510,7 +510,7 @@
           "Sets max value cached by the java.lang.Integer autobox cache")   \
           range(0, max_jint)                                                \
                                                                             \
-  experimental(bool, AggressiveUnboxing, true,                              \
+  diagnostic(bool, AggressiveUnboxing, true,                                \
           "Control optimizations for aggressive boxing elimination")        \
                                                                             \
   develop(bool, TracePostallocExpand, false, "Trace expanding nodes after"  \
--- a/src/hotspot/share/prims/jni.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/jni.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -568,7 +568,7 @@
   oop super_mirror = JNIHandles::resolve_non_null(super);
   if (java_lang_Class::is_primitive(sub_mirror) ||
       java_lang_Class::is_primitive(super_mirror)) {
-    jboolean ret = oopDesc::equals(sub_mirror, super_mirror);
+    jboolean ret = (sub_mirror == super_mirror);
 
     HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret);
     return ret;
--- a/src/hotspot/share/prims/jvm.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/jvm.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1257,7 +1257,7 @@
       protection_domain = method->method_holder()->protection_domain();
     }
 
-    if ((!oopDesc::equals(previous_protection_domain, protection_domain)) && (protection_domain != NULL)) {
+    if ((previous_protection_domain != protection_domain) && (protection_domain != NULL)) {
       local_array->push(protection_domain);
       previous_protection_domain = protection_domain;
     }
@@ -2974,7 +2974,7 @@
     THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
   }
 
-  if (Thread::is_interrupted (THREAD, true) && !HAS_PENDING_EXCEPTION) {
+  if (thread->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {
     THROW_MSG(vmSymbols::java_lang_InterruptedException(), "sleep interrupted");
   }
 
@@ -3071,7 +3071,7 @@
   bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
   if (is_alive) {
     // jthread refers to a live JavaThread.
-    Thread::interrupt(receiver);
+    receiver->interrupt();
   }
 JVM_END
 
@@ -3084,7 +3084,7 @@
   bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
   if (is_alive) {
     // jthread refers to a live JavaThread.
-    return (jboolean) Thread::is_interrupted(receiver, clear_interrupted != 0);
+    return (jboolean) receiver->is_interrupted(clear_interrupted != 0);
   } else {
     return JNI_FALSE;
   }
--- a/src/hotspot/share/prims/jvmtiEnv.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1101,7 +1101,7 @@
     return err;
   }
 
-  Thread::interrupt(java_thread);
+  java_thread->interrupt();
 
   return JVMTI_ERROR_NONE;
 } /* end InterruptThread */
--- a/src/hotspot/share/prims/jvmtiRawMonitor.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/jvmtiRawMonitor.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -373,8 +373,12 @@
   OrderAccess::fence() ;
 
   // check interrupt event
-  if (interruptible && Thread::is_interrupted(THREAD, true)) {
-    return OM_INTERRUPTED;
+  if (interruptible) {
+    assert(THREAD->is_Java_thread(), "Only JavaThreads can be interruptible");
+    JavaThread* jt = (JavaThread*) THREAD;
+    if (jt->is_interrupted(true)) {
+      return OM_INTERRUPTED;
+    }
   }
 
   intptr_t save = _recursions ;
@@ -401,8 +405,11 @@
   }
   guarantee (THREAD == _owner, "invariant") ;
 
-  if (interruptible && Thread::is_interrupted(THREAD, true)) {
-    return OM_INTERRUPTED;
+  if (interruptible) {
+    JavaThread* jt = (JavaThread*) THREAD;
+    if (jt->is_interrupted(true)) {
+      return OM_INTERRUPTED;
+    }
   }
   return OM_OK ;
 }
--- a/src/hotspot/share/prims/jvmtiTagMap.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/jvmtiTagMap.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -105,7 +105,7 @@
   }
 
   inline bool equals(oop object) {
-    return oopDesc::equals(object, object_peek());
+    return object == object_peek();
   }
 
   inline JvmtiTagHashmapEntry* next() const        { return _next; }
--- a/src/hotspot/share/prims/methodHandles.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/methodHandles.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1003,7 +1003,7 @@
         if (!java_lang_invoke_MemberName::is_instance(result()))
           return -99;  // caller bug!
         oop saved = MethodHandles::init_field_MemberName(result, st.field_descriptor());
-        if (!oopDesc::equals(saved, result()))
+        if (saved != result())
           results->obj_at_put(rfill-1, saved);  // show saved instance to user
       } else if (++overflow >= overflow_limit) {
         match_flags = 0; break; // got tired of looking at overflow
@@ -1055,7 +1055,7 @@
           return -99;  // caller bug!
         CallInfo info(m, NULL, CHECK_0);
         oop saved = MethodHandles::init_method_MemberName(result, info);
-        if (!oopDesc::equals(saved, result()))
+        if (saved != result())
           results->obj_at_put(rfill-1, saved);  // show saved instance to user
       } else if (++overflow >= overflow_limit) {
         match_flags = 0; break; // got tired of looking at overflow
--- a/src/hotspot/share/prims/stackwalk.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/stackwalk.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -50,7 +50,7 @@
 bool BaseFrameStream::check_magic(objArrayHandle frames_array) {
   oop   m1 = frames_array->obj_at(magic_pos);
   jlong m2 = _anchor;
-  if (oopDesc::equals(m1, _thread->threadObj()) && m2 == address_value())  return true;
+  if (m1 == _thread->threadObj() && m2 == address_value())  return true;
   return false;
 }
 
@@ -81,7 +81,7 @@
 {
   assert(thread != NULL && thread->is_Java_thread(), "");
   oop m1 = frames_array->obj_at(magic_pos);
-  if (!oopDesc::equals(m1, thread->threadObj())) return NULL;
+  if (m1 != thread->threadObj()) return NULL;
   if (magic == 0L)                    return NULL;
   BaseFrameStream* stream = (BaseFrameStream*) (intptr_t) magic;
   if (!stream->is_valid_in(thread, frames_array))   return NULL;
--- a/src/hotspot/share/prims/unsafe.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/prims/unsafe.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -935,7 +935,7 @@
   oop p = JNIHandles::resolve(obj);
   assert_field_offset_sane(p, offset);
   oop ret = HeapAccess<ON_UNKNOWN_OOP_REF>::oop_atomic_cmpxchg_at(x, p, (ptrdiff_t)offset, e);
-  return oopDesc::equals(ret, e);
+  return ret == e;
 } UNSAFE_END
 
 UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
--- a/src/hotspot/share/runtime/arguments.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/arguments.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -539,6 +539,7 @@
   { "FlightRecorder",               JDK_Version::jdk(13), JDK_Version::undefined(), JDK_Version::undefined() },
   { "FieldsAllocationStyle",        JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) },
   { "CompactFields",                JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) },
+  { "MonitorBound",                 JDK_Version::jdk(14), JDK_Version::jdk(15), JDK_Version::jdk(16) },
 
   // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
   { "DefaultMaxRAMFraction",        JDK_Version::jdk(8),  JDK_Version::undefined(), JDK_Version::undefined() },
--- a/src/hotspot/share/runtime/biasedLocking.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/biasedLocking.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -257,7 +257,7 @@
   BasicLock* highest_lock = NULL;
   for (int i = 0; i < cached_monitor_info->length(); i++) {
     MonitorInfo* mon_info = cached_monitor_info->at(i);
-    if (oopDesc::equals(mon_info->owner(), obj)) {
+    if (mon_info->owner() == obj) {
       log_trace(biasedlocking)("   mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")",
                                p2i((void *) mon_info->owner()),
                                p2i((void *) obj));
@@ -693,7 +693,7 @@
   BasicLock* highest_lock = NULL;
   for (int i = 0; i < cached_monitor_info->length(); i++) {
     MonitorInfo* mon_info = cached_monitor_info->at(i);
-    if (oopDesc::equals(mon_info->owner(), obj)) {
+    if (mon_info->owner() == obj) {
       log_trace(biasedlocking)("   mon_info->owner (" PTR_FORMAT ") == obj (" PTR_FORMAT ")",
                                p2i(mon_info->owner()),
                                p2i(obj));
--- a/src/hotspot/share/runtime/globals.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/globals.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -713,7 +713,7 @@
           "Use LWP-based instead of libthread-based synchronization "       \
           "(SPARC only)")                                                   \
                                                                             \
-  product(intx, MonitorBound, 0, "Bound Monitor population")                \
+  product(intx, MonitorBound, 0, "(Deprecated) Bound Monitor population")   \
           range(0, max_jint)                                                \
                                                                             \
   experimental(intx, MonitorUsedDeflationThreshold, 90,                     \
--- a/src/hotspot/share/runtime/handles.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/handles.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -79,8 +79,8 @@
   oop     operator () () const                   { return obj(); }
   oop     operator -> () const                   { return non_null_obj(); }
 
-  bool operator == (oop o) const                 { return oopDesc::equals(obj(), o); }
-  bool operator == (const Handle& h) const       { return oopDesc::equals(obj(), h.obj()); }
+  bool operator == (oop o) const                 { return obj() == o; }
+  bool operator == (const Handle& h) const       { return obj() == h.obj(); }
 
   // Null checks
   bool    is_null() const                        { return _handle == NULL; }
--- a/src/hotspot/share/runtime/jniHandles.inline.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/jniHandles.inline.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -84,7 +84,7 @@
 inline bool JNIHandles::is_same_object(jobject handle1, jobject handle2) {
   oop obj1 = resolve_no_keepalive(handle1);
   oop obj2 = resolve_no_keepalive(handle2);
-  return oopDesc::equals(obj1, obj2);
+  return obj1 == obj2;
 }
 
 inline oop JNIHandles::resolve_non_null(jobject handle) {
--- a/src/hotspot/share/runtime/objectMonitor.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/objectMonitor.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1205,7 +1205,7 @@
   EventJavaMonitorWait event;
 
   // check for a pending interrupt
-  if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
+  if (interruptible && jt->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {
     // post monitor waited event.  Note that this is past-tense, we are done waiting.
     if (JvmtiExport::should_post_monitor_waited()) {
       // Note: 'false' parameter is passed here because the
@@ -1275,7 +1275,7 @@
       // Thread is in thread_blocked state and oop access is unsafe.
       jt->set_suspend_equivalent();
 
-      if (interruptible && (Thread::is_interrupted(THREAD, false) || HAS_PENDING_EXCEPTION)) {
+      if (interruptible && (jt->is_interrupted(false) || HAS_PENDING_EXCEPTION)) {
         // Intentionally empty
       } else if (node._notified == 0) {
         if (millis <= 0) {
@@ -1401,7 +1401,7 @@
   if (!WasNotified) {
     // no, it could be timeout or Thread.interrupt() or both
     // check for interrupt event, otherwise it is timeout
-    if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
+    if (interruptible && jt->is_interrupted(true) && !HAS_PENDING_EXCEPTION) {
       THROW(vmSymbols::java_lang_InterruptedException());
     }
   }
--- a/src/hotspot/share/runtime/os.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/os.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -482,9 +482,6 @@
   static OSReturn set_priority(Thread* thread, ThreadPriority priority);
   static OSReturn get_priority(const Thread* const thread, ThreadPriority& priority);
 
-  static void interrupt(Thread* thread);
-  static bool is_interrupted(Thread* thread, bool clear_interrupted);
-
   static int pd_self_suspend_thread(Thread* thread);
 
   static ExtendedPC fetch_frame_from_context(const void* ucVoid, intptr_t** sp, intptr_t** fp);
--- a/src/hotspot/share/runtime/osThread.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/osThread.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -30,7 +30,7 @@
   pd_initialize();
   set_start_proc(start_proc);
   set_start_parm(start_parm);
-  set_interrupted(false);
+  _interrupted = 0;
 }
 
 OSThread::~OSThread() {
--- a/src/hotspot/share/runtime/osThread.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/osThread.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -82,10 +82,11 @@
   void set_start_proc(OSThreadStartFunc start_proc) { _start_proc = start_proc; }
   void* start_parm() const                          { return _start_parm; }
   void set_start_parm(void* start_parm)             { _start_parm = start_parm; }
-
+  // These are specialized on Windows.
+#ifndef _WINDOWS
   volatile bool interrupted() const                 { return _interrupted != 0; }
   void set_interrupted(bool z)                      { _interrupted = z ? 1 : 0; }
-
+#endif
   // Printing
   void print_on(outputStream* st) const;
   void print() const;
--- a/src/hotspot/share/runtime/synchronizer.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/synchronizer.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -171,7 +171,7 @@
 
   if (mark.has_monitor()) {
     ObjectMonitor* const mon = mark.monitor();
-    assert(oopDesc::equals((oop) mon->object(), obj), "invariant");
+    assert(mon->object() == obj, "invariant");
     if (mon->owner() != self) return false;  // slow-path for IMS exception
 
     if (mon->first_waiter() != NULL) {
@@ -215,7 +215,7 @@
 
   if (mark.has_monitor()) {
     ObjectMonitor* const m = mark.monitor();
-    assert(oopDesc::equals((oop) m->object(), obj), "invariant");
+    assert(m->object() == obj, "invariant");
     Thread* const owner = (Thread *) m->_owner;
 
     // Lock contention and Transactional Lock Elision (TLE) diagnostics
@@ -1301,7 +1301,7 @@
       ObjectMonitor* inf = mark.monitor();
       markWord dmw = inf->header();
       assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
-      assert(oopDesc::equals((oop) inf->object(), object), "invariant");
+      assert(inf->object() == object, "invariant");
       assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid");
       return inf;
     }
--- a/src/hotspot/share/runtime/thread.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/thread.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -166,7 +166,7 @@
 
 #ifndef USE_LIBRARY_BASED_TLS_ONLY
 // Current thread is maintained as a thread-local variable
-THREAD_LOCAL_DECL Thread* Thread::_thr_current = NULL;
+THREAD_LOCAL Thread* Thread::_thr_current = NULL;
 #endif
 
 // ======= Thread ========
@@ -856,19 +856,6 @@
   return true;
 }
 
-void Thread::interrupt(Thread* thread) {
-  debug_only(check_for_dangling_thread_pointer(thread);)
-  os::interrupt(thread);
-}
-
-bool Thread::is_interrupted(Thread* thread, bool clear_interrupted) {
-  debug_only(check_for_dangling_thread_pointer(thread);)
-  // Note:  If clear_interrupted==false, this simply fetches and
-  // returns the value of the field osthread()->interrupted().
-  return os::is_interrupted(thread, clear_interrupted);
-}
-
-
 // GC Support
 bool Thread::claim_par_threads_do(uintx claim_token) {
   uintx token = _threads_do_token;
@@ -1726,6 +1713,56 @@
   assert(deferred_card_mark().is_empty(), "Default MemRegion ctor");
 }
 
+
+// interrupt support
+
+void JavaThread::interrupt() {
+  debug_only(check_for_dangling_thread_pointer(this);)
+
+  if (!osthread()->interrupted()) {
+    osthread()->set_interrupted(true);
+    // More than one thread can get here with the same value of osthread,
+    // resulting in multiple notifications.  We do, however, want the store
+    // to interrupted() to be visible to other threads before we execute unpark().
+    OrderAccess::fence();
+
+    // For JavaThread::sleep. Historically we only unpark if changing to the interrupted
+    // state, in contrast to the other events below. Not clear exactly why.
+    _SleepEvent->unpark();
+  }
+
+  // For JSR166. Unpark even if interrupt status already was set.
+  parker()->unpark();
+
+  // For ObjectMonitor and JvmtiRawMonitor
+  _ParkEvent->unpark();
+}
+
+
+bool JavaThread::is_interrupted(bool clear_interrupted) {
+  debug_only(check_for_dangling_thread_pointer(this);)
+  bool interrupted = osthread()->interrupted();
+
+  // NOTE that since there is no "lock" around the interrupt and
+  // is_interrupted operations, there is the possibility that the
+  // interrupted flag (in osThread) will be "false" but that the
+  // low-level events will be in the signaled state. This is
+  // intentional. The effect of this is that Object.wait() and
+  // LockSupport.park() will appear to have a spurious wakeup, which
+  // is allowed and not harmful, and the possibility is so rare that
+  // it is not worth the added complexity to add yet another lock.
+  // For the sleep event an explicit reset is performed on entry
+  // to JavaThread::sleep, so there is no early return. It has also been
+  // recommended not to put the interrupted flag into the "event"
+  // structure because it hides the issue.
+  if (interrupted && clear_interrupted) {
+    osthread()->set_interrupted(false);
+    // consider thread->_SleepEvent->reset() ... optional optimization
+  }
+
+  return interrupted;
+}
+
 bool JavaThread::reguard_stack(address cur_sp) {
   if (_stack_guard_state != stack_guard_yellow_reserved_disabled
       && _stack_guard_state != stack_guard_reserved_disabled) {
@@ -2370,8 +2407,8 @@
   }
 
 
-  // Interrupt thread so it will wake up from a potential wait()
-  Thread::interrupt(this);
+  // Interrupt thread so it will wake up from a potential wait()/sleep()/park()
+  this->interrupt();
 }
 
 // External suspension mechanism.
@@ -3361,7 +3398,7 @@
 
   for (;;) {
     // interruption has precedence over timing out
-    if (os::is_interrupted(this, true)) {
+    if (this->is_interrupted(true)) {
       return false;
     }
 
@@ -3389,7 +3426,7 @@
       // time moving backwards, should only happen if no monotonic clock
       // not a guarantee() because JVM should not abort on kernel/glibc bugs
       assert(!os::supports_monotonic_clock(),
-             "unexpected time moving backwards detected in os::sleep()");
+             "unexpected time moving backwards detected in JavaThread::sleep()");
     } else {
       millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC;
     }
--- a/src/hotspot/share/runtime/thread.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/thread.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -142,7 +142,7 @@
 
 #ifndef USE_LIBRARY_BASED_TLS_ONLY
   // Current thread is maintained as a thread-local variable
-  static THREAD_LOCAL_DECL Thread* _thr_current;
+  static THREAD_LOCAL Thread* _thr_current;
 #endif
 
   // Thread local data area available to the GC. The internal
@@ -514,8 +514,6 @@
   static void set_priority(Thread* thread, ThreadPriority priority);
   static ThreadPriority get_priority(const Thread* const thread);
   static void start(Thread* thread);
-  static void interrupt(Thread* thr);
-  static bool is_interrupted(Thread* thr, bool clear_interrupted);
 
   void set_native_thread_name(const char *name) {
     assert(Thread::current() == this, "set_native_thread_name can only be called on the current thread");
@@ -2055,9 +2053,14 @@
   InstanceKlass* _class_to_be_initialized;
 
   // java.lang.Thread.sleep support
+  ParkEvent * _SleepEvent;
 public:
-  ParkEvent * _SleepEvent;
   bool sleep(jlong millis);
+
+  // java.lang.Thread interruption support
+  void interrupt();
+  bool is_interrupted(bool clear_interrupted);
+
 };
 
 // Inline implementation of JavaThread::current
--- a/src/hotspot/share/runtime/vframe.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/runtime/vframe.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -135,7 +135,7 @@
     //
     // Skip the monitor that the thread is blocked to enter or waiting on
     //
-    if (!found_first_monitor && (oopDesc::equals(obj, pending_obj) || oopDesc::equals(obj, waiting_obj))) {
+    if (!found_first_monitor && (obj == pending_obj || obj == waiting_obj)) {
       continue;
     }
     found_first_monitor = true;
--- a/src/hotspot/share/services/memoryManager.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/services/memoryManager.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -70,7 +70,7 @@
 
   int add_pool(MemoryPool* pool);
 
-  bool is_manager(instanceHandle mh)     { return oopDesc::equals(mh(), _memory_mgr_obj); }
+  bool is_manager(instanceHandle mh)     { return mh() == _memory_mgr_obj; }
 
   virtual instanceOop get_memory_manager_instance(TRAPS);
   virtual bool is_gc_memory_manager()    { return false; }
--- a/src/hotspot/share/services/memoryPool.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/services/memoryPool.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -95,7 +95,7 @@
   // max size could be changed
   virtual size_t max_size()    const       { return _max_size; }
 
-  bool is_pool(instanceHandle pool) { return oopDesc::equals(pool(), _memory_pool_obj); }
+  bool is_pool(instanceHandle pool) { return pool() == _memory_pool_obj; }
 
   bool available_for_allocation()   { return _available_for_allocation; }
   bool set_available_for_allocation(bool value) {
--- a/src/hotspot/share/services/threadService.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/services/threadService.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -680,7 +680,7 @@
     for (int j = 0; j < len; j++) {
       oop monitor = locked_monitors->at(j);
       assert(monitor != NULL, "must be a Java object");
-      if (oopDesc::equals(monitor, object)) {
+      if (monitor == object) {
         found = true;
         break;
       }
--- a/src/hotspot/share/utilities/exceptions.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/exceptions.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -435,9 +435,9 @@
 volatile int Exceptions::_out_of_memory_error_class_metaspace_errors = 0;
 
 void Exceptions::count_out_of_memory_exceptions(Handle exception) {
-  if (oopDesc::equals(exception(), Universe::out_of_memory_error_metaspace())) {
+  if (exception() == Universe::out_of_memory_error_metaspace()) {
      Atomic::inc(&_out_of_memory_error_metaspace_errors);
-  } else if (oopDesc::equals(exception(), Universe::out_of_memory_error_class_metaspace())) {
+  } else if (exception() == Universe::out_of_memory_error_class_metaspace()) {
      Atomic::inc(&_out_of_memory_error_class_metaspace_errors);
   } else {
      // everything else reported as java heap OOM
--- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -254,9 +254,7 @@
 #define JLONG_FORMAT_W(width) "%" #width "ld"
 #endif // _LP64 && __APPLE__
 
-#ifndef USE_LIBRARY_BASED_TLS_ONLY
-#define THREAD_LOCAL_DECL __thread
-#endif
+#define THREAD_LOCAL __thread
 
 // Inlining support
 #define NOINLINE     __attribute__ ((noinline))
--- a/src/hotspot/share/utilities/globalDefinitions_solstudio.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/globalDefinitions_solstudio.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -245,9 +245,7 @@
 
 #define offset_of(klass,field) offsetof(klass,field)
 
-#ifndef USE_LIBRARY_BASED_TLS_ONLY
-#define THREAD_LOCAL_DECL __thread
-#endif
+#define THREAD_LOCAL __thread
 
 // Inlining support
 #define NOINLINE
--- a/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/globalDefinitions_visCPP.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -153,9 +153,7 @@
 
 #define offset_of(klass,field) offsetof(klass,field)
 
-#ifndef USE_LIBRARY_BASED_TLS_ONLY
-#define THREAD_LOCAL_DECL __declspec( thread )
-#endif
+#define THREAD_LOCAL __declspec(thread)
 
 // Inlining support
 // MSVC has '__declspec(noinline)' but according to the official documentation
--- a/src/hotspot/share/utilities/globalDefinitions_xlc.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/globalDefinitions_xlc.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -130,10 +130,6 @@
 // AIX 5.3 has buggy __thread support. (see JDK-8176442).
 #define USE_LIBRARY_BASED_TLS_ONLY 1
 
-#ifndef USE_LIBRARY_BASED_TLS_ONLY
-#define THREAD_LOCAL_DECL __thread
-#endif
-
 // Inlining support
 //
 // Be aware that for function/method declarations, xlC only supports the following
--- a/src/hotspot/share/utilities/growableArray.hpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/growableArray.hpp	Wed Sep 18 07:46:02 2019 +0200
@@ -218,15 +218,6 @@
 
   void print();
 
-  inline static bool safe_equals(oop obj1, oop obj2) {
-    return oopDesc::equals(obj1, obj2);
-  }
-
-  template <class X>
-  inline static bool safe_equals(X i1, X i2) {
-    return i1 == i2;
-  }
-
   int append(const E& elem) {
     check_nesting();
     if (_len == _max) grow(_len);
@@ -311,7 +302,7 @@
 
   bool contains(const E& elem) const {
     for (int i = 0; i < _len; i++) {
-      if (safe_equals(_data[i], elem)) return true;
+      if (_data[i] == elem) return true;
     }
     return false;
   }
--- a/src/hotspot/share/utilities/ostream.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/hotspot/share/utilities/ostream.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -99,13 +99,14 @@
     result_len = strlen(result);
     if (add_cr && result_len >= buflen)  result_len = buflen-1;  // truncate
   } else {
-    int written = os::vsnprintf(buffer, buflen, format, ap);
-    assert(written >= 0, "vsnprintf encoding error");
+    int required_len = os::vsnprintf(buffer, buflen, format, ap);
+    assert(required_len >= 0, "vsnprintf encoding error");
     result = buffer;
-    if ((size_t)written < buflen) {
-      result_len = written;
+    if ((size_t)required_len < buflen) {
+      result_len = required_len;
     } else {
-      DEBUG_ONLY(warning("increase O_BUFLEN in ostream.hpp -- output truncated");)
+      DEBUG_ONLY(warning("outputStream::do_vsnprintf output truncated -- buffer length is %d bytes but %d bytes are needed.",
+                         add_cr ? (int)buflen + 1 : (int)buflen, add_cr ? required_len + 2 : required_len + 1);)
       result_len = buflen - 1;
     }
   }
--- a/src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/macosx/classes/sun/nio/fs/BsdFileStore.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -62,22 +62,14 @@
         }
 
         // step 2: find mount point
-        UnixPath parent = path.getParent();
-        while (parent != null) {
-            UnixFileAttributes attrs = null;
-            try {
-                attrs = UnixFileAttributes.get(parent, true);
-            } catch (UnixException x) {
-                x.rethrowAsIOException(parent);
-            }
-            if (attrs.dev() != dev())
-                break;
-            path = parent;
-            parent = parent.getParent();
+        byte[] dir = null;
+        try {
+            dir = BsdNativeDispatcher.getmntonname(path);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(path);
         }
 
         // step 3: lookup mounted file systems
-        byte[] dir = path.asByteArray();
         for (UnixMountEntry entry: fs.getMountEntries()) {
             if (Arrays.equals(dir, entry.dir()))
                 return entry;
--- a/src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/macosx/classes/sun/nio/fs/BsdNativeDispatcher.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,6 +51,20 @@
     */
     static native void endfsstat(long iter) throws UnixException;
 
+    /**
+     * int statfs(const char *path, struct statfs *buf);
+     * returns buf->f_mntonname (directory on which mounted)
+     */
+    static byte[] getmntonname(UnixPath path) throws UnixException {
+        NativeBuffer pathBuffer = copyToNativeBuffer(path);
+        try {
+            return getmntonname0(pathBuffer.address());
+        } finally {
+            pathBuffer.release();
+        }
+    }
+    static native byte[] getmntonname0(long pathAddress) throws UnixException;
+
     // initialize field IDs
     private static native void initIDs();
 
--- a/src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/macosx/native/libnio/fs/BsdNativeDispatcher.c	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -203,3 +203,24 @@
         free(iter);
     }
 }
+
+JNIEXPORT jbyteArray JNICALL
+Java_sun_nio_fs_BsdNativeDispatcher_getmntonname0(JNIEnv *env, jclass this,
+    jlong pathAddress)
+{
+    struct statfs buf;
+    const char* path = (const char*)jlong_to_ptr(pathAddress);
+
+    if (statfs(path, &buf) != 0) {
+        throwUnixException(env, errno);
+    }
+
+    jsize len = strlen(buf.f_mntonname);
+    jbyteArray mntonname = (*env)->NewByteArray(env, len);
+    if (mntonname != NULL) {
+        (*env)->SetByteArrayRegion(env, mntonname, 0, len,
+            (jbyte*)buf.f_mntonname);
+    }
+
+    return mntonname;
+}
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Sep 18 07:46:02 2019 +0200
@@ -385,7 +385,7 @@
      * cases where old nodes can be reused because their next fields
      * won't change.  On average, only about one-sixth of them need
      * cloning when a table doubles. The nodes they replace will be
-     * garbage collectable as soon as they are no longer referenced by
+     * garbage collectible as soon as they are no longer referenced by
      * any reader thread that may be in the midst of concurrently
      * traversing table.  Upon transfer, the old table bin contains
      * only a special forwarding node (with hash field "MOVED") that
@@ -3286,9 +3286,8 @@
             return true;
         }
 
-        private static final Unsafe U = Unsafe.getUnsafe();
         private static final long LOCKSTATE
-                = U.objectFieldOffset(TreeBin.class, "lockState");
+            = U.objectFieldOffset(TreeBin.class, "lockState");
     }
 
     /* ----------------Table Traversal -------------- */
@@ -6345,28 +6344,20 @@
 
     // Unsafe mechanics
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long SIZECTL;
-    private static final long TRANSFERINDEX;
-    private static final long BASECOUNT;
-    private static final long CELLSBUSY;
-    private static final long CELLVALUE;
-    private static final int ABASE;
+    private static final long SIZECTL
+        = U.objectFieldOffset(ConcurrentHashMap.class, "sizeCtl");
+    private static final long TRANSFERINDEX
+        = U.objectFieldOffset(ConcurrentHashMap.class, "transferIndex");
+    private static final long BASECOUNT
+        = U.objectFieldOffset(ConcurrentHashMap.class, "baseCount");
+    private static final long CELLSBUSY
+        = U.objectFieldOffset(ConcurrentHashMap.class, "cellsBusy");
+    private static final long CELLVALUE
+        = U.objectFieldOffset(CounterCell.class, "value");
+    private static final int ABASE = U.arrayBaseOffset(Node[].class);
     private static final int ASHIFT;
 
     static {
-        SIZECTL = U.objectFieldOffset
-            (ConcurrentHashMap.class, "sizeCtl");
-        TRANSFERINDEX = U.objectFieldOffset
-            (ConcurrentHashMap.class, "transferIndex");
-        BASECOUNT = U.objectFieldOffset
-            (ConcurrentHashMap.class, "baseCount");
-        CELLSBUSY = U.objectFieldOffset
-            (ConcurrentHashMap.class, "cellsBusy");
-
-        CELLVALUE = U.objectFieldOffset
-            (CounterCell.class, "value");
-
-        ABASE = U.arrayBaseOffset(Node[].class);
         int scale = U.arrayIndexScale(Node[].class);
         if ((scale & (scale - 1)) != 0)
             throw new ExceptionInInitializerError("array index scale not a power of two");
--- a/src/java.base/share/classes/java/util/concurrent/Phaser.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/Phaser.java	Wed Sep 18 07:46:02 2019 +0200
@@ -97,7 +97,7 @@
  *       associated recovery within handlers of those exceptions,
  *       often after invoking {@code forceTermination}.  Phasers may
  *       also be used by tasks executing in a {@link ForkJoinPool}.
- *       Progress is ensured if the pool's parallelismLevel can
+ *       Progress is ensured if the pool's parallelism level can
  *       accommodate the maximum number of simultaneously blocked
  *       parties.
  *
--- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1053,18 +1053,18 @@
 
     // Unsafe mechanics
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long SEED = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSeed");
-    private static final long PROBE = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomProbe");
-    private static final long SECONDARY = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSecondarySeed");
-    private static final long THREADLOCALS = U.objectFieldOffset
-            (Thread.class, "threadLocals");
-    private static final long INHERITABLETHREADLOCALS = U.objectFieldOffset
-            (Thread.class, "inheritableThreadLocals");
-    private static final long INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
-            (Thread.class, "inheritedAccessControlContext");
+    private static final long SEED
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomSeed");
+    private static final long PROBE
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomProbe");
+    private static final long SECONDARY
+        = U.objectFieldOffset(Thread.class, "threadLocalRandomSecondarySeed");
+    private static final long THREADLOCALS
+        = U.objectFieldOffset(Thread.class, "threadLocals");
+    private static final long INHERITABLETHREADLOCALS
+        = U.objectFieldOffset(Thread.class, "inheritableThreadLocals");
+    private static final long INHERITEDACCESSCONTROLCONTEXT
+        = U.objectFieldOffset(Thread.class, "inheritedAccessControlContext");
 
     /** Rarely-used holder for the second of a pair of Gaussians */
     private static final ThreadLocal<Double> nextLocalGaussian =
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicInteger.java	Wed Sep 18 07:46:02 2019 +0200
@@ -38,6 +38,7 @@
 import java.lang.invoke.VarHandle;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
+import jdk.internal.misc.Unsafe;
 
 /**
  * An {@code int} value that may be updated atomically.  See the
@@ -58,8 +59,9 @@
      * This class intended to be implemented using VarHandles, but there
      * are unresolved cyclic startup dependencies.
      */
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long VALUE
+        = U.objectFieldOffset(AtomicInteger.class, "value");
 
     private volatile int value;
 
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLong.java	Wed Sep 18 07:46:02 2019 +0200
@@ -38,6 +38,7 @@
 import java.lang.invoke.VarHandle;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A {@code long} value that may be updated atomically.  See the
@@ -72,8 +73,9 @@
      * This class intended to be implemented using VarHandles, but there
      * are unresolved cyclic startup dependencies.
      */
-    private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
-    private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long VALUE
+        = U.objectFieldOffset(AtomicLong.class, "value");
 
     private volatile long value;
 
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Sep 18 07:46:02 2019 +0200
@@ -35,13 +35,12 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.AbstractQueuedSynchronizer.Node;
+import java.util.concurrent.ForkJoinPool;
+import jdk.internal.misc.Unsafe;
 
 /**
  * A version of {@link AbstractQueuedSynchronizer} in
@@ -73,23 +72,76 @@
      * keep it that way.
      */
 
-    /**
-     * Creates a new {@code AbstractQueuedLongSynchronizer} instance
-     * with initial synchronization state of zero.
-     */
-    protected AbstractQueuedLongSynchronizer() { }
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
+
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
+
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
+
+        /**
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
+         */
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
+        }
+
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park(this);
+            return true;
+        }
+    }
 
     /**
-     * Head of the wait queue, lazily initialized.  Except for
-     * initialization, it is modified only via method setHead.  Note:
-     * If head exists, its waitStatus is guaranteed not to be
-     * CANCELLED.
+     * Head of the wait queue, lazily initialized.
      */
     private transient volatile Node head;
 
     /**
-     * Tail of the wait queue, lazily initialized.  Modified only via
-     * method enq to add new wait node.
+     * Tail of the wait queue. After initialization, modified only via casTail.
      */
     private transient volatile Node tail;
 
@@ -113,8 +165,7 @@
      * @param newState the new state value
      */
     protected final void setState(long newState) {
-        // See JDK-8180620: Clarify VarHandle mixed-access subtleties
-        STATE.setVolatile(this, newState);
+        state = newState;
     }
 
     /**
@@ -129,481 +180,234 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(long expect, long update) {
-        return STATE.compareAndSet(this, expect, update);
+        return U.compareAndSetLong(this, STATE, expect, update);
     }
 
     // Queuing utilities
 
-    /**
-     * The number of nanoseconds for which it is faster to spin
-     * rather than to use timed park. A rough estimate suffices
-     * to improve responsiveness with very short timeouts.
-     */
-    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
 
     /**
-     * Inserts node into queue, initializing if necessary. See picture above.
-     * @param node the node to insert
-     * @return node's predecessor
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
      */
-    private Node enq(Node node) {
-        for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return oldTail;
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
                 }
-            } else {
-                initializeSyncQueue();
             }
         }
     }
 
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
     /**
-     * Creates and enqueues node for current thread and given mode.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
      *
-     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
-     * @return the new node
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
      */
-    private Node addWaiter(Node mode) {
-        Node node = new Node(mode);
+    final int acquire(Node node, long arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
 
         for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return node;
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
                 }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
             } else {
-                initializeSyncQueue();
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
             }
         }
     }
 
     /**
-     * Sets head of queue to be node, thus dequeuing. Called only by
-     * acquire methods.  Also nulls out unused fields for sake of GC
-     * and to suppress unnecessary signals and traversals.
-     *
-     * @param node the node
-     */
-    private void setHead(Node node) {
-        head = node;
-        node.thread = null;
-        node.prev = null;
-    }
-
-    /**
-     * Wakes up node's successor, if one exists.
-     *
-     * @param node the node
-     */
-    private void unparkSuccessor(Node node) {
-        /*
-         * If status is negative (i.e., possibly needing signal) try
-         * to clear in anticipation of signalling.  It is OK if this
-         * fails or if status is changed by waiting thread.
-         */
-        int ws = node.waitStatus;
-        if (ws < 0)
-            node.compareAndSetWaitStatus(ws, 0);
-
-        /*
-         * Thread to unpark is held in successor, which is normally
-         * just the next node.  But if cancelled or apparently null,
-         * traverse backwards from tail to find the actual
-         * non-cancelled successor.
-         */
-        Node s = node.next;
-        if (s == null || s.waitStatus > 0) {
-            s = null;
-            for (Node p = tail; p != node && p != null; p = p.prev)
-                if (p.waitStatus <= 0)
-                    s = p;
-        }
-        if (s != null)
-            LockSupport.unpark(s.thread);
-    }
-
-    /**
-     * Release action for shared mode -- signals successor and ensures
-     * propagation. (Note: For exclusive mode, release just amounts
-     * to calling unparkSuccessor of head if it needs signal.)
-     */
-    private void doReleaseShared() {
-        /*
-         * Ensure that a release propagates, even if there are other
-         * in-progress acquires/releases.  This proceeds in the usual
-         * way of trying to unparkSuccessor of head if it needs
-         * signal. But if it does not, status is set to PROPAGATE to
-         * ensure that upon release, propagation continues.
-         * Additionally, we must loop in case a new node is added
-         * while we are doing this. Also, unlike other uses of
-         * unparkSuccessor, we need to know if CAS to reset status
-         * fails, if so rechecking.
-         */
-        for (;;) {
-            Node h = head;
-            if (h != null && h != tail) {
-                int ws = h.waitStatus;
-                if (ws == Node.SIGNAL) {
-                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
-                        continue;            // loop to recheck cases
-                    unparkSuccessor(h);
-                }
-                else if (ws == 0 &&
-                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
-                    continue;                // loop on failed CAS
-            }
-            if (h == head)                   // loop if head changed
-                break;
-        }
-    }
-
-    /**
-     * Sets head of queue, and checks if successor may be waiting
-     * in shared mode, if so propagating if either propagate > 0 or
-     * PROPAGATE status was set.
-     *
-     * @param node the node
-     * @param propagate the return value from a tryAcquireShared
-     */
-    private void setHeadAndPropagate(Node node, long propagate) {
-        Node h = head; // Record old head for check below
-        setHead(node);
-        /*
-         * Try to signal next queued node if:
-         *   Propagation was indicated by caller,
-         *     or was recorded (as h.waitStatus either before
-         *     or after setHead) by a previous operation
-         *     (note: this uses sign-check of waitStatus because
-         *      PROPAGATE status may transition to SIGNAL.)
-         * and
-         *   The next node is waiting in shared mode,
-         *     or we don't know, because it appears null
-         *
-         * The conservatism in both of these checks may cause
-         * unnecessary wake-ups, but only when there are multiple
-         * racing acquires/releases, so most need signals now or soon
-         * anyway.
-         */
-        if (propagate > 0 || h == null || h.waitStatus < 0 ||
-            (h = head) == null || h.waitStatus < 0) {
-            Node s = node.next;
-            if (s == null || s.isShared())
-                doReleaseShared();
-        }
-    }
-
-    // Utilities for various versions of acquire
-
-    /**
      * Cancels an ongoing attempt to acquire.
      *
-     * @param node the node
-     */
-    private void cancelAcquire(Node node) {
-        // Ignore if node doesn't exist
-        if (node == null)
-            return;
-
-        node.thread = null;
-
-        // Skip cancelled predecessors
-        Node pred = node.prev;
-        while (pred.waitStatus > 0)
-            node.prev = pred = pred.prev;
-
-        // predNext is the apparent node to unsplice. CASes below will
-        // fail if not, in which case, we lost race vs another cancel
-        // or signal, so no further action is necessary, although with
-        // a possibility that a cancelled node may transiently remain
-        // reachable.
-        Node predNext = pred.next;
-
-        // Can use unconditional write instead of CAS here.
-        // After this atomic step, other Nodes can skip past us.
-        // Before, we are free of interference from other threads.
-        node.waitStatus = Node.CANCELLED;
-
-        // If we are the tail, remove ourselves.
-        if (node == tail && compareAndSetTail(node, pred)) {
-            pred.compareAndSetNext(predNext, null);
-        } else {
-            // If successor needs signal, try to set pred's next-link
-            // so it will get one. Otherwise wake it up to propagate.
-            int ws;
-            if (pred != head &&
-                ((ws = pred.waitStatus) == Node.SIGNAL ||
-                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
-                pred.thread != null) {
-                Node next = node.next;
-                if (next != null && next.waitStatus <= 0)
-                    pred.compareAndSetNext(predNext, next);
-            } else {
-                unparkSuccessor(node);
-            }
-
-            node.next = node; // help GC
-        }
-    }
-
-    /**
-     * Checks and updates status for a node that failed to acquire.
-     * Returns true if thread should block. This is the main signal
-     * control in all acquire loops.  Requires that pred == node.prev.
-     *
-     * @param pred node's predecessor holding status
-     * @param node the node
-     * @return {@code true} if thread should block
-     */
-    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
-        int ws = pred.waitStatus;
-        if (ws == Node.SIGNAL)
-            /*
-             * This node has already set status asking a release
-             * to signal it, so it can safely park.
-             */
-            return true;
-        if (ws > 0) {
-            /*
-             * Predecessor was cancelled. Skip over predecessors and
-             * indicate retry.
-             */
-            do {
-                node.prev = pred = pred.prev;
-            } while (pred.waitStatus > 0);
-            pred.next = node;
-        } else {
-            /*
-             * waitStatus must be 0 or PROPAGATE.  Indicate that we
-             * need a signal, but don't park yet.  Caller will need to
-             * retry to make sure it cannot acquire before parking.
-             */
-            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
-        }
-        return false;
-    }
-
-    /**
-     * Convenience method to interrupt current thread.
-     */
-    static void selfInterrupt() {
-        Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Convenience method to park and then check if interrupted.
-     *
-     * @return {@code true} if interrupted
-     */
-    private final boolean parkAndCheckInterrupt() {
-        LockSupport.park(this);
-        return Thread.interrupted();
-    }
-
-    /*
-     * Various flavors of acquire, varying in exclusive/shared and
-     * control modes.  Each is mostly the same, but annoyingly
-     * different.  Only a little bit of factoring is possible due to
-     * interactions of exception mechanics (including ensuring that we
-     * cancel if tryAcquire throws exception) and other control, at
-     * least not without hurting performance too much.
-     */
-
-    /**
-     * Acquires in exclusive uninterruptible mode for thread already in
-     * queue. Used by condition wait methods as well as acquire.
-     *
-     * @param node the node
-     * @param arg the acquire argument
-     * @return {@code true} if interrupted while waiting
-     */
-    final boolean acquireQueued(final Node node, long arg) {
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return interrupted;
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            if (interrupted)
-                selfInterrupt();
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive interruptible mode.
-     * @param arg the acquire argument
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
      */
-    private void doAcquireInterruptibly(long arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return true;
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
         }
-    }
-
-    /**
-     * Acquires in shared uninterruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireShared(long arg) {
-        final Node node = addWaiter(Node.SHARED);
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        } finally {
-            if (interrupted)
-                selfInterrupt();
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
         }
-    }
-
-    /**
-     * Acquires in shared interruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireSharedInterruptibly(long arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in shared timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireSharedNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    long r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return true;
-                    }
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
+        return 0;
     }
 
     // Main exported methods
@@ -756,9 +560,8 @@
      *        can represent anything you like.
      */
     public final void acquire(long arg) {
-        if (!tryAcquire(arg) &&
-            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
-            selfInterrupt();
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
     }
 
     /**
@@ -776,11 +579,10 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireInterruptibly(long arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (!tryAcquire(arg))
-            doAcquireInterruptibly(arg);
     }
 
     /**
@@ -801,11 +603,20 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final boolean tryAcquireNanos(long arg, long nanosTimeout)
-            throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquire(arg) ||
-            doAcquireNanos(arg, nanosTimeout);
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -820,9 +631,7 @@
      */
     public final boolean release(long arg) {
         if (tryRelease(arg)) {
-            Node h = head;
-            if (h != null && h.waitStatus != 0)
-                unparkSuccessor(h);
+            signalNext(head);
             return true;
         }
         return false;
@@ -841,7 +650,7 @@
      */
     public final void acquireShared(long arg) {
         if (tryAcquireShared(arg) < 0)
-            doAcquireShared(arg);
+            acquire(null, arg, true, false, false, 0L);
     }
 
     /**
@@ -858,11 +667,11 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireSharedInterruptibly(long arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (tryAcquireShared(arg) < 0)
-            doAcquireSharedInterruptibly(arg);
     }
 
     /**
@@ -883,10 +692,19 @@
      */
     public final boolean tryAcquireSharedNanos(long arg, long nanosTimeout)
             throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquireShared(arg) >= 0 ||
-            doAcquireSharedNanos(arg, nanosTimeout);
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -900,7 +718,7 @@
      */
     public final boolean releaseShared(long arg) {
         if (tryReleaseShared(arg)) {
-            doReleaseShared();
+            signalNext(head);
             return true;
         }
         return false;
@@ -918,7 +736,7 @@
      */
     public final boolean hasQueuedThreads() {
         for (Node p = tail, h = head; p != h && p != null; p = p.prev)
-            if (p.waitStatus <= 0)
+            if (p.status >= 0)
                 return true;
         return false;
     }
@@ -948,45 +766,16 @@
      *         {@code null} if no threads are currently queued
      */
     public final Thread getFirstQueuedThread() {
-        // handle only fast path, else relay
-        return (head == tail) ? null : fullGetFirstQueuedThread();
-    }
-
-    /**
-     * Version of getFirstQueuedThread called when fastpath fails.
-     */
-    private Thread fullGetFirstQueuedThread() {
-        /*
-         * The first node is normally head.next. Try to get its
-         * thread field, ensuring consistent reads: If thread
-         * field is nulled out or s.prev is no longer head, then
-         * some other thread(s) concurrently performed setHead in
-         * between some of our reads. We try this twice before
-         * resorting to traversal.
-         */
-        Node h, s;
-        Thread st;
-        if (((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null) ||
-            ((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null))
-            return st;
-
-        /*
-         * Head's next field might not have been set yet, or may have
-         * been unset after setHead. So we must check to see if tail
-         * is actually first node. If not, we continue on, safely
-         * traversing from tail back to head to find first,
-         * guaranteeing termination.
-         */
-
-        Thread firstThread = null;
-        for (Node p = tail; p != null && p != head; p = p.prev) {
-            Thread t = p.thread;
-            if (t != null)
-                firstThread = t;
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
         }
-        return firstThread;
+        return first;
     }
 
     /**
@@ -1003,7 +792,7 @@
         if (thread == null)
             throw new NullPointerException();
         for (Node p = tail; p != null; p = p.prev)
-            if (p.thread == thread)
+            if (p.waiter == thread)
                 return true;
         return false;
     }
@@ -1019,10 +808,8 @@
      */
     final boolean apparentlyFirstQueuedIsExclusive() {
         Node h, s;
-        return (h = head) != null &&
-            (s = h.next)  != null &&
-            !s.isShared()         &&
-            s.thread != null;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
     }
 
     /**
@@ -1052,7 +839,7 @@
      * synchronizer might look like this:
      *
      * <pre> {@code
-     * protected boolean tryAcquire(int arg) {
+     * protected boolean tryAcquire(long arg) {
      *   if (isHeldExclusively()) {
      *     // A reentrant acquire; increment hold count
      *     return true;
@@ -1069,19 +856,12 @@
      * @since 1.7
      */
     public final boolean hasQueuedPredecessors() {
-        Node h, s;
-        if ((h = head) != null) {
-            if ((s = h.next) == null || s.waitStatus > 0) {
-                s = null; // traverse in case of concurrent cancellation
-                for (Node p = tail; p != h && p != null; p = p.prev) {
-                    if (p.waitStatus <= 0)
-                        s = p;
-                }
-            }
-            if (s != null && s.thread != Thread.currentThread())
-                return true;
-        }
-        return false;
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
     }
 
     // Instrumentation and monitoring methods
@@ -1098,7 +878,7 @@
     public final int getQueueLength() {
         int n = 0;
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.thread != null)
+            if (p.waiter != null)
                 ++n;
         }
         return n;
@@ -1118,7 +898,7 @@
     public final Collection<Thread> getQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            Thread t = p.thread;
+            Thread t = p.waiter;
             if (t != null)
                 list.add(t);
         }
@@ -1136,8 +916,8 @@
     public final Collection<Thread> getExclusiveQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (!p.isShared()) {
-                Thread t = p.thread;
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1156,8 +936,8 @@
     public final Collection<Thread> getSharedQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.isShared()) {
-                Thread t = p.thread;
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1180,117 +960,6 @@
             + (hasQueuedThreads() ? "non" : "") + "empty queue]";
     }
 
-
-    // Internal support methods for Conditions
-
-    /**
-     * Returns true if a node, always one that was initially placed on
-     * a condition queue, is now waiting to reacquire on sync queue.
-     * @param node the node
-     * @return true if is reacquiring
-     */
-    final boolean isOnSyncQueue(Node node) {
-        if (node.waitStatus == Node.CONDITION || node.prev == null)
-            return false;
-        if (node.next != null) // If has successor, it must be on queue
-            return true;
-        /*
-         * node.prev can be non-null, but not yet on queue because
-         * the CAS to place it on queue can fail. So we have to
-         * traverse from tail to make sure it actually made it.  It
-         * will always be near the tail in calls to this method, and
-         * unless the CAS failed (which is unlikely), it will be
-         * there, so we hardly ever traverse much.
-         */
-        return findNodeFromTail(node);
-    }
-
-    /**
-     * Returns true if node is on sync queue by searching backwards from tail.
-     * Called only when needed by isOnSyncQueue.
-     * @return true if present
-     */
-    private boolean findNodeFromTail(Node node) {
-        // We check for node first, since it's likely to be at or near tail.
-        // tail is known to be non-null, so we could re-order to "save"
-        // one null check, but we leave it this way to help the VM.
-        for (Node p = tail;;) {
-            if (p == node)
-                return true;
-            if (p == null)
-                return false;
-            p = p.prev;
-        }
-    }
-
-    /**
-     * Transfers a node from a condition queue onto sync queue.
-     * Returns true if successful.
-     * @param node the node
-     * @return true if successfully transferred (else the node was
-     * cancelled before signal)
-     */
-    final boolean transferForSignal(Node node) {
-        /*
-         * If cannot change waitStatus, the node has been cancelled.
-         */
-        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
-            return false;
-
-        /*
-         * Splice onto queue and try to set waitStatus of predecessor to
-         * indicate that thread is (probably) waiting. If cancelled or
-         * attempt to set waitStatus fails, wake up to resync (in which
-         * case the waitStatus can be transiently and harmlessly wrong).
-         */
-        Node p = enq(node);
-        int ws = p.waitStatus;
-        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
-            LockSupport.unpark(node.thread);
-        return true;
-    }
-
-    /**
-     * Transfers node, if necessary, to sync queue after a cancelled wait.
-     * Returns true if thread was cancelled before being signalled.
-     *
-     * @param node the node
-     * @return true if cancelled before the node was signalled
-     */
-    final boolean transferAfterCancelledWait(Node node) {
-        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
-            enq(node);
-            return true;
-        }
-        /*
-         * If we lost out to a signal(), then we can't proceed
-         * until it finishes its enq().  Cancelling during an
-         * incomplete transfer is both rare and transient, so just
-         * spin.
-         */
-        while (!isOnSyncQueue(node))
-            Thread.yield();
-        return false;
-    }
-
-    /**
-     * Invokes release with current state value; returns saved state.
-     * Cancels node and throws exception on failure.
-     * @param node the condition node for this wait
-     * @return previous sync state
-     */
-    final long fullyRelease(Node node) {
-        try {
-            long savedState = getState();
-            if (release(savedState))
-                return savedState;
-            throw new IllegalMonitorStateException();
-        } catch (Throwable t) {
-            node.waitStatus = Node.CANCELLED;
-            throw t;
-        }
-    }
-
     // Instrumentation methods for conditions
 
     /**
@@ -1384,112 +1053,38 @@
      *
      * <p>This class is Serializable, but all fields are transient,
      * so deserialized conditions have no waiters.
-     *
-     * @since 1.6
      */
     public class ConditionObject implements Condition, java.io.Serializable {
         private static final long serialVersionUID = 1173984872572414699L;
         /** First node of condition queue. */
-        private transient Node firstWaiter;
+        private transient ConditionNode firstWaiter;
         /** Last node of condition queue. */
-        private transient Node lastWaiter;
+        private transient ConditionNode lastWaiter;
 
         /**
          * Creates a new {@code ConditionObject} instance.
          */
         public ConditionObject() { }
 
-        // Internal methods
-
-        /**
-         * Adds a new waiter to wait queue.
-         * @return its new wait node
-         */
-        private Node addConditionWaiter() {
-            if (!isHeldExclusively())
-                throw new IllegalMonitorStateException();
-            Node t = lastWaiter;
-            // If lastWaiter is cancelled, clean out.
-            if (t != null && t.waitStatus != Node.CONDITION) {
-                unlinkCancelledWaiters();
-                t = lastWaiter;
-            }
-
-            Node node = new Node(Node.CONDITION);
-
-            if (t == null)
-                firstWaiter = node;
-            else
-                t.nextWaiter = node;
-            lastWaiter = node;
-            return node;
-        }
-
-        /**
-         * Removes and transfers nodes until hit non-cancelled one or
-         * null. Split out from signal in part to encourage compilers
-         * to inline the case of no waiters.
-         * @param first (non-null) the first node on condition queue
-         */
-        private void doSignal(Node first) {
-            do {
-                if ( (firstWaiter = first.nextWaiter) == null)
-                    lastWaiter = null;
-                first.nextWaiter = null;
-            } while (!transferForSignal(first) &&
-                     (first = firstWaiter) != null);
-        }
+        // Signalling methods
 
         /**
-         * Removes and transfers all nodes.
-         * @param first (non-null) the first node on condition queue
+         * Removes and transfers one or all waiters to sync queue.
          */
-        private void doSignalAll(Node first) {
-            lastWaiter = firstWaiter = null;
-            do {
-                Node next = first.nextWaiter;
-                first.nextWaiter = null;
-                transferForSignal(first);
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
                 first = next;
-            } while (first != null);
-        }
-
-        /**
-         * Unlinks cancelled waiter nodes from condition queue.
-         * Called only while holding lock. This is called when
-         * cancellation occurred during condition wait, and upon
-         * insertion of a new waiter when lastWaiter is seen to have
-         * been cancelled. This method is needed to avoid garbage
-         * retention in the absence of signals. So even though it may
-         * require a full traversal, it comes into play only when
-         * timeouts or cancellations occur in the absence of
-         * signals. It traverses all nodes rather than stopping at a
-         * particular target to unlink all pointers to garbage nodes
-         * without requiring many re-traversals during cancellation
-         * storms.
-         */
-        private void unlinkCancelledWaiters() {
-            Node t = firstWaiter;
-            Node trail = null;
-            while (t != null) {
-                Node next = t.nextWaiter;
-                if (t.waitStatus != Node.CONDITION) {
-                    t.nextWaiter = null;
-                    if (trail == null)
-                        firstWaiter = next;
-                    else
-                        trail.nextWaiter = next;
-                    if (next == null)
-                        lastWaiter = trail;
-                }
-                else
-                    trail = t;
-                t = next;
             }
         }
 
-        // public methods
-
         /**
          * Moves the longest-waiting thread, if one exists, from the
          * wait queue for this condition to the wait queue for the
@@ -1499,11 +1094,11 @@
          *         returns {@code false}
          */
         public final void signal() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignal(first);
+                doSignal(first, false);
         }
 
         /**
@@ -1514,11 +1109,72 @@
          *         returns {@code false}
          */
         public final void signalAll() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignalAll(first);
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private long enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                long savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
         }
 
         /**
@@ -1533,51 +1189,27 @@
          * </ol>
          */
         public final void awaitUninterruptibly() {
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
             boolean interrupted = false;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
+            while (!canReacquire(node)) {
                 if (Thread.interrupted())
                     interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) || interrupted)
-                selfInterrupt();
-        }
-
-        /*
-         * For interruptible waits, we need to track whether to throw
-         * InterruptedException, if interrupted while blocked on
-         * condition, versus reinterrupt current thread, if
-         * interrupted while blocked waiting to re-acquire.
-         */
-
-        /** Mode meaning to reinterrupt on exit from wait */
-        private static final int REINTERRUPT =  1;
-        /** Mode meaning to throw InterruptedException on exit from wait */
-        private static final int THROW_IE    = -1;
-
-        /**
-         * Checks for interrupt, returning THROW_IE if interrupted
-         * before signalled, REINTERRUPT if after signalled, or
-         * 0 if not interrupted.
-         */
-        private int checkInterruptWhileWaiting(Node node) {
-            return Thread.interrupted() ?
-                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
-                0;
-        }
-
-        /**
-         * Throws InterruptedException, reinterrupts current thread, or
-         * does nothing, depending on mode.
-         */
-        private void reportInterruptAfterWait(int interruptMode)
-            throws InterruptedException {
-            if (interruptMode == THROW_IE)
-                throw new InterruptedException();
-            else if (interruptMode == REINTERRUPT)
-                selfInterrupt();
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
         }
 
         /**
@@ -1596,20 +1228,33 @@
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null) // clean up if cancelled
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
         }
 
         /**
@@ -1629,32 +1274,29 @@
                 throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // awaitNanos(0) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            long initialNanos = nanosTimeout;
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
             long remaining = deadline - System.nanoTime(); // avoid overflow
-            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
         }
 
         /**
@@ -1676,26 +1318,26 @@
             long abstime = deadline.getTime();
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (System.currentTimeMillis() >= abstime) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                LockSupport.parkUntil(this, abstime);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         /**
@@ -1717,31 +1359,28 @@
             long nanosTimeout = unit.toNanos(time);
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // await(0, unit) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            Node node = addConditionWaiter();
-            long savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            long savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         //  support for instrumentation
@@ -1767,8 +1406,8 @@
         protected final boolean hasWaiters() {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     return true;
             }
             return false;
@@ -1787,8 +1426,8 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             int n = 0;
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     ++n;
             }
             return n;
@@ -1807,9 +1446,9 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             ArrayList<Thread> list = new ArrayList<>();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION) {
-                    Thread t = w.thread;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
                     if (t != null)
                         list.add(t);
                 }
@@ -1818,39 +1457,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedLongSynchronizer.class, "tail");
 
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "state", long.class);
-            HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
-            TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-
-        // Reduce the risk of rare disastrous classloading in first call to
-        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
     }
-
-    /**
-     * Initializes head and tail fields on first contention.
-     */
-    private final void initializeSyncQueue() {
-        Node h;
-        if (HEAD.compareAndSet(this, null, (h = new Node())))
-            tail = h;
-    }
-
-    /**
-     * CASes tail field.
-     */
-    private final boolean compareAndSetTail(Node expect, Node update) {
-        return TAIL.compareAndSet(this, expect, update);
-    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Sep 18 07:46:02 2019 +0200
@@ -35,12 +35,12 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ForkJoinPool;
+import jdk.internal.misc.Unsafe;
 
 /**
  * Provides a framework for implementing blocking locks and related
@@ -312,265 +312,208 @@
      */
     protected AbstractQueuedSynchronizer() { }
 
-    /**
-     * Wait queue node class.
+    /*
+     * Overview.
      *
-     * <p>The wait queue is a variant of a "CLH" (Craig, Landin, and
+     * The wait queue is a variant of a "CLH" (Craig, Landin, and
      * Hagersten) lock queue. CLH locks are normally used for
-     * spinlocks.  We instead use them for blocking synchronizers, but
-     * use the same basic tactic of holding some of the control
-     * information about a thread in the predecessor of its node.  A
-     * "status" field in each node keeps track of whether a thread
-     * should block.  A node is signalled when its predecessor
-     * releases.  Each node of the queue otherwise serves as a
-     * specific-notification-style monitor holding a single waiting
-     * thread. The status field does NOT control whether threads are
-     * granted locks etc though.  A thread may try to acquire if it is
-     * first in the queue. But being first does not guarantee success;
-     * it only gives the right to contend.  So the currently released
-     * contender thread may need to rewait.
+     * spinlocks.  We instead use them for blocking synchronizers by
+     * including explicit ("prev" and "next") links plus a "status"
+     * field that allow nodes to signal successors when releasing
+     * locks, and handle cancellation due to interrupts and timeouts.
+     * The status field includes bits that track whether a thread
+     * needs a signal (using LockSupport.unpark). Despite these
+     * additions, we maintain most CLH locality properties.
+     *
+     * To enqueue into a CLH lock, you atomically splice it in as new
+     * tail. To dequeue, you set the head field, so the next eligible
+     * waiter becomes first.
      *
-     * <p>To enqueue into a CLH lock, you atomically splice it in as new
-     * tail. To dequeue, you just set the head field.
-     * <pre>
-     *      +------+  prev +-----+       +-----+
-     * head |      | <---- |     | <---- |     |  tail
-     *      +------+       +-----+       +-----+
-     * </pre>
+     *  +------+  prev +-------+       +------+
+     *  | head | <---- | first | <---- | tail |
+     *  +------+       +-------+       +------+
+     *
+     * Insertion into a CLH queue requires only a single atomic
+     * operation on "tail", so there is a simple point of demarcation
+     * from unqueued to queued. The "next" link of the predecessor is
+     * set by the enqueuing thread after successful CAS. Even though
+     * non-atomic, this suffices to ensure that any blocked thread is
+     * signalled by a predecessor when eligible (although in the case
+     * of cancellation, possibly with the assistance of a signal in
+     * method cleanQueue). Signalling is based in part on a
+     * Dekker-like scheme in which the to-be waiting thread indicates
+     * WAITING status, then retries acquiring, and then rechecks
+     * status before blocking. The signaller atomically clears WAITING
+     * status when unparking.
      *
-     * <p>Insertion into a CLH queue requires only a single atomic
-     * operation on "tail", so there is a simple atomic point of
-     * demarcation from unqueued to queued. Similarly, dequeuing
-     * involves only updating the "head". However, it takes a bit
-     * more work for nodes to determine who their successors are,
-     * in part to deal with possible cancellation due to timeouts
-     * and interrupts.
-     *
-     * <p>The "prev" links (not used in original CLH locks), are mainly
-     * needed to handle cancellation. If a node is cancelled, its
-     * successor is (normally) relinked to a non-cancelled
-     * predecessor. For explanation of similar mechanics in the case
-     * of spin locks, see the papers by Scott and Scherer at
-     * http://www.cs.rochester.edu/u/scott/synchronization/
+     * Dequeuing on acquire involves detaching (nulling) a node's
+     * "prev" node and then updating the "head". Other threads check
+     * if a node is or was dequeued by checking "prev" rather than
+     * head. We enforce the nulling then setting order by spin-waiting
+     * if necessary. Because of this, the lock algorithm is not itself
+     * strictly "lock-free" because an acquiring thread may need to
+     * wait for a previous acquire to make progress. When used with
+     * exclusive locks, such progress is required anyway. However
+     * Shared mode may (uncommonly) require a spin-wait before
+     * setting head field to ensure proper propagation. (Historical
+     * note: This allows some simplifications and efficiencies
+     * compared to previous versions of this class.)
      *
-     * <p>We also use "next" links to implement blocking mechanics.
-     * The thread id for each node is kept in its own node, so a
-     * predecessor signals the next node to wake up by traversing
-     * next link to determine which thread it is.  Determination of
-     * successor must avoid races with newly queued nodes to set
-     * the "next" fields of their predecessors.  This is solved
-     * when necessary by checking backwards from the atomically
-     * updated "tail" when a node's successor appears to be null.
-     * (Or, said differently, the next-links are an optimization
-     * so that we don't usually need a backward scan.)
+     * A node's predecessor can change due to cancellation while it is
+     * waiting, until the node is first in queue, at which point it
+     * cannot change. The acquire methods cope with this by rechecking
+     * "prev" before waiting. The prev and next fields are modified
+     * only via CAS by cancelled nodes in method cleanQueue. The
+     * unsplice strategy is reminiscent of Michael-Scott queues in
+     * that after a successful CAS to prev field, other threads help
+     * fix next fields.  Because cancellation often occurs in bunches
+     * that complicate decisions about necessary signals, each call to
+     * cleanQueue traverses the queue until a clean sweep. Nodes that
+     * become relinked as first are unconditionally unparked
+     * (sometimes unnecessarily, but those cases are not worth
+     * avoiding).
      *
-     * <p>Cancellation introduces some conservatism to the basic
-     * algorithms.  Since we must poll for cancellation of other
-     * nodes, we can miss noticing whether a cancelled node is
-     * ahead or behind us. This is dealt with by always unparking
-     * successors upon cancellation, allowing them to stabilize on
-     * a new predecessor, unless we can identify an uncancelled
-     * predecessor who will carry this responsibility.
+     * A thread may try to acquire if it is first (frontmost) in the
+     * queue, and sometimes before.  Being first does not guarantee
+     * success; it only gives the right to contend. We balance
+     * throughput, overhead, and fairness by allowing incoming threads
+     * to "barge" and acquire the synchronizer while in the process of
+     * enqueuing, in which case an awakened first thread may need to
+     * rewait.  To counteract possible repeated unlucky rewaits, we
+     * exponentially increase retries (up to 256) to acquire each time
+     * a thread is unparked. Except in this case, AQS locks do not
+     * spin; they instead interleave attempts to acquire with
+     * bookkeeping steps. (Users who want spinlocks can use
+     * tryAcquire.)
      *
-     * <p>CLH queues need a dummy header node to get started. But
+     * To improve garbage collectibility, fields of nodes not yet on
+     * list are null. (It is not rare to create and then throw away a
+     * node without using it.) Fields of nodes coming off the list are
+     * nulled out as soon as possible. This accentuates the challenge
+     * of externally determining the first waiting thread (as in
+     * method getFirstQueuedThread). This sometimes requires the
+     * fallback of traversing backwards from the atomically updated
+     * "tail" when fields appear null. (This is never needed in the
+     * process of signalling though.)
+     *
+     * CLH queues need a dummy header node to get started. But
      * we don't create them on construction, because it would be wasted
      * effort if there is never contention. Instead, the node
      * is constructed and head and tail pointers are set upon first
      * contention.
      *
-     * <p>Threads waiting on Conditions use the same nodes, but
-     * use an additional link. Conditions only need to link nodes
-     * in simple (non-concurrent) linked queues because they are
-     * only accessed when exclusively held.  Upon await, a node is
-     * inserted into a condition queue.  Upon signal, the node is
-     * transferred to the main queue.  A special value of status
-     * field is used to mark which queue a node is on.
+     * Shared mode operations differ from Exclusive in that an acquire
+     * signals the next waiter to try to acquire if it is also
+     * Shared. The tryAcquireShared API allows users to indicate the
+     * degree of propagation, but in most applications, it is more
+     * efficient to ignore this, allowing the successor to try
+     * acquiring in any case.
+     *
+     * Threads waiting on Conditions use nodes with an additional
+     * link to maintain the (FIFO) list of conditions. Conditions only
+     * need to link nodes in simple (non-concurrent) linked queues
+     * because they are only accessed when exclusively held.  Upon
+     * await, a node is inserted into a condition queue.  Upon signal,
+     * the node is enqueued on the main queue.  A special status field
+     * value is used to track and atomically trigger this.
      *
-     * <p>Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
+     * Accesses to fields head, tail, and state use full Volatile
+     * mode, along with CAS. Node fields status, prev and next also do
+     * so while threads may be signallable, but sometimes use weaker
+     * modes otherwise. Accesses to field "waiter" (the thread to be
+     * signalled) are always sandwiched between other atomic accesses
+     * so are used in Plain mode. We use jdk.internal Unsafe versions
+     * of atomic access methods rather than VarHandles to avoid
+     * potential VM bootstrap issues.
+     *
+     * Most of the above is performed by primary internal method
+     * acquire, that is invoked in some way by all exported acquire
+     * methods.  (It is usually easy for compilers to optimize
+     * call-site specializations when heavily used.)
+     *
+     * There are several arbitrary decisions about when and how to
+     * check interrupts in both acquire and await before and/or after
+     * blocking. The decisions are less arbitrary in implementation
+     * updates because some users appear to rely on original behaviors
+     * in ways that are racy and so (rarely) wrong in general but hard
+     * to justify changing.
+     *
+     * Thanks go to Dave Dice, Mark Moir, Victor Luchangco, Bill
      * Scherer and Michael Scott, along with members of JSR-166
      * expert group, for helpful ideas, discussions, and critiques
      * on the design of this class.
      */
-    static final class Node {
-        /** Marker to indicate a node is waiting in shared mode */
-        static final Node SHARED = new Node();
-        /** Marker to indicate a node is waiting in exclusive mode */
-        static final Node EXCLUSIVE = null;
+
+    // Node status bits, also used as argument and return values
+    static final int WAITING   = 1;          // must be 1
+    static final int CANCELLED = 0x80000000; // must be negative
+    static final int COND      = 2;          // in a condition wait
 
-        /** waitStatus value to indicate thread has cancelled. */
-        static final int CANCELLED =  1;
-        /** waitStatus value to indicate successor's thread needs unparking. */
-        static final int SIGNAL    = -1;
-        /** waitStatus value to indicate thread is waiting on condition. */
-        static final int CONDITION = -2;
-        /**
-         * waitStatus value to indicate the next acquireShared should
-         * unconditionally propagate.
-         */
-        static final int PROPAGATE = -3;
+    /** CLH Nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
 
-        /**
-         * Status field, taking on only the values:
-         *   SIGNAL:     The successor of this node is (or will soon be)
-         *               blocked (via park), so the current node must
-         *               unpark its successor when it releases or
-         *               cancels. To avoid races, acquire methods must
-         *               first indicate they need a signal,
-         *               then retry the atomic acquire, and then,
-         *               on failure, block.
-         *   CANCELLED:  This node is cancelled due to timeout or interrupt.
-         *               Nodes never leave this state. In particular,
-         *               a thread with cancelled node never again blocks.
-         *   CONDITION:  This node is currently on a condition queue.
-         *               It will not be used as a sync queue node
-         *               until transferred, at which time the status
-         *               will be set to 0. (Use of this value here has
-         *               nothing to do with the other uses of the
-         *               field, but simplifies mechanics.)
-         *   PROPAGATE:  A releaseShared should be propagated to other
-         *               nodes. This is set (for head node only) in
-         *               doReleaseShared to ensure propagation
-         *               continues, even if other operations have
-         *               since intervened.
-         *   0:          None of the above
-         *
-         * The values are arranged numerically to simplify use.
-         * Non-negative values mean that a node doesn't need to
-         * signal. So, most code doesn't need to check for particular
-         * values, just for sign.
-         *
-         * The field is initialized to 0 for normal sync nodes, and
-         * CONDITION for condition nodes.  It is modified using CAS
-         * (or when possible, unconditional volatile writes).
-         */
-        volatile int waitStatus;
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
 
-        /**
-         * Link to predecessor node that current node/thread relies on
-         * for checking waitStatus. Assigned during enqueuing, and nulled
-         * out (for sake of GC) only upon dequeuing.  Also, upon
-         * cancellation of a predecessor, we short-circuit while
-         * finding a non-cancelled one, which will always exist
-         * because the head node is never cancelled: A node becomes
-         * head only as a result of successful acquire. A
-         * cancelled thread never succeeds in acquiring, and a thread only
-         * cancels itself, not any other node.
-         */
-        volatile Node prev;
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
 
-        /**
-         * Link to the successor node that the current node/thread
-         * unparks upon release. Assigned during enqueuing, adjusted
-         * when bypassing cancelled predecessors, and nulled out (for
-         * sake of GC) when dequeued.  The enq operation does not
-         * assign next field of a predecessor until after attachment,
-         * so seeing a null next field does not necessarily mean that
-         * node is at end of queue. However, if a next field appears
-         * to be null, we can scan prev's from the tail to
-         * double-check.  The next field of cancelled nodes is set to
-         * point to the node itself instead of null, to make life
-         * easier for isOnSyncQueue.
-         */
-        volatile Node next;
+    // Concrete classes tagged by type
+    static final class ExclusiveNode extends Node { }
+    static final class SharedNode extends Node { }
+
+    static final class ConditionNode extends Node
+        implements ForkJoinPool.ManagedBlocker {
+        ConditionNode nextWaiter;            // link to next waiting node
 
         /**
-         * The thread that enqueued this node.  Initialized on
-         * construction and nulled out after use.
-         */
-        volatile Thread thread;
-
-        /**
-         * Link to next node waiting on condition, or the special
-         * value SHARED.  Because condition queues are accessed only
-         * when holding in exclusive mode, we just need a simple
-         * linked queue to hold nodes while they are waiting on
-         * conditions. They are then transferred to the queue to
-         * re-acquire. And because conditions can only be exclusive,
-         * we save a field by using special value to indicate shared
-         * mode.
+         * Allows Conditions to be used in ForkJoinPools without
+         * risking fixed pool exhaustion. This is usable only for
+         * untimed Condition waits, not timed versions.
          */
-        Node nextWaiter;
-
-        /**
-         * Returns true if node is waiting in shared mode.
-         */
-        final boolean isShared() {
-            return nextWaiter == SHARED;
-        }
-
-        /**
-         * Returns previous node, or throws NullPointerException if null.
-         * Use when predecessor cannot be null.  The null check could
-         * be elided, but is present to help the VM.
-         *
-         * @return the predecessor of this node
-         */
-        final Node predecessor() {
-            Node p = prev;
-            if (p == null)
-                throw new NullPointerException();
-            else
-                return p;
+        public final boolean isReleasable() {
+            return status <= 1 || Thread.currentThread().isInterrupted();
         }
 
-        /** Establishes initial head or SHARED marker. */
-        Node() {}
-
-        /** Constructor used by addWaiter. */
-        Node(Node nextWaiter) {
-            this.nextWaiter = nextWaiter;
-            THREAD.set(this, Thread.currentThread());
-        }
-
-        /** Constructor used by addConditionWaiter. */
-        Node(int waitStatus) {
-            WAITSTATUS.set(this, waitStatus);
-            THREAD.set(this, Thread.currentThread());
-        }
-
-        /** CASes waitStatus field. */
-        final boolean compareAndSetWaitStatus(int expect, int update) {
-            return WAITSTATUS.compareAndSet(this, expect, update);
-        }
-
-        /** CASes next field. */
-        final boolean compareAndSetNext(Node expect, Node update) {
-            return NEXT.compareAndSet(this, expect, update);
-        }
-
-        final void setPrevRelaxed(Node p) {
-            PREV.set(this, p);
-        }
-
-        // VarHandle mechanics
-        private static final VarHandle NEXT;
-        private static final VarHandle PREV;
-        private static final VarHandle THREAD;
-        private static final VarHandle WAITSTATUS;
-        static {
-            try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                NEXT = l.findVarHandle(Node.class, "next", Node.class);
-                PREV = l.findVarHandle(Node.class, "prev", Node.class);
-                THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
-                WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
-            } catch (ReflectiveOperationException e) {
-                throw new ExceptionInInitializerError(e);
-            }
+        public final boolean block() {
+            while (!isReleasable()) LockSupport.park(this);
+            return true;
         }
     }
 
     /**
-     * Head of the wait queue, lazily initialized.  Except for
-     * initialization, it is modified only via method setHead.  Note:
-     * If head exists, its waitStatus is guaranteed not to be
-     * CANCELLED.
+     * Head of the wait queue, lazily initialized.
      */
     private transient volatile Node head;
 
     /**
-     * Tail of the wait queue, lazily initialized.  Modified only via
-     * method enq to add new wait node.
+     * Tail of the wait queue. After initialization, modified only via casTail.
      */
     private transient volatile Node tail;
 
@@ -609,481 +552,235 @@
      *         value was not equal to the expected value.
      */
     protected final boolean compareAndSetState(int expect, int update) {
-        return STATE.compareAndSet(this, expect, update);
+        return U.compareAndSetInt(this, STATE, expect, update);
     }
 
     // Queuing utilities
 
-    /**
-     * The number of nanoseconds for which it is faster to spin
-     * rather than to use timed park. A rough estimate suffices
-     * to improve responsiveness with very short timeouts.
-     */
-    static final long SPIN_FOR_TIMEOUT_THRESHOLD = 1000L;
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new ExclusiveNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
 
     /**
-     * Inserts node into queue, initializing if necessary. See picture above.
-     * @param node the node to insert
-     * @return node's predecessor
+     * Enqueues the node unless null. (Currently used only for
+     * ConditionNodes; other cases are interleaved with acquires.)
      */
-    private Node enq(Node node) {
-        for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return oldTail;
+    final void enqueue(Node node) {
+        if (node != null) {
+            for (;;) {
+                Node t = tail;
+                node.setPrevRelaxed(t);        // avoid unnecessary fence
+                if (t == null)                 // initialize
+                    tryInitializeHead();
+                else if (casTail(t, node)) {
+                    t.next = node;
+                    if (t.status < 0)          // wake up to clean link
+                        LockSupport.unpark(node.waiter);
+                    break;
                 }
-            } else {
-                initializeSyncQueue();
             }
         }
     }
 
+    /** Returns true if node is found in traversal from tail */
+    final boolean isEnqueued(Node node) {
+        for (Node t = tail; t != null; t = t.prev)
+            if (t == node)
+                return true;
+        return false;
+    }
+
     /**
-     * Creates and enqueues node for current thread and given mode.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
+     */
+    private static void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /** Wakes up the given node if in shared mode */
+    private static void signalNextIfShared(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null &&
+            (s instanceof SharedNode) && s.status != 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
+        }
+    }
+
+    /**
+     * Main acquire method, invoked by all exported acquire methods.
      *
-     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
-     * @return the new node
+     * @param node null unless a reacquiring Condition
+     * @param arg the acquire argument
+     * @param shared true if shared mode else exclusive
+     * @param interruptible if abort and return negative on interrupt
+     * @param timed if true use timed waits
+     * @param time if timed, the System.nanoTime value to timeout
+     * @return positive if acquired, 0 if timed out, negative if interrupted
      */
-    private Node addWaiter(Node mode) {
-        Node node = new Node(mode);
+    final int acquire(Node node, int arg, boolean shared,
+                      boolean interruptible, boolean timed, long time) {
+        Thread current = Thread.currentThread();
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        Node pred = null;                // predecessor of node when enqueued
+
+        /*
+         * Repeatedly:
+         *  Check if node now first
+         *    if so, ensure head stable, else ensure valid predecessor
+         *  if node is first or not yet enqueued, try acquiring
+         *  else if node not yet created, create it
+         *  else if not yet enqueued, try once to enqueue
+         *  else if woken from park, retry (up to postSpins times)
+         *  else if WAITING status not set, set and retry
+         *  else park and clear WAITING status, and check cancellation
+         */
 
         for (;;) {
-            Node oldTail = tail;
-            if (oldTail != null) {
-                node.setPrevRelaxed(oldTail);
-                if (compareAndSetTail(oldTail, node)) {
-                    oldTail.next = node;
-                    return node;
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
+            }
+            if (first || pred == null) {
+                boolean acquired;
+                try {
+                    if (shared)
+                        acquired = (tryAcquireShared(arg) >= 0);
+                    else
+                        acquired = tryAcquire(arg);
+                } catch (Throwable ex) {
+                    cancelAcquire(node, interrupted, false);
+                    throw ex;
+                }
+                if (acquired) {
+                    if (first) {
+                        node.prev = null;
+                        head = node;
+                        pred.next = null;
+                        node.waiter = null;
+                        if (shared)
+                            signalNextIfShared(node);
+                        if (interrupted)
+                            current.interrupt();
+                    }
+                    return 1;
                 }
+            }
+            if (node == null) {                 // allocate; retry before enqueue
+                if (shared)
+                    node = new SharedNode();
+                else
+                    node = new ExclusiveNode();
+            } else if (pred == null) {          // try to enqueue
+                node.waiter = current;
+                Node t = tail;
+                node.setPrevRelaxed(t);         // avoid unnecessary fence
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {
+                --spins;                        // reduce unfairness on rewaits
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                node.status = WAITING;          // enable signal and recheck
             } else {
-                initializeSyncQueue();
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted, interruptible);
+    }
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
             }
         }
     }
 
     /**
-     * Sets head of queue to be node, thus dequeuing. Called only by
-     * acquire methods.  Also nulls out unused fields for sake of GC
-     * and to suppress unnecessary signals and traversals.
-     *
-     * @param node the node
-     */
-    private void setHead(Node node) {
-        head = node;
-        node.thread = null;
-        node.prev = null;
-    }
-
-    /**
-     * Wakes up node's successor, if one exists.
-     *
-     * @param node the node
-     */
-    private void unparkSuccessor(Node node) {
-        /*
-         * If status is negative (i.e., possibly needing signal) try
-         * to clear in anticipation of signalling.  It is OK if this
-         * fails or if status is changed by waiting thread.
-         */
-        int ws = node.waitStatus;
-        if (ws < 0)
-            node.compareAndSetWaitStatus(ws, 0);
-
-        /*
-         * Thread to unpark is held in successor, which is normally
-         * just the next node.  But if cancelled or apparently null,
-         * traverse backwards from tail to find the actual
-         * non-cancelled successor.
-         */
-        Node s = node.next;
-        if (s == null || s.waitStatus > 0) {
-            s = null;
-            for (Node p = tail; p != node && p != null; p = p.prev)
-                if (p.waitStatus <= 0)
-                    s = p;
-        }
-        if (s != null)
-            LockSupport.unpark(s.thread);
-    }
-
-    /**
-     * Release action for shared mode -- signals successor and ensures
-     * propagation. (Note: For exclusive mode, release just amounts
-     * to calling unparkSuccessor of head if it needs signal.)
-     */
-    private void doReleaseShared() {
-        /*
-         * Ensure that a release propagates, even if there are other
-         * in-progress acquires/releases.  This proceeds in the usual
-         * way of trying to unparkSuccessor of head if it needs
-         * signal. But if it does not, status is set to PROPAGATE to
-         * ensure that upon release, propagation continues.
-         * Additionally, we must loop in case a new node is added
-         * while we are doing this. Also, unlike other uses of
-         * unparkSuccessor, we need to know if CAS to reset status
-         * fails, if so rechecking.
-         */
-        for (;;) {
-            Node h = head;
-            if (h != null && h != tail) {
-                int ws = h.waitStatus;
-                if (ws == Node.SIGNAL) {
-                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
-                        continue;            // loop to recheck cases
-                    unparkSuccessor(h);
-                }
-                else if (ws == 0 &&
-                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
-                    continue;                // loop on failed CAS
-            }
-            if (h == head)                   // loop if head changed
-                break;
-        }
-    }
-
-    /**
-     * Sets head of queue, and checks if successor may be waiting
-     * in shared mode, if so propagating if either propagate > 0 or
-     * PROPAGATE status was set.
-     *
-     * @param node the node
-     * @param propagate the return value from a tryAcquireShared
-     */
-    private void setHeadAndPropagate(Node node, int propagate) {
-        Node h = head; // Record old head for check below
-        setHead(node);
-        /*
-         * Try to signal next queued node if:
-         *   Propagation was indicated by caller,
-         *     or was recorded (as h.waitStatus either before
-         *     or after setHead) by a previous operation
-         *     (note: this uses sign-check of waitStatus because
-         *      PROPAGATE status may transition to SIGNAL.)
-         * and
-         *   The next node is waiting in shared mode,
-         *     or we don't know, because it appears null
-         *
-         * The conservatism in both of these checks may cause
-         * unnecessary wake-ups, but only when there are multiple
-         * racing acquires/releases, so most need signals now or soon
-         * anyway.
-         */
-        if (propagate > 0 || h == null || h.waitStatus < 0 ||
-            (h = head) == null || h.waitStatus < 0) {
-            Node s = node.next;
-            if (s == null || s.isShared())
-                doReleaseShared();
-        }
-    }
-
-    // Utilities for various versions of acquire
-
-    /**
      * Cancels an ongoing attempt to acquire.
      *
-     * @param node the node
-     */
-    private void cancelAcquire(Node node) {
-        // Ignore if node doesn't exist
-        if (node == null)
-            return;
-
-        node.thread = null;
-
-        // Skip cancelled predecessors
-        Node pred = node.prev;
-        while (pred.waitStatus > 0)
-            node.prev = pred = pred.prev;
-
-        // predNext is the apparent node to unsplice. CASes below will
-        // fail if not, in which case, we lost race vs another cancel
-        // or signal, so no further action is necessary, although with
-        // a possibility that a cancelled node may transiently remain
-        // reachable.
-        Node predNext = pred.next;
-
-        // Can use unconditional write instead of CAS here.
-        // After this atomic step, other Nodes can skip past us.
-        // Before, we are free of interference from other threads.
-        node.waitStatus = Node.CANCELLED;
-
-        // If we are the tail, remove ourselves.
-        if (node == tail && compareAndSetTail(node, pred)) {
-            pred.compareAndSetNext(predNext, null);
-        } else {
-            // If successor needs signal, try to set pred's next-link
-            // so it will get one. Otherwise wake it up to propagate.
-            int ws;
-            if (pred != head &&
-                ((ws = pred.waitStatus) == Node.SIGNAL ||
-                 (ws <= 0 && pred.compareAndSetWaitStatus(ws, Node.SIGNAL))) &&
-                pred.thread != null) {
-                Node next = node.next;
-                if (next != null && next.waitStatus <= 0)
-                    pred.compareAndSetNext(predNext, next);
-            } else {
-                unparkSuccessor(node);
-            }
-
-            node.next = node; // help GC
-        }
-    }
-
-    /**
-     * Checks and updates status for a node that failed to acquire.
-     * Returns true if thread should block. This is the main signal
-     * control in all acquire loops.  Requires that pred == node.prev.
-     *
-     * @param pred node's predecessor holding status
-     * @param node the node
-     * @return {@code true} if thread should block
-     */
-    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
-        int ws = pred.waitStatus;
-        if (ws == Node.SIGNAL)
-            /*
-             * This node has already set status asking a release
-             * to signal it, so it can safely park.
-             */
-            return true;
-        if (ws > 0) {
-            /*
-             * Predecessor was cancelled. Skip over predecessors and
-             * indicate retry.
-             */
-            do {
-                node.prev = pred = pred.prev;
-            } while (pred.waitStatus > 0);
-            pred.next = node;
-        } else {
-            /*
-             * waitStatus must be 0 or PROPAGATE.  Indicate that we
-             * need a signal, but don't park yet.  Caller will need to
-             * retry to make sure it cannot acquire before parking.
-             */
-            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
-        }
-        return false;
-    }
-
-    /**
-     * Convenience method to interrupt current thread.
-     */
-    static void selfInterrupt() {
-        Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Convenience method to park and then check if interrupted.
-     *
-     * @return {@code true} if interrupted
-     */
-    private final boolean parkAndCheckInterrupt() {
-        LockSupport.park(this);
-        return Thread.interrupted();
-    }
-
-    /*
-     * Various flavors of acquire, varying in exclusive/shared and
-     * control modes.  Each is mostly the same, but annoyingly
-     * different.  Only a little bit of factoring is possible due to
-     * interactions of exception mechanics (including ensuring that we
-     * cancel if tryAcquire throws exception) and other control, at
-     * least not without hurting performance too much.
-     */
-
-    /**
-     * Acquires in exclusive uninterruptible mode for thread already in
-     * queue. Used by condition wait methods as well as acquire.
-     *
-     * @param node the node
-     * @param arg the acquire argument
-     * @return {@code true} if interrupted while waiting
-     */
-    final boolean acquireQueued(final Node node, int arg) {
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return interrupted;
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            if (interrupted)
-                selfInterrupt();
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive interruptible mode.
-     * @param arg the acquire argument
+     * @param node the node (may be null if cancelled before enqueuing)
+     * @param interrupted true if thread interrupted
+     * @param interruptible if should report interruption vs reset
      */
-    private void doAcquireInterruptibly(int arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in exclusive timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.EXCLUSIVE);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head && tryAcquire(arg)) {
-                    setHead(node);
-                    p.next = null; // help GC
-                    return true;
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
+    private int cancelAcquire(Node node, boolean interrupted,
+                              boolean interruptible) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            if (node.prev != null)
+                cleanQueue();
         }
-    }
-
-    /**
-     * Acquires in shared uninterruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireShared(int arg) {
-        final Node node = addWaiter(Node.SHARED);
-        boolean interrupted = false;
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node))
-                    interrupted |= parkAndCheckInterrupt();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        } finally {
-            if (interrupted)
-                selfInterrupt();
+        if (interrupted) {
+            if (interruptible)
+                return CANCELLED;
+            else
+                Thread.currentThread().interrupt();
         }
-    }
-
-    /**
-     * Acquires in shared interruptible mode.
-     * @param arg the acquire argument
-     */
-    private void doAcquireSharedInterruptibly(int arg)
-        throws InterruptedException {
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return;
-                    }
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
-    }
-
-    /**
-     * Acquires in shared timed mode.
-     *
-     * @param arg the acquire argument
-     * @param nanosTimeout max wait time
-     * @return {@code true} if acquired
-     */
-    private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (nanosTimeout <= 0L)
-            return false;
-        final long deadline = System.nanoTime() + nanosTimeout;
-        final Node node = addWaiter(Node.SHARED);
-        try {
-            for (;;) {
-                final Node p = node.predecessor();
-                if (p == head) {
-                    int r = tryAcquireShared(arg);
-                    if (r >= 0) {
-                        setHeadAndPropagate(node, r);
-                        p.next = null; // help GC
-                        return true;
-                    }
-                }
-                nanosTimeout = deadline - System.nanoTime();
-                if (nanosTimeout <= 0L) {
-                    cancelAcquire(node);
-                    return false;
-                }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if (Thread.interrupted())
-                    throw new InterruptedException();
-            }
-        } catch (Throwable t) {
-            cancelAcquire(node);
-            throw t;
-        }
+        return 0;
     }
 
     // Main exported methods
@@ -1236,9 +933,8 @@
      *        can represent anything you like.
      */
     public final void acquire(int arg) {
-        if (!tryAcquire(arg) &&
-            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
-            selfInterrupt();
+        if (!tryAcquire(arg))
+            acquire(null, arg, false, false, false, 0L);
     }
 
     /**
@@ -1256,11 +952,10 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireInterruptibly(int arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (!tryAcquire(arg) && acquire(null, arg, false, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (!tryAcquire(arg))
-            doAcquireInterruptibly(arg);
     }
 
     /**
@@ -1281,11 +976,20 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final boolean tryAcquireNanos(int arg, long nanosTimeout)
-            throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquire(arg) ||
-            doAcquireNanos(arg, nanosTimeout);
+        throws InterruptedException {
+        if (!Thread.interrupted()) {
+            if (tryAcquire(arg))
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, false, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -1300,9 +1004,7 @@
      */
     public final boolean release(int arg) {
         if (tryRelease(arg)) {
-            Node h = head;
-            if (h != null && h.waitStatus != 0)
-                unparkSuccessor(h);
+            signalNext(head);
             return true;
         }
         return false;
@@ -1321,7 +1023,7 @@
      */
     public final void acquireShared(int arg) {
         if (tryAcquireShared(arg) < 0)
-            doAcquireShared(arg);
+            acquire(null, arg, true, false, false, 0L);
     }
 
     /**
@@ -1338,11 +1040,11 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public final void acquireSharedInterruptibly(int arg)
-            throws InterruptedException {
-        if (Thread.interrupted())
+        throws InterruptedException {
+        if (Thread.interrupted() ||
+            (tryAcquireShared(arg) < 0 &&
+             acquire(null, arg, true, true, false, 0L) < 0))
             throw new InterruptedException();
-        if (tryAcquireShared(arg) < 0)
-            doAcquireSharedInterruptibly(arg);
     }
 
     /**
@@ -1363,10 +1065,19 @@
      */
     public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
             throws InterruptedException {
-        if (Thread.interrupted())
-            throw new InterruptedException();
-        return tryAcquireShared(arg) >= 0 ||
-            doAcquireSharedNanos(arg, nanosTimeout);
+        if (!Thread.interrupted()) {
+            if (tryAcquireShared(arg) >= 0)
+                return true;
+            if (nanosTimeout <= 0L)
+                return false;
+            int stat = acquire(null, arg, true, true, true,
+                               System.nanoTime() + nanosTimeout);
+            if (stat > 0)
+                return true;
+            if (stat == 0)
+                return false;
+        }
+        throw new InterruptedException();
     }
 
     /**
@@ -1380,7 +1091,7 @@
      */
     public final boolean releaseShared(int arg) {
         if (tryReleaseShared(arg)) {
-            doReleaseShared();
+            signalNext(head);
             return true;
         }
         return false;
@@ -1398,7 +1109,7 @@
      */
     public final boolean hasQueuedThreads() {
         for (Node p = tail, h = head; p != h && p != null; p = p.prev)
-            if (p.waitStatus <= 0)
+            if (p.status >= 0)
                 return true;
         return false;
     }
@@ -1428,45 +1139,16 @@
      *         {@code null} if no threads are currently queued
      */
     public final Thread getFirstQueuedThread() {
-        // handle only fast path, else relay
-        return (head == tail) ? null : fullGetFirstQueuedThread();
-    }
-
-    /**
-     * Version of getFirstQueuedThread called when fastpath fails.
-     */
-    private Thread fullGetFirstQueuedThread() {
-        /*
-         * The first node is normally head.next. Try to get its
-         * thread field, ensuring consistent reads: If thread
-         * field is nulled out or s.prev is no longer head, then
-         * some other thread(s) concurrently performed setHead in
-         * between some of our reads. We try this twice before
-         * resorting to traversal.
-         */
-        Node h, s;
-        Thread st;
-        if (((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null) ||
-            ((h = head) != null && (s = h.next) != null &&
-             s.prev == head && (st = s.thread) != null))
-            return st;
-
-        /*
-         * Head's next field might not have been set yet, or may have
-         * been unset after setHead. So we must check to see if tail
-         * is actually first node. If not, we continue on, safely
-         * traversing from tail back to head to find first,
-         * guaranteeing termination.
-         */
-
-        Thread firstThread = null;
-        for (Node p = tail; p != null && p != head; p = p.prev) {
-            Thread t = p.thread;
-            if (t != null)
-                firstThread = t;
+        Thread first = null, w; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null)) {
+            // traverse from tail on stale reads
+            for (Node p = tail, q; p != null && (q = p.prev) != null; p = q)
+                if ((w = p.waiter) != null)
+                    first = w;
         }
-        return firstThread;
+        return first;
     }
 
     /**
@@ -1483,7 +1165,7 @@
         if (thread == null)
             throw new NullPointerException();
         for (Node p = tail; p != null; p = p.prev)
-            if (p.thread == thread)
+            if (p.waiter == thread)
                 return true;
         return false;
     }
@@ -1499,10 +1181,8 @@
      */
     final boolean apparentlyFirstQueuedIsExclusive() {
         Node h, s;
-        return (h = head) != null &&
-            (s = h.next)  != null &&
-            !s.isShared()         &&
-            s.thread != null;
+        return (h = head) != null && (s = h.next)  != null &&
+            !(s instanceof SharedNode) && s.waiter != null;
     }
 
     /**
@@ -1549,19 +1229,12 @@
      * @since 1.7
      */
     public final boolean hasQueuedPredecessors() {
-        Node h, s;
-        if ((h = head) != null) {
-            if ((s = h.next) == null || s.waitStatus > 0) {
-                s = null; // traverse in case of concurrent cancellation
-                for (Node p = tail; p != h && p != null; p = p.prev) {
-                    if (p.waitStatus <= 0)
-                        s = p;
-                }
-            }
-            if (s != null && s.thread != Thread.currentThread())
-                return true;
-        }
-        return false;
+        Thread first = null; Node h, s;
+        if ((h = head) != null && ((s = h.next) == null ||
+                                   (first = s.waiter) == null ||
+                                   s.prev == null))
+            first = getFirstQueuedThread(); // retry via getFirstQueuedThread
+        return first != null && first != Thread.currentThread();
     }
 
     // Instrumentation and monitoring methods
@@ -1578,7 +1251,7 @@
     public final int getQueueLength() {
         int n = 0;
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.thread != null)
+            if (p.waiter != null)
                 ++n;
         }
         return n;
@@ -1598,7 +1271,7 @@
     public final Collection<Thread> getQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            Thread t = p.thread;
+            Thread t = p.waiter;
             if (t != null)
                 list.add(t);
         }
@@ -1616,8 +1289,8 @@
     public final Collection<Thread> getExclusiveQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (!p.isShared()) {
-                Thread t = p.thread;
+            if (!(p instanceof SharedNode)) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1636,8 +1309,8 @@
     public final Collection<Thread> getSharedQueuedThreads() {
         ArrayList<Thread> list = new ArrayList<>();
         for (Node p = tail; p != null; p = p.prev) {
-            if (p.isShared()) {
-                Thread t = p.thread;
+            if (p instanceof SharedNode) {
+                Thread t = p.waiter;
                 if (t != null)
                     list.add(t);
             }
@@ -1660,117 +1333,6 @@
             + (hasQueuedThreads() ? "non" : "") + "empty queue]";
     }
 
-
-    // Internal support methods for Conditions
-
-    /**
-     * Returns true if a node, always one that was initially placed on
-     * a condition queue, is now waiting to reacquire on sync queue.
-     * @param node the node
-     * @return true if is reacquiring
-     */
-    final boolean isOnSyncQueue(Node node) {
-        if (node.waitStatus == Node.CONDITION || node.prev == null)
-            return false;
-        if (node.next != null) // If has successor, it must be on queue
-            return true;
-        /*
-         * node.prev can be non-null, but not yet on queue because
-         * the CAS to place it on queue can fail. So we have to
-         * traverse from tail to make sure it actually made it.  It
-         * will always be near the tail in calls to this method, and
-         * unless the CAS failed (which is unlikely), it will be
-         * there, so we hardly ever traverse much.
-         */
-        return findNodeFromTail(node);
-    }
-
-    /**
-     * Returns true if node is on sync queue by searching backwards from tail.
-     * Called only when needed by isOnSyncQueue.
-     * @return true if present
-     */
-    private boolean findNodeFromTail(Node node) {
-        // We check for node first, since it's likely to be at or near tail.
-        // tail is known to be non-null, so we could re-order to "save"
-        // one null check, but we leave it this way to help the VM.
-        for (Node p = tail;;) {
-            if (p == node)
-                return true;
-            if (p == null)
-                return false;
-            p = p.prev;
-        }
-    }
-
-    /**
-     * Transfers a node from a condition queue onto sync queue.
-     * Returns true if successful.
-     * @param node the node
-     * @return true if successfully transferred (else the node was
-     * cancelled before signal)
-     */
-    final boolean transferForSignal(Node node) {
-        /*
-         * If cannot change waitStatus, the node has been cancelled.
-         */
-        if (!node.compareAndSetWaitStatus(Node.CONDITION, 0))
-            return false;
-
-        /*
-         * Splice onto queue and try to set waitStatus of predecessor to
-         * indicate that thread is (probably) waiting. If cancelled or
-         * attempt to set waitStatus fails, wake up to resync (in which
-         * case the waitStatus can be transiently and harmlessly wrong).
-         */
-        Node p = enq(node);
-        int ws = p.waitStatus;
-        if (ws > 0 || !p.compareAndSetWaitStatus(ws, Node.SIGNAL))
-            LockSupport.unpark(node.thread);
-        return true;
-    }
-
-    /**
-     * Transfers node, if necessary, to sync queue after a cancelled wait.
-     * Returns true if thread was cancelled before being signalled.
-     *
-     * @param node the node
-     * @return true if cancelled before the node was signalled
-     */
-    final boolean transferAfterCancelledWait(Node node) {
-        if (node.compareAndSetWaitStatus(Node.CONDITION, 0)) {
-            enq(node);
-            return true;
-        }
-        /*
-         * If we lost out to a signal(), then we can't proceed
-         * until it finishes its enq().  Cancelling during an
-         * incomplete transfer is both rare and transient, so just
-         * spin.
-         */
-        while (!isOnSyncQueue(node))
-            Thread.yield();
-        return false;
-    }
-
-    /**
-     * Invokes release with current state value; returns saved state.
-     * Cancels node and throws exception on failure.
-     * @param node the condition node for this wait
-     * @return previous sync state
-     */
-    final int fullyRelease(Node node) {
-        try {
-            int savedState = getState();
-            if (release(savedState))
-                return savedState;
-            throw new IllegalMonitorStateException();
-        } catch (Throwable t) {
-            node.waitStatus = Node.CANCELLED;
-            throw t;
-        }
-    }
-
     // Instrumentation methods for conditions
 
     /**
@@ -1868,106 +1430,34 @@
     public class ConditionObject implements Condition, java.io.Serializable {
         private static final long serialVersionUID = 1173984872572414699L;
         /** First node of condition queue. */
-        private transient Node firstWaiter;
+        private transient ConditionNode firstWaiter;
         /** Last node of condition queue. */
-        private transient Node lastWaiter;
+        private transient ConditionNode lastWaiter;
 
         /**
          * Creates a new {@code ConditionObject} instance.
          */
         public ConditionObject() { }
 
-        // Internal methods
-
-        /**
-         * Adds a new waiter to wait queue.
-         * @return its new wait node
-         */
-        private Node addConditionWaiter() {
-            if (!isHeldExclusively())
-                throw new IllegalMonitorStateException();
-            Node t = lastWaiter;
-            // If lastWaiter is cancelled, clean out.
-            if (t != null && t.waitStatus != Node.CONDITION) {
-                unlinkCancelledWaiters();
-                t = lastWaiter;
-            }
-
-            Node node = new Node(Node.CONDITION);
-
-            if (t == null)
-                firstWaiter = node;
-            else
-                t.nextWaiter = node;
-            lastWaiter = node;
-            return node;
-        }
-
-        /**
-         * Removes and transfers nodes until hit non-cancelled one or
-         * null. Split out from signal in part to encourage compilers
-         * to inline the case of no waiters.
-         * @param first (non-null) the first node on condition queue
-         */
-        private void doSignal(Node first) {
-            do {
-                if ( (firstWaiter = first.nextWaiter) == null)
-                    lastWaiter = null;
-                first.nextWaiter = null;
-            } while (!transferForSignal(first) &&
-                     (first = firstWaiter) != null);
-        }
+        // Signalling methods
 
         /**
-         * Removes and transfers all nodes.
-         * @param first (non-null) the first node on condition queue
+         * Removes and transfers one or all waiters to sync queue.
          */
-        private void doSignalAll(Node first) {
-            lastWaiter = firstWaiter = null;
-            do {
-                Node next = first.nextWaiter;
-                first.nextWaiter = null;
-                transferForSignal(first);
+        private void doSignal(ConditionNode first, boolean all) {
+            while (first != null) {
+                ConditionNode next = first.nextWaiter;
+                if ((firstWaiter = next) == null)
+                    lastWaiter = null;
+                if ((first.getAndUnsetStatus(COND) & COND) != 0) {
+                    enqueue(first);
+                    if (!all)
+                        break;
+                }
                 first = next;
-            } while (first != null);
-        }
-
-        /**
-         * Unlinks cancelled waiter nodes from condition queue.
-         * Called only while holding lock. This is called when
-         * cancellation occurred during condition wait, and upon
-         * insertion of a new waiter when lastWaiter is seen to have
-         * been cancelled. This method is needed to avoid garbage
-         * retention in the absence of signals. So even though it may
-         * require a full traversal, it comes into play only when
-         * timeouts or cancellations occur in the absence of
-         * signals. It traverses all nodes rather than stopping at a
-         * particular target to unlink all pointers to garbage nodes
-         * without requiring many re-traversals during cancellation
-         * storms.
-         */
-        private void unlinkCancelledWaiters() {
-            Node t = firstWaiter;
-            Node trail = null;
-            while (t != null) {
-                Node next = t.nextWaiter;
-                if (t.waitStatus != Node.CONDITION) {
-                    t.nextWaiter = null;
-                    if (trail == null)
-                        firstWaiter = next;
-                    else
-                        trail.nextWaiter = next;
-                    if (next == null)
-                        lastWaiter = trail;
-                }
-                else
-                    trail = t;
-                t = next;
             }
         }
 
-        // public methods
-
         /**
          * Moves the longest-waiting thread, if one exists, from the
          * wait queue for this condition to the wait queue for the
@@ -1977,11 +1467,11 @@
          *         returns {@code false}
          */
         public final void signal() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignal(first);
+                doSignal(first, false);
         }
 
         /**
@@ -1992,11 +1482,72 @@
          *         returns {@code false}
          */
         public final void signalAll() {
+            ConditionNode first = firstWaiter;
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            Node first = firstWaiter;
             if (first != null)
-                doSignalAll(first);
+                doSignal(first, true);
+        }
+
+        // Waiting methods
+
+        /**
+         * Adds node to condition list and releases lock.
+         *
+         * @param node the node
+         * @return savedState to reacquire after wait
+         */
+        private int enableWait(ConditionNode node) {
+            if (isHeldExclusively()) {
+                node.waiter = Thread.currentThread();
+                node.setStatusRelaxed(COND | WAITING);
+                ConditionNode last = lastWaiter;
+                if (last == null)
+                    firstWaiter = node;
+                else
+                    last.nextWaiter = node;
+                lastWaiter = node;
+                int savedState = getState();
+                if (release(savedState))
+                    return savedState;
+            }
+            node.status = CANCELLED; // lock not held or inconsistent
+            throw new IllegalMonitorStateException();
+        }
+
+        /**
+         * Returns true if a node that was initially placed on a condition
+         * queue is now ready to reacquire on sync queue.
+         * @param node the node
+         * @return true if is reacquiring
+         */
+        private boolean canReacquire(ConditionNode node) {
+            // check links, not status to avoid enqueue race
+            return node != null && node.prev != null && isEnqueued(node);
+        }
+
+        /**
+         * Unlinks the given node and other non-waiting nodes from
+         * condition queue unless already unlinked.
+         */
+        private void unlinkCancelledWaiters(ConditionNode node) {
+            if (node == null || node.nextWaiter != null || node == lastWaiter) {
+                ConditionNode w = firstWaiter, trail = null;
+                while (w != null) {
+                    ConditionNode next = w.nextWaiter;
+                    if ((w.status & COND) == 0) {
+                        w.nextWaiter = null;
+                        if (trail == null)
+                            firstWaiter = next;
+                        else
+                            trail.nextWaiter = next;
+                        if (next == null)
+                            lastWaiter = trail;
+                    } else
+                        trail = w;
+                    w = next;
+                }
+            }
         }
 
         /**
@@ -2011,51 +1562,27 @@
          * </ol>
          */
         public final void awaitUninterruptibly() {
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
             boolean interrupted = false;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
+            while (!canReacquire(node)) {
                 if (Thread.interrupted())
                     interrupted = true;
+                else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) || interrupted)
-                selfInterrupt();
-        }
-
-        /*
-         * For interruptible waits, we need to track whether to throw
-         * InterruptedException, if interrupted while blocked on
-         * condition, versus reinterrupt current thread, if
-         * interrupted while blocked waiting to re-acquire.
-         */
-
-        /** Mode meaning to reinterrupt on exit from wait */
-        private static final int REINTERRUPT =  1;
-        /** Mode meaning to throw InterruptedException on exit from wait */
-        private static final int THROW_IE    = -1;
-
-        /**
-         * Checks for interrupt, returning THROW_IE if interrupted
-         * before signalled, REINTERRUPT if after signalled, or
-         * 0 if not interrupted.
-         */
-        private int checkInterruptWhileWaiting(Node node) {
-            return Thread.interrupted() ?
-                (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
-                0;
-        }
-
-        /**
-         * Throws InterruptedException, reinterrupts current thread, or
-         * does nothing, depending on mode.
-         */
-        private void reportInterruptAfterWait(int interruptMode)
-            throws InterruptedException {
-            if (interruptMode == THROW_IE)
-                throw new InterruptedException();
-            else if (interruptMode == REINTERRUPT)
-                selfInterrupt();
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted)
+                Thread.currentThread().interrupt();
         }
 
         /**
@@ -2074,20 +1601,33 @@
         public final void await() throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                LockSupport.park(this);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            LockSupport.setCurrentBlocker(this); // for back-compatibility
+            boolean interrupted = false, cancelled = false;
+            while (!canReacquire(node)) {
+                if (interrupted |= Thread.interrupted()) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;              // else interrupted after signal
+                } else if ((node.status & COND) != 0) {
+                    try {
+                        ForkJoinPool.managedBlock(node);
+                    } catch (InterruptedException ie) {
+                        interrupted = true;
+                    }
+                } else
+                    Thread.onSpinWait();    // awoke while enqueuing
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null) // clean up if cancelled
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            LockSupport.setCurrentBlocker(null);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (interrupted) {
+                if (cancelled) {
+                    unlinkCancelledWaiters(node);
+                    throw new InterruptedException();
+                }
+                Thread.currentThread().interrupt();
+            }
         }
 
         /**
@@ -2107,32 +1647,29 @@
                 throws InterruptedException {
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // awaitNanos(0) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            long initialNanos = nanosTimeout;
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
             long remaining = deadline - System.nanoTime(); // avoid overflow
-            return (remaining <= initialNanos) ? remaining : Long.MIN_VALUE;
+            return (remaining <= nanosTimeout) ? remaining : Long.MIN_VALUE;
         }
 
         /**
@@ -2154,26 +1691,26 @@
             long abstime = deadline.getTime();
             if (Thread.interrupted())
                 throw new InterruptedException();
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (System.currentTimeMillis() >= abstime) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                LockSupport.parkUntil(this, abstime);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    System.currentTimeMillis() >= abstime) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkUntil(this, abstime);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         /**
@@ -2195,31 +1732,28 @@
             long nanosTimeout = unit.toNanos(time);
             if (Thread.interrupted())
                 throw new InterruptedException();
-            // We don't check for nanosTimeout <= 0L here, to allow
-            // await(0, unit) as a way to "yield the lock".
-            final long deadline = System.nanoTime() + nanosTimeout;
-            Node node = addConditionWaiter();
-            int savedState = fullyRelease(node);
-            boolean timedout = false;
-            int interruptMode = 0;
-            while (!isOnSyncQueue(node)) {
-                if (nanosTimeout <= 0L) {
-                    timedout = transferAfterCancelledWait(node);
-                    break;
-                }
-                if (nanosTimeout > SPIN_FOR_TIMEOUT_THRESHOLD)
-                    LockSupport.parkNanos(this, nanosTimeout);
-                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
-                    break;
-                nanosTimeout = deadline - System.nanoTime();
+            ConditionNode node = new ConditionNode();
+            int savedState = enableWait(node);
+            long nanos = (nanosTimeout < 0L) ? 0L : nanosTimeout;
+            long deadline = System.nanoTime() + nanos;
+            boolean cancelled = false, interrupted = false;
+            while (!canReacquire(node)) {
+                if ((interrupted |= Thread.interrupted()) ||
+                    (nanos = deadline - System.nanoTime()) <= 0L) {
+                    if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
+                        break;
+                } else
+                    LockSupport.parkNanos(this, nanos);
             }
-            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
-                interruptMode = REINTERRUPT;
-            if (node.nextWaiter != null)
-                unlinkCancelledWaiters();
-            if (interruptMode != 0)
-                reportInterruptAfterWait(interruptMode);
-            return !timedout;
+            node.clearStatus();
+            acquire(node, savedState, false, false, false, 0L);
+            if (cancelled) {
+                unlinkCancelledWaiters(node);
+                if (interrupted)
+                    throw new InterruptedException();
+            } else if (interrupted)
+                Thread.currentThread().interrupt();
+            return !cancelled;
         }
 
         //  support for instrumentation
@@ -2245,8 +1779,8 @@
         protected final boolean hasWaiters() {
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     return true;
             }
             return false;
@@ -2265,8 +1799,8 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             int n = 0;
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION)
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0)
                     ++n;
             }
             return n;
@@ -2285,9 +1819,9 @@
             if (!isHeldExclusively())
                 throw new IllegalMonitorStateException();
             ArrayList<Thread> list = new ArrayList<>();
-            for (Node w = firstWaiter; w != null; w = w.nextWaiter) {
-                if (w.waitStatus == Node.CONDITION) {
-                    Thread t = w.thread;
+            for (ConditionNode w = firstWaiter; w != null; w = w.nextWaiter) {
+                if ((w.status & COND) != 0) {
+                    Thread t = w.waiter;
                     if (t != null)
                         list.add(t);
                 }
@@ -2296,39 +1830,16 @@
         }
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle HEAD;
-    private static final VarHandle TAIL;
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(AbstractQueuedSynchronizer.class, "tail");
 
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(AbstractQueuedSynchronizer.class, "state", int.class);
-            HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
-            TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
-
-        // Reduce the risk of rare disastrous classloading in first call to
-        // LockSupport.park: https://bugs.openjdk.java.net/browse/JDK-8074773
         Class<?> ensureLoaded = LockSupport.class;
     }
-
-    /**
-     * Initializes head and tail fields on first contention.
-     */
-    private final void initializeSyncQueue() {
-        Node h;
-        if (HEAD.compareAndSet(this, null, (h = new Node())))
-            tail = h;
-    }
-
-    /**
-     * CASes tail field.
-     */
-    private final boolean compareAndSetTail(Node expect, Node update) {
-        return TAIL.compareAndSet(this, expect, update);
-    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/Lock.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Lock.java	Wed Sep 18 07:46:02 2019 +0200
@@ -122,9 +122,8 @@
  * <p>All {@code Lock} implementations <em>must</em> enforce the same
  * memory synchronization semantics as provided by the built-in monitor
  * lock, as described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
  * Chapter 17 of
- * <cite>The Java&trade; Language Specification</cite></a>:
+ * <cite>The Java&trade; Language Specification</cite>:
  * <ul>
  * <li>A successful {@code lock} operation has the same memory
  * synchronization effects as a successful <em>Lock</em> action.
@@ -162,6 +161,7 @@
  * @see ReentrantLock
  * @see Condition
  * @see ReadWriteLock
+ * @jls 17.4 Memory Model
  *
  * @since 1.5
  * @author Doug Lea
--- a/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Wed Sep 18 07:46:02 2019 +0200
@@ -140,8 +140,25 @@
     private LockSupport() {} // Cannot be instantiated.
 
     private static void setBlocker(Thread t, Object arg) {
-        // Even though volatile, hotspot doesn't need a write barrier here.
-        U.putReference(t, PARKBLOCKER, arg);
+        U.putReferenceOpaque(t, PARKBLOCKER, arg);
+    }
+
+    /**
+     * Sets the object to be returned by invocations of {@link
+     * #getBlocker getBlocker} for the current thread. This method may
+     * be used before invoking the no-argument version of {@link
+     * LockSupport#park() park()} from non-public objects, allowing
+     * more helpful diagnostics, or retaining compatibility with
+     * previous implementations of blocking methods.  Previous values
+     * of the blocker are not automatically restored after blocking.
+     * To obtain the effects of {@code park(b}}, use {@code
+     * setCurrentBlocker(b); park(); setCurrentBlocker(null);}
+     *
+     * @param blocker the blocker object
+     * @since 14
+     */
+    public static void setCurrentBlocker(Object blocker) {
+        U.putReferenceOpaque(Thread.currentThread(), PARKBLOCKER, blocker);
     }
 
     /**
@@ -292,7 +309,7 @@
     public static Object getBlocker(Thread t) {
         if (t == null)
             throw new NullPointerException();
-        return U.getReferenceVolatile(t, PARKBLOCKER);
+        return U.getReferenceOpaque(t, PARKBLOCKER);
     }
 
     /**
@@ -394,24 +411,6 @@
     }
 
     /**
-     * Returns the pseudo-randomly initialized or updated secondary seed.
-     * Copied from ThreadLocalRandom due to package access restrictions.
-     */
-    static final int nextSecondarySeed() {
-        int r;
-        Thread t = Thread.currentThread();
-        if ((r = U.getInt(t, SECONDARY)) != 0) {
-            r ^= r << 13;   // xorshift
-            r ^= r >>> 17;
-            r ^= r << 5;
-        }
-        else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0)
-            r = 1; // avoid zero
-        U.putInt(t, SECONDARY, r);
-        return r;
-    }
-
-    /**
      * Returns the thread id for the given thread.  We must access
      * this directly rather than via method Thread.getId() because
      * getId() has been known to be overridden in ways that do not
@@ -423,11 +422,9 @@
 
     // Hotspot implementation via intrinsics API
     private static final Unsafe U = Unsafe.getUnsafe();
-    private static final long PARKBLOCKER = U.objectFieldOffset
-            (Thread.class, "parkBlocker");
-    private static final long SECONDARY = U.objectFieldOffset
-            (Thread.class, "threadLocalRandomSecondarySeed");
-    private static final long TID = U.objectFieldOffset
-            (Thread.class, "tid");
+    private static final long PARKBLOCKER
+        = U.objectFieldOffset(Thread.class, "parkBlocker");
+    private static final long TID
+        = U.objectFieldOffset(Thread.class, "tid");
 
 }
--- a/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/ReentrantLock.java	Wed Sep 18 07:46:02 2019 +0200
@@ -119,39 +119,63 @@
         private static final long serialVersionUID = -5179523762034025860L;
 
         /**
-         * Performs non-fair tryLock.  tryAcquire is implemented in
-         * subclasses, but both need nonfair try for trylock method.
+         * Performs non-fair tryLock.
          */
         @ReservedStackAccess
-        final boolean nonfairTryAcquire(int acquires) {
-            final Thread current = Thread.currentThread();
+        final boolean tryLock() {
+            Thread current = Thread.currentThread();
             int c = getState();
             if (c == 0) {
-                if (compareAndSetState(0, acquires)) {
+                if (compareAndSetState(0, 1)) {
                     setExclusiveOwnerThread(current);
                     return true;
                 }
-            }
-            else if (current == getExclusiveOwnerThread()) {
-                int nextc = c + acquires;
-                if (nextc < 0) // overflow
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
                     throw new Error("Maximum lock count exceeded");
-                setState(nextc);
+                setState(c);
                 return true;
             }
             return false;
         }
 
+        /**
+         * Checks for reentrancy and acquires if lock immediately
+         * available under fair vs nonfair rules. Locking methods
+         * perform initialTryLock check before relaying to
+         * corresponding AQS acquire methods.
+         */
+        abstract boolean initialTryLock();
+
+        @ReservedStackAccess
+        final void lock() {
+            if (!initialTryLock())
+                acquire(1);
+        }
+
+        @ReservedStackAccess
+        final void lockInterruptibly() throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            if (!initialTryLock())
+                acquireInterruptibly(1);
+        }
+
+        @ReservedStackAccess
+        final boolean tryLockNanos(long nanos) throws InterruptedException {
+            if (Thread.interrupted())
+                throw new InterruptedException();
+            return initialTryLock() || tryAcquireNanos(1, nanos);
+        }
+
         @ReservedStackAccess
         protected final boolean tryRelease(int releases) {
             int c = getState() - releases;
-            if (Thread.currentThread() != getExclusiveOwnerThread())
+            if (getExclusiveOwnerThread() != Thread.currentThread())
                 throw new IllegalMonitorStateException();
-            boolean free = false;
-            if (c == 0) {
-                free = true;
+            boolean free = (c == 0);
+            if (free)
                 setExclusiveOwnerThread(null);
-            }
             setState(c);
             return free;
         }
@@ -195,8 +219,31 @@
      */
     static final class NonfairSync extends Sync {
         private static final long serialVersionUID = 7316153563782823691L;
+
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
+            if (compareAndSetState(0, 1)) { // first attempt is unguarded
+                setExclusiveOwnerThread(current);
+                return true;
+            } else if (getExclusiveOwnerThread() == current) {
+                int c = getState() + 1;
+                if (c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
+            } else
+                return false;
+        }
+
+        /**
+         * Acquire for non-reentrant cases after initialTryLock prescreen
+         */
         protected final boolean tryAcquire(int acquires) {
-            return nonfairTryAcquire(acquires);
+            if (getState() == 0 && compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
+                return true;
+            }
+            return false;
         }
     }
 
@@ -205,26 +252,34 @@
      */
     static final class FairSync extends Sync {
         private static final long serialVersionUID = -3000897897090466540L;
+
         /**
-         * Fair version of tryAcquire.  Don't grant access unless
-         * recursive call or no waiters or is first.
+         * Acquires only if reentrant or queue is empty.
          */
-        @ReservedStackAccess
-        protected final boolean tryAcquire(int acquires) {
-            final Thread current = Thread.currentThread();
+        final boolean initialTryLock() {
+            Thread current = Thread.currentThread();
             int c = getState();
             if (c == 0) {
-                if (!hasQueuedPredecessors() &&
-                    compareAndSetState(0, acquires)) {
+                if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
                     setExclusiveOwnerThread(current);
                     return true;
                 }
+            } else if (getExclusiveOwnerThread() == current) {
+                if (++c < 0) // overflow
+                    throw new Error("Maximum lock count exceeded");
+                setState(c);
+                return true;
             }
-            else if (current == getExclusiveOwnerThread()) {
-                int nextc = c + acquires;
-                if (nextc < 0)
-                    throw new Error("Maximum lock count exceeded");
-                setState(nextc);
+            return false;
+        }
+
+        /**
+         * Acquires only if thread is first waiter or empty
+         */
+        protected final boolean tryAcquire(int acquires) {
+            if (getState() == 0 && !hasQueuedPredecessors() &&
+                compareAndSetState(0, acquires)) {
+                setExclusiveOwnerThread(Thread.currentThread());
                 return true;
             }
             return false;
@@ -264,7 +319,7 @@
      * at which time the lock hold count is set to one.
      */
     public void lock() {
-        sync.acquire(1);
+        sync.lock();
     }
 
     /**
@@ -314,7 +369,7 @@
      * @throws InterruptedException if the current thread is interrupted
      */
     public void lockInterruptibly() throws InterruptedException {
-        sync.acquireInterruptibly(1);
+        sync.lockInterruptibly();
     }
 
     /**
@@ -344,7 +399,7 @@
      *         thread; and {@code false} otherwise
      */
     public boolean tryLock() {
-        return sync.nonfairTryAcquire(1);
+        return sync.tryLock();
     }
 
     /**
@@ -421,7 +476,7 @@
      */
     public boolean tryLock(long timeout, TimeUnit unit)
             throws InterruptedException {
-        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
+        return sync.tryLockNanos(unit.toNanos(timeout));
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Wed Sep 18 07:46:02 2019 +0200
@@ -35,9 +35,8 @@
 
 package java.util.concurrent.locks;
 
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.VarHandle;
 import java.util.concurrent.TimeUnit;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.vm.annotation.ReservedStackAccess;
 
 /**
@@ -132,9 +131,8 @@
  *
  * <p><b>Memory Synchronization.</b> Methods with the effect of
  * successfully locking in any mode have the same memory
- * synchronization effects as a <em>Lock</em> action described in
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4">
- * Chapter 17 of <cite>The Java&trade; Language Specification</cite></a>.
+ * synchronization effects as a <em>Lock</em> action, as described in
+ * Chapter 17 of <cite>The Java&trade; Language Specification</cite>.
  * Methods successfully unlocking in write mode have the same memory
  * synchronization effects as an <em>Unlock</em> action.  In optimistic
  * read usages, actions prior to the most recent write mode unlock action
@@ -237,6 +235,7 @@
  *   }
  * }}</pre>
  *
+ * @jls 17.4 Memory Model
  * @since 1.8
  * @author Doug Lea
  */
@@ -264,122 +263,54 @@
      * updates.
      *
      * Waiters use a modified form of CLH lock used in
-     * AbstractQueuedSynchronizer (see its internal documentation for
-     * a fuller account), where each node is tagged (field mode) as
-     * either a reader or writer. Sets of waiting readers are grouped
-     * (linked) under a common node (field cowait) so act as a single
-     * node with respect to most CLH mechanics.  By virtue of the
-     * queue structure, wait nodes need not actually carry sequence
-     * numbers; we know each is greater than its predecessor.  This
-     * simplifies the scheduling policy to a mainly-FIFO scheme that
-     * incorporates elements of Phase-Fair locks (see Brandenburg &
-     * Anderson, especially http://www.cs.unc.edu/~bbb/diss/).  In
-     * particular, we use the phase-fair anti-barging rule: If an
-     * incoming reader arrives while read lock is held but there is a
-     * queued writer, this incoming reader is queued.  (This rule is
-     * responsible for some of the complexity of method acquireRead,
-     * but without it, the lock becomes highly unfair.) Method release
-     * does not (and sometimes cannot) itself wake up cowaiters. This
-     * is done by the primary thread, but helped by any other threads
-     * with nothing better to do in methods acquireRead and
-     * acquireWrite.
+     * AbstractQueuedSynchronizer (AQS; see its internal documentation
+     * for a fuller account), where each node is either a ReaderNode
+     * or WriterNode. Implementation of queued Writer mode is
+     * identical to AQS except for lock-state operations.  Sets of
+     * waiting readers are grouped (linked) under a common node (field
+     * cowaiters) so act as a single node with respect to most CLH
+     * mechanics.  This simplifies the scheduling policy to a
+     * mainly-FIFO scheme that incorporates elements of Phase-Fair
+     * locks (see Brandenburg & Anderson, especially
+     * http://www.cs.unc.edu/~bbb/diss/).  Method release does not
+     * itself wake up cowaiters. This is done by the primary thread,
+     * but helped by other cowaiters as they awaken.
      *
-     * These rules apply to threads actually queued. All tryLock forms
-     * opportunistically try to acquire locks regardless of preference
-     * rules, and so may "barge" their way in.  Randomized spinning is
-     * used in the acquire methods to reduce (increasingly expensive)
-     * context switching while also avoiding sustained memory
-     * thrashing among many threads.  We limit spins to the head of
-     * queue. If, upon wakening, a thread fails to obtain lock, and is
-     * still (or becomes) the first waiting thread (which indicates
-     * that some other thread barged and obtained lock), it escalates
-     * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of
-     * continually losing to barging threads.
+     * These rules apply to threads actually queued. Threads may also
+     * try to acquire locks before or in the process of enqueueing
+     * regardless of preference rules, and so may "barge" their way
+     * in.  Methods writeLock and readLock (but not the other variants
+     * of each) first unconditionally try to CAS state, falling back
+     * to test-and-test-and-set retries on failure, slightly shrinking
+     * race windows on initial attempts, thus making success more
+     * likely. Also, when some threads cancel (via interrupt or
+     * timeout), phase-fairness is at best roughly approximated.
      *
      * Nearly all of these mechanics are carried out in methods
      * acquireWrite and acquireRead, that, as typical of such code,
      * sprawl out because actions and retries rely on consistent sets
      * of locally cached reads.
      *
-     * As noted in Boehm's paper (above), sequence validation (mainly
-     * method validate()) requires stricter ordering rules than apply
-     * to normal volatile reads (of "state").  To force orderings of
-     * reads before a validation and the validation itself in those
-     * cases where this is not already forced, we use acquireFence.
-     * Unlike in that paper, we allow writers to use plain writes.
-     * One would not expect reorderings of such writes with the lock
-     * acquisition CAS because there is a "control dependency", but it
-     * is theoretically possible, so we additionally add a
-     * storeStoreFence after lock acquisition CAS.
-     *
-     * ----------------------------------------------------------------
-     * Here's an informal proof that plain reads by _successful_
-     * readers see plain writes from preceding but not following
-     * writers (following Boehm and the C++ standard [atomics.fences]):
-     *
-     * Because of the total synchronization order of accesses to
-     * volatile long state containing the sequence number, writers and
-     * _successful_ readers can be globally sequenced.
-     *
-     * int x, y;
-     *
-     * Writer 1:
-     * inc sequence (odd - "locked")
-     * storeStoreFence();
-     * x = 1; y = 2;
-     * inc sequence (even - "unlocked")
-     *
-     * Successful Reader:
-     * read sequence (even)
-     * // must see writes from Writer 1 but not Writer 2
-     * r1 = x; r2 = y;
-     * acquireFence();
-     * read sequence (even - validated unchanged)
-     * // use r1 and r2
-     *
-     * Writer 2:
-     * inc sequence (odd - "locked")
-     * storeStoreFence();
-     * x = 3; y = 4;
-     * inc sequence (even - "unlocked")
-     *
-     * Visibility of writer 1's stores is normal - reader's initial
-     * read of state synchronizes with writer 1's final write to state.
-     * Lack of visibility of writer 2's plain writes is less obvious.
-     * If reader's read of x or y saw writer 2's write, then (assuming
-     * semantics of C++ fences) the storeStoreFence would "synchronize"
-     * with reader's acquireFence and reader's validation read must see
-     * writer 2's initial write to state and so validation must fail.
-     * But making this "proof" formal and rigorous is an open problem!
-     * ----------------------------------------------------------------
+     * For an explanation of the use of acquireFence, see
+     * http://gee.cs.oswego.edu/dl/html/j9mm.html as well as Boehm's
+     * paper (above). Note that sequence validation (mainly method
+     * validate()) requires stricter ordering rules than apply to
+     * normal volatile reads (of "state").  To ensure that writeLock
+     * acquisitions strictly precede subsequent writes in cases where
+     * this is not already forced, we use a storeStoreFence.
      *
      * The memory layout keeps lock state and queue pointers together
      * (normally on the same cache line). This usually works well for
      * read-mostly loads. In most other cases, the natural tendency of
-     * adaptive-spin CLH locks to reduce memory contention lessens
-     * motivation to further spread out contended locations, but might
-     * be subject to future improvements.
+     * CLH locks to reduce memory contention lessens motivation to
+     * further spread out contended locations, but might be subject to
+     * future improvements.
      */
 
     private static final long serialVersionUID = -6001602636862214147L;
 
-    /** Number of processors, for spin control */
-    private static final int NCPU = Runtime.getRuntime().availableProcessors();
-
-    /** Maximum number of retries before enqueuing on acquisition; at least 1 */
-    private static final int SPINS = (NCPU > 1) ? 1 << 6 : 1;
-
-    /** Maximum number of tries before blocking at head on acquisition */
-    private static final int HEAD_SPINS = (NCPU > 1) ? 1 << 10 : 1;
-
-    /** Maximum number of retries before re-blocking */
-    private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 16 : 1;
-
-    /** The period for yielding when waiting for overflow spinlock */
-    private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1
-
     /** The number of bits to use for reader count before overflowing */
-    private static final int LG_READERS = 7;
+    private static final int LG_READERS = 7; // 127 readers
 
     // Values for lock state and stamp operations
     private static final long RUNIT = 1L;
@@ -388,6 +319,8 @@
     private static final long RFULL = RBITS - 1L;
     private static final long ABITS = RBITS | WBIT;
     private static final long SBITS = ~RBITS; // note overlap with ABITS
+    // not writing and conservatively non-overflowing
+    private static final long RSAFE = ~(3L << (LG_READERS - 1));
 
     /*
      * 3 stamp modes can be distinguished by examining (m = stamp & ABITS):
@@ -408,29 +341,64 @@
     // Special value from cancelled acquire methods so caller can throw IE
     private static final long INTERRUPTED = 1L;
 
-    // Values for node status; order matters
-    private static final int WAITING   = -1;
-    private static final int CANCELLED =  1;
+    // Bits for Node.status
+    static final int WAITING   = 1;
+    static final int CANCELLED = 0x80000000; // must be negative
 
-    // Modes for nodes (int not boolean to allow arithmetic)
-    private static final int RMODE = 0;
-    private static final int WMODE = 1;
+    /** CLH nodes */
+    abstract static class Node {
+        volatile Node prev;       // initially attached via casTail
+        volatile Node next;       // visibly nonnull when signallable
+        Thread waiter;            // visibly nonnull when enqueued
+        volatile int status;      // written by owner, atomic bit ops by others
 
-    /** Wait nodes */
-    static final class WNode {
-        volatile WNode prev;
-        volatile WNode next;
-        volatile WNode cowait;    // list of linked readers
-        volatile Thread thread;   // non-null while possibly parked
-        volatile int status;      // 0, WAITING, or CANCELLED
-        final int mode;           // RMODE or WMODE
-        WNode(int m, WNode p) { mode = m; prev = p; }
+        // methods for atomic operations
+        final boolean casPrev(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, PREV, c, v);
+        }
+        final boolean casNext(Node c, Node v) {  // for cleanQueue
+            return U.weakCompareAndSetReference(this, NEXT, c, v);
+        }
+        final int getAndUnsetStatus(int v) {     // for signalling
+            return U.getAndBitwiseAndInt(this, STATUS, ~v);
+        }
+        final void setPrevRelaxed(Node p) {      // for off-queue assignment
+            U.putReference(this, PREV, p);
+        }
+        final void setStatusRelaxed(int s) {     // for off-queue assignment
+            U.putInt(this, STATUS, s);
+        }
+        final void clearStatus() {               // for reducing unneeded signals
+            U.putIntOpaque(this, STATUS, 0);
+        }
+
+        private static final long STATUS
+            = U.objectFieldOffset(Node.class, "status");
+        private static final long NEXT
+            = U.objectFieldOffset(Node.class, "next");
+        private static final long PREV
+            = U.objectFieldOffset(Node.class, "prev");
+    }
+
+    static final class WriterNode extends Node { // node for writers
+    }
+
+    static final class ReaderNode extends Node { // node for readers
+        volatile ReaderNode cowaiters;           // list of linked readers
+        final boolean casCowaiters(ReaderNode c, ReaderNode v) {
+            return U.weakCompareAndSetReference(this, COWAITERS, c, v);
+        }
+        final void setCowaitersRelaxed(ReaderNode p) {
+            U.putReference(this, COWAITERS, p);
+        }
+        private static final long COWAITERS
+            = U.objectFieldOffset(ReaderNode.class, "cowaiters");
     }
 
     /** Head of CLH queue */
-    private transient volatile WNode whead;
+    private transient volatile Node head;
     /** Tail (last) of CLH queue */
-    private transient volatile WNode wtail;
+    private transient volatile Node tail;
 
     // views
     transient ReadLockView readLockView;
@@ -449,18 +417,50 @@
         state = ORIGIN;
     }
 
-    private boolean casState(long expectedValue, long newValue) {
-        return STATE.compareAndSet(this, expectedValue, newValue);
+    // internal lock methods
+
+    private boolean casState(long expect, long update) {
+        return U.compareAndSetLong(this, STATE, expect, update);
+    }
+
+    @ReservedStackAccess
+    private long tryAcquireWrite() {
+        long s, nextState;
+        if (((s = state) & ABITS) == 0L && casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return 0L;
     }
 
-    private long tryWriteLock(long s) {
-        // assert (s & ABITS) == 0L;
-        long next;
-        if (casState(s, next = s | WBIT)) {
-            VarHandle.storeStoreFence();
-            return next;
+    @ReservedStackAccess
+    private long tryAcquireRead() {
+        for (long s, m, nextState;;) {
+            if ((m = (s = state) & ABITS) < RFULL) {
+                if (casState(s, nextState = s + RUNIT))
+                    return nextState;
+            }
+            else if (m == WBIT)
+                return 0L;
+            else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                return nextState;
         }
-        return 0L;
+    }
+
+    /**
+     * Returns an unlocked state, incrementing the version and
+     * avoiding special failure value 0L.
+     *
+     * @param s a write-locked state (or stamp)
+     */
+    private static long unlockWriteState(long s) {
+        return ((s += WBIT) == 0L) ? ORIGIN : s;
+    }
+
+    private long releaseWrite(long s) {
+        long nextState = state = unlockWriteState(s);
+        signalNext(head);
+        return nextState;
     }
 
     /**
@@ -471,8 +471,13 @@
      */
     @ReservedStackAccess
     public long writeLock() {
-        long next;
-        return ((next = tryWriteLock()) != 0L) ? next : acquireWrite(false, 0L);
+        // try unconditional CAS confirming weak read
+        long s = U.getLongOpaque(this, STATE) & ~ABITS, nextState;
+        if (casState(s, nextState = s | WBIT)) {
+            U.storeStoreFence();
+            return nextState;
+        }
+        return acquireWrite(false, false, 0L);
     }
 
     /**
@@ -481,10 +486,8 @@
      * @return a write stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    @ReservedStackAccess
     public long tryWriteLock() {
-        long s;
-        return (((s = state) & ABITS) == 0L) ? tryWriteLock(s) : 0L;
+        return tryAcquireWrite();
     }
 
     /**
@@ -504,15 +507,14 @@
         throws InterruptedException {
         long nanos = unit.toNanos(time);
         if (!Thread.interrupted()) {
-            long next, deadline;
-            if ((next = tryWriteLock()) != 0L)
-                return next;
+            long nextState;
+            if ((nextState = tryAcquireWrite()) != 0L)
+                return nextState;
             if (nanos <= 0L)
                 return 0L;
-            if ((deadline = System.nanoTime() + nanos) == 0L)
-                deadline = 1L;
-            if ((next = acquireWrite(true, deadline)) != INTERRUPTED)
-                return next;
+            nextState = acquireWrite(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
         }
         throw new InterruptedException();
     }
@@ -527,12 +529,12 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long writeLockInterruptibly() throws InterruptedException {
-        long next;
+        long nextState;
         if (!Thread.interrupted() &&
-            (next = acquireWrite(true, 0L)) != INTERRUPTED)
-            return next;
+            ((nextState = tryAcquireWrite()) != 0L ||
+             (nextState = acquireWrite(true, false, 0L)) != INTERRUPTED))
+            return nextState;
         throw new InterruptedException();
     }
 
@@ -544,13 +546,12 @@
      */
     @ReservedStackAccess
     public long readLock() {
-        long s, next;
-        // bypass acquireRead on common uncontended case
-        return (whead == wtail
-                && ((s = state) & ABITS) < RFULL
-                && casState(s, next = s + RUNIT))
-            ? next
-            : acquireRead(false, 0L);
+        // unconditionally optimistically try non-overflow case once
+        long s = U.getLongOpaque(this, STATE) & RSAFE, nextState;
+        if (casState(s, nextState = s + RUNIT))
+            return nextState;
+        else
+            return acquireRead(false, false, 0L);
     }
 
     /**
@@ -559,18 +560,8 @@
      * @return a read stamp that can be used to unlock or convert mode,
      * or zero if the lock is not available
      */
-    @ReservedStackAccess
     public long tryReadLock() {
-        long s, m, next;
-        while ((m = (s = state) & ABITS) != WBIT) {
-            if (m < RFULL) {
-                if (casState(s, next = s + RUNIT))
-                    return next;
-            }
-            else if ((next = tryIncReaderOverflow(s)) != 0L)
-                return next;
-        }
-        return 0L;
+        return tryAcquireRead();
     }
 
     /**
@@ -586,26 +577,18 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long tryReadLock(long time, TimeUnit unit)
         throws InterruptedException {
-        long s, m, next, deadline;
         long nanos = unit.toNanos(time);
         if (!Thread.interrupted()) {
-            if ((m = (s = state) & ABITS) != WBIT) {
-                if (m < RFULL) {
-                    if (casState(s, next = s + RUNIT))
-                        return next;
-                }
-                else if ((next = tryIncReaderOverflow(s)) != 0L)
-                    return next;
-            }
+            long nextState;
+            if (tail == head && (nextState = tryAcquireRead()) != 0L)
+                return nextState;
             if (nanos <= 0L)
                 return 0L;
-            if ((deadline = System.nanoTime() + nanos) == 0L)
-                deadline = 1L;
-            if ((next = acquireRead(true, deadline)) != INTERRUPTED)
-                return next;
+            nextState = acquireRead(true, true, System.nanoTime() + nanos);
+            if (nextState != INTERRUPTED)
+                return nextState;
         }
         throw new InterruptedException();
     }
@@ -620,17 +603,12 @@
      * @throws InterruptedException if the current thread is interrupted
      * before acquiring the lock
      */
-    @ReservedStackAccess
     public long readLockInterruptibly() throws InterruptedException {
-        long s, next;
-        if (!Thread.interrupted()
-            // bypass acquireRead on common uncontended case
-            && ((whead == wtail
-                 && ((s = state) & ABITS) < RFULL
-                 && casState(s, next = s + RUNIT))
-                ||
-                (next = acquireRead(true, 0L)) != INTERRUPTED))
-            return next;
+        long nextState;
+        if (!Thread.interrupted() &&
+            ((nextState = tryAcquireRead()) != 0L ||
+             (nextState = acquireRead(true, false, 0L)) != INTERRUPTED))
+            return nextState;
         throw new InterruptedException();
     }
 
@@ -658,29 +636,11 @@
      * since issuance of the given stamp; else false
      */
     public boolean validate(long stamp) {
-        VarHandle.acquireFence();
+        U.loadFence();
         return (stamp & SBITS) == (state & SBITS);
     }
 
     /**
-     * Returns an unlocked state, incrementing the version and
-     * avoiding special failure value 0L.
-     *
-     * @param s a write-locked state (or stamp)
-     */
-    private static long unlockWriteState(long s) {
-        return ((s += WBIT) == 0L) ? ORIGIN : s;
-    }
-
-    private long unlockWriteInternal(long s) {
-        long next; WNode h;
-        STATE.setVolatile(this, next = unlockWriteState(s));
-        if ((h = whead) != null && h.status != 0)
-            release(h);
-        return next;
-    }
-
-    /**
      * If the lock state matches the given stamp, releases the
      * exclusive lock.
      *
@@ -692,7 +652,7 @@
     public void unlockWrite(long stamp) {
         if (state != stamp || (stamp & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        unlockWriteInternal(stamp);
+        releaseWrite(stamp);
     }
 
     /**
@@ -705,19 +665,20 @@
      */
     @ReservedStackAccess
     public void unlockRead(long stamp) {
-        long s, m; WNode h;
-        while (((s = state) & SBITS) == (stamp & SBITS)
-               && (stamp & RBITS) > 0L
-               && ((m = s & RBITS) > 0L)) {
-            if (m < RFULL) {
-                if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+        long s, m;
+        if ((stamp & RBITS) != 0L) {
+            while (((s = state) & SBITS) == (stamp & SBITS) &&
+                   ((m = s & RBITS) != 0L)) {
+                if (m < RFULL) {
+                    if (casState(s, s - RUNIT)) {
+                        if (m == RUNIT)
+                            signalNext(head);
+                        return;
+                    }
+                }
+                else if (tryDecReaderOverflow(s) != 0L)
                     return;
-                }
             }
-            else if (tryDecReaderOverflow(s) != 0L)
-                return;
         }
         throw new IllegalMonitorStateException();
     }
@@ -730,7 +691,6 @@
      * @throws IllegalMonitorStateException if the stamp does
      * not match the current state of this lock
      */
-    @ReservedStackAccess
     public void unlock(long stamp) {
         if ((stamp & WBIT) != 0L)
             unlockWrite(stamp);
@@ -751,26 +711,23 @@
      * @return a valid write stamp, or zero on failure
      */
     public long tryConvertToWriteLock(long stamp) {
-        long a = stamp & ABITS, m, s, next;
+        long a = stamp & ABITS, m, s, nextState;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((m = s & ABITS) == 0L) {
                 if (a != 0L)
                     break;
-                if ((next = tryWriteLock(s)) != 0L)
-                    return next;
-            }
-            else if (m == WBIT) {
+                if (casState(s, nextState = s | WBIT)) {
+                    U.storeStoreFence();
+                    return nextState;
+                }
+            } else if (m == WBIT) {
                 if (a != m)
                     break;
                 return stamp;
-            }
-            else if (m == RUNIT && a != 0L) {
-                if (casState(s, next = s - RUNIT + WBIT)) {
-                    VarHandle.storeStoreFence();
-                    return next;
-                }
-            }
-            else
+            } else if (m == RUNIT && a != 0L) {
+                if (casState(s, nextState = s - RUNIT + WBIT))
+                    return nextState;
+            } else
                 break;
         }
         return 0L;
@@ -788,28 +745,21 @@
      * @return a valid read stamp, or zero on failure
      */
     public long tryConvertToReadLock(long stamp) {
-        long a, s, next; WNode h;
+        long a, s, nextState;
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((a = stamp & ABITS) >= WBIT) {
-                // write stamp
-                if (s != stamp)
+                if (s != stamp) // write stamp
                     break;
-                STATE.setVolatile(this, next = unlockWriteState(s) + RUNIT);
-                if ((h = whead) != null && h.status != 0)
-                    release(h);
-                return next;
-            }
-            else if (a == 0L) {
-                // optimistic read stamp
+                nextState = state = unlockWriteState(s) + RUNIT;
+                signalNext(head);
+                return nextState;
+            } else if (a == 0L) { // optimistic read stamp
                 if ((s & ABITS) < RFULL) {
-                    if (casState(s, next = s + RUNIT))
-                        return next;
-                }
-                else if ((next = tryIncReaderOverflow(s)) != 0L)
-                    return next;
-            }
-            else {
-                // already a read stamp
+                    if (casState(s, nextState = s + RUNIT))
+                        return nextState;
+                } else if ((nextState = tryIncReaderOverflow(s)) != 0L)
+                    return nextState;
+            } else { // already a read stamp
                 if ((s & ABITS) == 0L)
                     break;
                 return stamp;
@@ -829,29 +779,25 @@
      * @return a valid optimistic read stamp, or zero on failure
      */
     public long tryConvertToOptimisticRead(long stamp) {
-        long a, m, s, next; WNode h;
-        VarHandle.acquireFence();
+        long a, m, s, nextState;
+        U.loadFence();
         while (((s = state) & SBITS) == (stamp & SBITS)) {
             if ((a = stamp & ABITS) >= WBIT) {
-                // write stamp
-                if (s != stamp)
+                if (s != stamp)   // write stamp
                     break;
-                return unlockWriteInternal(s);
-            }
-            else if (a == 0L)
-                // already an optimistic read stamp
+                return releaseWrite(s);
+            } else if (a == 0L) { // already an optimistic read stamp
                 return stamp;
-            else if ((m = s & ABITS) == 0L) // invalid read stamp
+            } else if ((m = s & ABITS) == 0L) { // invalid read stamp
                 break;
-            else if (m < RFULL) {
-                if (casState(s, next = s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
-                    return next & SBITS;
+            } else if (m < RFULL) {
+                if (casState(s, nextState = s - RUNIT)) {
+                    if (m == RUNIT)
+                        signalNext(head);
+                    return nextState & SBITS;
                 }
-            }
-            else if ((next = tryDecReaderOverflow(s)) != 0L)
-                return next & SBITS;
+            } else if ((nextState = tryDecReaderOverflow(s)) != 0L)
+                return nextState & SBITS;
         }
         return 0L;
     }
@@ -867,7 +813,7 @@
     public boolean tryUnlockWrite() {
         long s;
         if (((s = state) & WBIT) != 0L) {
-            unlockWriteInternal(s);
+            releaseWrite(s);
             return true;
         }
         return false;
@@ -882,12 +828,12 @@
      */
     @ReservedStackAccess
     public boolean tryUnlockRead() {
-        long s, m; WNode h;
+        long s, m;
         while ((m = (s = state) & ABITS) != 0L && m < WBIT) {
             if (m < RFULL) {
                 if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+                    if (m == RUNIT)
+                        signalNext(head);
                     return true;
                 }
             }
@@ -1133,16 +1079,16 @@
         long s;
         if (((s = state) & WBIT) == 0L)
             throw new IllegalMonitorStateException();
-        unlockWriteInternal(s);
+        releaseWrite(s);
     }
 
     final void unstampedUnlockRead() {
-        long s, m; WNode h;
+        long s, m;
         while ((m = (s = state) & RBITS) > 0L) {
             if (m < RFULL) {
                 if (casState(s, s - RUNIT)) {
-                    if (m == RUNIT && (h = whead) != null && h.status != 0)
-                        release(h);
+                    if (m == RUNIT)
+                        signalNext(head);
                     return;
                 }
             }
@@ -1155,10 +1101,10 @@
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
-        STATE.setVolatile(this, ORIGIN); // reset to unlocked state
+        state = ORIGIN; // reset to unlocked state
     }
 
-    // internals
+    // overflow handling methods
 
     /**
      * Tries to increment readerOverflow by first setting state
@@ -1170,17 +1116,12 @@
      */
     private long tryIncReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
-        if ((s & ABITS) == RFULL) {
-            if (casState(s, s | RBITS)) {
-                ++readerOverflow;
-                STATE.setVolatile(this, s);
-                return s;
-            }
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            ++readerOverflow;
+            return state = s;
         }
-        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
-            Thread.yield();
-        else
-            Thread.onSpinWait();
         return 0L;
     }
 
@@ -1192,153 +1133,132 @@
      */
     private long tryDecReaderOverflow(long s) {
         // assert (s & ABITS) >= RFULL;
-        if ((s & ABITS) == RFULL) {
-            if (casState(s, s | RBITS)) {
-                int r; long next;
-                if ((r = readerOverflow) > 0) {
-                    readerOverflow = r - 1;
-                    next = s;
-                }
-                else
-                    next = s - RUNIT;
-                STATE.setVolatile(this, next);
-                return next;
+        if ((s & ABITS) != RFULL)
+            Thread.onSpinWait();
+        else if (casState(s, s | RBITS)) {
+            int r; long nextState;
+            if ((r = readerOverflow) > 0) {
+                readerOverflow = r - 1;
+                nextState = s;
             }
+            else
+                nextState = s - RUNIT;
+            return state = nextState;
         }
-        else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
-            Thread.yield();
-        else
-            Thread.onSpinWait();
         return 0L;
     }
 
+    // release methods
+
     /**
-     * Wakes up the successor of h (normally whead). This is normally
-     * just h.next, but may require traversal from wtail if next
-     * pointers are lagging. This may fail to wake up an acquiring
-     * thread when one or more have been cancelled, but the cancel
-     * methods themselves provide extra safeguards to ensure liveness.
+     * Wakes up the successor of given node, if one exists, and unsets its
+     * WAITING status to avoid park race. This may fail to wake up an
+     * eligible thread when one or more have been cancelled, but
+     * cancelAcquire ensures liveness.
      */
-    private void release(WNode h) {
-        if (h != null) {
-            WNode q; Thread w;
-            WSTATUS.compareAndSet(h, WAITING, 0);
-            if ((q = h.next) == null || q.status == CANCELLED) {
-                for (WNode t = wtail; t != null && t != h; t = t.prev)
-                    if (t.status <= 0)
-                        q = t;
-            }
-            if (q != null && (w = q.thread) != null)
-                LockSupport.unpark(w);
+    static final void signalNext(Node h) {
+        Node s;
+        if (h != null && (s = h.next) != null && s.status > 0) {
+            s.getAndUnsetStatus(WAITING);
+            LockSupport.unpark(s.waiter);
         }
     }
 
     /**
-     * See above for explanation.
+     * Removes and unparks all cowaiters of node, if it exists.
+     */
+    private static void signalCowaiters(ReaderNode node) {
+        if (node != null) {
+            for (ReaderNode c; (c = node.cowaiters) != null; ) {
+                if (node.casCowaiters(c, c.cowaiters))
+                    LockSupport.unpark(c.waiter);
+            }
+        }
+    }
+
+    // queue link methods
+    private boolean casTail(Node c, Node v) {
+        return U.compareAndSetReference(this, TAIL, c, v);
+    }
+
+    /** tries once to CAS a new dummy node for head */
+    private void tryInitializeHead() {
+        Node h = new WriterNode();
+        if (U.compareAndSetReference(this, HEAD, null, h))
+            tail = h;
+    }
+
+    /**
+     * For explanation, see above and AbstractQueuedSynchronizer
+     * internal documentation.
      *
      * @param interruptible true if should check interrupts and if so
      * return INTERRUPTED
-     * @param deadline if nonzero, the System.nanoTime value to timeout
-     * at (and return zero)
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
      * @return next state, or INTERRUPTED
      */
-    private long acquireWrite(boolean interruptible, long deadline) {
-        WNode node = null, p;
-        for (int spins = -1;;) { // spin while enqueuing
-            long m, s, ns;
-            if ((m = (s = state) & ABITS) == 0L) {
-                if ((ns = tryWriteLock(s)) != 0L)
-                    return ns;
+    private long acquireWrite(boolean interruptible, boolean timed, long time) {
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean interrupted = false, first = false;
+        WriterNode node = null;
+        Node pred = null;
+        for (long s, nextState;;) {
+            if (!first && (pred = (node == null) ? null : node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
+                }
             }
-            else if (spins < 0)
-                spins = (m == WBIT && wtail == whead) ? SPINS : 0;
-            else if (spins > 0) {
+            if ((first || pred == null) && ((s = state) & ABITS) == 0L &&
+                casState(s, nextState = s | WBIT)) {
+                U.storeStoreFence();
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
+                    if (interrupted)
+                        Thread.currentThread().interrupt();
+                }
+                return nextState;
+            } else if (node == null) {          // retry before enqueuing
+                node = new WriterNode();
+            } else if (pred == null) {          // try to enqueue
+                Node t = tail;
+                node.setPrevRelaxed(t);
+                if (t == null)
+                    tryInitializeHead();
+                else if (!casTail(t, node))
+                    node.setPrevRelaxed(null);  // back out
+                else
+                    t.next = node;
+            } else if (first && spins != 0) {   // reduce unfairness
                 --spins;
                 Thread.onSpinWait();
-            }
-            else if ((p = wtail) == null) { // initialize queue
-                WNode hd = new WNode(WMODE, null);
-                if (WHEAD.weakCompareAndSet(this, null, hd))
-                    wtail = hd;
-            }
-            else if (node == null)
-                node = new WNode(WMODE, p);
-            else if (node.prev != p)
-                node.prev = p;
-            else if (WTAIL.weakCompareAndSet(this, p, node)) {
-                p.next = node;
-                break;
+            } else if (node.status == 0) {      // enable signal
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
             }
         }
-
-        boolean wasInterrupted = false;
-        for (int spins = -1;;) {
-            WNode h, np, pp; int ps;
-            if ((h = whead) == p) {
-                if (spins < 0)
-                    spins = HEAD_SPINS;
-                else if (spins < MAX_HEAD_SPINS)
-                    spins <<= 1;
-                for (int k = spins; k > 0; --k) { // spin at head
-                    long s, ns;
-                    if (((s = state) & ABITS) == 0L) {
-                        if ((ns = tryWriteLock(s)) != 0L) {
-                            whead = node;
-                            node.prev = null;
-                            if (wasInterrupted)
-                                Thread.currentThread().interrupt();
-                            return ns;
-                        }
-                    }
-                    else
-                        Thread.onSpinWait();
-                }
-            }
-            else if (h != null) { // help release stale waiters
-                WNode c; Thread w;
-                while ((c = h.cowait) != null) {
-                    if (WCOWAIT.weakCompareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null)
-                        LockSupport.unpark(w);
-                }
-            }
-            if (whead == h) {
-                if ((np = node.prev) != p) {
-                    if (np != null)
-                        (p = np).next = node;   // stale
-                }
-                else if ((ps = p.status) == 0)
-                    WSTATUS.compareAndSet(p, 0, WAITING);
-                else if (ps == CANCELLED) {
-                    if ((pp = p.prev) != null) {
-                        node.prev = pp;
-                        pp.next = node;
-                    }
-                }
-                else {
-                    long time; // 0 argument to park means no timeout
-                    if (deadline == 0L)
-                        time = 0L;
-                    else if ((time = deadline - System.nanoTime()) <= 0L)
-                        return cancelWaiter(node, node, false);
-                    Thread wt = Thread.currentThread();
-                    node.thread = wt;
-                    if (p.status < 0 && (p != h || (state & ABITS) != 0L) &&
-                        whead == h && node.prev == p) {
-                        if (time == 0L)
-                            LockSupport.park(this);
-                        else
-                            LockSupport.parkNanos(this, time);
-                    }
-                    node.thread = null;
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, node, true);
-                        wasInterrupted = true;
-                    }
-                }
-            }
-        }
+        return cancelAcquire(node, interrupted);
     }
 
     /**
@@ -1346,182 +1266,178 @@
      *
      * @param interruptible true if should check interrupts and if so
      * return INTERRUPTED
-     * @param deadline if nonzero, the System.nanoTime value to timeout
-     * at (and return zero)
+     * @param timed if true use timed waits
+     * @param time the System.nanoTime value to timeout at (and return zero)
      * @return next state, or INTERRUPTED
      */
-    private long acquireRead(boolean interruptible, long deadline) {
-        boolean wasInterrupted = false;
-        WNode node = null, p;
-        for (int spins = -1;;) {
-            WNode h;
-            if ((h = whead) == (p = wtail)) {
-                for (long m, s, ns;;) {
-                    if ((m = (s = state) & ABITS) < RFULL ?
-                        casState(s, ns = s + RUNIT) :
-                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
-                        if (wasInterrupted)
-                            Thread.currentThread().interrupt();
-                        return ns;
+    private long acquireRead(boolean interruptible, boolean timed, long time) {
+        boolean interrupted = false;
+        ReaderNode node = null;
+        /*
+         * Loop:
+         *   if empty, try to acquire
+         *   if tail is Reader, try to cowait; restart if leader stale or cancels
+         *   else try to create and enqueue node, and wait in 2nd loop below
+         */
+        for (;;) {
+            ReaderNode leader; long nextState;
+            Node tailPred = null, t = tail;
+            if ((t == null || (tailPred = t.prev) == null) &&
+                (nextState = tryAcquireRead()) != 0L) // try now if empty
+                return nextState;
+            else if (t == null)
+                tryInitializeHead();
+            else if (tailPred == null || !(t instanceof ReaderNode)) {
+                if (node == null)
+                    node = new ReaderNode();
+                if (tail == t) {
+                    node.setPrevRelaxed(t);
+                    if (casTail(t, node)) {
+                        t.next = node;
+                        break; // node is leader; wait in loop below
                     }
-                    else if (m >= WBIT) {
-                        if (spins > 0) {
-                            --spins;
-                            Thread.onSpinWait();
-                        }
-                        else {
-                            if (spins == 0) {
-                                WNode nh = whead, np = wtail;
-                                if ((nh == h && np == p) || (h = nh) != (p = np))
-                                    break;
-                            }
-                            spins = SPINS;
-                        }
+                    node.setPrevRelaxed(null);
+                }
+            } else if ((leader = (ReaderNode)t) == tail) { // try to cowait
+                for (boolean attached = false;;) {
+                    if (leader.status < 0 || leader.prev == null)
+                        break;
+                    else if (node == null)
+                        node = new ReaderNode();
+                    else if (node.waiter == null)
+                        node.waiter = Thread.currentThread();
+                    else if (!attached) {
+                        ReaderNode c = leader.cowaiters;
+                        node.setCowaitersRelaxed(c);
+                        attached = leader.casCowaiters(c, node);
+                        if (!attached)
+                            node.setCowaitersRelaxed(null);
+                    } else {
+                        long nanos = 0L;
+                        if (!timed)
+                            LockSupport.park(this);
+                        else if ((nanos = time - System.nanoTime()) > 0L)
+                            LockSupport.parkNanos(this, nanos);
+                        interrupted |= Thread.interrupted();
+                        if ((interrupted && interruptible) ||
+                            (timed && nanos <= 0L))
+                            return cancelCowaiter(node, leader, interrupted);
                     }
                 }
-            }
-            if (p == null) { // initialize queue
-                WNode hd = new WNode(WMODE, null);
-                if (WHEAD.weakCompareAndSet(this, null, hd))
-                    wtail = hd;
-            }
-            else if (node == null)
-                node = new WNode(RMODE, p);
-            else if (h == p || p.mode != RMODE) {
-                if (node.prev != p)
-                    node.prev = p;
-                else if (WTAIL.weakCompareAndSet(this, p, node)) {
-                    p.next = node;
-                    break;
-                }
-            }
-            else if (!WCOWAIT.compareAndSet(p, node.cowait = p.cowait, node))
-                node.cowait = null;
-            else {
-                for (;;) {
-                    WNode pp, c; Thread w;
-                    if ((h = whead) != null && (c = h.cowait) != null &&
-                        WCOWAIT.compareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null) // help release
-                        LockSupport.unpark(w);
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, p, true);
-                        wasInterrupted = true;
-                    }
-                    if (h == (pp = p.prev) || h == p || pp == null) {
-                        long m, s, ns;
-                        do {
-                            if ((m = (s = state) & ABITS) < RFULL ?
-                                casState(s, ns = s + RUNIT) :
-                                (m < WBIT &&
-                                 (ns = tryIncReaderOverflow(s)) != 0L)) {
-                                if (wasInterrupted)
-                                    Thread.currentThread().interrupt();
-                                return ns;
-                            }
-                        } while (m < WBIT);
-                    }
-                    if (whead == h && p.prev == pp) {
-                        long time;
-                        if (pp == null || h == p || p.status > 0) {
-                            node = null; // throw away
-                            break;
-                        }
-                        if (deadline == 0L)
-                            time = 0L;
-                        else if ((time = deadline - System.nanoTime()) <= 0L) {
-                            if (wasInterrupted)
-                                Thread.currentThread().interrupt();
-                            return cancelWaiter(node, p, false);
-                        }
-                        Thread wt = Thread.currentThread();
-                        node.thread = wt;
-                        if ((h != pp || (state & ABITS) == WBIT) &&
-                            whead == h && p.prev == pp) {
-                            if (time == 0L)
-                                LockSupport.park(this);
-                            else
-                                LockSupport.parkNanos(this, time);
-                        }
-                        node.thread = null;
-                    }
-                }
+                if (node != null)
+                    node.waiter = null;
+                long ns = tryAcquireRead();
+                signalCowaiters(leader);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                if (ns != 0L)
+                    return ns;
+                else
+                    node = null; // restart if stale, missed, or leader cancelled
             }
         }
 
-        for (int spins = -1;;) {
-            WNode h, np, pp; int ps;
-            if ((h = whead) == p) {
-                if (spins < 0)
-                    spins = HEAD_SPINS;
-                else if (spins < MAX_HEAD_SPINS)
-                    spins <<= 1;
-                for (int k = spins;;) { // spin at head
-                    long m, s, ns;
-                    if ((m = (s = state) & ABITS) < RFULL ?
-                        casState(s, ns = s + RUNIT) :
-                        (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) {
-                        WNode c; Thread w;
-                        whead = node;
-                        node.prev = null;
-                        while ((c = node.cowait) != null) {
-                            if (WCOWAIT.compareAndSet(node, c, c.cowait) &&
-                                (w = c.thread) != null)
-                                LockSupport.unpark(w);
-                        }
-                        if (wasInterrupted)
-                            Thread.currentThread().interrupt();
-                        return ns;
-                    }
-                    else if (m >= WBIT && --k <= 0)
-                        break;
-                    else
-                        Thread.onSpinWait();
+        // node is leader of a cowait group; almost same as acquireWrite
+        byte spins = 0, postSpins = 0;   // retries upon unpark of first thread
+        boolean first = false;
+        Node pred = null;
+        for (long nextState;;) {
+            if (!first && (pred = node.prev) != null &&
+                !(first = (head == pred))) {
+                if (pred.status < 0) {
+                    cleanQueue();           // predecessor cancelled
+                    continue;
+                } else if (pred.prev == null) {
+                    Thread.onSpinWait();    // ensure serialization
+                    continue;
                 }
             }
-            else if (h != null) {
-                WNode c; Thread w;
-                while ((c = h.cowait) != null) {
-                    if (WCOWAIT.compareAndSet(h, c, c.cowait) &&
-                        (w = c.thread) != null)
-                        LockSupport.unpark(w);
-                }
-            }
-            if (whead == h) {
-                if ((np = node.prev) != p) {
-                    if (np != null)
-                        (p = np).next = node;   // stale
-                }
-                else if ((ps = p.status) == 0)
-                    WSTATUS.compareAndSet(p, 0, WAITING);
-                else if (ps == CANCELLED) {
-                    if ((pp = p.prev) != null) {
-                        node.prev = pp;
-                        pp.next = node;
-                    }
+            if ((first || pred == null) &&
+                (nextState = tryAcquireRead()) != 0L) {
+                if (first) {
+                    node.prev = null;
+                    head = node;
+                    pred.next = null;
+                    node.waiter = null;
                 }
-                else {
-                    long time;
-                    if (deadline == 0L)
-                        time = 0L;
-                    else if ((time = deadline - System.nanoTime()) <= 0L)
-                        return cancelWaiter(node, node, false);
-                    Thread wt = Thread.currentThread();
-                    node.thread = wt;
-                    if (p.status < 0 &&
-                        (p != h || (state & ABITS) == WBIT) &&
-                        whead == h && node.prev == p) {
-                            if (time == 0L)
-                                LockSupport.park(this);
-                            else
-                                LockSupport.parkNanos(this, time);
+                signalCowaiters(node);
+                if (interrupted)
+                    Thread.currentThread().interrupt();
+                return nextState;
+            } else if (first && spins != 0) {
+                --spins;
+                Thread.onSpinWait();
+            } else if (node.status == 0) {
+                if (node.waiter == null)
+                    node.waiter = Thread.currentThread();
+                node.status = WAITING;
+            } else {
+                long nanos;
+                spins = postSpins = (byte)((postSpins << 1) | 1);
+                if (!timed)
+                    LockSupport.park(this);
+                else if ((nanos = time - System.nanoTime()) > 0L)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    break;
+                node.clearStatus();
+                if ((interrupted |= Thread.interrupted()) && interruptible)
+                    break;
+            }
+        }
+        return cancelAcquire(node, interrupted);
+    }
+
+    // Cancellation support
+
+    /**
+     * Possibly repeatedly traverses from tail, unsplicing cancelled
+     * nodes until none are found. Unparks nodes that may have been
+     * relinked to be next eligible acquirer.
+     */
+    private void cleanQueue() {
+        for (;;) {                               // restart point
+            for (Node q = tail, s = null, p, n;;) { // (p, q, s) triples
+                if (q == null || (p = q.prev) == null)
+                    return;                      // end of list
+                if (s == null ? tail != q : (s.prev != q || s.status < 0))
+                    break;                       // inconsistent
+                if (q.status < 0) {              // cancelled
+                    if ((s == null ? casTail(q, p) : s.casPrev(q, p)) &&
+                        q.prev == p) {
+                        p.casNext(q, s);         // OK if fails
+                        if (p.prev == null)
+                            signalNext(p);
                     }
-                    node.thread = null;
-                    if (Thread.interrupted()) {
-                        if (interruptible)
-                            return cancelWaiter(node, node, true);
-                        wasInterrupted = true;
+                    break;
+                }
+                if ((n = p.next) != q) {         // help finish
+                    if (n != null && q.prev == p && q.status >= 0) {
+                        p.casNext(n, q);
+                        if (p.prev == null)
+                            signalNext(p);
+                    }
+                    break;
+                }
+                s = q;
+                q = q.prev;
+            }
+        }
+    }
+
+    /**
+     * If leader exists, possibly repeatedly traverses cowaiters,
+     * unsplicing the given cancelled node until not found.
+     */
+    private void unlinkCowaiter(ReaderNode node, ReaderNode leader) {
+        if (leader != null) {
+            while (leader.prev != null && leader.status >= 0) {
+                for (ReaderNode p = leader, q; ; p = q) {
+                    if ((q = p.cowaiters) == null)
+                        return;
+                    if (q == node) {
+                        p.casCowaiters(q, q.cowaiters);
+                        break;  // recheck even if succeeded
                     }
                 }
             }
@@ -1530,105 +1446,53 @@
 
     /**
      * If node non-null, forces cancel status and unsplices it from
-     * queue if possible and wakes up any cowaiters (of the node, or
-     * group, as applicable), and in any case helps release current
-     * first waiter if lock is free. (Calling with null arguments
-     * serves as a conditional form of release, which is not currently
-     * needed but may be needed under possible future cancellation
-     * policies). This is a variant of cancellation methods in
-     * AbstractQueuedSynchronizer (see its detailed explanation in AQS
-     * internal documentation).
+     * queue, wakes up any cowaiters, and possibly wakes up successor
+     * to recheck status.
      *
-     * @param node if non-null, the waiter
-     * @param group either node or the group node is cowaiting with
+     * @param node the waiter (may be null if not yet enqueued)
      * @param interrupted if already interrupted
      * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
      */
-    private long cancelWaiter(WNode node, WNode group, boolean interrupted) {
-        if (node != null && group != null) {
-            Thread w;
+    private long cancelAcquire(Node node, boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
             node.status = CANCELLED;
-            // unsplice cancelled nodes from group
-            for (WNode p = group, q; (q = p.cowait) != null;) {
-                if (q.status == CANCELLED) {
-                    WCOWAIT.compareAndSet(p, q, q.cowait);
-                    p = group; // restart
-                }
-                else
-                    p = q;
-            }
-            if (group == node) {
-                for (WNode r = group.cowait; r != null; r = r.cowait) {
-                    if ((w = r.thread) != null)
-                        LockSupport.unpark(w); // wake up uncancelled co-waiters
-                }
-                for (WNode pred = node.prev; pred != null; ) { // unsplice
-                    WNode succ, pp;        // find valid successor
-                    while ((succ = node.next) == null ||
-                           succ.status == CANCELLED) {
-                        WNode q = null;    // find successor the slow way
-                        for (WNode t = wtail; t != null && t != node; t = t.prev)
-                            if (t.status != CANCELLED)
-                                q = t;     // don't link if succ cancelled
-                        if (succ == q ||   // ensure accurate successor
-                            WNEXT.compareAndSet(node, succ, succ = q)) {
-                            if (succ == null && node == wtail)
-                                WTAIL.compareAndSet(this, node, pred);
-                            break;
-                        }
-                    }
-                    if (pred.next == node) // unsplice pred link
-                        WNEXT.compareAndSet(pred, node, succ);
-                    if (succ != null && (w = succ.thread) != null) {
-                        // wake up succ to observe new pred
-                        succ.thread = null;
-                        LockSupport.unpark(w);
-                    }
-                    if (pred.status != CANCELLED || (pp = pred.prev) == null)
-                        break;
-                    node.prev = pp;        // repeat if new pred wrong/cancelled
-                    WNEXT.compareAndSet(pp, pred, succ);
-                    pred = pp;
-                }
-            }
-        }
-        WNode h; // Possibly release first waiter
-        while ((h = whead) != null) {
-            long s; WNode q; // similar to release() but check eligibility
-            if ((q = h.next) == null || q.status == CANCELLED) {
-                for (WNode t = wtail; t != null && t != h; t = t.prev)
-                    if (t.status <= 0)
-                        q = t;
-            }
-            if (h == whead) {
-                if (q != null && h.status == 0 &&
-                    ((s = state) & ABITS) != WBIT && // waiter is eligible
-                    (s == 0L || q.mode == RMODE))
-                    release(h);
-                break;
-            }
+            cleanQueue();
+            if (node instanceof ReaderNode)
+                signalCowaiters((ReaderNode)node);
         }
         return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
     }
 
-    // VarHandle mechanics
-    private static final VarHandle STATE;
-    private static final VarHandle WHEAD;
-    private static final VarHandle WTAIL;
-    private static final VarHandle WNEXT;
-    private static final VarHandle WSTATUS;
-    private static final VarHandle WCOWAIT;
+    /**
+     * If node non-null, forces cancel status and unsplices from
+     * leader's cowaiters list unless/until it is also cancelled.
+     *
+     * @param node if non-null, the waiter
+     * @param leader if non-null, the node heading cowaiters list
+     * @param interrupted if already interrupted
+     * @return INTERRUPTED if interrupted or Thread.interrupted, else zero
+     */
+    private long cancelCowaiter(ReaderNode node, ReaderNode leader,
+                                boolean interrupted) {
+        if (node != null) {
+            node.waiter = null;
+            node.status = CANCELLED;
+            unlinkCowaiter(node, leader);
+        }
+        return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L;
+    }
+
+    // Unsafe
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final long STATE
+        = U.objectFieldOffset(StampedLock.class, "state");
+    private static final long HEAD
+        = U.objectFieldOffset(StampedLock.class, "head");
+    private static final long TAIL
+        = U.objectFieldOffset(StampedLock.class, "tail");
+
     static {
-        try {
-            MethodHandles.Lookup l = MethodHandles.lookup();
-            STATE = l.findVarHandle(StampedLock.class, "state", long.class);
-            WHEAD = l.findVarHandle(StampedLock.class, "whead", WNode.class);
-            WTAIL = l.findVarHandle(StampedLock.class, "wtail", WNode.class);
-            WSTATUS = l.findVarHandle(WNode.class, "status", int.class);
-            WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
-            WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
-        } catch (ReflectiveOperationException e) {
-            throw new ExceptionInInitializerError(e);
-        }
+        Class<?> ensureLoaded = LockSupport.class;
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/package-info.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/concurrent/package-info.java	Wed Sep 18 07:46:02 2019 +0200
@@ -226,9 +226,8 @@
  *
  * <h2 id="MemoryVisibility">Memory Consistency Properties</h2>
  *
- * <a href="https://docs.oracle.com/javase/specs/jls/se11/html/jls-17.html#jls-17.4.5">
  * Chapter 17 of
- * <cite>The Java&trade; Language Specification</cite></a> defines the
+ * <cite>The Java&trade; Language Specification</cite> defines the
  * <i>happens-before</i> relation on memory operations such as reads and
  * writes of shared variables.  The results of a write by one thread are
  * guaranteed to be visible to a read by another thread only if the write
@@ -302,6 +301,8 @@
  *
  * </ul>
  *
+ * @jls 17.4.5 Happens-before Order
+ *
  * @since 1.5
  */
 package java.util.concurrent;
--- a/src/java.base/share/classes/java/util/regex/Pattern.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java	Wed Sep 18 07:46:02 2019 +0200
@@ -3931,12 +3931,14 @@
         boolean match(Matcher matcher, int i, CharSequence seq) {
             if (i < matcher.to) {
                 int ch = Character.codePointAt(seq, i);
-                return predicate.is(ch) &&
-                       next.match(matcher, i + Character.charCount(ch), seq);
-            } else {
-                matcher.hitEnd = true;
-                return false;
+                i += Character.charCount(ch);
+                if (i <= matcher.to) {
+                    return predicate.is(ch) &&
+                           next.match(matcher, i, seq);
+                }
             }
+            matcher.hitEnd = true;
+            return false;
         }
         boolean study(TreeInfo info) {
             info.minLength++;
--- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java	Wed Sep 18 07:46:02 2019 +0200
@@ -33,7 +33,7 @@
     protected UnixNativeDispatcher() { }
 
     // returns a NativeBuffer containing the given path
-    private static NativeBuffer copyToNativeBuffer(UnixPath path) {
+    static NativeBuffer copyToNativeBuffer(UnixPath path) {
         byte[] cstr = path.getByteArrayForSysCalls();
         int size = cstr.length + 1;
         NativeBuffer buffer = NativeBuffers.getNativeBufferFromCache(size);
--- a/src/java.base/unix/native/libjava/TimeZone_md.c	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.base/unix/native/libjava/TimeZone_md.c	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,8 @@
 #include "jvm.h"
 #include "TimeZone_md.h"
 
+static char *isFileIdentical(char* buf, size_t size, char *pathname);
+
 #define SKIP_SPACE(p)   while (*p == ' ' || *p == '\t') p++;
 
 #define RESTARTABLE(_cmd, _result) do { \
@@ -72,6 +74,8 @@
 static const char *DEFAULT_ZONEINFO_FILE = "/usr/share/lib/zoneinfo/localtime";
 #endif /* defined(__linux__) || defined(_ALLBSD_SOURCE) */
 
+static const char popularZones[][4] = {"UTC", "GMT"};
+
 #if defined(_AIX)
 static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
 #endif
@@ -121,14 +125,27 @@
 findZoneinfoFile(char *buf, size_t size, const char *dir)
 {
     DIR *dirp = NULL;
-    struct stat64 statbuf;
     struct dirent *dp = NULL;
     char *pathname = NULL;
-    int fd = -1;
-    char *dbuf = NULL;
     char *tz = NULL;
     int res;
 
+    if (strcmp(dir, ZONEINFO_DIR) == 0) {
+        /* fast path for 1st iteration */
+        for (unsigned int i = 0; i < sizeof (popularZones) / sizeof (popularZones[0]); i++) {
+            pathname = getPathName(dir, popularZones[i]);
+            if (pathname == NULL) {
+                continue;
+            }
+            tz = isFileIdentical(buf, size, pathname);
+            free((void *) pathname);
+            pathname = NULL;
+            if (tz != NULL) {
+                return tz;
+            }
+        }
+    }
+
     dirp = opendir(dir);
     if (dirp == NULL) {
         return NULL;
@@ -162,58 +179,67 @@
         if (pathname == NULL) {
             break;
         }
-        RESTARTABLE(stat64(pathname, &statbuf), res);
-        if (res == -1) {
-            break;
-        }
 
-        if (S_ISDIR(statbuf.st_mode)) {
-            tz = findZoneinfoFile(buf, size, pathname);
-            if (tz != NULL) {
-                break;
-            }
-        } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
-            dbuf = (char *) malloc(size);
-            if (dbuf == NULL) {
-                break;
-            }
-            RESTARTABLE(open(pathname, O_RDONLY), fd);
-            if (fd == -1) {
-                break;
-            }
-            RESTARTABLE(read(fd, dbuf, size), res);
-            if (res != (ssize_t) size) {
-                break;
-            }
-            if (memcmp(buf, dbuf, size) == 0) {
-                tz = getZoneName(pathname);
-                if (tz != NULL) {
-                    tz = strdup(tz);
-                }
-                break;
-            }
-            free((void *) dbuf);
-            dbuf = NULL;
-            (void) close(fd);
-            fd = -1;
-        }
+        tz = isFileIdentical(buf, size, pathname);
         free((void *) pathname);
         pathname = NULL;
+        if (tz != NULL) {
+           break;
+        }
     }
 
     if (dirp != NULL) {
         (void) closedir(dirp);
     }
-    if (pathname != NULL) {
-        free((void *) pathname);
+    return tz;
+}
+
+/*
+ * Checks if the file pointed to by pathname matches
+ * the data contents in buf.
+ * Returns a representation of the timezone file name
+ * if file match is found, otherwise NULL.
+ */
+static char *
+isFileIdentical(char *buf, size_t size, char *pathname)
+{
+    char *possibleMatch = NULL;
+    struct stat64 statbuf;
+    char *dbuf = NULL;
+    int fd = -1;
+    int res;
+
+    RESTARTABLE(stat64(pathname, &statbuf), res);
+    if (res == -1) {
+        return NULL;
     }
-    if (fd != -1) {
+
+    if (S_ISDIR(statbuf.st_mode)) {
+        possibleMatch  = findZoneinfoFile(buf, size, pathname);
+    } else if (S_ISREG(statbuf.st_mode) && (size_t)statbuf.st_size == size) {
+        dbuf = (char *) malloc(size);
+        if (dbuf == NULL) {
+            return NULL;
+        }
+        RESTARTABLE(open(pathname, O_RDONLY), fd);
+        if (fd == -1) {
+            goto freedata;
+        }
+        RESTARTABLE(read(fd, dbuf, size), res);
+        if (res != (ssize_t) size) {
+            goto freedata;
+        }
+        if (memcmp(buf, dbuf, size) == 0) {
+            possibleMatch = getZoneName(pathname);
+            if (possibleMatch != NULL) {
+                possibleMatch = strdup(possibleMatch);
+            }
+        }
+        freedata:
+        free((void *) dbuf);
         (void) close(fd);
     }
-    if (dbuf != NULL) {
-        free((void *) dbuf);
-    }
-    return tz;
+    return possibleMatch;
 }
 
 #if defined(__linux__) || defined(MACOSX)
--- a/src/java.compiler/share/classes/javax/lang/model/package-info.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.compiler/share/classes/javax/lang/model/package-info.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -24,7 +24,8 @@
  */
 
 /**
- * Classes and hierarchies of packages used to model the Java
+ * Types and hierarchies of packages comprising a {@index "Java language
+ * model"}, a model of the declarations and types of the Java
  * programming language.
  *
  * The members of this package and its subpackages are for use in
@@ -41,14 +42,14 @@
  * Languages and Applications, October 2004.
  * </blockquote>
  *
- * In particular, the model makes a distinction between static
+ * In particular, the model makes a distinction between declared
  * language constructs, like the {@linkplain javax.lang.model.element
  * element} representing {@code java.util.Set}, and the family of
  * {@linkplain javax.lang.model.type types} that may be associated
  * with an element, like the raw type {@code java.util.Set}, {@code
  * java.util.Set<String>}, and {@code java.util.Set<T>}.
  *
- * <p> Unless otherwise specified, methods in this package will throw
+ * <p>Unless otherwise specified, methods in this package will throw
  * a {@code NullPointerException} if given a {@code null} argument.
  *
  * @author Joseph D. Darcy
--- a/src/java.desktop/unix/native/common/awt/fontpath.c	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.desktop/unix/native/common/awt/fontpath.c	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, 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
@@ -887,9 +887,9 @@
     locale = (*env)->GetStringUTFChars(env, localeStr, 0);
 
     if ((libfontconfig = openFontConfig()) == NULL) {
-        (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
+        (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
         if (locale) {
-            (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);
+            (*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale);
         }
         return -1;
     }
@@ -918,9 +918,9 @@
         FcPatternGetInteger  == NULL ||
         FcPatternDestroy     == NULL) { /* problem with the library: return. */
 
-        (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
+        (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
         if (locale) {
-            (*env)->ReleaseStringUTFChars (env, localeStr,(const char*)locale);
+            (*env)->ReleaseStringUTFChars(env, localeStr,(const char*)locale);
         }
         closeFontConfig(libfontconfig, JNI_FALSE);
         return -1;
@@ -945,9 +945,9 @@
     }
     (*FcPatternDestroy)(pattern);
 
-    (*env)->ReleaseStringUTFChars (env, fcNameStr, (const char*)fcName);
+    (*env)->ReleaseStringUTFChars(env, fcNameStr, (const char*)fcName);
     if (locale) {
-        (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
+        (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
     }
     closeFontConfig(libfontconfig, JNI_TRUE);
 
@@ -1179,6 +1179,9 @@
         (*env)->DeleteLocalRef(env, fcNameStr);
         if (pattern == NULL) {
             closeFontConfig(libfontconfig, JNI_FALSE);
+            if (locale) {
+                (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
+            }
             return;
         }
 
@@ -1196,6 +1199,9 @@
         if (fontset == NULL) {
             (*FcPatternDestroy)(pattern);
             closeFontConfig(libfontconfig, JNI_FALSE);
+            if (locale) {
+                (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
+            }
             return;
         }
 
@@ -1227,6 +1233,9 @@
             (*FcPatternDestroy)(pattern);
             (*FcFontSetDestroy)(fontset);
             closeFontConfig(libfontconfig, JNI_FALSE);
+            if (locale) {
+                (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
+            }
             return;
         }
         fontCount = 0;
@@ -1269,6 +1278,9 @@
                 (*FcPatternDestroy)(pattern);
                 (*FcFontSetDestroy)(fontset);
                 closeFontConfig(libfontconfig, JNI_FALSE);
+                if (locale) {
+                    (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
+                }
                 return;
             }
 
@@ -1323,6 +1335,9 @@
                 (*FcPatternDestroy)(pattern);
                 (*FcFontSetDestroy)(fontset);
                 closeFontConfig(libfontconfig, JNI_FALSE);
+                if (locale) {
+                    (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
+                }
                 return;
             }
             (*env)->SetObjectField(env,fcCompFontObj, fcAllFontsID, fcFontArr);
@@ -1384,7 +1399,7 @@
     /* release resources and close the ".so" */
 
     if (locale) {
-        (*env)->ReleaseStringUTFChars (env, localeStr, (const char*)locale);
+        (*env)->ReleaseStringUTFChars(env, localeStr, (const char*)locale);
     }
     closeFontConfig(libfontconfig, JNI_TRUE);
 }
--- a/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -1130,6 +1130,9 @@
     const char *pLibName = env->GetStringUTFChars(libName, NULL);
     JNU_CHECK_EXCEPTION_RETURN(env, 0);
     HINSTANCE libHandle = (HINSTANCE)JDK_LoadSystemLibrary(pLibName);
+    if (pLibName != NULL) {
+        env->ReleaseStringUTFChars(libName, pLibName);
+    }
     if (libHandle != NULL) {
         UINT fuLoad = (useVGAColors && !IS_WINXP) ? LR_VGACOLOR : 0;
         return ptr_to_jlong(LoadImage(libHandle, MAKEINTRESOURCE(iconID),
--- a/src/java.instrument/share/native/libinstrument/JPLISAgent.c	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.c	Wed Sep 18 07:46:02 2019 +0200
@@ -1486,6 +1486,7 @@
             platformLen = convertUft8ToPlatformString((char*)utf8Chars, utf8Len, platformChars, MAXPATHLEN);
             if (platformLen < 0) {
                 createAndThrowInternalError(jnienv);
+                (*jnienv)->ReleaseStringUTFChars(jnienv, jarFile, utf8Chars);
                 return;
             }
 
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/DefaultLdapDnsProvider.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/DefaultLdapDnsProvider.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -76,7 +76,7 @@
         }
 
         LdapDnsProviderResult res = new LdapDnsProviderResult(domainName, endpoints);
-        if (res.getEndpoints().size() == 0 && res.getDomainName().isEmpty()) {
+        if (res.getEndpoints().isEmpty() && res.getDomainName().isEmpty()) {
             return Optional.empty();
         } else {
             return Optional.of(res);
--- a/src/java.naming/share/classes/com/sun/jndi/ldap/LdapDnsProviderService.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.naming/share/classes/com/sun/jndi/ldap/LdapDnsProviderService.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,8 @@
  * The {@code LdapDnsProviderService} is responsible for creating and providing
  * access to the registered {@code LdapDnsProvider}s. The {@link ServiceLoader}
  * is used to find and register any implementations of {@link LdapDnsProvider}.
+ *
+ * <p> Instances of this class are safe for use by multiple threads.
  */
 final class LdapDnsProviderService {
 
@@ -68,11 +70,11 @@
     }
 
     /**
-     * Retrieve the singleton static instance of LdapDnsProviderService.
+     * Retrieves the singleton instance of LdapDnsProviderService.
      */
     static LdapDnsProviderService getInstance() {
         if (service != null) return service;
-        synchronized(LOCK) {
+        synchronized (LOCK) {
             if (service != null) return service;
             service = new LdapDnsProviderService();
         }
@@ -80,7 +82,7 @@
     }
 
     /**
-     * Retrieve result from the first provider that successfully resolves
+     * Retrieves result from the first provider that successfully resolves
      * the endpoints. If no results are found when calling installed
      * subclasses of {@code LdapDnsProvider} then this method will fall back
      * to the {@code DefaultLdapDnsProvider}.
@@ -91,14 +93,15 @@
     LdapDnsProviderResult lookupEndpoints(String url, Hashtable<?,?> env)
         throws NamingException
     {
-        Iterator<LdapDnsProvider> iterator = providers.iterator();
+        LdapDnsProviderResult result = null;
         Hashtable<?, ?> envCopy = new Hashtable<>(env);
-        LdapDnsProviderResult result = null;
-
-        while (result == null && iterator.hasNext()) {
-            result = iterator.next().lookupEndpoints(url, envCopy)
-                    .filter(r -> r.getEndpoints().size() > 0)
-                    .orElse(null);
+        synchronized (LOCK) {
+            Iterator<LdapDnsProvider> iterator = providers.iterator();
+            while (result == null && iterator.hasNext()) {
+                result = iterator.next().lookupEndpoints(url, envCopy)
+                        .filter(r -> !r.getEndpoints().isEmpty())
+                        .orElse(null);
+            }
         }
 
         if (result == null) {
--- a/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/java.security.jgss/windows/native/libsspi_bridge/sspi.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -218,7 +218,7 @@
 static BOOLEAN
 has_oid(gss_const_OID_set set, gss_const_OID oid)
 {
-    for (int i = 0; i < set->count; i++) {
+    for (size_t i = 0; i < set->count; i++) {
         if (is_same_oid(&set->elements[i], oid)) {
             return TRUE;
         }
@@ -257,7 +257,7 @@
             return;
         }
         PP("gss_OID_set.count is %d", (int)mechs->count);
-        for (int i = 0; i < mechs->count; i++) {
+        for (size_t i = 0; i < mechs->count; i++) {
             show_oid(&mechs->elements[i]);
         }
     }
@@ -1584,7 +1584,7 @@
     if (set == NULL || *set == GSS_C_NO_OID_SET) {
         return GSS_S_COMPLETE;
     }
-    for (int i = 0; i < (*set)->count; i++) {
+    for (size_t i = 0; i < (*set)->count; i++) {
         delete[] (*set)->elements[i].elements;
     }
     delete[] (*set)->elements;
--- a/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp	Thu Sep 12 15:04:00 2019 +0200
+++ b/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, 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
@@ -692,11 +692,15 @@
   char errMsg[ERR_MSG_SIZE];
   td_err_e te;
   CHECK_EXCEPTION;
+  if (cmdLine_cstr == NULL) {
+    return;
+  }
 
   // some older versions of libproc.so crash when trying to attach 32 bit
   // debugger to 64 bit core file. check and throw error.
 #ifndef _LP64
-  atoi(cmdLine_cstr);
+  errno = 0;
+  strtol(cmdLine_cstr, NULL, 10);
   if (errno) {
      // core file
      int core_fd;
@@ -706,6 +710,7 @@
             memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 &&
             e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) {
               close(core_fd);
+              env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
               THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger");
         }
         close(core_fd);
@@ -718,6 +723,7 @@
   ps_prochandle_t* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode, NULL);
 
   env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
+
   if (! ph) {
      if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) {
         snprintf(errMsg, ERR_MSG_SIZE, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]);
--- a/test/hotspot/jtreg/ProblemList.txt	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/hotspot/jtreg/ProblemList.txt	Wed Sep 18 07:46:02 2019 +0200
@@ -90,6 +90,7 @@
 # :hotspot_runtime
 
 runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64
+runtime/ReservedStack/ReservedStackTest.java 8231031 generic-all
 
 #############################################################################
 
@@ -167,7 +168,7 @@
 vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses021/TestDescription.java 8065773 generic-all
 vmTestbase/nsk/jdi/VirtualMachine/redefineClasses/redefineclasses023/TestDescription.java 8065773 generic-all
 
-vmTestbase/nsk/jdb/eval/eval001/eval001.java 8212117 generic-all
+vmTestbase/nsk/jdb/eval/eval001/eval001.java 8221503 generic-all
 
 vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java 8208250 generic-all
 vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java 8208250 generic-all
@@ -204,4 +205,16 @@
 
 vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEarlyReturn001.java 7199837 generic-all
 
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/SynchronizerLockingThreads/SynchronizerLockingThreads001/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/SynchronizerLockingThreads/SynchronizerLockingThreads002/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/SynchronizerLockingThreads/SynchronizerLockingThreads003/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/SynchronizerLockingThreads/SynchronizerLockingThreads004/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/SynchronizerLockingThreads/SynchronizerLockingThreads005/TestDescription.java 8231032 generic-all
+
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi001/Multi001.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi002/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi003/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi004/TestDescription.java 8231032 generic-all
+vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Multi/Multi005/TestDescription.java 8231032 generic-all
+
 #############################################################################
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/print/PrintCompileQueue.java	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Loongson Technology Co. Ltd. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8230943
+ * @summary possible deadlock was detected when ran with -XX:+CIPrintCompileQueue
+ * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+CIPrintCompileQueue
+ *                   compiler.print.PrintCompileQueue
+ *
+ */
+
+package compiler.print;
+
+public class PrintCompileQueue {
+    public static void main(String[] args) {
+        System.out.println("Passed");
+    }
+}
--- a/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/hotspot/jtreg/serviceability/sa/TestJmapCore.java	Wed Sep 18 07:46:02 2019 +0200
@@ -98,8 +98,8 @@
             : ProcessTools.executeProcess("sh", "-c", "ulimit -c unlimited && "
                     + ProcessTools.getCommandLine(pb));
         File core;
-        String pattern = Platform.isWindows() ? "mdmp" : "core";
-        File[] cores = new File(".").listFiles((dir, name) -> name.contains(pattern));
+        String pattern = Platform.isWindows() ? ".*\\.mdmp" : "core(\\.\\d+)?";
+        File[] cores = new File(".").listFiles((dir, name) -> name.matches(pattern));
         if (cores.length == 0) {
             // /cores/core.$pid might be generated on macosx by default
             String pid = output.firstMatch("^(\\d+)" + pidSeparator, 1);
--- a/test/jdk/ProblemList.txt	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/ProblemList.txt	Wed Sep 18 07:46:02 2019 +0200
@@ -564,6 +564,8 @@
 javax/management/monitor/DerivedGaugeMonitorTest.java         8042211 generic-all
 javax/management/remote/mandatory/connection/MultiThreadDeadLockTest.java 8042215 generic-all
 
+java/lang/management/ThreadMXBean/LockedSynchronizers.java 8231032 generic-all
+
 ############################################################################
 
 # jdk_io
@@ -872,8 +874,6 @@
 
 com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java                   8169942 linux-i586,macosx-all,windows-x64
 
-com/sun/jndi/ldap/LdapTimeoutTest.java                          8151678 generic-all
-
 com/sun/jndi/dns/ConfigTests/PortUnreachable.java               7164518 macosx-all
 
 javax/rmi/ssl/SSLSocketParametersTest.sh                        8162906 generic-all
--- a/test/jdk/com/sun/jndi/ldap/LdapTimeoutTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/com/sun/jndi/ldap/LdapTimeoutTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2019, 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
@@ -21,424 +21,487 @@
  * questions.
  */
 
-/**
+/*
  * @test
- * @run main/othervm LdapTimeoutTest
- * @bug 7094377 8000487 6176036 7056489
+ * @library /test/lib
+ *          lib/
+ * @run testng/othervm LdapTimeoutTest
+ * @bug 7094377 8000487 6176036 7056489 8151678
  * @summary Timeout tests for ldap
  */
 
+import org.testng.Assert;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.net.Socket;
-import java.net.ServerSocket;
-import java.net.SocketTimeoutException;
-import java.io.*;
-import javax.naming.*;
-import javax.naming.directory.*;
+import java.util.ArrayList;
+import java.util.Hashtable;
 import java.util.List;
-import java.util.Hashtable;
-import java.util.ArrayList;
+import java.util.Objects;
 import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.TimeUnit;
-import javax.net.ssl.SSLHandshakeException;
 
+import static java.lang.String.format;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import static jdk.test.lib.Utils.adjustTimeout;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.expectThrows;
 
+public class LdapTimeoutTest {
+
+    // ------ configure test timeouts here ------
 
-abstract class LdapTest implements Callable {
+    /*
+     * Practical representation of an infinite timeout.
+     */
+    private static final long INFINITY_MILLIS = adjustTimeout(20_000);
+    /*
+     * The acceptable variation in timeout measurements.
+     */
+    private static final long TOLERANCE       = adjustTimeout( 3_500);
 
-    Hashtable env;
-    TestServer server;
-    ScheduledExecutorService killSwitchPool;
-    boolean passed = false;
-    private int HANGING_TEST_TIMEOUT = 20_000;
+    private static final long CONNECT_MILLIS  = adjustTimeout( 3_000);
+    private static final long READ_MILLIS     = adjustTimeout(10_000);
+
+    static {
+        // a series of checks to make sure this timeouts configuration is
+        // consistent and the timeouts do not overlap
 
-    public LdapTest (TestServer server, Hashtable env) {
-        this.server = server;
-        this.env = env;
+        assert (TOLERANCE >= 0);
+        // context creation
+        assert (2 * CONNECT_MILLIS + TOLERANCE < READ_MILLIS);
+        // context creation immediately followed by search
+        assert (2 * CONNECT_MILLIS + READ_MILLIS + TOLERANCE < INFINITY_MILLIS);
+    }
+
+    @BeforeTest
+    public void beforeTest() {
+        startAuxiliaryDiagnosticOutput();
     }
 
-    public LdapTest(TestServer server, Hashtable env,
-            ScheduledExecutorService killSwitchPool)
-    {
-        this(server, env);
-        this.killSwitchPool = killSwitchPool;
+    /*
+     * These are timeout tests and they are run in parallel to reduce the total
+     * amount of run time.
+     *
+     * Currently it doesn't seem possible to instruct JTREG to run TestNG test
+     * methods in parallel. That said, this JTREG test is still
+     * a "TestNG-flavored" test for the sake of having org.testng.Assert
+     * capability.
+     */
+    @Test
+    public void test() throws Exception {
+        List<Future<?>> futures = new ArrayList<>();
+        ExecutorService executorService = Executors.newCachedThreadPool();
+        try {
+            futures.add(executorService.submit(() -> { test1(); return null; }));
+            futures.add(executorService.submit(() -> { test2(); return null; }));
+            futures.add(executorService.submit(() -> { test3(); return null; }));
+            futures.add(executorService.submit(() -> { test4(); return null; }));
+            futures.add(executorService.submit(() -> { test5(); return null; }));
+            futures.add(executorService.submit(() -> { test6(); return null; }));
+            futures.add(executorService.submit(() -> { test7(); return null; }));
+        } finally {
+            executorService.shutdown();
+        }
+        int failedCount = 0;
+        for (var f : futures) {
+            try {
+                f.get();
+            } catch (ExecutionException e) {
+                failedCount++;
+                e.getCause().printStackTrace(System.out);
+            }
+        }
+        if (failedCount > 0)
+            throw new RuntimeException(failedCount + " (sub)tests failed");
+    }
+
+    static void test1() throws Exception {
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        // Here and in the other tests it's important to close the server as
+        // calling `thread.interrupt` from assertion may not be enough
+        // (depending on where the blocking call has stuck)
+        try (TestServer server = new NotBindableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            // Here and in the other tests joining done purely to reduce timing
+            // jitter. Commenting out or removing that should not make the test
+            // incorrect. (ServerSocket can accept connection as soon as it is
+            // bound, not need to call `accept` before that.)
+            server.starting().join();
+            assertIncompletion(INFINITY_MILLIS, () -> new InitialDirContext(env));
+        }
     }
 
-    public abstract void performOp(InitialContext ctx) throws NamingException;
-    public abstract void handleNamingException(
-        NamingException e, long start, long end);
+    static void test2() throws Exception {
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
+        try (TestServer server = new BindableButNotReadableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            server.starting().join();
+            InitialDirContext ctx = new InitialDirContext(env);
+            SearchControls scl = new SearchControls();
+            scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
+            assertIncompletion(INFINITY_MILLIS,
+                               () -> ctx.search("ou=People,o=JNDITutorial", "(objectClass=*)", scl));
+        }
+    }
 
-    public void pass() {
-        this.passed = true;
+    static void test3() throws Exception {
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        try (TestServer server = new BindableButNotReadableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            server.starting().join();
+            InitialDirContext ctx = new InitialDirContext(env);
+            SearchControls scl = new SearchControls();
+            scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
+            assertIncompletion(INFINITY_MILLIS,
+                               () -> ctx.search("ou=People,o=JNDITutorial", "(objectClass=*)", scl));
+        }
     }
 
-    public void fail() {
-        throw new RuntimeException("Test failed");
+    static void test4() throws Exception {
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
+        env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
+        try (TestServer server = new NotBindableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            server.starting().join();
+            Assert.ThrowingRunnable completion =
+                    () -> assertCompletion(CONNECT_MILLIS,
+                                           2 * CONNECT_MILLIS + TOLERANCE,
+                                           () -> new InitialDirContext(env));
+            NamingException e = expectThrows(NamingException.class, completion);
+            String msg = e.getMessage();
+            assertTrue(msg != null && msg.contains("timeout")
+                               && msg.contains(String.valueOf(CONNECT_MILLIS)),
+                       msg);
+        }
     }
 
-    public void fail(Exception e) {
-        throw new RuntimeException("Test failed", e);
+    static void test5() throws Exception {
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
+        env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
+        try (TestServer server = new BindableButNotReadableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            server.starting().join();
+            InitialDirContext ctx = new InitialDirContext(env);
+            SearchControls scl = new SearchControls();
+            scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
+            Assert.ThrowingRunnable completion =
+                    () -> assertCompletion(READ_MILLIS,
+                                           READ_MILLIS + TOLERANCE,
+                                           () -> ctx.search("ou=People,o=JNDITutorial", "(objectClass=*)", scl));
+            NamingException e = expectThrows(NamingException.class, completion);
+            String msg = e.getMessage();
+            assertTrue(msg != null && msg.contains("timeout")
+                               && msg.contains(String.valueOf(READ_MILLIS)),
+                       msg);
+        }
     }
 
-    boolean shutItDown(InitialContext ctx) {
-        try {
-            if (ctx != null) ctx.close();
-            return true;
-        } catch (NamingException ex) {
-            return false;
+    static void test6() throws Exception {
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
+        env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
+        try (TestServer server = new NotBindableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            server.starting().join();
+            Assert.ThrowingRunnable completion =
+                    () -> assertCompletion(CONNECT_MILLIS,
+                                           2 * CONNECT_MILLIS + TOLERANCE,
+                                           () -> new InitialDirContext(env));
+            NamingException e = expectThrows(NamingException.class, completion);
+            String msg = e.getMessage();
+            assertTrue(msg != null && msg.contains("timeout")
+                               && msg.contains(String.valueOf(CONNECT_MILLIS)),
+                       msg);
         }
     }
 
-    public Boolean call() {
-        InitialContext ctx = null;
-        ScheduledFuture killer = null;
-        long start = System.nanoTime();
-
-        try {
-            while(!server.accepting())
-                Thread.sleep(200); // allow the server to start up
-            Thread.sleep(200); // to be sure
-
-            // if this is a hanging test, scheduled a thread to
-            // interrupt after a certain time
-            if (killSwitchPool != null) {
-                final Thread current = Thread.currentThread();
-                killer = killSwitchPool.schedule(
-                    new Callable<Void>() {
-                        public Void call() throws Exception {
-                            current.interrupt();
-                            return null;
-                        }
-                    }, HANGING_TEST_TIMEOUT, MILLISECONDS);
-            }
-
-            env.put(Context.PROVIDER_URL, "ldap://localhost:" +
-                    server.getLocalPort());
-
-            try {
-                ctx = new InitialDirContext(env);
-                performOp(ctx);
-                fail();
-            } catch (NamingException e) {
-                long end = System.nanoTime();
-                System.out.println(this.getClass().toString() + " - elapsed: "
-                        + NANOSECONDS.toMillis(end - start));
-                handleNamingException(e, start, end);
-            } finally {
-                if (killer != null && !killer.isDone())
-                    killer.cancel(true);
-                shutItDown(ctx);
-                server.close();
-            }
-            return passed;
-        } catch (IOException|InterruptedException e) {
-            throw new RuntimeException(e);
+    static void test7() throws Exception {
+        // 8000487: Java JNDI connection library on ldap conn is
+        // not honoring configured timeout
+        Hashtable<Object, Object> env = new Hashtable<>();
+        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
+        env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(CONNECT_MILLIS));
+        env.put("com.sun.jndi.ldap.read.timeout", String.valueOf(READ_MILLIS));
+        env.put(Context.SECURITY_AUTHENTICATION, "simple");
+        env.put(Context.SECURITY_PRINCIPAL, "user");
+        env.put(Context.SECURITY_CREDENTIALS, "password");
+        try (TestServer server = new NotBindableServer()) {
+            env.put(Context.PROVIDER_URL, urlTo(server));
+            server.start();
+            server.starting().join();
+            Assert.ThrowingRunnable completion =
+                    () -> assertCompletion(CONNECT_MILLIS,
+                                           2 * CONNECT_MILLIS + TOLERANCE,
+                                           () -> new InitialDirContext(env));
+            NamingException e = expectThrows(NamingException.class, completion);
+            String msg = e.getMessage();
+            assertTrue(msg != null && msg.contains("timeout")
+                               && msg.contains(String.valueOf(CONNECT_MILLIS)),
+                       msg);
         }
     }
-}
-
-abstract class ReadServerTest extends LdapTest {
-
-    public ReadServerTest(Hashtable env) throws IOException {
-        super(new BindableServer(), env);
-    }
-
-    public ReadServerTest(Hashtable env,
-                          ScheduledExecutorService killSwitchPool)
-            throws IOException
-    {
-        super(new BindableServer(), env, killSwitchPool);
-    }
-
-    public void performOp(InitialContext ctx) throws NamingException {
-        SearchControls scl = new SearchControls();
-        scl.setSearchScope(SearchControls.SUBTREE_SCOPE);
-        NamingEnumeration<SearchResult> answer = ((InitialDirContext)ctx)
-            .search("ou=People,o=JNDITutorial", "(objectClass=*)", scl);
-    }
-}
-
-abstract class DeadServerTest extends LdapTest {
-
-    public DeadServerTest(Hashtable env) throws IOException {
-        super(new DeadServer(), env);
-    }
-
-    public DeadServerTest(Hashtable env,
-                          ScheduledExecutorService killSwitchPool)
-            throws IOException
-    {
-        super(new DeadServer(), env, killSwitchPool);
-    }
-
-    public void performOp(InitialContext ctx) throws NamingException {}
-}
-
-class DeadServerNoTimeoutTest extends DeadServerTest {
-
-    public DeadServerNoTimeoutTest(Hashtable env,
-                                   ScheduledExecutorService killSwitchPool)
-            throws IOException
-    {
-        super(env, killSwitchPool);
-    }
-
-    public void handleNamingException(NamingException e, long start, long end) {
-        if (e instanceof InterruptedNamingException) Thread.interrupted();
-
-        if (NANOSECONDS.toMillis(end - start) < LdapTimeoutTest.MIN_TIMEOUT) {
-            System.err.printf("DeadServerNoTimeoutTest fail: timeout should be " +
-                              "at least %s ms, actual time is %s ms%n",
-                              LdapTimeoutTest.MIN_TIMEOUT,
-                              NANOSECONDS.toMillis(end - start));
-            fail();
-        } else {
-            pass();
-        }
-    }
-}
-
-class DeadServerTimeoutTest extends DeadServerTest {
-
-    public DeadServerTimeoutTest(Hashtable env) throws IOException {
-        super(env);
-    }
 
-    public void handleNamingException(NamingException e, long start, long end)
-    {
-        // non SSL connect will timeout via readReply using connectTimeout
-        if (NANOSECONDS.toMillis(end - start) < 2_900) {
-            pass();
-        } else {
-            System.err.println("Fail: Waited too long");
-            fail();
-        }
-    }
-}
+    // ------ test stub servers ------
+
+    static class TestServer extends BaseLdapServer {
 
-
-class ReadServerNoTimeoutTest extends ReadServerTest {
+        private final CompletableFuture<Void> starting = new CompletableFuture<>();
 
-    public ReadServerNoTimeoutTest(Hashtable env,
-                                   ScheduledExecutorService killSwitchPool)
-            throws IOException
-    {
-        super(env, killSwitchPool);
-    }
-
-    public void handleNamingException(NamingException e, long start, long end) {
-        if (e instanceof InterruptedNamingException) Thread.interrupted();
+        TestServer() throws IOException { }
 
-        if (NANOSECONDS.toMillis(end - start) < LdapTimeoutTest.MIN_TIMEOUT) {
-            System.err.printf("ReadServerNoTimeoutTest fail: timeout should be " +
-                              "at least %s ms, actual time is %s ms%n",
-                              LdapTimeoutTest.MIN_TIMEOUT,
-                              NANOSECONDS.toMillis(end - start));
-            fail();
-        } else {
-            pass();
+        @Override
+        protected void beforeAcceptingConnections() {
+            starting.completeAsync(() -> null);
         }
-    }
-}
 
-class ReadServerTimeoutTest extends ReadServerTest {
-
-    public ReadServerTimeoutTest(Hashtable env) throws IOException {
-        super(env);
-    }
-
-    public void handleNamingException(NamingException e, long start, long end) {
-        System.out.println("ReadServerTimeoutTest: end-start=" + NANOSECONDS.toMillis(end - start));
-        if (NANOSECONDS.toMillis(end - start) < 2_500) {
-            fail();
-        } else {
-            pass();
+        public CompletableFuture<Void> starting() {
+            return starting.copy();
         }
     }
-}
+
+    static class BindableButNotReadableServer extends TestServer {
+
+        BindableButNotReadableServer() throws IOException { }
 
-class TestServer extends Thread {
-    ServerSocket serverSock;
-    boolean accepting = false;
-
-    public TestServer() throws IOException {
-        this.serverSock = new ServerSocket(0);
-        start();
-    }
+        private static final byte[] bindResponse = {
+                0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
+                0x01, 0x00, 0x04, 0x00, 0x04, 0x00
+        };
 
-    public int getLocalPort() {
-        return serverSock.getLocalPort();
-    }
-
-    public boolean accepting() {
-        return accepting;
-    }
-
-    public void close() throws IOException {
-        serverSock.close();
-    }
-}
-
-class BindableServer extends TestServer {
-
-    public BindableServer() throws IOException {
-        super();
+        @Override
+        protected void handleRequest(Socket socket,
+                                     LdapMessage msg,
+                                     OutputStream out)
+                throws IOException {
+            switch (msg.getOperation()) {
+                case BIND_REQUEST:
+                    out.write(bindResponse);
+                    out.flush();
+                default:
+                    break;
+            }
+        }
     }
 
-    private byte[] bindResponse = {
-        0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
-        0x01, 0x00, 0x04, 0x00, 0x04, 0x00
-    };
+    static class NotBindableServer extends TestServer {
 
-    public void run() {
-        try {
-            accepting = true;
-            Socket socket = serverSock.accept();
-            InputStream in = socket.getInputStream();
-            OutputStream out = socket.getOutputStream();
-
-            // Read the LDAP BindRequest
-            while (in.read() != -1) {
-                in.skip(in.available());
-                break;
-            }
+        NotBindableServer() throws IOException { }
 
-            // Write an LDAP BindResponse
-            out.write(bindResponse);
-            out.flush();
-        } catch (IOException e) {
-            // ignore
-        }
-    }
-}
-
-class DeadServer extends TestServer {
-
-    public DeadServer() throws IOException {
-        super();
-    }
-
-    public void run() {
-        while(true) {
+        @Override
+        protected void beforeConnectionHandled(Socket socket) {
             try {
-                accepting = true;
-                Socket socket = serverSock.accept();
-            } catch (Exception e) {
-                break;
+                TimeUnit.DAYS.sleep(Integer.MAX_VALUE);
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
             }
         }
     }
-}
 
-public class LdapTimeoutTest {
+    // ------ timeouts check utilities ------
 
-    private static final ExecutorService testPool =
-        Executors.newFixedThreadPool(3);
-    private static final ScheduledExecutorService killSwitchPool =
-        Executors.newScheduledThreadPool(3);
-    public static int MIN_TIMEOUT = 18_000;
+    /*
+     * Asserts that the specified executable yields a result or an exception
+     * within the specified time frame. Interrupts the executable
+     * unconditionally.
+     *
+     * If the executable yields a result or an exception within the specified
+     * time frame, the result will be returned and the exception will be
+     * rethrown respectively in a transparent fashion as if the executable was
+     * executed directly.
+     */
+    public static <T> T assertCompletion(long loMillis,
+                                         long hiMillis,
+                                         Callable<T> code)
+            throws Throwable {
+        if (loMillis < 0 || hiMillis < 0 || loMillis > hiMillis) {
+            throw new IllegalArgumentException("loMillis=" + loMillis +
+                                                       ", hiMillis=" + hiMillis);
+        }
+        Objects.requireNonNull(code);
 
-    static Hashtable createEnv() {
-        Hashtable env = new Hashtable(11);
-        env.put(Context.INITIAL_CONTEXT_FACTORY,
-            "com.sun.jndi.ldap.LdapCtxFactory");
-        return env;
-    }
+        // this queue acts both as an exchange point and a barrier
+        SynchronousQueue<Long> startTime = new SynchronousQueue<>();
+
+        Callable<T> wrappedTask = () -> {
+            // by the time this value reaches the "stopwatch" thread it might be
+            // well outdated and that's okay, we will adjust the wait time
+            startTime.put(System.nanoTime());
+            return code.call();
+        };
 
-    public static void main(String[] args) throws Exception {
+        FutureTask<T> task = new FutureTask<>(wrappedTask);
+        Thread t = new Thread(task);
+        t.start();
 
-        InitialContext ctx = null;
-        List<Future> results = new ArrayList<>();
+        final long startNanos;
+        try {
+            startNanos = startTime.take(); // (1) wait for the initial time mark
+        } catch (Throwable e) {
+            t.interrupt();
+            throw e;
+        }
+
+        final long waitTime = hiMillis -
+                NANOSECONDS.toMillis(System.nanoTime() - startNanos); // (2) adjust wait time
 
         try {
-            // run the DeadServerTest with no timeouts set
-            // this should get stuck indefinitely, so we need to kill
-            // it after a timeout
-            System.out.println("Running connect timeout test with 20s kill switch");
-            Hashtable env = createEnv();
-            results.add(
-                    testPool.submit(new DeadServerNoTimeoutTest(env, killSwitchPool)));
-
-            // run the ReadServerTest with connect timeout set
-            // this should get stuck indefinitely so we need to kill
-            // it after a timeout
-            System.out.println("Running read timeout test with 10ms connect timeout & 20s kill switch");
-            Hashtable env1 = createEnv();
-            env1.put("com.sun.jndi.ldap.connect.timeout", "10");
-            results.add(testPool.submit(
-                    new ReadServerNoTimeoutTest(env1, killSwitchPool)));
-
-            // run the ReadServerTest with no timeouts set
-            // this should get stuck indefinitely, so we need to kill
-            // it after a timeout
-            System.out.println("Running read timeout test with 20s kill switch");
-            Hashtable env2 = createEnv();
-            results.add(testPool.submit(
-                    new ReadServerNoTimeoutTest(env2, killSwitchPool)));
-
-            // run the DeadServerTest with connect / read timeouts set
-            // this should exit after the connect timeout expires
-            System.out.println("Running connect timeout test with 10ms connect timeout, 3000ms read timeout");
-            Hashtable env3 = createEnv();
-            env3.put("com.sun.jndi.ldap.connect.timeout", "10");
-            env3.put("com.sun.jndi.ldap.read.timeout", "3000");
-            results.add(testPool.submit(new DeadServerTimeoutTest(env3)));
-
-
-            // run the ReadServerTest with connect / read timeouts set
-            // this should exit after the connect timeout expires
-            //
-            // NOTE: commenting this test out as it is failing intermittently.
-            //
-            // System.out.println("Running read timeout test with 10ms connect timeout, 3000ms read timeout");
-            // Hashtable env4 = createEnv();
-            // env4.put("com.sun.jndi.ldap.connect.timeout", "10");
-            // env4.put("com.sun.jndi.ldap.read.timeout", "3000");
-            // results.add(testPool.submit(new ReadServerTimeoutTest(env4)));
-
-            // run the DeadServerTest with connect timeout set
-            // this should exit after the connect timeout expires
-            System.out.println("Running connect timeout test with 10ms connect timeout");
-            Hashtable env5 = createEnv();
-            env5.put("com.sun.jndi.ldap.connect.timeout", "10");
-            results.add(testPool.submit(new DeadServerTimeoutTest(env5)));
-
-            // 8000487: Java JNDI connection library on ldap conn is
-            // not honoring configured timeout
-            System.out.println("Running simple auth connection test");
-            Hashtable env6 = createEnv();
-            env6.put("com.sun.jndi.ldap.connect.timeout", "10");
-            env6.put("com.sun.jndi.ldap.read.timeout", "3000");
-            env6.put(Context.SECURITY_AUTHENTICATION, "simple");
-            env6.put(Context.SECURITY_PRINCIPAL, "user");
-            env6.put(Context.SECURITY_CREDENTIALS, "password");
-            results.add(testPool.submit(new DeadServerTimeoutTest(env6)));
-
-            boolean testFailed = false;
-            for (Future test : results) {
-                while (!test.isDone()) {
-                    if ((Boolean) test.get() == false)
-                        testFailed = true;
-                }
+            T r = task.get(waitTime, MILLISECONDS); // (3) wait for the task to complete
+            long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+            if (elapsed < loMillis || elapsed > hiMillis) {
+                throw new RuntimeException(format(
+                        "After %s ms. (waitTime %s ms.) returned result '%s'", elapsed, waitTime, r));
             }
-
-            if (testFailed) {
-                throw new AssertionError("some tests failed");
+            return r;
+        } catch (ExecutionException e) {
+            long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+            if (elapsed < loMillis || elapsed > hiMillis) {
+                throw new RuntimeException(format(
+                        "After %s ms. (waitTime %s ms.) thrown exception", elapsed, waitTime), e);
             }
-
+            throw e.getCause();
+        } catch (TimeoutException e) {
+            // We trust timed get not to throw TimeoutException prematurely
+            // (i.e. before the wait time elapses)
+            long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+            throw new RuntimeException(format(
+                    "After %s ms. (waitTime %s ms.) is incomplete", elapsed, waitTime));
         } finally {
-            LdapTimeoutTest.killSwitchPool.shutdown();
-            LdapTimeoutTest.testPool.shutdown();
+            t.interrupt();
         }
     }
 
+    /*
+     * Asserts that the specified executable yields no result and no exception
+     * for at least the specified amount of time. Interrupts the executable
+     * unconditionally.
+     */
+    public static void assertIncompletion(long millis, Callable<?> code)
+            throws Exception
+    {
+        if (millis < 0) {
+            throw new IllegalArgumentException("millis=" + millis);
+        }
+        Objects.requireNonNull(code);
+
+        // this queue acts both as an exchange point and a barrier
+        SynchronousQueue<Long> startTime = new SynchronousQueue<>();
+
+        Callable<?> wrappedTask = () -> {
+            // by the time this value reaches the "stopwatch" thread it might be
+            // well outdated and that's okay, we will adjust the wait time
+            startTime.put(System.nanoTime());
+            return code.call();
+        };
+
+        FutureTask<?> task = new FutureTask<>(wrappedTask);
+        Thread t = new Thread(task);
+        t.start();
+
+        final long startNanos;
+        try {
+            startNanos = startTime.take(); // (1) wait for the initial time mark
+        } catch (Throwable e) {
+            t.interrupt();
+            throw e;
+        }
+
+        final long waitTime = millis -
+                NANOSECONDS.toMillis(System.nanoTime() - startNanos); // (2) adjust wait time
+
+        try {
+            Object r = task.get(waitTime, MILLISECONDS); // (3) wait for the task to complete
+            long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+            if (elapsed < waitTime) {
+                throw new RuntimeException(format(
+                        "After %s ms. (waitTime %s ms.) returned result '%s'", elapsed, waitTime, r));
+            }
+        } catch (ExecutionException e) {
+            long elapsed = NANOSECONDS.toMillis(System.nanoTime() - startNanos);
+            if (elapsed < waitTime) {
+                throw new RuntimeException(format(
+                        "After %s ms. (waitTime %s ms.) thrown exception", elapsed, waitTime), e);
+            }
+        } catch (TimeoutException expected) {
+        } finally {
+            t.interrupt();
+        }
+    }
+
+    // ------ miscellaneous utilities ------
+
+    private static String urlTo(TestServer server) {
+        String hostAddress = server.getInetAddress().getHostAddress();
+        String addr;
+        if (hostAddress.contains(":")) { // IPv6
+            addr = '[' + hostAddress + ']';
+        } else {                         // IPv4
+            addr = hostAddress;
+        }
+        return "ldap://" + addr + ":" + server.getPort();
+    }
+
+    /*
+     * A diagnostic aid that might help with debugging timeout issues. The idea
+     * is to continuously measure accuracy and responsiveness of the system that
+     * runs this test. If the system is overwhelmed (with something else), it
+     * might affect the test run. At the very least we will have traces of that
+     * in the logs.
+     *
+     * This utility does not automatically scale up test timeouts, it simply
+     * gathers information.
+     */
+    private static void startAuxiliaryDiagnosticOutput() {
+        System.out.printf("Starting diagnostic output (probe)%n");
+        Thread t = new Thread(() -> {
+            for (int i = 0; ; i = ((i % 20) + 1)) {
+                // 500, 1_000, 1_500, ..., 9_500, 10_000, 500, 1_000, ...
+                long expected = i * 500;
+                long start = System.nanoTime();
+                try {
+                    MILLISECONDS.sleep(expected);
+                } catch (InterruptedException e) {
+                    return;
+                }
+                long stop = System.nanoTime();
+                long actual = NANOSECONDS.toMillis(stop - start);
+                System.out.printf("(probe) expected [ms.]: %s, actual [ms.]: %s%n",
+                                  expected, actual);
+
+            }
+        }, "probe");
+        t.setDaemon(true);
+        t.start();
+    }
 }
-
--- a/test/jdk/com/sun/jndi/ldap/lib/BaseLdapServer.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/com/sun/jndi/ldap/lib/BaseLdapServer.java	Wed Sep 18 07:46:02 2019 +0200
@@ -35,7 +35,6 @@
 import java.util.Objects;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.RejectedExecutionException;
 
 import static java.lang.System.Logger.Level.INFO;
 
@@ -44,6 +43,7 @@
  *
  * Override the following methods to provide customized behavior
  *
+ *     * beforeAcceptingConnections
  *     * beforeConnectionHandled
  *     * handleRequest
  *
@@ -83,6 +83,7 @@
         logger().log(INFO, "Server is accepting connections at port {0}",
                      getPort());
         try {
+            beforeAcceptingConnections();
             while (isRunning()) {
                 Socket socket = serverSocket.accept();
                 logger().log(INFO, "Accepted new connection at {0}", socket);
@@ -97,10 +98,10 @@
                 }
                 connectionsPool.submit(() -> handleConnection(socket));
             }
-        } catch (IOException | RejectedExecutionException e) {
+        } catch (Throwable t) {
             if (isRunning()) {
                 throw new RuntimeException(
-                        "Unexpected exception while accepting connections", e);
+                        "Unexpected exception while accepting connections", t);
             }
         } finally {
             logger().log(INFO, "Server stopped accepting connections at port {0}",
@@ -109,6 +110,13 @@
     }
 
     /*
+     * Called once immediately preceding the server accepting connections.
+     *
+     * Override to customize the behavior.
+     */
+    protected void beforeAcceptingConnections() { }
+
+    /*
      * A "Template Method" describing how a connection (represented by a socket)
      * is handled.
      *
@@ -240,12 +248,25 @@
     /**
      * Returns the local port this server is listening at.
      *
+     * This method can be called at any time.
+     *
      * @return the port this server is listening at
      */
     public int getPort() {
         return serverSocket.getLocalPort();
     }
 
+    /**
+     * Returns the address this server is listening at.
+     *
+     * This method can be called at any time.
+     *
+     * @return the address
+     */
+    public InetAddress getInetAddress() {
+        return serverSocket.getInetAddress();
+    }
+
     /*
      * Returns a flag to indicate whether this server is running or not.
      *
--- a/test/jdk/java/net/CookieHandler/CookieManagerTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/net/CookieHandler/CookieManagerTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -26,7 +26,8 @@
  * @summary Unit test for java.net.CookieManager
  * @bug 6244040 7150552 7051862
  * @modules jdk.httpserver
- * @run main/othervm -ea CookieManagerTest
+ *          java.logging
+ * @run main/othervm -ea -esa CookieManagerTest
  * @author Edward Wang
  */
 
@@ -36,6 +37,8 @@
 import java.util.List;
 import java.io.IOException;
 import java.net.*;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import static java.net.Proxy.NO_PROXY;
 
 public class CookieManagerTest {
@@ -63,6 +66,11 @@
     }
 
     public static void main(String[] args) throws Exception {
+        // logs everything...
+        Logger root = Logger.getLogger("");
+        root.setLevel(Level.ALL);
+        root.getHandlers()[0].setLevel(Level.ALL);
+
         startHttpServer();
         makeHttpCall();
 
--- a/test/jdk/java/net/Socket/HttpProxy.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/net/Socket/HttpProxy.java	Wed Sep 18 07:46:02 2019 +0200
@@ -160,6 +160,7 @@
             public void run() {
                 try { simpleWrite(os, start); }
                 catch (Exception e) {unexpected(e); }
+                finally { out.println(threadName + ": done"); }
             }}, threadName)).start();
     }
 
@@ -170,6 +171,7 @@
             b[1] = (byte) (i % 256);
             os.write(b);
         }
+        out.println("Wrote " + start + " -> " + (start + 100));
     }
 
     void simpleRead(InputStream is, int start) throws Exception {
@@ -184,6 +186,7 @@
             if (r != i)
                 throw new Exception("read " + r + " expected " +i);
         }
+        out.println("Read " + start + " -> " + (start + 100));
     }
 
     int bytes(byte b1, byte b2) {
@@ -249,6 +252,7 @@
 
             // retrieve the host and port info from the status-line
             InetSocketAddress serverAddr = getConnectInfo(statusLine);
+            out.println("Proxy serving CONNECT request to " + serverAddr);
 
             //open socket to the server
             try (Socket serverSocket = new Socket(serverAddr.getAddress(),
--- a/test/jdk/java/net/Socket/NullHost.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/net/Socket/NullHost.java	Wed Sep 18 07:46:02 2019 +0200
@@ -46,8 +46,10 @@
             return svr.getLocalPort();
         }
 
+        volatile boolean done;
         public void shutdown() {
             try {
+                done = true;
                 svr.close();
             } catch (IOException e) {
             }
@@ -56,11 +58,12 @@
         public void run() {
             Socket s;
             try {
-                while (true) {
+                while (!done) {
                     s = svr.accept();
                     s.close();
                 }
             } catch (IOException e) {
+                if (!done) e.printStackTrace();
             }
         }
     }
@@ -74,13 +77,9 @@
         int port = s.getPort();
         s.start();
         try {
-            Socket sock = new Socket((String)null, port);
-            sock.close();
-            sock = new Socket((String)null, port, true);
-            sock.close();
-            sock = new Socket((String)null, port, null, 0);
-            sock.close();
-
+            try (var sock = new Socket((String)null, port)) {}
+            try (var sock = new Socket((String)null, port, true)) {}
+            try (var sock = new Socket((String)null, port, null, 0)) {}
         } catch (NullPointerException e) {
             throw new RuntimeException("Got a NPE");
         } finally {
--- a/test/jdk/java/util/Map/Get.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/Map/Get.java	Wed Sep 18 07:46:02 2019 +0200
@@ -120,8 +120,8 @@
     //--------------------- Infrastructure ---------------------------
     static volatile int passed = 0, failed = 0;
     static void pass() { passed++; }
-    static void fail() { failed++; (new Error("Failure")).printStackTrace(System.err); }
-    static void fail(String msg) { failed++; (new Error("Failure: " + msg)).printStackTrace(System.err); }
+    static void fail() { failed++; new Error("Failure").printStackTrace(System.err); }
+    static void fail(String msg) { failed++; new Error("Failure: " + msg).printStackTrace(System.err); }
     static void unexpected(String msg, Throwable t) { System.err.println("Unexpected: " + msg); unexpected(t); }
     static void unexpected(Throwable t) { failed++; t.printStackTrace(System.err); }
     static void check(boolean cond) { if (cond) pass(); else fail(); }
--- a/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/BlockingQueue/OfferDrainToLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -34,6 +34,7 @@
 /*
  * @test
  * @bug 6805775 6815766
+ * @library /test/lib
  * @run main OfferDrainToLoops 100
  * @summary Test concurrent offer vs. drainTo
  */
@@ -47,10 +48,12 @@
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.LinkedTransferQueue;
 import java.util.concurrent.atomic.AtomicLong;
+import jdk.test.lib.Utils;
 
 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class OfferDrainToLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
 
     OfferDrainToLoops(String[] args) {
@@ -76,7 +79,6 @@
         System.out.println(q.getClass().getSimpleName());
         final long testDurationNanos = testDurationMillis * 1000L * 1000L;
         final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
-        final long timeoutMillis = 10L * 1000L;
         final SplittableRandom rnd = new SplittableRandom();
 
         // Poor man's bounded buffer.
@@ -155,13 +157,13 @@
                 }}};
 
         for (Thread thread : new Thread[] { offerer, drainer, scanner }) {
-            thread.join(timeoutMillis + testDurationMillis);
+            thread.join(LONG_DELAY_MS + testDurationMillis);
             if (thread.isAlive()) {
                 System.err.printf("Hung thread: %s%n", thread.getName());
                 failed++;
                 for (StackTraceElement e : thread.getStackTrace())
                     System.err.println(e);
-                thread.join(timeoutMillis);
+                thread.join(LONG_DELAY_MS);
             }
         }
     }
--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapCheck.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapCheck.java	Wed Sep 18 07:46:02 2019 +0200
@@ -537,7 +537,7 @@
         static void printStats() {
             for (Iterator it = accum.entrySet().iterator(); it.hasNext(); ) {
                 Map.Entry e = (Map.Entry)(it.next());
-                Stats stats = ((Stats)(e.getValue()));
+                Stats stats = (Stats)(e.getValue());
                 int n = stats.number;
                 double t;
                 if (n > 0)
--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -99,8 +99,8 @@
             nops = Integer.parseInt(args[5]);
 
         // normalize probabilities wrt random number generator
-        removesPerMaxRandom = (int)(((double)premove/100.0 * 0x7FFFFFFFL));
-        insertsPerMaxRandom = (int)(((double)pinsert/100.0 * 0x7FFFFFFFL));
+        removesPerMaxRandom = (int)((double)premove/100.0 * 0x7FFFFFFFL);
+        insertsPerMaxRandom = (int)((double)pinsert/100.0 * 0x7FFFFFFFL);
 
         System.out.print("Class: " + mapClass.getName());
         System.out.print(" threads: " + maxThreads);
@@ -172,7 +172,7 @@
         long time = timer.getTime();
         long tpo = time / (i * (long)nops);
         System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
-        double secs = (double)(time) / 1000000000.0;
+        double secs = (double)time / 1000000000.0;
         System.out.println("\t " + secs + "s run time");
         map.clear();
     }
--- a/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/ToArray.java	Wed Sep 18 07:46:02 2019 +0200
@@ -24,37 +24,40 @@
 /*
  * @test
  * @bug 4486658 8010293
- * @summary thread safety of toArray methods of subCollections
+ * @summary thread safety of toArray methods of collection views
  * @author Martin Buchholz
  */
 
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 public class ToArray {
 
     public static void main(String[] args) throws Throwable {
-        // Execute a number of times to increase the probability of
-        // failure if there is an issue
-        for (int i = 0; i < 16; i++) {
+        final int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
+        final int reps = 10 * runsPerTest;
+        for (int i = reps; i--> 0; )
             executeTest();
-        }
     }
 
     static void executeTest() throws Throwable {
-        final Throwable[] throwable = new Throwable[1];
         final ConcurrentHashMap<Integer, Integer> m = new ConcurrentHashMap<>();
-
-        // Number of workers equal to the number of processors
-        // Each worker will put globally unique keys into the map
-        final int nWorkers = Runtime.getRuntime().availableProcessors();
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        final int nCPU = Runtime.getRuntime().availableProcessors();
+        final int minWorkers = 2;
+        final int maxWorkers = Math.max(minWorkers, Math.min(32, nCPU));
+        final int nWorkers = rnd.nextInt(minWorkers, maxWorkers + 1);
         final int sizePerWorker = 1024;
         final int maxSize = nWorkers * sizePerWorker;
 
-        // The foreman keeps checking that the size of the arrays
-        // obtained from the key and value sets is never less than the
-        // previously observed size and is never greater than the maximum size
+        // The foreman busy-checks that the size of the arrays obtained
+        // from the keys and values views grows monotonically until it
+        // reaches the maximum size.
+
         // NOTE: these size constraints are not specific to toArray and are
         // applicable to any form of traversal of the collection views
         CompletableFuture<?> foreman = CompletableFuture.runAsync(new Runnable() {
@@ -62,44 +65,37 @@
 
             private boolean checkProgress(Object[] a) {
                 int size = a.length;
-                if (size < prevSize) throw new RuntimeException("WRONG WAY");
-                if (size > maxSize) throw new RuntimeException("OVERSHOOT");
-                if (size == maxSize) return true;
+                if (size < prevSize || size > maxSize)
+                    throw new AssertionError(
+                        String.format("prevSize=%d size=%d maxSize=%d",
+                                      prevSize, size, maxSize));
                 prevSize = size;
-                return false;
+                return size == maxSize;
             }
 
-            @Override
             public void run() {
-                try {
-                    Integer[] empty = new Integer[0];
-                    while (true) {
-                        if (checkProgress(m.values().toArray())) return;
-                        if (checkProgress(m.keySet().toArray())) return;
-                        if (checkProgress(m.values().toArray(empty))) return;
-                        if (checkProgress(m.keySet().toArray(empty))) return;
-                    }
-                }
-                catch (Throwable t) {
-                    throwable[0] = t;
-                }
+                Integer[] empty = new Integer[0];
+                for (;;)
+                    if (checkProgress(m.values().toArray())
+                        & checkProgress(m.keySet().toArray())
+                        & checkProgress(m.values().toArray(empty))
+                        & checkProgress(m.keySet().toArray(empty)))
+                        return;
             }
         });
 
-        // Create workers
-        // Each worker will put globally unique keys into the map
-        CompletableFuture<?>[] workers = IntStream.range(0, nWorkers).
-                mapToObj(w -> CompletableFuture.runAsync(() -> {
-                    for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
-                        m.put(o + i, i);
-                })).
-                toArray(CompletableFuture<?>[]::new);
+        // Each worker puts globally unique keys into the map
+        List<CompletableFuture<?>> workers =
+            IntStream.range(0, nWorkers)
+            .mapToObj(w -> (Runnable) () -> {
+                for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
+                    m.put(o + i, i);
+            })
+            .map(CompletableFuture::runAsync)
+            .collect(Collectors.toList());
 
-        // Wait for workers and then foreman to complete
-        CompletableFuture.allOf(workers).join();
+        // Wait for workers and foreman to complete
+        workers.forEach(CompletableFuture<?>::join);
         foreman.join();
-
-        if (throwable[0] != null)
-            throw throwable[0];
     }
 }
--- a/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/ConcurrentQueues/OfferRemoveLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -25,7 +25,8 @@
  * @test
  * @bug 6316155 6595669 6871697 6868712
  * @summary Test concurrent offer vs. remove
- * @run main OfferRemoveLoops 300
+ * @library /test/lib
+ * @run main OfferRemoveLoops 100
  * @author Martin Buchholz
  */
 
@@ -43,10 +44,12 @@
 import java.util.concurrent.LinkedTransferQueue;
 import java.util.concurrent.PriorityBlockingQueue;
 import java.util.concurrent.Semaphore;
+import jdk.test.lib.Utils;
 
 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class OfferRemoveLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
 
     OfferRemoveLoops(String[] args) {
@@ -75,7 +78,6 @@
         System.err.println(q.getClass().getSimpleName());
         final long testDurationNanos = testDurationMillis * 1000L * 1000L;
         final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
-        final long timeoutMillis = 10L * 1000L;
         final int maxChunkSize = 1042;
         final int maxQueueSize = 10 * maxChunkSize;
         final CountDownLatch done = new CountDownLatch(3);
@@ -156,7 +158,7 @@
                 done.countDown();
             }};
 
-        if (! done.await(timeoutMillis + testDurationMillis, MILLISECONDS)) {
+        if (! done.await(LONG_DELAY_MS + testDurationMillis, MILLISECONDS)) {
             for (Thread thread : new Thread[] { offerer, remover, scanner }) {
                 if (thread.isAlive()) {
                     System.err.printf("Hung thread: %s%n", thread.getName());
--- a/test/jdk/java/util/concurrent/CountDownLatch/Basic.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/CountDownLatch/Basic.java	Wed Sep 18 07:46:02 2019 +0200
@@ -23,70 +23,57 @@
 
 /*
  * @test
- * @bug 6332435
+ * @bug 6332435 8221168
  * @summary Basic tests for CountDownLatch
  * @library /test/lib
  * @author Seetharam Avadhanam, Martin Buchholz
  */
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
 import jdk.test.lib.Utils;
 
 public class Basic {
     static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
 
-    interface AwaiterFactory {
-        Awaiter getAwaiter();
-    }
-
     abstract static class Awaiter extends Thread {
-        private volatile Throwable result = null;
-        protected void result(Throwable result) { this.result = result; }
-        public Throwable result() { return this.result; }
-    }
-
-    private void toTheStartingGate(CountDownLatch gate) {
-        try {
-            gate.await();
-        }
-        catch (Throwable t) { fail(t); }
+        volatile Throwable exception;
+        volatile boolean interrupted;
+        abstract void realRun() throws Exception;
+        public final void run() {
+            try { realRun(); }
+            catch (Throwable ex) { exception = ex; }
+            interrupted = Thread.interrupted();
+        };
     }
 
-    private Awaiter awaiter(final CountDownLatch latch,
-                            final CountDownLatch gate) {
-        return new Awaiter() { public void run() {
-            System.out.println("without millis: " + latch.toString());
-            gate.countDown();
-
-            try {
+    static Awaiter awaiter(CountDownLatch latch,
+                           CountDownLatch gate) {
+        return new Awaiter() {
+            public void realRun() throws InterruptedException {
+                gate.countDown();
                 latch.await();
-                System.out.println("without millis - ComingOut");
-            }
-            catch (Throwable result) { result(result); }}};
+            }};
     }
 
-    private Awaiter awaiter(final CountDownLatch latch,
-                            final CountDownLatch gate,
-                            final long millis) {
-        return new Awaiter() { public void run() {
-            System.out.println("with millis: "+latch.toString());
-            gate.countDown();
-
-            try {
-                latch.await(millis, TimeUnit.MILLISECONDS);
-                System.out.println("with millis - ComingOut");
-            }
-            catch (Throwable result) { result(result); }}};
+    static Awaiter awaiter(CountDownLatch latch,
+                           CountDownLatch gate,
+                           long timeoutMillis) {
+        return new Awaiter() {
+            public void realRun() throws InterruptedException {
+                gate.countDown();
+                latch.await(timeoutMillis, TimeUnit.MILLISECONDS);
+            }};
     }
 
-    AwaiterFactory awaiterFactory(CountDownLatch latch, CountDownLatch gate) {
-        return () -> awaiter(latch, gate);
-    }
-
-    AwaiterFactory timedAwaiterFactory(CountDownLatch latch, CountDownLatch gate) {
-        return () -> awaiter(latch, gate, LONG_DELAY_MS);
+    static Supplier<Awaiter> randomAwaiterSupplier(
+            CountDownLatch latch, CountDownLatch gate) {
+        return () -> (ThreadLocalRandom.current().nextBoolean())
+            ? awaiter(latch, gate)
+            : awaiter(latch, gate, LONG_DELAY_MS);
     }
 
     //----------------------------------------------------------------
@@ -94,28 +81,24 @@
     //----------------------------------------------------------------
     public static void normalUse() throws Throwable {
         int count = 0;
-        Basic test = new Basic();
         CountDownLatch latch = new CountDownLatch(3);
         Awaiter[] a = new Awaiter[12];
 
         for (int i = 0; i < 3; i++) {
             CountDownLatch gate = new CountDownLatch(4);
-            AwaiterFactory factory1 = test.awaiterFactory(latch, gate);
-            AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate);
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            test.toTheStartingGate(gate);
-            System.out.println("Main Thread: " + latch.toString());
+            Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            gate.await();
             latch.countDown();
             checkCount(latch, 2-i);
         }
-        for (int i = 0; i < 12; i++)
-            a[i].join();
-
-        for (int i = 0; i < 12; i++)
-            checkResult(a[i], null);
+        for (Awaiter awaiter : a)
+            awaiter.join();
+        for (Awaiter awaiter : a)
+            checkException(awaiter, null);
     }
 
     //----------------------------------------------------------------
@@ -123,38 +106,38 @@
     //----------------------------------------------------------------
     public static void threadInterrupted() throws Throwable {
         int count = 0;
-        Basic test = new Basic();
         CountDownLatch latch = new CountDownLatch(3);
         Awaiter[] a = new Awaiter[12];
 
         for (int i = 0; i < 3; i++) {
             CountDownLatch gate = new CountDownLatch(4);
-            AwaiterFactory factory1 = test.awaiterFactory(latch, gate);
-            AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate);
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
+            Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            gate.await();
             a[count-1].interrupt();
-            test.toTheStartingGate(gate);
-            System.out.println("Main Thread: " + latch.toString());
             latch.countDown();
             checkCount(latch, 2-i);
         }
-        for (int i = 0; i < 12; i++)
-            a[i].join();
-
-        for (int i = 0; i < 12; i++)
-            checkResult(a[i],
-                        (i % 4) == 3 ? InterruptedException.class : null);
+        for (Awaiter awaiter : a)
+            awaiter.join();
+        for (int i = 0; i < a.length; i++) {
+            Awaiter awaiter = a[i];
+            Throwable ex = awaiter.exception;
+            if ((i % 4) == 3 && !awaiter.interrupted)
+                checkException(awaiter, InterruptedException.class);
+            else
+                checkException(awaiter, null);
+        }
     }
 
     //----------------------------------------------------------------
     // One thread timed out
     //----------------------------------------------------------------
     public static void timeOut() throws Throwable {
-        int count =0;
-        Basic test = new Basic();
+        int count = 0;
         CountDownLatch latch = new CountDownLatch(3);
         Awaiter[] a = new Awaiter[12];
 
@@ -162,54 +145,56 @@
 
         for (int i = 0; i < 3; i++) {
             CountDownLatch gate = new CountDownLatch(4);
-            AwaiterFactory factory1 = test.awaiterFactory(latch, gate);
-            AwaiterFactory factory2 = test.timedAwaiterFactory(latch, gate);
-            a[count] = test.awaiter(latch, gate, timeout[i]); a[count++].start();
-            a[count] = factory1.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            a[count] = factory2.getAwaiter(); a[count++].start();
-            test.toTheStartingGate(gate);
-            System.out.println("Main Thread: " + latch.toString());
+            Supplier<Awaiter> s = randomAwaiterSupplier(latch, gate);
+            a[count] = awaiter(latch, gate, timeout[i]); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            a[count] = s.get(); a[count++].start();
+            gate.await();
             latch.countDown();
             checkCount(latch, 2-i);
         }
-        for (int i = 0; i < 12; i++)
-            a[i].join();
-
-        for (int i = 0; i < 12; i++)
-            checkResult(a[i], null);
+        for (Awaiter awaiter : a)
+            awaiter.join();
+        for (Awaiter awaiter : a)
+            checkException(awaiter, null);
     }
 
     public static void main(String[] args) throws Throwable {
-        normalUse();
-        threadInterrupted();
-        timeOut();
+        try {
+            normalUse();
+        } catch (Throwable ex) { fail(ex); }
+        try {
+            threadInterrupted();
+        } catch (Throwable ex) { fail(ex); }
+        try {
+            timeOut();
+        } catch (Throwable ex) { fail(ex); }
+
         if (failures.get() > 0L)
             throw new AssertionError(failures.get() + " failures");
     }
 
-    private static final AtomicInteger failures = new AtomicInteger(0);
+    static final AtomicInteger failures = new AtomicInteger(0);
 
-    private static void fail(String msg) {
+    static void fail(String msg) {
         fail(new AssertionError(msg));
     }
 
-    private static void fail(Throwable t) {
+    static void fail(Throwable t) {
         t.printStackTrace();
         failures.getAndIncrement();
     }
 
-    private static void checkCount(CountDownLatch b, int expected) {
+    static void checkCount(CountDownLatch b, int expected) {
         if (b.getCount() != expected)
             fail("Count = " + b.getCount() +
                  ", expected = " + expected);
     }
 
-    private static void checkResult(Awaiter a, Class c) {
-        Throwable t = a.result();
-        if (! ((t == null && c == null) || c.isInstance(t))) {
-            System.out.println("Mismatch: " + t + ", " + c.getName());
-            failures.getAndIncrement();
-        }
+    static void checkException(Awaiter awaiter, Class<? extends Throwable> c) {
+        Throwable ex = awaiter.exception;
+        if (! ((ex == null && c == null) || c.isInstance(ex)))
+            fail("Expected: " + c + ", got: " + ex);
     }
 }
--- a/test/jdk/java/util/concurrent/CyclicBarrier/Basic.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/CyclicBarrier/Basic.java	Wed Sep 18 07:46:02 2019 +0200
@@ -37,6 +37,7 @@
 import java.util.concurrent.BrokenBarrierException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
 import jdk.test.lib.Utils;
@@ -293,37 +294,42 @@
      * Handling of extra interrupts while waiting - tests for bug 6366811
      */
     private static void testInterrupts() {
-        final int N = 10;
+        final int N = ThreadLocalRandom.current().nextInt(2, 10);
         final CyclicBarrier startingGate = new CyclicBarrier(N+1);
 
         /**
          * A version of Awaiter that also records interrupted state.
          */
         class Waiter extends CheckedThread {
-            private boolean timed;
-            private CyclicBarrier barrier;
-            private CountDownLatch doneSignal;
-            private Throwable throwable;
-            private boolean interrupted;
+            private final boolean timed;
+            private final CyclicBarrier barrier;
+            private final CountDownLatch doneSignal;
+            volatile Throwable throwable;
+            volatile boolean interruptStatusSetAfterAwait;
 
-            public Waiter(boolean timed,
-                          CountDownLatch doneSignal,
-                          CyclicBarrier barrier) {
-                this.timed = timed;
+            public Waiter(CountDownLatch doneSignal, CyclicBarrier barrier) {
+                this.timed = ThreadLocalRandom.current().nextBoolean();
                 this.doneSignal = doneSignal;
                 this.barrier = barrier;
             }
-            Throwable throwable() { return this.throwable; }
-            boolean interruptBit() { return this.interrupted; }
+
             void realRun() throws Throwable {
                 startingGate.await(LONG_DELAY_MS, MILLISECONDS);
+
                 try {
                     if (timed) barrier.await(LONG_DELAY_MS, MILLISECONDS);
-                    else barrier.await(); }
-                catch (Throwable throwable) { this.throwable = throwable; }
+                    else barrier.await();
+                } catch (Throwable throwable) {
+                    this.throwable = throwable;
+                }
 
-                try { doneSignal.await(LONG_DELAY_MS, MILLISECONDS); }
-                catch (InterruptedException e) { interrupted = true; }
+                try {
+                    check(doneSignal.await(LONG_DELAY_MS, MILLISECONDS));
+                    if (Thread.interrupted())
+                        interruptStatusSetAfterAwait = true;
+                } catch (InterruptedException e) {
+                    interruptStatusSetAfterAwait = true;
+                }
             }
         }
 
@@ -352,7 +358,7 @@
                 } catch (Throwable t) { unexpected(t); }
             }};
             for (int i = 0; i < N; i++) {
-                Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
+                Waiter waiter = new Waiter(doneSignal, barrier);
                 waiter.start();
                 waiters.add(waiter);
             }
@@ -360,16 +366,14 @@
             while (barrier.getNumberWaiting() < N) Thread.yield();
             barrier.await();
             doneSignal.countDown();
-            int countInterrupted = 0;
-            int countInterruptedException = 0;
-            int countBrokenBarrierException = 0;
+            int countInterruptStatusSetAfterAwait = 0;
             for (Waiter waiter : waiters) {
                 waiter.join();
-                equal(waiter.throwable(), null);
-                if (waiter.interruptBit())
-                    countInterrupted++;
+                equal(waiter.throwable, null);
+                if (waiter.interruptStatusSetAfterAwait)
+                    countInterruptStatusSetAfterAwait++;
             }
-            equal(countInterrupted, N/2);
+            equal(countInterruptStatusSetAfterAwait, N/2);
             check(! barrier.isBroken());
         } catch (Throwable t) { unexpected(t); }
 
@@ -381,31 +385,33 @@
             final CyclicBarrier barrier = new CyclicBarrier(N+1);
             final List<Waiter> waiters = new ArrayList<>(N);
             for (int i = 0; i < N; i++) {
-                Waiter waiter = new Waiter(i < N/2, doneSignal, barrier);
+                Waiter waiter = new Waiter(doneSignal, barrier);
                 waiter.start();
                 waiters.add(waiter);
             }
             startingGate.await(LONG_DELAY_MS, MILLISECONDS);
             while (barrier.getNumberWaiting() < N) Thread.yield();
-            for (int i = 0; i < N/2; i++)
-                waiters.get(i).interrupt();
+            for (int i = 0; i < N/2; i++) {
+                Thread waiter = waiters.get(i);
+                waiter.interrupt();
+            }
             doneSignal.countDown();
-            int countInterrupted = 0;
             int countInterruptedException = 0;
             int countBrokenBarrierException = 0;
+            int countInterruptStatusSetAfterAwait = 0;
             for (Waiter waiter : waiters) {
                 waiter.join();
-                if (waiter.throwable() instanceof InterruptedException)
+                if (waiter.throwable instanceof InterruptedException)
                     countInterruptedException++;
-                if (waiter.throwable() instanceof BrokenBarrierException)
+                if (waiter.throwable instanceof BrokenBarrierException)
                     countBrokenBarrierException++;
-                if (waiter.interruptBit())
-                    countInterrupted++;
+                if (waiter.interruptStatusSetAfterAwait)
+                    countInterruptStatusSetAfterAwait++;
             }
-            equal(countInterrupted, N/2-1);
             equal(countInterruptedException, 1);
             equal(countBrokenBarrierException, N-1);
             checkBroken(barrier);
+            equal(countInterruptStatusSetAfterAwait, N/2-1);
             reset(barrier);
         } catch (Throwable t) { unexpected(t); }
     }
--- a/test/jdk/java/util/concurrent/FutureTask/BlockingTaskExecutor.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/FutureTask/BlockingTaskExecutor.java	Wed Sep 18 07:46:02 2019 +0200
@@ -103,7 +103,7 @@
      */
     static class NotificationReceiver {
         /** Has the notifiee been notified? */
-        boolean notified = false;
+        boolean notified;
 
         /**
          * Notify the notification receiver.
--- a/test/jdk/java/util/concurrent/FutureTask/CancelledFutureLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/FutureTask/CancelledFutureLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -130,7 +130,7 @@
             long endTime = System.nanoTime();
             long time = endTime - timer.startTime;
             if (print) {
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/FutureTask/DoneTimedGetLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/FutureTask/DoneTimedGetLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -33,6 +33,7 @@
 
 /*
  * @test
+ * @library /test/lib
  * @run main DoneTimedGetLoops 300
  * @summary isDone returning true guarantees that subsequent timed get
  * will never throw TimeoutException.
@@ -42,10 +43,12 @@
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import jdk.test.lib.Utils;
 
 @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
 public class DoneTimedGetLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
 
     static class PublicFutureTask extends FutureTask<Boolean> {
@@ -63,7 +66,6 @@
     void test(String[] args) throws Throwable {
         final long testDurationNanos = testDurationMillis * 1000L * 1000L;
         final long quittingTimeNanos = System.nanoTime() + testDurationNanos;
-        final long timeoutMillis = 10L * 1000L;
 
         final AtomicReference<PublicFutureTask> normalRef
             = new AtomicReference<>();
@@ -136,13 +138,13 @@
                  setterException,
                  doneTimedGetNormal,
                  doneTimedGetAbnormal }) {
-            thread.join(timeoutMillis + testDurationMillis);
+            thread.join(LONG_DELAY_MS + testDurationMillis);
             if (thread.isAlive()) {
                 System.err.printf("Hung thread: %s%n", thread.getName());
                 failed++;
                 for (StackTraceElement e : thread.getStackTrace())
                     System.err.println(e);
-                thread.join(timeoutMillis);
+                thread.join(LONG_DELAY_MS);
             }
         }
     }
--- a/test/jdk/java/util/concurrent/Phaser/FickleRegister.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/Phaser/FickleRegister.java	Wed Sep 18 07:46:02 2019 +0200
@@ -43,7 +43,7 @@
 
 public class FickleRegister {
     final AtomicLong count = new AtomicLong(0);
-    final long testDurationMillisDefault = 10L * 1000L;
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
     final long quittingTimeNanos;
     final int chunkSize = 1000;
--- a/test/jdk/java/util/concurrent/Phaser/TieredArriveLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/Phaser/TieredArriveLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -40,7 +40,7 @@
 import java.util.concurrent.Phaser;
 
 public class TieredArriveLoops {
-    final long testDurationMillisDefault = 10L * 1000L;
+    final long testDurationMillisDefault = 10_000L;
     final long testDurationMillis;
     final long quittingTimeNanos;
 
--- a/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/GCRetention.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/ScheduledThreadPoolExecutor/GCRetention.java	Wed Sep 18 07:46:02 2019 +0200
@@ -86,7 +86,7 @@
                     if (q.remove(1000) != null)
                         break;
                     System.out.printf(
-                        "%d/%d unqueued references remaining%n", j, n);
+                        "%d/%d unqueued references remaining%n", j + 1, n);
                 }
             }
         }
--- a/test/jdk/java/util/concurrent/TimeUnit/Basic.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/TimeUnit/Basic.java	Wed Sep 18 07:46:02 2019 +0200
@@ -24,6 +24,7 @@
 /* @test
  * @bug 5057341 6363898
  * @summary Basic tests for TimeUnit
+ * @library /test/lib
  * @author Martin Buchholz
  */
 
@@ -39,12 +40,20 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.io.ObjectOutputStream;
 import java.io.ObjectInputStream;
 import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import jdk.test.lib.Utils;
 
 public class Basic {
+    static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000);
+
     private static void realMain(String[] args) throws Throwable {
 
         for (TimeUnit u : TimeUnit.values()) {
@@ -71,18 +80,33 @@
         equal(1000L, MILLISECONDS.toMicros(1));
         equal(1000L, MICROSECONDS.toNanos(1));
 
-        long t0 = System.nanoTime();
-        MILLISECONDS.sleep(3); /* See windows bug 6313903, might not sleep */
-        long elapsedMillis = (System.nanoTime() - t0)/(1000L * 1000L);
-        System.out.printf("elapsed=%d%n", elapsedMillis);
-        check(elapsedMillis >= 0);
-        /* Might not sleep on windows: check(elapsedMillis >= 3); */
-        check(elapsedMillis < 1000);
+        //----------------------------------------------------------------
+        // TimeUnit.sleep sleeps for at least the specified time.
+        // TimeUnit.sleep(x, unit) for x <= 0 does not sleep at all.
+        //----------------------------------------------------------------
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int maxTimeoutMillis = rnd.nextInt(1, 12);
+        List<CompletableFuture<?>> workers =
+            IntStream.range(-1, maxTimeoutMillis + 1)
+            .mapToObj(timeoutMillis -> (Runnable) () -> {
+                try {
+                    long startTime = System.nanoTime();
+                    MILLISECONDS.sleep(timeoutMillis);
+                    long elapsedNanos = System.nanoTime() - startTime;
+                    long timeoutNanos = MILLISECONDS.toNanos(timeoutMillis);
+                    check(elapsedNanos >= timeoutNanos);
+                } catch (InterruptedException fail) {
+                    throw new AssertionError(fail);
+                }})
+            .map(CompletableFuture::runAsync)
+            .collect(Collectors.toList());
+
+        workers.forEach(CompletableFuture<?>::join);
 
         //----------------------------------------------------------------
         // Tests for serialized form compatibility with previous release
         //----------------------------------------------------------------
-        byte[] serializedForm = /* Generated using tiger */
+        byte[] serializedForm = /* Generated using JDK 5 */
             {-84, -19, 0, 5, '~', 'r', 0, 29, 'j', 'a', 'v', 'a', '.',
              'u', 't', 'i', 'l', '.', 'c', 'o', 'n', 'c', 'u', 'r', 'r', 'e',
              'n', 't', '.', 'T', 'i', 'm', 'e', 'U', 'n', 'i', 't', 0, 0,
--- a/test/jdk/java/util/concurrent/atomic/DoubleAdderDemo.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/atomic/DoubleAdderDemo.java	Wed Sep 18 07:46:02 2019 +0200
@@ -103,8 +103,8 @@
         long total = (long)nthreads * incs;
         if (sum != (double)total)
             throw new Error(sum + " != " + total);
-        double secs = (double)time / (1000L * 1000 * 1000);
-        long rate = total * (1000L) / time;
+        double secs = (double)time / 1000_000_000L;
+        long rate = total * 1000L / time;
         System.out.printf("threads:%3d  Time: %7.3fsec  Incs per microsec: %4d\n",
                           nthreads, secs, rate);
     }
--- a/test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/CheckedLockLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -136,7 +136,7 @@
             long time = timer.getTime();
             long tpi = time / (iters * nthreads);
             System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per update");
-            //                double secs = (double)(time) / 1000000000.0;
+            //                double secs = (double)time / 1000000000.0;
             //                System.out.print("\t " + secs + "s run time");
             System.out.println();
 
--- a/test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/FlakyMutex.java	Wed Sep 18 07:46:02 2019 +0200
@@ -49,31 +49,51 @@
     static class MyRuntimeException extends RuntimeException {}
 
     static void checkThrowable(Throwable t) {
-        check((t instanceof MyError) ||
+        if (!((t instanceof MyError) ||
               (t instanceof MyException) ||
-              (t instanceof MyRuntimeException));
+              (t instanceof MyRuntimeException)))
+            unexpected(t);
     }
 
     static void realMain(String[] args) throws Throwable {
-        final int nThreads = 3;
+        final ThreadLocalRandom rndMain = ThreadLocalRandom.current();
+        final int nCpus = Runtime.getRuntime().availableProcessors();
+        final int maxThreads = Math.min(4, nCpus);
+        final int nThreads = rndMain.nextInt(1, maxThreads + 1);
         final int iterations = 10_000;
         final CyclicBarrier startingGate = new CyclicBarrier(nThreads);
+        final ExecutorService es = Executors.newFixedThreadPool(nThreads);
         final FlakyMutex mutex = new FlakyMutex();
-        final ExecutorService es = Executors.newFixedThreadPool(nThreads);
         final Runnable task = () -> {
             try {
+                ThreadLocalRandom rnd = ThreadLocalRandom.current();
                 startingGate.await();
                 for (int i = 0; i < iterations; i++) {
                     for (;;) {
-                        try { mutex.lock(); break; }
-                        catch (Throwable t) { checkThrowable(t); }
+                        try {
+                            if (rnd.nextBoolean())
+                                mutex.lock();
+                            else
+                                mutex.lockInterruptibly();
+                            break;
+                        } catch (Throwable t) { checkThrowable(t); }
                     }
 
-                    try { check(! mutex.tryLock()); }
-                    catch (Throwable t) { checkThrowable(t); }
+                    if (rnd.nextBoolean()) {
+                        try {
+                            check(! mutex.tryLock());
+                        } catch (Throwable t) { checkThrowable(t); }
+                    }
 
-                    try { check(! mutex.tryLock(1, TimeUnit.MICROSECONDS)); }
-                    catch (Throwable t) { checkThrowable(t); }
+                    if (rnd.nextInt(10) == 0) {
+                        try {
+                            check(! mutex.tryLock(1, TimeUnit.MICROSECONDS));
+                        } catch (Throwable t) { checkThrowable(t); }
+                    }
+
+                    if (rnd.nextBoolean()) {
+                        check(mutex.isLocked());
+                    }
 
                     mutex.unlock();
                 }
@@ -146,7 +166,11 @@
         if (x == null ? y == null : x.equals(y)) pass();
         else fail(x + " not equal to " + y);}
     public static void main(String[] args) throws Throwable {
-        try {realMain(args);} catch (Throwable t) {unexpected(t);}
+        int runsPerTest = Integer.getInteger("jsr166.runsPerTest", 1);
+        try {
+            for (int i = runsPerTest; i--> 0; )
+                realMain(args);
+        } catch (Throwable t) { unexpected(t); }
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
     @SuppressWarnings("unchecked")
--- a/test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/Lock/TimedAcquireLeak.java	Wed Sep 18 07:46:02 2019 +0200
@@ -42,6 +42,8 @@
 import java.io.Reader;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -72,9 +74,9 @@
         return new File(bin, programName).getPath();
     }
 
-    static final String java = javaProgramPath("java");
-    static final String jmap = javaProgramPath("jmap");
-    static final String jps  = javaProgramPath("jps");
+    static final String javaPath = javaProgramPath("java");
+    static final String jmapPath = javaProgramPath("jmap");
+    static final String jpsPath  = javaProgramPath("jps");
 
     static String outputOf(Reader r) throws IOException {
         final StringBuilder sb = new StringBuilder();
@@ -159,7 +161,11 @@
 
     static String match(String s, String regex, int group) {
         Matcher matcher = Pattern.compile(regex).matcher(s);
-        matcher.find();
+        if (! matcher.find()) {
+            String msg = String.format(
+                "match failed: s=%s regex=%s", s, regex);
+            throw new AssertionError(msg);
+        }
         return matcher.group(group);
     }
 
@@ -171,21 +177,20 @@
 
     static int objectsInUse(final Process child,
                             final String childPid,
-                            final String className) {
-        final String regex =
-            "(?m)^ *[0-9]+: +([0-9]+) +[0-9]+ +\\Q"+className+"\\E(?:$| )";
-        final Callable<Integer> objectsInUse =
-            new Callable<Integer>() { public Integer call() {
-                Integer i = Integer.parseInt(
-                    match(commandOutputOf(jmap, "-histo:live", childPid),
-                          regex, 1));
-                if (i > 100)
-                    System.out.print(
-                        commandOutputOf(jmap,
-                                        "-dump:file=dump,format=b",
-                                        childPid));
-                return i;
-            }};
+                            final String classNameRegex) {
+        String regex =
+            "(?m)^ *[0-9]+: +([0-9]+) +[0-9]+ +"+classNameRegex+"(?:$| )";
+        Callable<Integer> objectsInUse = () -> {
+            int i = Integer.parseInt(
+                match(commandOutputOf(jmapPath, "-histo:live", childPid),
+                      regex, 1));
+            if (i > 100)
+                System.out.print(
+                    commandOutputOf(jmapPath,
+                                    "-dump:file=dump,format=b",
+                                    childPid));
+            return i;
+        };
         try { return rendezvousParent(child, objectsInUse); }
         catch (Throwable t) { unexpected(t); return -1; }
     }
@@ -196,26 +201,27 @@
             return;
 
         final String childClassName = Job.class.getName();
-        final String classToCheckForLeaks = Job.classToCheckForLeaks();
-        final String uniqueID =
-            String.valueOf(ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
+        final String classNameRegex = Job.classNameRegexToCheckForLeaks();
+        final String uniqueID = String.valueOf(
+            ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE));
 
-        final String[] jobCmd = {
-            java, "-Xmx8m", "-XX:+UsePerfData",
-            "-classpath", System.getProperty("test.class.path"),
-            childClassName, uniqueID
-        };
+        final ArrayList<String> jobCmd = new ArrayList<>();
+        Collections.addAll(
+            jobCmd, javaPath, "-Xmx8m", "-XX:+UsePerfData",
+            "-classpath", System.getProperty("test.class.path"));
+        Collections.addAll(jobCmd, Utils.getTestJavaOpts());
+        Collections.addAll(jobCmd, childClassName, uniqueID);
         final Process p = new ProcessBuilder(jobCmd).start();
         // Ensure subprocess jvm has started, so that jps can find it
         p.getInputStream().read();
         sendByte(p.getOutputStream());
 
         final String childPid =
-            match(commandOutputOf(jps, "-m"),
+            match(commandOutputOf(jpsPath, "-m"),
                   "(?m)^ *([0-9]+) +\\Q"+childClassName+"\\E *"+uniqueID+"$", 1);
 
-        final int n0 = objectsInUse(p, childPid, classToCheckForLeaks);
-        final int n1 = objectsInUse(p, childPid, classToCheckForLeaks);
+        final int n0 = objectsInUse(p, childPid, classNameRegex);
+        final int n1 = objectsInUse(p, childPid, classNameRegex);
         equal(p.waitFor(), 0);
         equal(p.exitValue(), 0);
         failed += p.exitValue();
@@ -226,7 +232,7 @@
         // implementation, and needing occasional adjustment.
         System.out.printf("%d -> %d%n", n0, n1);
         // Almost always n0 == n1
-        // Maximum jitter observed in practice is 10 -> 17
+        // Maximum jitter observed in practice is 7
         check(Math.abs(n1 - n0) < 10);
         check(n1 < 25);
         drainers.shutdown();
@@ -244,9 +250,9 @@
     // - in between calls to rendezvousChild, run code that may leak.
     //----------------------------------------------------------------
     public static class Job {
-        static String classToCheckForLeaks() {
+        static String classNameRegexToCheckForLeaks() {
             return
-                "java.util.concurrent.locks.AbstractQueuedSynchronizer$Node";
+                "\\Qjava.util.concurrent.locks.AbstractQueuedSynchronizer$\\E[A-Za-z]+";
         }
 
         public static void main(String[] args) throws Throwable {
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/CancelledLockLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -93,7 +93,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/LockOncePerThreadLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -94,7 +94,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/SimpleReentrantLockLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -95,7 +95,7 @@
                 long time = timer.getTime();
                 long tpi = time / ((long)iters * nthreads);
                 System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per lock");
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantLock/TimeoutLockLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -96,7 +96,7 @@
             barrier.await();
             if (print) {
                 long time = timer.getTime();
-                double secs = (double)(time) / 1000000000.0;
+                double secs = (double)time / 1000000000.0;
                 System.out.println("\t " + secs + "s run time");
             }
 
--- a/test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/locks/ReentrantReadWriteLock/MapLoops.java	Wed Sep 18 07:46:02 2019 +0200
@@ -91,8 +91,8 @@
             premove = Integer.parseInt(args[4]);
 
         // normalize probabilities wrt random number generator
-        removesPerMaxRandom = (int)(((double)premove/100.0 * 0x7FFFFFFFL));
-        insertsPerMaxRandom = (int)(((double)pinsert/100.0 * 0x7FFFFFFFL));
+        removesPerMaxRandom = (int)((double)premove/100.0 * 0x7FFFFFFFL);
+        insertsPerMaxRandom = (int)((double)pinsert/100.0 * 0x7FFFFFFFL);
 
         System.out.println("Using " + mapClass.getName());
 
@@ -125,7 +125,7 @@
             long time = timer.getTime();
             long tpo = time / (i * (long)nops);
             System.out.print(LoopHelpers.rightJustify(tpo) + " ns per op");
-            double secs = (double)(time) / 1000000000.0;
+            double secs = (double)time / 1000000000.0;
             System.out.println("\t " + secs + "s run time");
             map.clear();
         }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -39,7 +39,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
 
@@ -1286,19 +1286,31 @@
     /**
      * Tests scenario for
      * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw
+     * ant -Djsr166.tckTestClass=AbstractQueuedLongSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck
      */
-    public void testInterruptedFailingAcquire() throws InterruptedException {
-        final RuntimeException ex = new RuntimeException();
+    public void testInterruptedFailingAcquire() throws Throwable {
+        class PleaseThrow extends RuntimeException {}
+        final PleaseThrow ex = new PleaseThrow();
+        final AtomicBoolean thrown = new AtomicBoolean();
 
         // A synchronizer only offering a choice of failure modes
         class Sync extends AbstractQueuedLongSynchronizer {
-            boolean pleaseThrow;
+            volatile boolean pleaseThrow;
+            void maybeThrow() {
+                if (pleaseThrow) {
+                    // assert: tryAcquire methods can throw at most once
+                    if (! thrown.compareAndSet(false, true))
+                        throw new AssertionError();
+                    throw ex;
+                }
+            }
+
             @Override protected boolean tryAcquire(long ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return false;
             }
             @Override protected long tryAcquireShared(long ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return -1;
             }
             @Override protected boolean tryRelease(long ignored) {
@@ -1310,30 +1322,87 @@
         }
 
         final Sync s = new Sync();
+        final boolean acquireInterruptibly = randomBoolean();
+        final Action[] uninterruptibleAcquireActions = {
+            () -> s.acquire(1),
+            () -> s.acquireShared(1),
+        };
+        final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+        final Action[] interruptibleAcquireActions = {
+            () -> s.acquireInterruptibly(1),
+            () -> s.acquireSharedInterruptibly(1),
+            () -> s.tryAcquireNanos(1, nanosTimeout),
+            () -> s.tryAcquireSharedNanos(1, nanosTimeout),
+        };
+        final Action[] releaseActions = {
+            () -> s.release(1),
+            () -> s.releaseShared(1),
+        };
+        final Action acquireAction = acquireInterruptibly
+            ? chooseRandomly(interruptibleAcquireActions)
+            : chooseRandomly(uninterruptibleAcquireActions);
+        final Action releaseAction
+            = chooseRandomly(releaseActions);
 
+        // From os_posix.cpp:
+        //
+        // NOTE that since there is no "lock" around the interrupt and
+        // is_interrupted operations, there is the possibility that the
+        // interrupted flag (in osThread) will be "false" but that the
+        // low-level events will be in the signaled state. This is
+        // intentional. The effect of this is that Object.wait() and
+        // LockSupport.park() will appear to have a spurious wakeup, which
+        // is allowed and not harmful, and the possibility is so rare that
+        // it is not worth the added complexity to add yet another lock.
         final Thread thread = newStartedThread(new CheckedRunnable() {
-            public void realRun() {
+            public void realRun() throws Throwable {
                 try {
-                    if (ThreadLocalRandom.current().nextBoolean())
-                        s.acquire(1);
-                    else
-                        s.acquireShared(1);
+                    acquireAction.run();
                     shouldThrow();
-                } catch (Throwable t) {
-                    assertSame(ex, t);
-                    assertTrue(Thread.interrupted());
+                } catch (InterruptedException possible) {
+                    assertTrue(acquireInterruptibly);
+                    assertFalse(Thread.interrupted());
+                } catch (PleaseThrow possible) {
+                    awaitInterrupted();
                 }
             }});
-        waitForThreadToEnterWaitState(thread);
-        assertSame(thread, s.getFirstQueuedThread());
-        assertTrue(s.hasQueuedPredecessors());
-        assertTrue(s.hasQueuedThreads());
-        assertEquals(1, s.getQueueLength());
+        for (long startTime = 0L;; ) {
+            waitForThreadToEnterWaitState(thread);
+            if (s.getFirstQueuedThread() == thread
+                && s.hasQueuedPredecessors()
+                && s.hasQueuedThreads()
+                && s.getQueueLength() == 1
+                && s.hasContended())
+                break;
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for AQS state: "
+                     + "thread state=" + thread.getState()
+                     + ", queued threads=" + s.getQueuedThreads());
+            Thread.yield();
+        }
 
         s.pleaseThrow = true;
-        thread.interrupt();
-        s.release(1);
+        // release and interrupt, in random order
+        if (randomBoolean()) {
+            thread.interrupt();
+            releaseAction.run();
+        } else {
+            releaseAction.run();
+            thread.interrupt();
+        }
         awaitTermination(thread);
+
+        if (! acquireInterruptibly)
+            assertTrue(thrown.get());
+
+        assertNull(s.getFirstQueuedThread());
+        assertFalse(s.hasQueuedPredecessors());
+        assertFalse(s.hasQueuedThreads());
+        assertEquals(0, s.getQueueLength());
+        assertTrue(s.getQueuedThreads().isEmpty());
+        assertTrue(s.hasContended());
     }
 
 }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -40,7 +40,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject;
 
@@ -1337,19 +1337,31 @@
     /**
      * Tests scenario for
      * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw
+     * ant -Djsr166.tckTestClass=AbstractQueuedSynchronizerTest -Djsr166.methodFilter=testInterruptedFailingAcquire -Djsr166.runsPerTest=10000 tck
      */
-    public void testInterruptedFailingAcquire() throws InterruptedException {
-        final RuntimeException ex = new RuntimeException();
+    public void testInterruptedFailingAcquire() throws Throwable {
+        class PleaseThrow extends RuntimeException {}
+        final PleaseThrow ex = new PleaseThrow();
+        final AtomicBoolean thrown = new AtomicBoolean();
 
         // A synchronizer only offering a choice of failure modes
         class Sync extends AbstractQueuedSynchronizer {
-            boolean pleaseThrow;
+            volatile boolean pleaseThrow;
+            void maybeThrow() {
+                if (pleaseThrow) {
+                    // assert: tryAcquire methods can throw at most once
+                    if (! thrown.compareAndSet(false, true))
+                        throw new AssertionError();
+                    throw ex;
+                }
+            }
+
             @Override protected boolean tryAcquire(int ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return false;
             }
             @Override protected int tryAcquireShared(int ignored) {
-                if (pleaseThrow) throw ex;
+                maybeThrow();
                 return -1;
             }
             @Override protected boolean tryRelease(int ignored) {
@@ -1361,30 +1373,87 @@
         }
 
         final Sync s = new Sync();
+        final boolean acquireInterruptibly = randomBoolean();
+        final Action[] uninterruptibleAcquireActions = {
+            () -> s.acquire(1),
+            () -> s.acquireShared(1),
+        };
+        final long nanosTimeout = MILLISECONDS.toNanos(2 * LONG_DELAY_MS);
+        final Action[] interruptibleAcquireActions = {
+            () -> s.acquireInterruptibly(1),
+            () -> s.acquireSharedInterruptibly(1),
+            () -> s.tryAcquireNanos(1, nanosTimeout),
+            () -> s.tryAcquireSharedNanos(1, nanosTimeout),
+        };
+        final Action[] releaseActions = {
+            () -> s.release(1),
+            () -> s.releaseShared(1),
+        };
+        final Action acquireAction = acquireInterruptibly
+            ? chooseRandomly(interruptibleAcquireActions)
+            : chooseRandomly(uninterruptibleAcquireActions);
+        final Action releaseAction
+            = chooseRandomly(releaseActions);
 
+        // From os_posix.cpp:
+        //
+        // NOTE that since there is no "lock" around the interrupt and
+        // is_interrupted operations, there is the possibility that the
+        // interrupted flag (in osThread) will be "false" but that the
+        // low-level events will be in the signaled state. This is
+        // intentional. The effect of this is that Object.wait() and
+        // LockSupport.park() will appear to have a spurious wakeup, which
+        // is allowed and not harmful, and the possibility is so rare that
+        // it is not worth the added complexity to add yet another lock.
         final Thread thread = newStartedThread(new CheckedRunnable() {
-            public void realRun() {
+            public void realRun() throws Throwable {
                 try {
-                    if (ThreadLocalRandom.current().nextBoolean())
-                        s.acquire(1);
-                    else
-                        s.acquireShared(1);
+                    acquireAction.run();
                     shouldThrow();
-                } catch (Throwable t) {
-                    assertSame(ex, t);
-                    assertTrue(Thread.interrupted());
+                } catch (InterruptedException possible) {
+                    assertTrue(acquireInterruptibly);
+                    assertFalse(Thread.interrupted());
+                } catch (PleaseThrow possible) {
+                    awaitInterrupted();
                 }
             }});
-        waitForThreadToEnterWaitState(thread);
-        assertSame(thread, s.getFirstQueuedThread());
-        assertTrue(s.hasQueuedPredecessors());
-        assertTrue(s.hasQueuedThreads());
-        assertEquals(1, s.getQueueLength());
+        for (long startTime = 0L;; ) {
+            waitForThreadToEnterWaitState(thread);
+            if (s.getFirstQueuedThread() == thread
+                && s.hasQueuedPredecessors()
+                && s.hasQueuedThreads()
+                && s.getQueueLength() == 1
+                && s.hasContended())
+                break;
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for AQS state: "
+                     + "thread state=" + thread.getState()
+                     + ", queued threads=" + s.getQueuedThreads());
+            Thread.yield();
+        }
 
         s.pleaseThrow = true;
-        thread.interrupt();
-        s.release(1);
+        // release and interrupt, in random order
+        if (randomBoolean()) {
+            thread.interrupt();
+            releaseAction.run();
+        } else {
+            releaseAction.run();
+            thread.interrupt();
+        }
         awaitTermination(thread);
+
+        if (! acquireInterruptibly)
+            assertTrue(thrown.get());
+
+        assertNull(s.getFirstQueuedThread());
+        assertFalse(s.hasQueuedPredecessors());
+        assertFalse(s.hasQueuedThreads());
+        assertEquals(0, s.getQueueLength());
+        assertTrue(s.getQueuedThreads().isEmpty());
+        assertTrue(s.hasContended());
     }
 
 }
--- a/test/jdk/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ArrayBlockingQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -61,7 +61,7 @@
         class Implementation implements CollectionImplementation {
             public Class<?> klazz() { return ArrayBlockingQueue.class; }
             public Collection emptyCollection() {
-                boolean fair = ThreadLocalRandom.current().nextBoolean();
+                boolean fair = randomBoolean();
                 return populatedQueue(0, SIZE, 2 * SIZE, fair);
             }
             public Object makeElement(int i) { return i; }
@@ -367,7 +367,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -409,7 +409,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -431,21 +431,21 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -486,7 +486,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -539,29 +539,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/BlockingQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/BlockingQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -253,7 +253,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -274,7 +274,7 @@
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
 
         barrier.await();
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -296,7 +296,7 @@
             }});
 
         await(threadStarted);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -325,19 +325,19 @@
      */
     public void testTimedPollFromEmptyBlocksInterruptibly() {
         final BlockingQueue q = emptyCollection();
-        final CountDownLatch threadStarted = new CountDownLatch(1);
+        final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() {
-                threadStarted.countDown();
+                pleaseInterrupt.countDown();
                 try {
-                    q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
-        await(threadStarted);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        await(pleaseInterrupt);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -352,7 +352,7 @@
             public void realRun() {
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
--- a/test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ConcurrentLinkedDequeTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -940,7 +940,7 @@
     }
 
     void runAsync(Runnable r1, Runnable r2) {
-        boolean b = ThreadLocalRandom.current().nextBoolean();
+        boolean b = randomBoolean();
         CompletableFuture<Void> f1 = CompletableFuture.runAsync(b ? r1 : r2);
         CompletableFuture<Void> f2 = CompletableFuture.runAsync(b ? r2 : r1);
         f1.join();
@@ -1003,10 +1003,6 @@
         }
     }
 
-    <T> T chooseRandomly(T... choices) {
-        return choices[ThreadLocalRandom.current().nextInt(choices.length)];
-    }
-
     /**
      * Non-traversing Deque operations (that return null) are linearizable.
      * Don't return null when the deque is observably never empty.
--- a/test/jdk/java/util/concurrent/tck/CountDownLatchTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/CountDownLatchTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -36,6 +36,7 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -99,7 +100,7 @@
         assertEquals(2, l.getCount());
         l.countDown();
         assertEquals(1, l.getCount());
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         l.countDown();
         assertEquals(0, l.getCount());
         awaitTermination(t);
@@ -124,7 +125,7 @@
         assertEquals(2, l.getCount());
         l.countDown();
         assertEquals(1, l.getCount());
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         l.countDown();
         assertEquals(0, l.getCount());
         awaitTermination(t);
@@ -156,7 +157,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -165,29 +166,30 @@
      * timed await throws InterruptedException if interrupted before counted down
      */
     public void testTimedAwait_Interruptible() {
-        final CountDownLatch l = new CountDownLatch(1);
+        final int initialCount = ThreadLocalRandom.current().nextInt(1, 3);
+        final CountDownLatch l = new CountDownLatch(initialCount);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 Thread.currentThread().interrupt();
                 try {
-                    l.await(LONG_DELAY_MS, MILLISECONDS);
+                    l.await(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    l.await(LONG_DELAY_MS, MILLISECONDS);
+                    l.await(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
-                assertEquals(1, l.getCount());
+                assertEquals(initialCount, l.getCount());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -200,7 +202,11 @@
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 assertEquals(1, l.getCount());
+
+                long startTime = System.nanoTime();
                 assertFalse(l.await(timeoutMillis(), MILLISECONDS));
+                assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
+
                 assertEquals(1, l.getCount());
             }});
 
--- a/test/jdk/java/util/concurrent/tck/CyclicBarrierTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/CyclicBarrierTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -42,7 +42,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import junit.framework.Test;
@@ -323,34 +322,6 @@
     }
 
     /**
-     * All threads block while a barrier is broken.
-     */
-    public void testReset_Leakage() throws InterruptedException {
-        final CyclicBarrier c = new CyclicBarrier(2);
-        final AtomicBoolean done = new AtomicBoolean();
-        Thread t = newStartedThread(new CheckedRunnable() {
-            public void realRun() {
-                while (!done.get()) {
-                    try {
-                        while (c.isBroken())
-                            c.reset();
-
-                        c.await();
-                        shouldThrow();
-                    }
-                    catch (BrokenBarrierException | InterruptedException ok) {}
-                }}});
-
-        for (int i = 0; i < 4; i++) {
-            delay(timeoutMillis());
-            t.interrupt();
-        }
-        done.set(true);
-        t.interrupt();
-        awaitTermination(t);
-    }
-
-    /**
      * Reset of a non-broken barrier does not break barrier
      */
     public void testResetWithoutBreakage() throws Exception {
@@ -505,7 +476,7 @@
         final ExecutorService e = Executors.newFixedThreadPool(nTasks);
         final Runnable awaiter = () -> {
             try {
-                if (ThreadLocalRandom.current().nextBoolean())
+                if (randomBoolean())
                     barrier.await();
                 else
                     barrier.await(LONG_DELAY_MS, MILLISECONDS);
--- a/test/jdk/java/util/concurrent/tck/DelayQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/DelayQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -332,7 +332,7 @@
     }
 
     /**
-     * timed offer does not time out
+     * Queue is unbounded, so timed offer never times out
      */
     public void testTimedOffer() throws InterruptedException {
         final DelayQueue q = new DelayQueue();
@@ -384,7 +384,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -436,30 +436,27 @@
         final DelayQueue q = populatedQueue(SIZE);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(new PDelay(i),
                                  ((PDelay)q.poll(LONG_DELAY_MS, MILLISECONDS)));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/DoubleAccumulatorTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/DoubleAccumulatorTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -156,7 +156,7 @@
             = new DoubleAccumulator((x, y) -> x + y, 0.0);
         final int nThreads = ThreadLocalRandom.current().nextInt(1, 5);
         final Phaser phaser = new Phaser(nThreads + 1);
-        final int incs = 1_000_000;
+        final int incs = expensiveTests ? 1_000_000 : 100_000;
         final double total = nThreads * incs/2.0 * (incs - 1); // Gauss
         final Runnable task = () -> {
             phaser.arriveAndAwaitAdvance();
--- a/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java	Wed Sep 18 07:46:02 2019 +0200
@@ -38,7 +38,6 @@
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.ForkJoinTask;
 import java.util.concurrent.Future;
-import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.Stream;
 
 import junit.framework.Test;
@@ -81,7 +80,7 @@
             Thread currentThread = Thread.currentThread();
 
             Stream.of(systemClassLoader, null).forEach(cl -> {
-                if (ThreadLocalRandom.current().nextBoolean())
+                if (randomBoolean())
                     // should always be permitted, without effect
                     currentThread.setContextClassLoader(cl);
                 });
--- a/test/jdk/java/util/concurrent/tck/ForkJoinTask8Test.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinTask8Test.java	Wed Sep 18 07:46:02 2019 +0200
@@ -559,6 +559,8 @@
                 AsyncFib f = new AsyncFib(8);
                 assertSame(f, f.fork());
                 helpQuiesce();
+                while (!f.isDone()) // wait out race
+                    ;
                 assertEquals(0, getQueuedTaskCount());
                 f.checkCompletedNormally();
             }};
--- a/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ForkJoinTaskTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -526,6 +526,8 @@
                 AsyncFib f = new AsyncFib(8);
                 assertSame(f, f.fork());
                 helpQuiesce();
+                while (!f.isDone()) // wait out race
+                    ;
                 assertEquals(21, f.number);
                 assertEquals(0, getQueuedTaskCount());
                 checkCompletedNormally(f);
--- a/test/jdk/java/util/concurrent/tck/FutureTaskTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/FutureTaskTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -747,7 +747,7 @@
     /**
      * get is interruptible
      */
-    public void testGet_interruptible() {
+    public void testGet_Interruptible() {
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         final FutureTask task = new FutureTask(new NoOpCallable());
         Thread t = newStartedThread(new CheckedRunnable() {
@@ -776,27 +776,28 @@
     /**
      * timed get is interruptible
      */
-    public void testTimedGet_interruptible() {
+    public void testTimedGet_Interruptible() {
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         final FutureTask task = new FutureTask(new NoOpCallable());
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws Exception {
                 Thread.currentThread().interrupt();
                 try {
-                    task.get(2*LONG_DELAY_MS, MILLISECONDS);
+                    task.get(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    task.get(2*LONG_DELAY_MS, MILLISECONDS);
+                    task.get(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkNotDone(task);
--- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java	Wed Sep 18 07:46:02 2019 +0200
@@ -311,12 +311,13 @@
     static volatile TestCase currentTestCase;
     // static volatile int currentRun = 0;
     static {
-        Runnable checkForWedgedTest = new Runnable() { public void run() {
+        Runnable wedgedTestDetector = new Runnable() { public void run() {
             // Avoid spurious reports with enormous runsPerTest.
             // A single test case run should never take more than 1 second.
             // But let's cap it at the high end too ...
-            final int timeoutMinutes =
-                Math.min(15, Math.max(runsPerTest / 60, 1));
+            final int timeoutMinutesMin = Math.max(runsPerTest / 60, 1)
+                * Math.max((int) delayFactor, 1);
+            final int timeoutMinutes = Math.min(15, timeoutMinutesMin);
             for (TestCase lastTestCase = currentTestCase;;) {
                 try { MINUTES.sleep(timeoutMinutes); }
                 catch (InterruptedException unexpected) { break; }
@@ -336,7 +337,7 @@
                 }
                 lastTestCase = currentTestCase;
             }}};
-        Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest");
+        Thread thread = new Thread(wedgedTestDetector, "WedgedTestDetector");
         thread.setDaemon(true);
         thread.start();
     }
@@ -380,7 +381,7 @@
             // Never report first run of any test; treat it as a
             // warmup run, notably to trigger all needed classloading,
             if (i > 0)
-                System.out.printf("%n%s: %d%n", toString(), elapsedMillis);
+                System.out.printf("%s: %d%n", toString(), elapsedMillis);
         }
     }
 
@@ -683,6 +684,12 @@
     public static long MEDIUM_DELAY_MS;
     public static long LONG_DELAY_MS;
 
+    /**
+     * A delay significantly longer than LONG_DELAY_MS.
+     * Use this in a thread that is waited for via awaitTermination(Thread).
+     */
+    public static long LONGER_DELAY_MS;
+
     private static final long RANDOM_TIMEOUT;
     private static final long RANDOM_EXPIRED_TIMEOUT;
     private static final TimeUnit RANDOM_TIMEUNIT;
@@ -711,6 +718,20 @@
     static TimeUnit randomTimeUnit() { return RANDOM_TIMEUNIT; }
 
     /**
+     * Returns a random boolean; a "coin flip".
+     */
+    static boolean randomBoolean() {
+        return ThreadLocalRandom.current().nextBoolean();
+    }
+
+    /**
+     * Returns a random element from given choices.
+     */
+    <T> T chooseRandomly(T... choices) {
+        return choices[ThreadLocalRandom.current().nextInt(choices.length)];
+    }
+
+    /**
      * Returns the shortest timed delay. This can be scaled up for
      * slow machines using the jsr166.delay.factor system property,
      * or via jtreg's -timeoutFactor: flag.
@@ -728,6 +749,7 @@
         SMALL_DELAY_MS  = SHORT_DELAY_MS * 5;
         MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10;
         LONG_DELAY_MS   = SHORT_DELAY_MS * 200;
+        LONGER_DELAY_MS = 2 * LONG_DELAY_MS;
     }
 
     private static final long TIMEOUT_DELAY_MS
@@ -766,8 +788,8 @@
      */
     public void threadRecordFailure(Throwable t) {
         System.err.println(t);
-        dumpTestThreads();
-        threadFailure.compareAndSet(null, t);
+        if (threadFailure.compareAndSet(null, t))
+            dumpTestThreads();
     }
 
     public void setUp() {
@@ -1088,6 +1110,39 @@
         }
     }
 
+    /** Returns true if thread info might be useful in a thread dump. */
+    static boolean threadOfInterest(ThreadInfo info) {
+        final String name = info.getThreadName();
+        String lockName;
+        if (name == null)
+            return true;
+        if (name.equals("Signal Dispatcher")
+            || name.equals("WedgedTestDetector"))
+            return false;
+        if (name.equals("Reference Handler")) {
+            // Reference Handler stacktrace changed in JDK-8156500
+            StackTraceElement[] stackTrace; String methodName;
+            if ((stackTrace = info.getStackTrace()) != null
+                && stackTrace.length > 0
+                && (methodName = stackTrace[0].getMethodName()) != null
+                && methodName.equals("waitForReferencePendingList"))
+                return false;
+            // jdk8 Reference Handler stacktrace
+            if ((lockName = info.getLockName()) != null
+                && lockName.startsWith("java.lang.ref"))
+                return false;
+        }
+        if ((name.equals("Finalizer") || name.equals("Common-Cleaner"))
+            && (lockName = info.getLockName()) != null
+            && lockName.startsWith("java.lang.ref"))
+            return false;
+        if (name.startsWith("ForkJoinPool.commonPool-worker")
+            && (lockName = info.getLockName()) != null
+            && lockName.startsWith("java.util.concurrent.ForkJoinPool"))
+            return false;
+        return true;
+    }
+
     /**
      * A debugging tool to print stack traces of most threads, as jstack does.
      * Uninteresting threads are filtered out.
@@ -1104,23 +1159,9 @@
 
         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
         System.err.println("------ stacktrace dump start ------");
-        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
-            final String name = info.getThreadName();
-            String lockName;
-            if ("Signal Dispatcher".equals(name))
-                continue;
-            if ("Reference Handler".equals(name)
-                && (lockName = info.getLockName()) != null
-                && lockName.startsWith("java.lang.ref.Reference$Lock"))
-                continue;
-            if ("Finalizer".equals(name)
-                && (lockName = info.getLockName()) != null
-                && lockName.startsWith("java.lang.ref.ReferenceQueue$Lock"))
-                continue;
-            if ("checkForWedgedTest".equals(name))
-                continue;
-            System.err.print(info);
-        }
+        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true))
+            if (threadOfInterest(info))
+                System.err.print(info);
         System.err.println("------ stacktrace dump end ------");
 
         if (sm != null) System.setSecurityManager(sm);
@@ -1393,6 +1434,20 @@
     }
 
     /**
+     * Spin-waits up to LONG_DELAY_MS milliseconds for the current thread to
+     * be interrupted.  Clears the interrupt status before returning.
+     */
+    void awaitInterrupted() {
+        for (long startTime = 0L; !Thread.interrupted(); ) {
+            if (startTime == 0L)
+                startTime = System.nanoTime();
+            else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+                fail("timed out waiting for thread interrupt");
+            Thread.yield();
+        }
+    }
+
+    /**
      * Returns the number of milliseconds since time given by
      * startNanoTime, which must have been previously returned from a
      * call to {@link System#nanoTime()}.
@@ -1401,19 +1456,6 @@
         return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
     }
 
-//     void assertTerminatesPromptly(long timeoutMillis, Runnable r) {
-//         long startTime = System.nanoTime();
-//         try {
-//             r.run();
-//         } catch (Throwable fail) { threadUnexpectedException(fail); }
-//         if (millisElapsedSince(startTime) > timeoutMillis/2)
-//             throw new AssertionError("did not return promptly");
-//     }
-
-//     void assertTerminatesPromptly(Runnable r) {
-//         assertTerminatesPromptly(LONG_DELAY_MS/2, r);
-//     }
-
     /**
      * Checks that timed f.get() returns the expected value, and does not
      * wait for the timeout to elapse before returning.
@@ -1448,15 +1490,21 @@
      * to terminate (using {@link Thread#join(long)}), else interrupts
      * the thread (in the hope that it may terminate later) and fails.
      */
-    void awaitTermination(Thread t, long timeoutMillis) {
+    void awaitTermination(Thread thread, long timeoutMillis) {
         try {
-            t.join(timeoutMillis);
+            thread.join(timeoutMillis);
         } catch (InterruptedException fail) {
             threadUnexpectedException(fail);
-        } finally {
-            if (t.getState() != Thread.State.TERMINATED) {
-                t.interrupt();
-                threadFail("timed out waiting for thread to terminate");
+        }
+        if (thread.getState() != Thread.State.TERMINATED) {
+            String detail = String.format(
+                    "timed out waiting for thread to terminate, thread=%s, state=%s" ,
+                    thread, thread.getState());
+            try {
+                threadFail(detail);
+            } finally {
+                // Interrupt thread __after__ having reported its stack trace
+                thread.interrupt();
             }
         }
     }
--- a/test/jdk/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LinkedBlockingDequeTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -631,7 +631,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -673,7 +673,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -690,26 +690,27 @@
                 q.put(new Object());
                 q.put(new Object());
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -750,7 +751,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -802,29 +803,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
@@ -883,7 +881,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -918,7 +916,7 @@
         assertEquals(capacity - 1, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -935,26 +933,27 @@
                 q.putFirst(new Object());
                 q.putFirst(new Object());
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offerFirst(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offerFirst(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerFirst(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offerFirst(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerFirst(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -986,7 +985,7 @@
             }});
 
         await(threadStarted);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1027,7 +1026,7 @@
             }});
 
         await(threadStarted);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1077,7 +1076,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1118,29 +1117,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, q.pollFirst(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollFirst(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollFirst(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1164,7 +1160,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.pollFirst(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollFirst(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
 
@@ -1174,6 +1170,7 @@
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
+
                 assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
@@ -1182,7 +1179,7 @@
         assertTrue(q.offerFirst(zero, LONG_DELAY_MS, MILLISECONDS));
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
         barrier.await();
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1240,7 +1237,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -1282,7 +1279,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -1299,24 +1296,25 @@
                 q.putLast(new Object());
                 q.putLast(new Object());
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offerLast(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offerLast(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerLast(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offerLast(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offerLast(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1358,7 +1356,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -1399,30 +1397,27 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(SIZE - i - 1,
                                  q.pollLast(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.pollLast(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollLast(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.pollLast(LONG_DELAY_MS, MILLISECONDS);
+                    q.pollLast(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
@@ -1447,7 +1442,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -1468,7 +1463,7 @@
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
 
         barrier.await();
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
--- a/test/jdk/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LinkedBlockingQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -318,7 +318,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(SIZE, q.size());
@@ -360,7 +360,7 @@
         assertEquals(0, q.take());
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -376,28 +376,28 @@
             public void realRun() throws InterruptedException {
                 q.put(new Object());
                 q.put(new Object());
+                long startTime = System.nanoTime();
 
-                long startTime = System.nanoTime();
                 assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -438,7 +438,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -490,29 +490,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LinkedTransferQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -254,7 +254,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -308,29 +308,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
@@ -344,16 +341,14 @@
         final BlockingQueue<Integer> q = populatedQueue(SIZE);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 Thread.currentThread().interrupt();
                 for (int i = 0; i < SIZE; ++i)
-                    assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
+                    assertEquals(i, (int) q.poll(randomTimeout(), randomTimeUnit()));
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         awaitTermination(t);
@@ -982,25 +977,23 @@
 
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 Thread.currentThread().interrupt();
                 try {
-                    q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
+                    q.tryTransfer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.tryTransfer(new Object(), LONG_DELAY_MS, MILLISECONDS);
+                    q.tryTransfer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         checkEmpty(q);
--- a/test/jdk/java/util/concurrent/tck/LongAccumulatorTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/LongAccumulatorTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -150,7 +150,7 @@
             = new LongAccumulator((x, y) -> x + y, 0L);
         final int nThreads = ThreadLocalRandom.current().nextInt(1, 5);
         final Phaser phaser = new Phaser(nThreads + 1);
-        final int incs = 1_000_000;
+        final int incs = expensiveTests ? 1_000_000 : 100_000;
         final long total = nThreads * incs/2L * (incs - 1); // Gauss
         final Runnable task = () -> {
             phaser.arriveAndAwaitAdvance();
--- a/test/jdk/java/util/concurrent/tck/MapTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/MapTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -122,6 +122,7 @@
      */
     public void testBug8186171() {
         if (!impl.supportsSetValue()) return;
+        if (!atLeastJava10()) return; // jdk9 is no longer maintained
         final ThreadLocalRandom rnd = ThreadLocalRandom.current();
         final boolean permitsNullValues = impl.permitsNullValues();
         final Object v1 = (permitsNullValues && rnd.nextBoolean())
--- a/test/jdk/java/util/concurrent/tck/PhaserTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/PhaserTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -480,7 +480,7 @@
     /**
      * awaitAdvanceInterruptibly blocks interruptibly
      */
-    public void testAwaitAdvanceInterruptibly_interruptible() throws InterruptedException {
+    public void testAwaitAdvanceInterruptibly_Interruptible() throws InterruptedException {
         final Phaser phaser = new Phaser(1);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(2);
 
@@ -505,14 +505,14 @@
             public void realRun() throws TimeoutException {
                 Thread.currentThread().interrupt();
                 try {
-                    phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS);
+                    phaser.awaitAdvanceInterruptibly(0, randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    phaser.awaitAdvanceInterruptibly(0, 2*LONG_DELAY_MS, MILLISECONDS);
+                    phaser.awaitAdvanceInterruptibly(0, LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -520,8 +520,8 @@
 
         await(pleaseInterrupt);
         assertState(phaser, 0, 1, 1);
-        assertThreadBlocks(t1, Thread.State.WAITING);
-        assertThreadBlocks(t2, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t1, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t2, Thread.State.TIMED_WAITING);
         t1.interrupt();
         t2.interrupt();
         awaitTermination(t1);
--- a/test/jdk/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/PriorityBlockingQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -346,7 +346,7 @@
     }
 
     /**
-     * timed offer does not time out
+     * Queue is unbounded, so timed offer never times out
      */
     public void testTimedOffer() {
         final PriorityBlockingQueue q = new PriorityBlockingQueue(2);
@@ -397,7 +397,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -449,29 +449,26 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                long startTime = System.nanoTime();
                 for (int i = 0; i < SIZE; i++)
                     assertEquals(i, (int) q.poll(LONG_DELAY_MS, MILLISECONDS));
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
-
-                assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
--- a/test/jdk/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ScheduledExecutorSubclassTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -707,7 +707,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
--- a/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ScheduledExecutorTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -666,7 +666,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
--- a/test/jdk/java/util/concurrent/tck/SemaphoreTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/SemaphoreTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -38,7 +38,6 @@
 import java.util.Collection;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Semaphore;
-import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -220,24 +219,22 @@
     /**
      * timed tryAcquire times out
      */
-    public void testTryAcquire_timeout() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+    public void testTryAcquire_timeout() throws InterruptedException {
+        final boolean fair = randomBoolean();
         final Semaphore s = new Semaphore(0, fair);
         final long startTime = System.nanoTime();
-        try { assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS)); }
-        catch (InterruptedException e) { threadUnexpectedException(e); }
+        assertFalse(s.tryAcquire(timeoutMillis(), MILLISECONDS));
         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
     }
 
     /**
      * timed tryAcquire(N) times out
      */
-    public void testTryAcquireN_timeout() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+    public void testTryAcquireN_timeout() throws InterruptedException {
+        final boolean fair = randomBoolean();
         final Semaphore s = new Semaphore(2, fair);
         final long startTime = System.nanoTime();
-        try { assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS)); }
-        catch (InterruptedException e) { threadUnexpectedException(e); }
+        assertFalse(s.tryAcquire(3, timeoutMillis(), MILLISECONDS));
         assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
     }
 
--- a/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/SynchronousQueueTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -45,7 +45,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
@@ -166,7 +165,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -207,7 +206,7 @@
         catch (InterruptedException e) { threadUnexpectedException(e); }
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.WAITING);
         t.interrupt();
         awaitTermination(t);
         assertEquals(0, q.remainingCapacity());
@@ -217,32 +216,33 @@
      * timed offer times out if elements not taken
      */
     public void testTimedOffer() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+        final boolean fair = randomBoolean();
         final SynchronousQueue q = new SynchronousQueue(fair);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 long startTime = System.nanoTime();
+
                 assertFalse(q.offer(new Object(), timeoutMillis(), MILLISECONDS));
                 assertTrue(millisElapsedSince(startTime) >= timeoutMillis());
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    q.offer(new Object(), 2 * LONG_DELAY_MS, MILLISECONDS);
+                    q.offer(new Object(), LONGER_DELAY_MS, MILLISECONDS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -272,7 +272,7 @@
      * timed poll with nonzero timeout times out if no active putter
      */
     public void testTimedPoll() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+        final boolean fair = randomBoolean();
         final SynchronousQueue q = new SynchronousQueue(fair);
         final long startTime = System.nanoTime();
         try { assertNull(q.poll(timeoutMillis(), MILLISECONDS)); }
@@ -285,7 +285,7 @@
      * after offer succeeds; on interruption throws
      */
     public void testTimedPollWithOffer() {
-        final boolean fair = ThreadLocalRandom.current().nextBoolean();
+        final boolean fair = randomBoolean();
         final SynchronousQueue q = new SynchronousQueue(fair);
         final CountDownLatch pleaseOffer = new CountDownLatch(1);
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
@@ -301,7 +301,7 @@
 
                 Thread.currentThread().interrupt();
                 try {
-                    q.poll(LONG_DELAY_MS, MILLISECONDS);
+                    q.poll(randomTimeout(), randomTimeUnit());
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
@@ -323,7 +323,7 @@
         assertTrue(millisElapsedSince(startTime) < LONG_DELAY_MS);
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
--- a/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorSubclassTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -796,7 +796,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
@@ -1669,7 +1669,7 @@
             l.add(latchAwaitingStringTask(latch));
             l.add(null);
             try {
-                e.invokeAny(l, randomTimeout(), MILLISECONDS);
+                e.invokeAny(l, randomTimeout(), randomTimeUnit());
                 shouldThrow();
             } catch (NullPointerException success) {}
             latch.countDown();
--- a/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/ThreadPoolExecutorTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -699,7 +699,7 @@
         Runnable waiter = new CheckedRunnable() { public void realRun() {
             threadsStarted.countDown();
             try {
-                MILLISECONDS.sleep(2 * LONG_DELAY_MS);
+                MILLISECONDS.sleep(LONGER_DELAY_MS);
             } catch (InterruptedException success) {}
             ran.getAndIncrement();
         }};
--- a/test/jdk/java/util/concurrent/tck/TimeUnitTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/concurrent/tck/TimeUnitTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -56,243 +56,56 @@
         return new TestSuite(TimeUnitTest.class);
     }
 
-    // (loops to 88888 check increments at all time divisions.)
-
-    /**
-     * convert correctly converts sample values across the units
-     */
-    public void testConvert() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*60*60*24,
-                         SECONDS.convert(t, DAYS));
-            assertEquals(t*60*60,
-                         SECONDS.convert(t, HOURS));
-            assertEquals(t*60,
-                         SECONDS.convert(t, MINUTES));
-            assertEquals(t,
-                         SECONDS.convert(t, SECONDS));
-            assertEquals(t,
-                         SECONDS.convert(1000L*t, MILLISECONDS));
-            assertEquals(t,
-                         SECONDS.convert(1000000L*t, MICROSECONDS));
-            assertEquals(t,
-                         SECONDS.convert(1000000000L*t, NANOSECONDS));
-
-            assertEquals(1000L*t*60*60*24,
-                         MILLISECONDS.convert(t, DAYS));
-            assertEquals(1000L*t*60*60,
-                         MILLISECONDS.convert(t, HOURS));
-            assertEquals(1000L*t*60,
-                         MILLISECONDS.convert(t, MINUTES));
-            assertEquals(1000L*t,
-                         MILLISECONDS.convert(t, SECONDS));
-            assertEquals(t,
-                         MILLISECONDS.convert(t, MILLISECONDS));
-            assertEquals(t,
-                         MILLISECONDS.convert(1000L*t, MICROSECONDS));
-            assertEquals(t,
-                         MILLISECONDS.convert(1000000L*t, NANOSECONDS));
-
-            assertEquals(1000000L*t*60*60*24,
-                         MICROSECONDS.convert(t, DAYS));
-            assertEquals(1000000L*t*60*60,
-                         MICROSECONDS.convert(t, HOURS));
-            assertEquals(1000000L*t*60,
-                         MICROSECONDS.convert(t, MINUTES));
-            assertEquals(1000000L*t,
-                         MICROSECONDS.convert(t, SECONDS));
-            assertEquals(1000L*t,
-                         MICROSECONDS.convert(t, MILLISECONDS));
-            assertEquals(t,
-                         MICROSECONDS.convert(t, MICROSECONDS));
-            assertEquals(t,
-                         MICROSECONDS.convert(1000L*t, NANOSECONDS));
-
-            assertEquals(1000000000L*t*60*60*24,
-                         NANOSECONDS.convert(t, DAYS));
-            assertEquals(1000000000L*t*60*60,
-                         NANOSECONDS.convert(t, HOURS));
-            assertEquals(1000000000L*t*60,
-                         NANOSECONDS.convert(t, MINUTES));
-            assertEquals(1000000000L*t,
-                         NANOSECONDS.convert(t, SECONDS));
-            assertEquals(1000000L*t,
-                         NANOSECONDS.convert(t, MILLISECONDS));
-            assertEquals(1000L*t,
-                         NANOSECONDS.convert(t, MICROSECONDS));
-            assertEquals(t,
-                         NANOSECONDS.convert(t, NANOSECONDS));
+    void testConversion(TimeUnit x, TimeUnit y, long n, long expected) {
+        assertEquals(expected, x.convert(n, y));
+        switch (x) {
+        case NANOSECONDS:  assertEquals(expected, y.toNanos(n));   break;
+        case MICROSECONDS: assertEquals(expected, y.toMicros(n));  break;
+        case MILLISECONDS: assertEquals(expected, y.toMillis(n));  break;
+        case SECONDS:      assertEquals(expected, y.toSeconds(n)); break;
+        case MINUTES:      assertEquals(expected, y.toMinutes(n)); break;
+        case HOURS:        assertEquals(expected, y.toHours(n));   break;
+        case DAYS:         assertEquals(expected, y.toDays(n));    break;
+        default: throw new AssertionError();
         }
 
-        for (TimeUnit x : TimeUnit.values()) {
-            long[] zs = {
-                0, 1, -1,
-                Integer.MAX_VALUE, Integer.MIN_VALUE,
-                Long.MAX_VALUE, Long.MIN_VALUE,
-            };
-            for (long z : zs) assertEquals(z, x.convert(z, x));
-        }
+        if (n > 0) testConversion(x, y, -n, -expected);
     }
 
-    /**
-     * toNanos correctly converts sample values in different units to
-     * nanoseconds
-     */
-    public void testToNanos() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*1000000000L*60*60*24,
-                         DAYS.toNanos(t));
-            assertEquals(t*1000000000L*60*60,
-                         HOURS.toNanos(t));
-            assertEquals(t*1000000000L*60,
-                         MINUTES.toNanos(t));
-            assertEquals(1000000000L*t,
-                         SECONDS.toNanos(t));
-            assertEquals(1000000L*t,
-                         MILLISECONDS.toNanos(t));
-            assertEquals(1000L*t,
-                         MICROSECONDS.toNanos(t));
-            assertEquals(t,
-                         NANOSECONDS.toNanos(t));
+    void testConversion(TimeUnit x, TimeUnit y) {
+        long ratio = x.toNanos(1)/y.toNanos(1);
+        assertTrue(ratio > 0);
+        long[] ns = { 0, 1, 2, Long.MAX_VALUE/ratio, Long.MIN_VALUE/ratio };
+        for (long n : ns) {
+            testConversion(y, x, n, n * ratio);
+            long[] ks = { n * ratio, n * ratio + 1, n * ratio - 1 };
+            for (long k : ks) {
+                testConversion(x, y, k, k / ratio);
+            }
         }
     }
 
     /**
-     * toMicros correctly converts sample values in different units to
-     * microseconds
-     */
-    public void testToMicros() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*1000000L*60*60*24,
-                         DAYS.toMicros(t));
-            assertEquals(t*1000000L*60*60,
-                         HOURS.toMicros(t));
-            assertEquals(t*1000000L*60,
-                         MINUTES.toMicros(t));
-            assertEquals(1000000L*t,
-                         SECONDS.toMicros(t));
-            assertEquals(1000L*t,
-                         MILLISECONDS.toMicros(t));
-            assertEquals(t,
-                         MICROSECONDS.toMicros(t));
-            assertEquals(t,
-                         NANOSECONDS.toMicros(t*1000L));
-        }
-    }
-
-    /**
-     * toMillis correctly converts sample values in different units to
-     * milliseconds
+     * Conversion methods correctly convert sample values
      */
-    public void testToMillis() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*1000L*60*60*24,
-                         DAYS.toMillis(t));
-            assertEquals(t*1000L*60*60,
-                         HOURS.toMillis(t));
-            assertEquals(t*1000L*60,
-                         MINUTES.toMillis(t));
-            assertEquals(1000L*t,
-                         SECONDS.toMillis(t));
-            assertEquals(t,
-                         MILLISECONDS.toMillis(t));
-            assertEquals(t,
-                         MICROSECONDS.toMillis(t*1000L));
-            assertEquals(t,
-                         NANOSECONDS.toMillis(t*1000000L));
-        }
-    }
-
-    /**
-     * toSeconds correctly converts sample values in different units to
-     * seconds
-     */
-    public void testToSeconds() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*60*60*24,
-                         DAYS.toSeconds(t));
-            assertEquals(t*60*60,
-                         HOURS.toSeconds(t));
-            assertEquals(t*60,
-                         MINUTES.toSeconds(t));
-            assertEquals(t,
-                         SECONDS.toSeconds(t));
-            assertEquals(t,
-                         MILLISECONDS.toSeconds(t*1000L));
-            assertEquals(t,
-                         MICROSECONDS.toSeconds(t*1000000L));
-            assertEquals(t,
-                         NANOSECONDS.toSeconds(t*1000000000L));
-        }
-    }
+    public void testConversions() {
+        // Sanity check
+        assertEquals(1, NANOSECONDS.toNanos(1));
+        assertEquals(1000L * NANOSECONDS.toNanos(1), MICROSECONDS.toNanos(1));
+        assertEquals(1000L * MICROSECONDS.toNanos(1), MILLISECONDS.toNanos(1));
+        assertEquals(1000L * MILLISECONDS.toNanos(1), SECONDS.toNanos(1));
+        assertEquals(60L * SECONDS.toNanos(1), MINUTES.toNanos(1));
+        assertEquals(60L * MINUTES.toNanos(1), HOURS.toNanos(1));
+        assertEquals(24L * HOURS.toNanos(1), DAYS.toNanos(1));
 
-    /**
-     * toMinutes correctly converts sample values in different units to
-     * minutes
-     */
-    public void testToMinutes() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*60*24,
-                         DAYS.toMinutes(t));
-            assertEquals(t*60,
-                         HOURS.toMinutes(t));
-            assertEquals(t,
-                         MINUTES.toMinutes(t));
-            assertEquals(t,
-                         SECONDS.toMinutes(t*60));
-            assertEquals(t,
-                         MILLISECONDS.toMinutes(t*1000L*60));
-            assertEquals(t,
-                         MICROSECONDS.toMinutes(t*1000000L*60));
-            assertEquals(t,
-                         NANOSECONDS.toMinutes(t*1000000000L*60));
+        for (TimeUnit x : TimeUnit.values()) {
+            assertEquals(x.toNanos(1), NANOSECONDS.convert(1, x));
         }
-    }
 
-    /**
-     * toHours correctly converts sample values in different units to
-     * hours
-     */
-    public void testToHours() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t*24,
-                         DAYS.toHours(t));
-            assertEquals(t,
-                         HOURS.toHours(t));
-            assertEquals(t,
-                         MINUTES.toHours(t*60));
-            assertEquals(t,
-                         SECONDS.toHours(t*60*60));
-            assertEquals(t,
-                         MILLISECONDS.toHours(t*1000L*60*60));
-            assertEquals(t,
-                         MICROSECONDS.toHours(t*1000000L*60*60));
-            assertEquals(t,
-                         NANOSECONDS.toHours(t*1000000000L*60*60));
-        }
-    }
-
-    /**
-     * toDays correctly converts sample values in different units to
-     * days
-     */
-    public void testToDays() {
-        for (long t = 0; t < 88888; ++t) {
-            assertEquals(t,
-                         DAYS.toDays(t));
-            assertEquals(t,
-                         HOURS.toDays(t*24));
-            assertEquals(t,
-                         MINUTES.toDays(t*60*24));
-            assertEquals(t,
-                         SECONDS.toDays(t*60*60*24));
-            assertEquals(t,
-                         MILLISECONDS.toDays(t*1000L*60*60*24));
-            assertEquals(t,
-                         MICROSECONDS.toDays(t*1000000L*60*60*24));
-            assertEquals(t,
-                         NANOSECONDS.toDays(t*1000000000L*60*60*24));
-        }
+        for (TimeUnit x : TimeUnit.values())
+            for (TimeUnit y : TimeUnit.values())
+                if (x.toNanos(1) >= y.toNanos(1))
+                    testConversion(x, y);
     }
 
     /**
@@ -494,14 +307,21 @@
      * toString returns name of unit
      */
     public void testToString() {
+        assertEquals("NANOSECONDS", NANOSECONDS.toString());
+        assertEquals("MICROSECONDS", MICROSECONDS.toString());
+        assertEquals("MILLISECONDS", MILLISECONDS.toString());
         assertEquals("SECONDS", SECONDS.toString());
+        assertEquals("MINUTES", MINUTES.toString());
+        assertEquals("HOURS", HOURS.toString());
+        assertEquals("DAYS", DAYS.toString());
     }
 
     /**
      * name returns name of unit
      */
     public void testName() {
-        assertEquals("SECONDS", SECONDS.name());
+        for (TimeUnit x : TimeUnit.values())
+            assertEquals(x.toString(), x.name());
     }
 
     /**
@@ -512,10 +332,8 @@
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 Object o = new Object();
-                TimeUnit tu = MILLISECONDS;
-
                 try {
-                    tu.timedWait(o, LONG_DELAY_MS);
+                    MILLISECONDS.timedWait(o, LONGER_DELAY_MS);
                     threadShouldThrow();
                 } catch (IllegalMonitorStateException success) {}
             }});
@@ -531,12 +349,11 @@
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
                 Object o = new Object();
-                TimeUnit tu = MILLISECONDS;
 
                 Thread.currentThread().interrupt();
                 try {
                     synchronized (o) {
-                        tu.timedWait(o, LONG_DELAY_MS);
+                        MILLISECONDS.timedWait(o, LONGER_DELAY_MS);
                     }
                     shouldThrow();
                 } catch (InterruptedException success) {}
@@ -545,7 +362,7 @@
                 pleaseInterrupt.countDown();
                 try {
                     synchronized (o) {
-                        tu.timedWait(o, LONG_DELAY_MS);
+                        MILLISECONDS.timedWait(o, LONGER_DELAY_MS);
                     }
                     shouldThrow();
                 } catch (InterruptedException success) {}
@@ -553,7 +370,7 @@
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
@@ -565,28 +382,27 @@
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         final Thread s = newStartedThread(new CheckedInterruptedRunnable() {
             public void realRun() throws InterruptedException {
-                Thread.sleep(LONG_DELAY_MS);
+                Thread.sleep(LONGER_DELAY_MS);
             }});
         final Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                TimeUnit tu = MILLISECONDS;
                 Thread.currentThread().interrupt();
                 try {
-                    tu.timedJoin(s, LONG_DELAY_MS);
+                    MILLISECONDS.timedJoin(s, LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    tu.timedJoin(s, LONG_DELAY_MS);
+                    MILLISECONDS.timedJoin(s, LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
         s.interrupt();
@@ -594,35 +410,46 @@
     }
 
     /**
-     * timedSleep throws InterruptedException when interrupted
+     * timeUnit.sleep throws InterruptedException when interrupted
      */
     public void testTimedSleep_Interruptible() {
         final CountDownLatch pleaseInterrupt = new CountDownLatch(1);
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() throws InterruptedException {
-                TimeUnit tu = MILLISECONDS;
                 Thread.currentThread().interrupt();
                 try {
-                    tu.sleep(LONG_DELAY_MS);
+                    MILLISECONDS.sleep(LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
 
                 pleaseInterrupt.countDown();
                 try {
-                    tu.sleep(LONG_DELAY_MS);
+                    MILLISECONDS.sleep(LONGER_DELAY_MS);
                     shouldThrow();
                 } catch (InterruptedException success) {}
                 assertFalse(Thread.interrupted());
             }});
 
         await(pleaseInterrupt);
-        assertThreadBlocks(t, Thread.State.TIMED_WAITING);
+        if (randomBoolean()) assertThreadBlocks(t, Thread.State.TIMED_WAITING);
         t.interrupt();
         awaitTermination(t);
     }
 
     /**
+     * timeUnit.sleep(x) for x <= 0 does not sleep at all.
+     */
+    public void testTimedSleep_nonPositive() throws InterruptedException {
+        boolean interrupt = randomBoolean();
+        if (interrupt) Thread.currentThread().interrupt();
+        randomTimeUnit().sleep(0L);
+        randomTimeUnit().sleep(-1L);
+        randomTimeUnit().sleep(Long.MIN_VALUE);
+        if (interrupt) assertTrue(Thread.interrupted());
+    }
+
+    /**
      * a deserialized/reserialized unit is the same instance
      */
     public void testSerialization() throws Exception {
--- a/test/jdk/java/util/regex/RegExTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/java/util/regex/RegExTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -35,7 +35,7 @@
  * 8027645 8035076 8039124 8035975 8074678 6854417 8143854 8147531 7071819
  * 8151481 4867170 7080302 6728861 6995635 6736245 4916384 6328855 6192895
  * 6345469 6988218 6693451 7006761 8140212 8143282 8158482 8176029 8184706
- * 8194667 8197462 8184692 8221431 8224789 8228352
+ * 8194667 8197462 8184692 8221431 8224789 8228352 8230829
  *
  * @library /test/lib
  * @library /lib/testlibrary/java/lang
@@ -1070,6 +1070,22 @@
         matcher.useAnchoringBounds(false);
         if (matcher.find())
            failCount++;
+
+        // JDK-8230829
+        pattern = Pattern.compile("\\ud800\\udc61");
+        matcher = pattern.matcher("\ud800\udc61");
+        matcher.region(0, 1);
+        if (matcher.find()) {
+            failCount++;
+            System.out.println("Matched a surrogate pair" +
+                    " that crosses border of region");
+        }
+        if (!matcher.hitEnd()) {
+            failCount++;
+            System.out.println("Expected to hit the end when" +
+                    " matching a surrogate pair crossing region");
+        }
+
         report("Regions");
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/nio/zipfs/LargeEntriesTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2019, 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 org.testng.annotations.*;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystem;
+import java.nio.file.*;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import static java.lang.Boolean.TRUE;
+import static java.lang.String.format;
+import static java.util.stream.Collectors.joining;
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @bug 8230870
+ * @summary Test ZIP Filesystem behavior with ~64k entries
+ * @modules jdk.zipfs
+ * @run testng LargeEntriesTest
+ */
+public class LargeEntriesTest {
+
+    private static final Path HERE = Path.of(".");
+
+    /**
+     * Number of ZIP entries which results in the use of ZIP64
+     */
+    private static final int ZIP64_ENTRIES = 65535;
+
+    /**
+     * Classes and MANIFEST attribute used for invoking Main via java -jar
+     */
+    private static final String MANIFEST_MAIN_CLASS = "LargeEntriesTest$Main";
+    private static final String MAIN_CLASS = "LargeEntriesTest$Main.class";
+    private static final String THIS_CLASS = "LargeEntriesTest.class";
+
+    /**
+     * Number of entries included in the JAR file including  META-INF,
+     * MANIFEST.MF, and the classes associated with this test
+     */
+    private static final int ADDITIONAL_JAR_ENTRIES = 4;
+
+    /**
+     * Value used for creating the required entries in a ZIP or JAR file
+     */
+    private static final String ZIP_FILE_VALUE = "US Open 2019";
+    private static final byte[] ZIP_FILE_ENTRY =
+            ZIP_FILE_VALUE.getBytes(StandardCharsets.UTF_8);
+
+    /**
+     * Location of the classes to be added to the JAR file
+     */
+    static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
+
+    private static final SecureRandom random = new SecureRandom();
+
+    /**
+     * Fields used for timing runs
+     */
+    private static int testNumberRunning;
+    private static long runningTestTime;
+    private static long startTestRunTime;
+    private static final double NANOS_IN_SECOND = 1_000_000_000.0;
+
+    @BeforeTest(enabled = false)
+    public void beforeTest() {
+        startTestRunTime = System.nanoTime();
+    }
+
+    @AfterTest(enabled = false)
+    public void afterTest() {
+        long endTestRunTime = System.nanoTime();
+        long duration = endTestRunTime - startTestRunTime;
+        System.out.printf("#### Completed test run, total running time: %.4f in seconds%n",
+                duration / NANOS_IN_SECOND);
+    }
+
+    @BeforeMethod(enabled = false)
+    public static void beforeMethod() {
+        runningTestTime = System.nanoTime();
+        System.out.printf("**** Starting test number: %s%n", testNumberRunning);
+    }
+
+    @AfterMethod(enabled = false)
+    public void afterMethod() {
+        long endRunningTestTime = System.nanoTime();
+        long duration = endRunningTestTime - runningTestTime;
+        System.out.printf("**** Completed test number: %s, Time: %.4f%n",
+                testNumberRunning, duration / NANOS_IN_SECOND);
+        testNumberRunning++;
+    }
+
+    /**
+     * Validate that you can create a ZIP file with and without compression
+     * and that the ZIP file is created using ZIP64 if there are 65535 or
+     * more entries.
+     *
+     * @param env         Properties used for creating the ZIP Filesystem
+     * @param compression Indicates whether the files are DEFLATED(default)
+     *                    or STORED
+     * @throws Exception If an error occurs during the creation, verification or
+     *                   deletion of the ZIP file
+     */
+    @Test(dataProvider = "zipfsMap", enabled = true)
+    public void testZip(Map<String, String> env, int compression) throws Exception {
+
+        System.out.printf("ZIP FS Map = %s, Compression mode= %s%n ",
+                formatMap(env), compression);
+
+        for (int entries = ZIP64_ENTRIES - 1; entries < ZIP64_ENTRIES + 2; entries++) {
+            Path zipfile = generatePath(HERE, "test", ".zip");
+            Files.deleteIfExists(zipfile);
+            createZipFile(zipfile, env, entries);
+            verify(zipfile, compression, entries,
+                    isTrue(env, "forceZIP64End"), 0);
+            Files.deleteIfExists(zipfile);
+        }
+    }
+
+    /**
+     * Validate that when the forceZIP64End property is set to true,
+     * that ZIP64 is used.
+     *
+     * @param env         Properties used for creating the ZIP Filesystem
+     * @param compression Indicates whether the files are DEFLATED(default)
+     *                    or STORED
+     * @throws Exception If an error occurs during the creation, verification or
+     *                   deletion of the ZIP file
+     */
+    @Test(dataProvider = "zip64Map", enabled = true)
+    public void testForceZIP64End(Map<String, String> env, int compression) throws Exception {
+
+        System.out.printf("ZIP FS Map = %s, Compression mode= %s%n ",
+                formatMap(env), compression);
+
+        // Generate a ZIP file path
+        Path zipfile = generatePath(HERE, "test", ".zip");
+        Files.deleteIfExists(zipfile);
+        createZipFile(zipfile, env, 1);
+        verify(zipfile, compression, 1, isTrue(env, "forceZIP64End"), 0);
+        Files.deleteIfExists(zipfile);
+    }
+
+    /**
+     * Validate that you can create a JAR file with and without compression
+     * and that the JAR file is created using ZIP64 if there are 65535 or
+     * more entries.
+     *
+     * @param env         Properties used for creating the ZIP Filesystem
+     * @param compression Indicates whether the files are DEFLATED(default)
+     *                    or STORED
+     * @throws Exception If an error occurs during the creation, verification or
+     *                   deletion of the JAR file
+     */
+    @Test(dataProvider = "zipfsMap", enabled = true)
+    public void testJar(Map<String, String> env, int compression) throws Exception {
+        for (int entries = ZIP64_ENTRIES - 1; entries < ZIP64_ENTRIES + 2; entries++) {
+            Path jar = generatePath(HERE, "test", ".jar");
+
+            Files.deleteIfExists(jar);
+            createJarFile(jar, env, entries);
+
+            // Now run the Main-Class specified the Manifest
+            runJar(jar.getFileName().toString()).assertSuccess()
+                    .validate(r -> assertTrue(r.output.matches("\\AMain\\Z")));
+
+            verify(jar, compression, entries, isTrue(env, "forceZIP64End"),
+                    ADDITIONAL_JAR_ENTRIES);
+            Files.deleteIfExists(jar);
+        }
+    }
+
+    /**
+     * Create a ZIP File System using the specified properties and a ZIP file
+     * with the specified number of entries
+     *
+     * @param zipFile Path to the ZIP File to create
+     * @param env     Properties used for creating the ZIP Filesystem
+     * @param entries Number of entries to add to the ZIP File
+     * @throws IOException If an error occurs while creating the ZIP file
+     */
+    private void createZipFile(Path zipFile, Map<String, String> env,
+                               int entries) throws IOException {
+        System.out.printf("Creating file = %s%n", zipFile);
+        try (FileSystem zipfs =
+                     FileSystems.newFileSystem(zipFile, env)) {
+
+            for (int i = 0; i < entries; i++) {
+                Files.writeString(zipfs.getPath("Entry-" + i), ZIP_FILE_VALUE);
+            }
+        }
+    }
+
+    /**
+     * Create a ZIP File System using the specified properties and a JAR file
+     * with the specified number of entries
+     *
+     * @param zipFile Path to the JAR File to create
+     * @param env     Properties used for creating the ZIP Filesystem
+     * @param entries Number of entries to add to the JAR File
+     * @throws IOException If an error occurs while creating the JAR file
+     */
+    private void createJarFile(Path zipFile, Map<String, String> env,
+                               int entries) throws IOException {
+        System.out.printf("Creating file = %s%n", zipFile);
+        String jdkVendor = System.getProperty("java.vendor");
+        String jdkVersion = System.getProperty("java.version");
+        String manifest = "Manifest-Version: 1.0"
+                + System.lineSeparator()
+                + "Main-Class: " + MANIFEST_MAIN_CLASS
+                + System.lineSeparator()
+                + "Created-By: " + jdkVersion + " (" + jdkVendor + ")";
+
+        try (FileSystem zipfs =
+                     FileSystems.newFileSystem(zipFile, env);
+             InputStream in = new ByteArrayInputStream(manifest.getBytes())) {
+
+            // Get ZIP FS path to META-INF/MANIFEST.MF
+            Path metadir = zipfs.getPath("/", "META-INF");
+            Path manifestFile = metadir.resolve("MANIFEST.MF");
+
+            // Create META-INF directory if it does not already exist and
+            // add the MANIFEST.MF file
+            if (!Files.exists(metadir))
+                Files.createDirectory(zipfs.getPath("/", "META-INF"));
+            Files.copy(in, manifestFile);
+
+            // Add the needed test classes
+            Path target = zipfs.getPath("/");
+            Files.copy(TEST_CLASSES.resolve(MAIN_CLASS),
+                    target.resolve(MAIN_CLASS));
+            Files.copy(TEST_CLASSES.resolve(THIS_CLASS),
+                    target.resolve(THIS_CLASS));
+
+            // Add the remaining entries that are required
+            for (int i = ADDITIONAL_JAR_ENTRIES; i < entries; i++) {
+                Files.writeString(zipfs.getPath("Entry-" + i), ZIP_FILE_VALUE);
+            }
+        }
+    }
+
+    /*
+     * DataProvider used to validate that you can create a ZIP file with and
+     * without compression.
+     */
+    @DataProvider(name = "zipfsMap")
+    private Object[][] zipfsMap() {
+        return new Object[][]{
+                {Map.of("create", "true"), ZipEntry.DEFLATED},
+                {Map.of("create", "true", "noCompression", "true"),
+                        ZipEntry.STORED},
+                {Map.of("create", "true", "noCompression", "false"),
+                        ZipEntry.DEFLATED}
+        };
+    }
+
+    /*
+     * DataProvider used to validate that you can create a ZIP file with/without
+     * ZIP64 format extensions
+     */
+    @DataProvider(name = "zip64Map")
+    private Object[][] zip64Map() {
+        return new Object[][]{
+                {Map.of("create", "true", "forceZIP64End", "true"),
+                        ZipEntry.DEFLATED},
+                {Map.of("create", "true", "noCompression", "true",
+                        "forceZIP64End", "true"), ZipEntry.STORED},
+                {Map.of("create", "true", "noCompression", "false",
+                        "forceZIP64End", "false"), ZipEntry.DEFLATED},
+                {Map.of("create", "true", "noCompression", "true",
+                        "forceZIP64End", "false"), ZipEntry.STORED}
+        };
+    }
+
+    /**
+     * Verify that the given path is a ZIP file containing the
+     * expected entries.
+     *
+     * @param zipfile       ZIP file to be validated
+     * @param method        Expected Compression method: STORED or DEFLATED
+     * @param entries       Number of expected entries
+     * @param isZip64Forced true if ZIP64 use is being forced; false otherwise
+     * @param start         Starting number for verifying entries
+     * @throws Exception If an error occurs while examining the ZIP file
+     */
+    private static void verify(Path zipfile, int method, int entries,
+                               boolean isZip64Forced, int start) throws Exception {
+        // check entries with ZIP API
+        try (ZipFile zf = new ZipFile(zipfile.toFile())) {
+            // check entry count
+            assertEquals(entries, zf.size());
+
+            // check compression method and content of each entry
+            for (int i = start; i < entries; i++) {
+                ZipEntry ze = zf.getEntry("Entry-" + i);
+                assertNotNull(ze);
+                assertEquals(method, ze.getMethod());
+                try (InputStream is = zf.getInputStream(ze)) {
+                    byte[] bytes = is.readAllBytes();
+                    assertTrue(Arrays.equals(bytes, ZIP_FILE_ENTRY));
+                }
+            }
+        }
+        // check entries with FileSystem API
+        try (FileSystem fs = FileSystems.newFileSystem(zipfile)) {
+
+            // check entry count
+            Path top = fs.getPath("/");
+            long count = Files.find(top, Integer.MAX_VALUE, (path, attrs) ->
+                    attrs.isRegularFile() || (attrs.isDirectory() &&
+                            path.getFileName() != null &&
+                            path.getFileName().toString().equals("META-INF")))
+                    .count();
+            assertEquals(entries, count);
+
+            // check content of each entry
+            for (int i = start; i < entries; i++) {
+                Path file = fs.getPath("Entry-" + i);
+                byte[] bytes = Files.readAllBytes(file);
+                assertTrue(Arrays.equals(bytes, ZIP_FILE_ENTRY));
+            }
+        }
+
+        // Check for a ZIP64 End of Central Directory Locator
+        boolean foundZip64 = usesZip64(zipfile.toFile());
+
+        // Is ZIP64 required?
+        boolean requireZip64 = entries >= ZIP64_ENTRIES || isZip64Forced;
+        System.out.printf(" isZip64Forced = %s, foundZip64= %s, requireZip64= %s%n",
+                isZip64Forced, foundZip64, requireZip64);
+        assertEquals(requireZip64, foundZip64);
+
+
+    }
+
+    /**
+     * Determine if the specified property name=true/"true"
+     *
+     * @param env  ZIP Filesystem Map
+     * @param name property to validate
+     * @return true if the property value is set to true/"true"; false otherwise
+     */
+    private static boolean isTrue(Map<String, ?> env, String name) {
+        return "true".equals(env.get(name)) || TRUE.equals(env.get(name));
+    }
+
+    /**
+     * Check to see if the ZIP64 End of Central Directory Locator has been found
+     *
+     * @param b byte array to check for the locator in
+     * @param n starting offset for the search
+     * @return true if the Zip64 End of Central Directory Locator is found; false
+     * otherwise
+     */
+    private static boolean end64SigAt(byte[] b, int n) {
+        return b[n] == 'P' & b[n + 1] == 'K' & b[n + 2] == 6 & b[n + 3] == 6;
+    }
+
+    /**
+     * Utility method that checks the ZIP file for the use of the ZIP64
+     * End of Central Directory Locator
+     *
+     * @param zipFile ZIP file to check
+     * @return true if the ZIP64 End of Central Directory Locator is found; false
+     * otherwise
+     * * @throws Exception If an error occurs while traversing the file
+     */
+    private static boolean usesZip64(File zipFile) throws Exception {
+
+        try (RandomAccessFile raf = new RandomAccessFile(zipFile, "r")) {
+            byte[] buf = new byte[4096];
+            long seeklen = raf.length() - buf.length;
+
+            if (seeklen < 0)
+                seeklen = 0;
+            raf.seek(seeklen);
+            raf.read(buf);
+            for (int i = 0; i < buf.length - 4; i++) {
+                // Is there a ZIP64 End of Central Directory Locator?
+                if (end64SigAt(buf, i)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Generate a temporary file Path
+     *
+     * @param dir    Directory used to create the path
+     * @param prefix The prefix string used to create the path
+     * @param suffix The suffix string used to create the path
+     * @return Path that was generated
+     */
+    private static Path generatePath(Path dir, String prefix, String suffix) {
+        long n = random.nextLong();
+        String s = prefix + Long.toUnsignedString(n) + suffix;
+        Path name = dir.getFileSystem().getPath(s);
+        // the generated name should be a simple file name
+        if (name.getParent() != null)
+            throw new IllegalArgumentException("Invalid prefix or suffix");
+        return dir.resolve(name);
+    }
+
+    /**
+     * Utility method to return a formatted String of the key:value entries for
+     * a Map
+     *
+     * @param env Map to format
+     * @return Formatted string of the Map entries
+     */
+    private static String formatMap(Map<String, String> env) {
+        return env.entrySet().stream()
+                .map(e -> format("(%s:%s)", e.getKey(), e.getValue()))
+                .collect(joining(", "));
+    }
+
+    /**
+     * Validates that a jar created using ZIP FS can be used by the java
+     * tool to run a program specified in the Main-Class Manifest attribute
+     *
+     * @param jarFile Name of the JAR file to specify to the -jar option
+     * @return A Result object representing the return code and output from the
+     * program that was invoked
+     */
+    private static Result runJar(String jarFile) {
+        String javaHome = System.getProperty("java.home");
+        String java = Paths.get(javaHome, "bin", "java").toString();
+        String[] cmd = {java, "-jar", jarFile};
+        String output;
+        ProcessBuilder pb = new ProcessBuilder(cmd);
+        Process p;
+        try {
+            p = pb.start();
+            output = toString(p.getInputStream(), p.getErrorStream());
+            p.waitFor();
+        } catch (IOException | InterruptedException e) {
+            throw new RuntimeException(
+                    format("Error invoking: '%s', Exception= %s", pb.command(), e));
+        }
+
+        return new Result(p.exitValue(), output);
+    }
+
+    /**
+     * Utility method to combine the output and error streams for the Process
+     * started by ProcessBuilder
+     *
+     * @param is  Process Outputstream
+     * @param is2 Process ErrorStream
+     * @return String representing the combination of the OutputStream & ErrorStream
+     * @throws IOException If an error occurs while combining the streams
+     */
+    private static String toString(InputStream is, InputStream is2) throws IOException {
+        try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
+             InputStream concatenated = new SequenceInputStream(is, is2)) {
+            concatenated.transferTo(dst);
+            return new String(dst.toByteArray(), StandardCharsets.UTF_8);
+        }
+    }
+
+    /**
+     * Wrapper class used to verify the results from a ProcessBuilder invocation
+     */
+    private static class Result {
+        final int ec;         // Return code for command that was executed
+        final String output;  // Output from the command that was executed
+
+        /**
+         * Constructor
+         *
+         * @param ec     Return code from the ProcessBuilder invocation
+         * @param output ProcessBuilder output to be validated
+         */
+        private Result(int ec, String output) {
+            this.ec = ec;
+            this.output = output;
+        }
+
+        /**
+         * Validate that the command that was executed completed successfully
+         *
+         * @return This Result object
+         */
+        Result assertSuccess() {
+            assertEquals(ec, 0, format("Expected ec 0, received: %s, output [%s]", ec, output));
+            return this;
+        }
+
+        /**
+         * Validate that the expected result is received
+         *
+         * @param r The operation to perform
+         * @return This Result object
+         */
+        Result validate(Consumer<Result> r) {
+            r.accept(this);
+            return this;
+        }
+    }
+
+    /**
+     * Trivial class used to validate that a JAR created using ZIP FS
+     * can be successfully executed
+     */
+    public static class Main {
+        public static void main(String[] args) {
+            System.out.print("Main");
+        }
+    }
+}
--- a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -62,7 +62,7 @@
     public static void startHttpServer() {
         try {
             httpTrans = new SimpleHttpTransaction();
-            server = new TestHttpServer(httpTrans, 1, 10, 0);
+            server = new TestHttpServer(httpTrans, 1, 10, InetAddress.getLocalHost(), 0);
         } catch (IOException e) {
             e.printStackTrace();
         }
@@ -71,13 +71,14 @@
     public static void clientHttpCalls() {
         try {
             System.out.println("http server listen on: " + server.getLocalPort());
-            String baseURLStr = "http://" + InetAddress.getLocalHost().getHostAddress() + ":" +
-                                  server.getLocalPort() + "/";
+            String hostAddr =  InetAddress.getLocalHost().getHostAddress();
+            if (hostAddr.indexOf(':') > -1) hostAddr = "[" + hostAddr + "]";
+            String baseURLStr = "http://" + hostAddr + ":" + server.getLocalPort() + "/";
 
             URL bigDataURL = new URL (baseURLStr + "firstCall");
             URL smallDataURL = new URL (baseURLStr + "secondCall");
 
-            HttpURLConnection uc = (HttpURLConnection)bigDataURL.openConnection();
+            HttpURLConnection uc = (HttpURLConnection)bigDataURL.openConnection(Proxy.NO_PROXY);
 
             //Only read 1 byte of response data and close the stream
             InputStream is = uc.getInputStream();
@@ -88,7 +89,7 @@
             // Allow the KeepAliveStreamCleaner thread to read the data left behind and cache the connection.
             try { Thread.sleep(2000); } catch (Exception e) {}
 
-            uc = (HttpURLConnection)smallDataURL.openConnection();
+            uc = (HttpURLConnection)smallDataURL.openConnection(Proxy.NO_PROXY);
             uc.getResponseCode();
 
             if (SimpleHttpTransaction.failed)
@@ -96,7 +97,7 @@
 
             // Part 2
             URL part2Url = new URL (baseURLStr + "part2");
-            uc = (HttpURLConnection)part2Url.openConnection();
+            uc = (HttpURLConnection)part2Url.openConnection(Proxy.NO_PROXY);
             is = uc.getInputStream();
             is.close();
 
--- a/test/jdk/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,10 @@
 import java.io.BufferedWriter;
 import java.io.OutputStreamWriter;
 import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.Proxy;
 import java.net.URL;
+import java.net.UnknownHostException;
 
 import javax.net.ssl.HttpsURLConnection;
 import javax.net.ssl.SSLContext;
@@ -64,6 +67,10 @@
         (new ServerIdentityTest()).run();
     }
 
+    ServerIdentityTest() throws UnknownHostException {
+        serverAddress = InetAddress.getByName(hostname);
+    }
+
     @Override
     protected boolean isCustomizedClientConnection() {
         return true;
@@ -88,7 +95,7 @@
         HttpURLConnection urlc = null;
         InputStream is = null;
         try {
-            urlc = (HttpURLConnection)url.openConnection();
+            urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
             is = urlc.getInputStream();
         } finally {
             if (is != null) {
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/DNSIdentities.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, 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
@@ -651,8 +651,13 @@
             serverModulus, serverPrivateExponent, passphrase);
         SSLServerSocketFactory sslssf = context.getServerSocketFactory();
 
+        // doClientSide() connects to "localhost"
+        InetAddress localHost = InetAddress.getByName("localhost");
+        InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
+
         sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            (SSLServerSocket) sslssf.createServerSocket();
+        sslServerSocket.bind(address);
         serverPort = sslServerSocket.getLocalPort();
 
         /*
@@ -717,7 +722,7 @@
             System.out.println("url is "+url.toString());
 
             try {
-                http = (HttpsURLConnection)url.openConnection();
+                http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
 
                 int respCode = http.getResponseCode();
                 System.out.println("respCode = "+respCode);
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressDNSIdentities.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, 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
@@ -650,8 +650,13 @@
             serverModulus, serverPrivateExponent, passphrase);
         SSLServerSocketFactory sslssf = context.getServerSocketFactory();
 
+        // doClientSide() connects to the loopback address
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback, serverPort);
+
         sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            (SSLServerSocket) sslssf.createServerSocket();
+        sslServerSocket.bind(address);
         serverPort = sslServerSocket.getLocalPort();
 
         /*
@@ -721,7 +726,7 @@
             System.out.println("url is "+url.toString());
 
             try {
-                http = (HttpsURLConnection)url.openConnection();
+                http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
 
                 int respCode = http.getResponseCode();
                 System.out.println("respCode = " + respCode);
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPAddressIPIdentities.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, 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
@@ -654,8 +654,13 @@
             serverModulus, serverPrivateExponent, passphrase);
         SSLServerSocketFactory sslssf = context.getServerSocketFactory();
 
+        // doClientSide() connects to the loopback address
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback, serverPort);
+
         sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            (SSLServerSocket) sslssf.createServerSocket();
+        sslServerSocket.bind(address);
         serverPort = sslServerSocket.getLocalPort();
 
         /*
@@ -725,7 +730,7 @@
             System.out.println("url is "+url.toString());
 
             try {
-                http = (HttpsURLConnection)url.openConnection();
+                http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
 
                 int respCode = http.getResponseCode();
                 System.out.println("respCode = "+respCode);
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/IPIdentities.java	Wed Sep 18 07:46:02 2019 +0200
@@ -29,6 +29,7 @@
 /* @test
  * @summary X509 certificate hostname checking is broken in JDK1.6.0_10
  * @bug 6766775
+ * @library /test/lib
  * @run main/othervm IPIdentities
  * @author Xuelei Fan
  */
@@ -45,6 +46,7 @@
 import java.security.spec.*;
 import java.security.interfaces.*;
 import java.math.BigInteger;
+import jdk.test.lib.net.URIBuilder;
 
 /*
  * Certificates and key used in the test.
@@ -652,8 +654,13 @@
             serverModulus, serverPrivateExponent, passphrase);
         SSLServerSocketFactory sslssf = context.getServerSocketFactory();
 
+        // doClientSide() connects to the loopback address
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetSocketAddress address = new InetSocketAddress(loopback, serverPort);
+
         sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            (SSLServerSocket) sslssf.createServerSocket();
+        sslServerSocket.bind(address);
         serverPort = sslServerSocket.getLocalPort();
 
         /*
@@ -713,11 +720,16 @@
             HttpsURLConnection http = null;
 
             /* establish http connection to server */
-            URL url = new URL("https://localhost:" + serverPort+"/");
+            URL url = URIBuilder.newBuilder()
+                .scheme("https")
+                .loopback()
+                .port(serverPort)
+                .path("/")
+                .toURL();
             System.out.println("url is "+url.toString());
 
             try {
-                http = (HttpsURLConnection)url.openConnection();
+                http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
 
                 int respCode = http.getResponseCode();
                 System.out.println("respCode = "+respCode);
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/Identities.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2019, 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
@@ -651,8 +651,13 @@
             serverModulus, serverPrivateExponent, passphrase);
         SSLServerSocketFactory sslssf = context.getServerSocketFactory();
 
+        // doClientSide() connects to "localhost"
+        InetAddress localHost = InetAddress.getByName("localhost");
+        InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
+
         sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            (SSLServerSocket) sslssf.createServerSocket();
+        sslServerSocket.bind(address);
         serverPort = sslServerSocket.getLocalPort();
 
         /*
@@ -717,7 +722,7 @@
             System.out.println("url is "+url.toString());
 
             try {
-                http = (HttpsURLConnection)url.openConnection();
+                http = (HttpsURLConnection)url.openConnection(Proxy.NO_PROXY);
 
                 int respCode = http.getResponseCode();
                 System.out.println("respCode = "+respCode);
--- a/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpsURLConnection/ImpactOnSNI.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -95,6 +95,16 @@
      * smart about it....
      */
 
+    private SSLServerSocket createServerSocket(SSLServerSocketFactory sslssf)
+        throws Exception {
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket();
+        InetAddress localHost = InetAddress.getLocalHost();
+        InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
+        sslServerSocket.bind(address);
+        return sslServerSocket;
+    }
+
     /*
      * Define the server side of the test.
      *
@@ -104,8 +114,7 @@
     private void doServerSide() throws Exception {
         SSLServerSocketFactory sslssf =
             (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
-        try (SSLServerSocket sslServerSocket =
-                (SSLServerSocket)sslssf.createServerSocket(serverPort)) {
+        try (SSLServerSocket sslServerSocket = createServerSocket(sslssf)) {
 
             serverPort = sslServerSocket.getLocalPort();
 
--- a/test/jdk/sun/net/www/protocol/https/NewImpl/JavaxHostnameVerifier.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/NewImpl/JavaxHostnameVerifier.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, 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
@@ -135,8 +135,14 @@
 
         SSLServerSocketFactory sslssf =
           (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+
+        // doClientSide() connects to "localhost"
+        InetAddress localHost = InetAddress.getByName("localhost");
+        InetSocketAddress address = new InetSocketAddress(localHost, serverPort);
+
         SSLServerSocket sslServerSocket =
-            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            (SSLServerSocket) sslssf.createServerSocket();
+        sslServerSocket.bind(address);
         serverPort = sslServerSocket.getLocalPort();
 
         String ciphers[]= { "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA" };
@@ -205,7 +211,7 @@
 
         URL url = new URL("https://" + "localhost:" + serverPort +
                                 "/etc/hosts");
-        URLConnection urlc = url.openConnection();
+        URLConnection urlc = url.openConnection(Proxy.NO_PROXY);
 
         if (!(urlc instanceof javax.net.ssl.HttpsURLConnection)) {
             throw new Exception(
--- a/test/jdk/sun/net/www/protocol/jar/B4957695.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/jar/B4957695.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, 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
@@ -96,7 +96,10 @@
     public static void main (String[] args) throws Exception {
         String tmpdir = System.getProperty("java.io.tmpdir");
         String[] list1 = listTmpFiles(tmpdir);
-        ServerSocket serverSocket = new ServerSocket(0);
+        InetAddress localHost = InetAddress.getByName("localhost");
+        InetSocketAddress address = new InetSocketAddress(localHost, 0);
+        ServerSocket serverSocket = new ServerSocket();
+        serverSocket.bind(address);
         server = new Server(serverSocket);
         server.start();
         int port = serverSocket.getLocalPort();
@@ -108,7 +111,9 @@
             read (is);
             is.close();
         } catch (IOException e) {
-            System.out.println ("Received IOException as expected");
+            System.out.println ("Received IOException as expected: " + e);
+        } finally {
+            try {serverSocket.close();} catch (IOException x) {}
         }
         String[] list2 = listTmpFiles(tmpdir);
         if (!sameList (list1, list2)) {
--- a/test/jdk/sun/tools/jcmd/TestProcessHelper.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/jdk/sun/tools/jcmd/TestProcessHelper.java	Wed Sep 18 07:46:02 2019 +0200
@@ -189,6 +189,26 @@
 
     private void checkMainClass(Process p, String expectedMainClass) {
         String mainClass = PROCESS_HELPER.getMainClass(Long.toString(p.pid()));
+        // getMainClass() may return null, e.g. due to timing issues.
+        // Attempt some limited retries.
+        if (mainClass == null) {
+            System.err.println("Main class returned by ProcessHelper was null.");
+            // sleep time doubles each round, altogether, wait no longer than 1 sec
+            final int MAX_RETRIES = 10;
+            int retrycount = 0;
+            long sleepms = 1;
+            while (retrycount < MAX_RETRIES && mainClass == null) {
+                System.err.println("Retry " + retrycount + ", sleeping for " + sleepms + "ms.");
+                try {
+                    Thread.sleep(sleepms);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+                mainClass = PROCESS_HELPER.getMainClass(Long.toString(p.pid()));
+                retrycount++;
+                sleepms *= 2;
+            }
+        }
         p.destroyForcibly();
         if (!expectedMainClass.equals(mainClass)) {
             throw new RuntimeException("Main class is wrong: " + mainClass);
--- a/test/lib/jdk/test/lib/Platform.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/lib/jdk/test/lib/Platform.java	Wed Sep 18 07:46:02 2019 +0200
@@ -265,7 +265,6 @@
                     return false;
                 }
             } catch (PrivilegedActionException e) {
-                @SuppressWarnings("unchecked")
                 IOException t = (IOException) e.getException();
                 throw t;
             }
@@ -289,7 +288,6 @@
                     return false;
                 }
             } catch (PrivilegedActionException e) {
-                @SuppressWarnings("unchecked")
                 IOException t = (IOException) e.getException();
                 throw t;
             }
--- a/test/lib/jdk/test/lib/Utils.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/lib/jdk/test/lib/Utils.java	Wed Sep 18 07:46:02 2019 +0200
@@ -25,6 +25,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.annotation.Annotation;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.MalformedURLException;
@@ -749,13 +750,14 @@
     // until the method main() is found; the class containing that method is the
     // main test class and will be returned as the name of the test.
     // Special handling is used for testng tests.
+    @SuppressWarnings("unchecked")
     public static String getTestName() {
         String result = null;
         // If we are using testng, then we should be able to load the "Test" annotation.
-        Class testClassAnnotation;
+        Class<? extends Annotation> testClassAnnotation;
 
         try {
-            testClassAnnotation = Class.forName("org.testng.annotations.Test");
+            testClassAnnotation = (Class<? extends Annotation>)Class.forName("org.testng.annotations.Test");
         } catch (ClassNotFoundException e) {
             testClassAnnotation = null;
         }
@@ -776,7 +778,7 @@
             // annotation. If present, then use the name of this class.
             if (testClassAnnotation != null) {
                 try {
-                    Class c = Class.forName(className);
+                    Class<?> c = Class.forName(className);
                     if (c.isAnnotationPresent(testClassAnnotation)) {
                         result = className;
                         break;
--- a/test/lib/jdk/test/lib/process/ProcessTools.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/lib/jdk/test/lib/process/ProcessTools.java	Wed Sep 18 07:46:02 2019 +0200
@@ -495,7 +495,6 @@
             return AccessController.doPrivileged(
                 (PrivilegedExceptionAction<Process>) () -> pb.start());
         } catch (PrivilegedActionException e) {
-            @SuppressWarnings("unchecked")
             IOException t = (IOException) e.getException();
             throw t;
         }
--- a/test/lib/jdk/test/lib/process/StreamPumper.java	Thu Sep 12 15:04:00 2019 +0200
+++ b/test/lib/jdk/test/lib/process/StreamPumper.java	Wed Sep 18 07:46:02 2019 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -144,7 +144,9 @@
             }
 
         } catch (IOException e) {
-            e.printStackTrace();
+            if (!e.getMessage().equalsIgnoreCase("stream closed")) {
+                e.printStackTrace();
+            }
         } finally {
             for (OutputStream out : outStreams) {
                 try {