changeset 57500:14fa9e70ae71

8230876: baseline cleanups from Async Monitor Deflation v2.0[789] Reviewed-by: dholmes, kvn
author dcubed
date Wed, 20 Nov 2019 09:10:02 -0500
parents 0c2e1808f800
children b313bcb68b4c
files src/hotspot/cpu/x86/macroAssembler_x86.cpp src/hotspot/share/classfile/systemDictionary.cpp src/hotspot/share/runtime/objectMonitor.cpp src/hotspot/share/runtime/objectMonitor.hpp src/hotspot/share/runtime/objectMonitor.inline.hpp src/hotspot/share/runtime/synchronizer.cpp src/hotspot/share/runtime/synchronizer.hpp src/hotspot/share/runtime/threadSMR.cpp src/hotspot/share/runtime/vmStructs.cpp
diffstat 9 files changed, 113 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Wed Nov 20 09:10:02 2019 -0500
@@ -1532,7 +1532,7 @@
   Label L_rtm_retry, L_decrement_retry, L_on_abort;
   int owner_offset = OM_OFFSET_NO_MONITOR_VALUE_TAG(owner);
 
-  // Without cast to int32_t a movptr will destroy r10 which is typically obj
+  // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
   movptr(Address(boxReg, 0), (int32_t)intptr_t(markWord::unused_mark().value()));
   movptr(boxReg, tmpReg); // Save ObjectMonitor address
 
@@ -1602,11 +1602,11 @@
 
 #endif //  INCLUDE_RTM_OPT
 
-// Fast_Lock and Fast_Unlock used by C2
+// fast_lock and fast_unlock used by C2
 
 // Because the transitions from emitted code to the runtime
 // monitorenter/exit helper stubs are so slow it's critical that
-// we inline both the stack-locking fast-path and the inflated fast path.
+// we inline both the stack-locking fast path and the inflated fast path.
 //
 // See also: cmpFastLock and cmpFastUnlock.
 //
@@ -1615,7 +1615,7 @@
 // option would be to emit TrySlowEnter and TrySlowExit methods
 // at startup-time.  These methods would accept arguments as
 // (rax,=Obj, rbx=Self, rcx=box, rdx=Scratch) and return success-failure
-// indications in the icc.ZFlag.  Fast_Lock and Fast_Unlock would simply
+// indications in the icc.ZFlag.  fast_lock and fast_unlock would simply
 // marshal the arguments and emit calls to TrySlowEnter and TrySlowExit.
 // In practice, however, the # of lock sites is bounded and is usually small.
 // Besides the call overhead, TrySlowEnter and TrySlowExit might suffer
@@ -1634,8 +1634,8 @@
 //
 // TODO:
 //
-// *  Arrange for C2 to pass "Self" into Fast_Lock and Fast_Unlock in one of the registers (scr).
-//    This avoids manifesting the Self pointer in the Fast_Lock and Fast_Unlock terminals.
+// *  Arrange for C2 to pass "Self" into fast_lock and fast_unlock in one of the registers (scr).
+//    This avoids manifesting the Self pointer in the fast_lock and fast_unlock terminals.
 //    Given TLAB allocation, Self is usually manifested in a register, so passing it into
 //    the lock operators would typically be faster than reifying Self.
 //
@@ -1661,14 +1661,14 @@
 // *  use jccb and jmpb instead of jcc and jmp to improve code density.
 //    But beware of excessive branch density on AMD Opterons.
 //
-// *  Both Fast_Lock and Fast_Unlock set the ICC.ZF to indicate success
-//    or failure of the fast-path.  If the fast-path fails then we pass
-//    control to the slow-path, typically in C.  In Fast_Lock and
-//    Fast_Unlock we often branch to DONE_LABEL, just to find that C2
+// *  Both fast_lock and fast_unlock set the ICC.ZF to indicate success
+//    or failure of the fast path.  If the fast path fails then we pass
+//    control to the slow path, typically in C.  In fast_lock and
+//    fast_unlock we often branch to DONE_LABEL, just to find that C2
 //    will emit a conditional branch immediately after the node.
 //    So we have branches to branches and lots of ICC.ZF games.
 //    Instead, it might be better to have C2 pass a "FailureLabel"
-//    into Fast_Lock and Fast_Unlock.  In the case of success, control
+//    into fast_lock and fast_unlock.  In the case of success, control
 //    will drop through the node.  ICC.ZF is undefined at exit.
 //    In the case of failure, the node will branch directly to the
 //    FailureLabel
@@ -1813,7 +1813,7 @@
   movptr(Address(boxReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), scrReg);
   xorptr(boxReg, boxReg);                 // set icc.ZFlag = 1 to indicate success
 
-  // If the CAS fails we can either retry or pass control to the slow-path.
+  // If the CAS fails we can either retry or pass control to the slow path.
   // We use the latter tactic.
   // Pass the CAS result in the icc.ZFlag into DONE_LABEL
   // If the CAS was successful ...
@@ -1821,14 +1821,13 @@
   //   Invariant: m->_recursions should already be 0, so we don't need to explicitly set it.
   // Intentional fall-through into DONE_LABEL ...
 #else // _LP64
-  // It's inflated
+  // It's inflated and we use scrReg for ObjectMonitor* in this section.
   movq(scrReg, tmpReg);
   xorq(tmpReg, tmpReg);
-
   lock();
   cmpxchgptr(r15_thread, Address(scrReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)));
   // Unconditionally set box->_displaced_header = markWord::unused_mark().
-  // Without cast to int32_t movptr will destroy r10 which is typically obj.
+  // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
   movptr(Address(boxReg, 0), (int32_t)intptr_t(markWord::unused_mark().value()));
   // Intentional fall-through into DONE_LABEL ...
   // Propagate ICC.ZF from CAS above into DONE_LABEL.
@@ -1844,9 +1843,9 @@
   bind(DONE_LABEL);
 
   // At DONE_LABEL the icc ZFlag is set as follows ...
-  // Fast_Unlock uses the same protocol.
+  // fast_unlock uses the same protocol.
   // ZFlag == 1 -> Success
-  // ZFlag == 0 -> Failure - force control through the slow-path
+  // ZFlag == 0 -> Failure - force control through the slow path
 }
 
 // obj: object to unlock
@@ -1855,7 +1854,7 @@
 //
 // Some commentary on balanced locking:
 //
-// Fast_Lock and Fast_Unlock are emitted only for provably balanced lock sites.
+// fast_lock and fast_unlock are emitted only for provably balanced lock sites.
 // Methods that don't have provably balanced locking are forced to run in the
 // interpreter - such methods won't be compiled to use fast_lock and fast_unlock.
 // The interpreter provides two properties:
@@ -1876,7 +1875,7 @@
 // should not be unlocked by "normal" java-level locking and vice-versa.  The specification
 // doesn't specify what will occur if a program engages in such mixed-mode locking, however.
 // Arguably given that the spec legislates the JNI case as undefined our implementation
-// could reasonably *avoid* checking owner in Fast_Unlock().
+// could reasonably *avoid* checking owner in fast_unlock().
 // In the interest of performance we elide m->Owner==Self check in unlock.
 // A perfectly viable alternative is to elide the owner check except when
 // Xcheck:jni is enabled.
@@ -1941,7 +1940,7 @@
   // a costly MEMBAR or CAS.  See synchronizer.cpp for details on how
   // we detect and recover from the race that the 1-0 exit admits.
   //
-  // Conceptually Fast_Unlock() must execute a STST|LDST "release" barrier
+  // Conceptually fast_unlock() must execute a STST|LDST "release" barrier
   // before it STs null into _owner, releasing the lock.  Updates
   // to data protected by the critical section must be visible before
   // we drop the lock (and thus before any other thread could acquire
@@ -1990,6 +1989,7 @@
   movptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq)));
   orptr(boxReg, Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList)));
   jccb  (Assembler::notZero, CheckSucc);
+  // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
   movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD);
   jmpb  (DONE_LABEL);
 
@@ -1998,13 +1998,14 @@
   bind  (CheckSucc);
 
   // The following optional optimization can be elided if necessary
-  // Effectively: if (succ == null) goto SlowPath
+  // Effectively: if (succ == null) goto slow path
   // The code reduces the window for a race, however,
   // and thus benefits performance.
   cmpptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(succ)), (int32_t)NULL_WORD);
   jccb  (Assembler::zero, LGoSlowPath);
 
   xorptr(boxReg, boxReg);
+  // Without cast to int32_t this style of movptr will destroy r10 which is typically obj.
   movptr(Address(tmpReg, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner)), (int32_t)NULL_WORD);
 
   // Memory barrier/fence
@@ -2039,7 +2040,7 @@
   // If that didn't work, then another thread grabbed the
   // lock so we're done (and exit was a success).
   jccb  (Assembler::notEqual, LSuccess);
-  // Intentional fall-through into slow-path
+  // Intentional fall-through into slow path
 
   bind  (LGoSlowPath);
   orl   (boxReg, 1);                      // set ICC.ZF=0 to indicate failure
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Wed Nov 20 09:10:02 2019 -0500
@@ -540,7 +540,7 @@
   assert(calledholdinglock,"must hold lock for notify");
   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);
+  intx recursions =  ObjectSynchronizer::complete_exit(lockObject, THREAD);
   SystemDictionary_lock->wait();
   SystemDictionary_lock->unlock();
   ObjectSynchronizer::reenter(lockObject, recursions, THREAD);
--- a/src/hotspot/share/runtime/objectMonitor.cpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/objectMonitor.cpp	Wed Nov 20 09:10:02 2019 -0500
@@ -26,6 +26,8 @@
 #include "classfile/vmSymbols.hpp"
 #include "jfr/jfrEvents.hpp"
 #include "jfr/support/jfrThreadId.hpp"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/markWord.hpp"
@@ -255,7 +257,7 @@
     return;
   }
 
-  if (Self->is_lock_owned ((address)cur)) {
+  if (Self->is_lock_owned((address)cur)) {
     assert(_recursions == 0, "internal state error");
     _recursions = 1;
     // Commute owner from a thread-specific on-stack BasicLockObject address to
@@ -275,8 +277,7 @@
   // we forgo posting JVMTI events and firing DTRACE probes.
   if (TrySpin(Self) > 0) {
     assert(_owner == Self, "must be Self: owner=" INTPTR_FORMAT, p2i(_owner));
-    assert(_recursions == 0, "must be 0: recursions=" INTPTR_FORMAT,
-           _recursions);
+    assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
     assert(((oop)object())->mark() == markWord::encode(this),
            "object mark must match encoded this: mark=" INTPTR_FORMAT
            ", encoded this=" INTPTR_FORMAT, ((oop)object())->mark().value(),
@@ -881,7 +882,14 @@
       // way we should encounter this situation is in the presence of
       // unbalanced JNI locking. TODO: CheckJNICalls.
       // See also: CR4414101
-      assert(false, "Non-balanced monitor enter/exit! Likely JNI locking");
+#ifdef ASSERT
+      LogStreamHandle(Error, monitorinflation) lsh;
+      lsh.print_cr("ERROR: ObjectMonitor::exit(): thread=" INTPTR_FORMAT
+                    " is exiting an ObjectMonitor it does not own.", p2i(THREAD));
+      lsh.print_cr("The imbalance is possibly caused by JNI locking.");
+      print_debug_style_on(&lsh);
+#endif
+      assert(false, "Non-balanced monitor enter/exit!");
       return;
     }
   }
@@ -908,8 +916,6 @@
 
     // release semantics: prior loads and stores from within the critical section
     // must not float (reorder) past the following store that drops the lock.
-    // On SPARC that requires MEMBAR #loadstore|#storestore.
-    // But of course in TSO #loadstore|#storestore is not required.
     OrderAccess::release_store(&_owner, (void*)NULL);   // drop the lock
     OrderAccess::storeload();                        // See if we need to wake a successor
     if ((intptr_t(_EntryList)|intptr_t(_cxq)) == 0 || _succ != NULL) {
@@ -1106,7 +1112,7 @@
 // The _owner field is not always the Thread addr even with an
 // inflated monitor, e.g. the monitor can be inflated by a non-owning
 // thread due to contention.
-intptr_t ObjectMonitor::complete_exit(TRAPS) {
+intx ObjectMonitor::complete_exit(TRAPS) {
   Thread * const Self = THREAD;
   assert(Self->is_Java_thread(), "Must be Java thread!");
   JavaThread *jt = (JavaThread *)THREAD;
@@ -1122,7 +1128,7 @@
   }
 
   guarantee(Self == _owner, "complete_exit not owner");
-  intptr_t save = _recursions; // record the old recursion count
+  intx save = _recursions; // record the old recursion count
   _recursions = 0;        // set the recursion level to be 0
   exit(true, Self);           // exit the monitor
   guarantee(_owner != Self, "invariant");
@@ -1131,7 +1137,7 @@
 
 // reenter() enters a lock and sets recursion count
 // complete_exit/reenter operate as a wait without waiting
-void ObjectMonitor::reenter(intptr_t recursions, TRAPS) {
+void ObjectMonitor::reenter(intx recursions, TRAPS) {
   Thread * const Self = THREAD;
   assert(Self->is_Java_thread(), "Must be Java thread!");
   JavaThread *jt = (JavaThread *)THREAD;
@@ -1252,7 +1258,7 @@
 
   _Responsible = NULL;
 
-  intptr_t save = _recursions; // record the old recursion count
+  intx save = _recursions;     // record the old recursion count
   _waiters++;                  // increment the number of waiters
   _recursions = 0;             // set the recursion level to be 1
   exit(true, Self);                    // exit the monitor
@@ -1941,8 +1947,62 @@
 void ObjectMonitor::print_on(outputStream* st) const {
   // The minimal things to print for markWord printing, more can be added for debugging and logging.
   st->print("{contentions=0x%08x,waiters=0x%08x"
-            ",recursions=" INTPTR_FORMAT ",owner=" INTPTR_FORMAT "}",
+            ",recursions=" INTX_FORMAT ",owner=" INTPTR_FORMAT "}",
             contentions(), waiters(), recursions(),
             p2i(owner()));
 }
 void ObjectMonitor::print() const { print_on(tty); }
+
+#ifdef ASSERT
+// Print the ObjectMonitor like a debugger would:
+//
+// (ObjectMonitor) 0x00007fdfb6012e40 = {
+//   _header = 0x0000000000000001
+//   _object = 0x000000070ff45fd0
+//   _next_om = 0x0000000000000000
+//   _pad_buf0 = {
+//     [0] = '\0'
+//     ...
+//     [103] = '\0'
+//   }
+//   _owner = 0x0000000000000000
+//   _previous_owner_tid = 0
+//   _recursions = 0
+//   _EntryList = 0x0000000000000000
+//   _cxq = 0x0000000000000000
+//   _succ = 0x0000000000000000
+//   _Responsible = 0x0000000000000000
+//   _Spinner = 0
+//   _SpinDuration = 5000
+//   _contentions = 0
+//   _WaitSet = 0x0000700009756248
+//   _waiters = 1
+//   _WaitSetLock = 0
+// }
+//
+void ObjectMonitor::print_debug_style_on(outputStream* st) const {
+  st->print_cr("(ObjectMonitor*) " INTPTR_FORMAT " = {", p2i(this));
+  st->print_cr("  _header = " INTPTR_FORMAT, header().value());
+  st->print_cr("  _object = " INTPTR_FORMAT, p2i(_object));
+  st->print_cr("  _next_om = " INTPTR_FORMAT, p2i(_next_om));
+  st->print_cr("  _pad_buf0 = {");
+  st->print_cr("    [0] = '\\0'");
+  st->print_cr("    ...");
+  st->print_cr("    [%d] = '\\0'", (int)sizeof(_pad_buf0) - 1);
+  st->print_cr("  }");
+  st->print_cr("  _owner = " INTPTR_FORMAT, p2i(_owner));
+  st->print_cr("  _previous_owner_tid = " JLONG_FORMAT, _previous_owner_tid);
+  st->print_cr("  _recursions = " INTX_FORMAT, _recursions);
+  st->print_cr("  _EntryList = " INTPTR_FORMAT, p2i(_EntryList));
+  st->print_cr("  _cxq = " INTPTR_FORMAT, p2i(_cxq));
+  st->print_cr("  _succ = " INTPTR_FORMAT, p2i(_succ));
+  st->print_cr("  _Responsible = " INTPTR_FORMAT, p2i(_Responsible));
+  st->print_cr("  _Spinner = %d", _Spinner);
+  st->print_cr("  _SpinDuration = %d", _SpinDuration);
+  st->print_cr("  _contentions = %d", _contentions);
+  st->print_cr("  _WaitSet = " INTPTR_FORMAT, p2i(_WaitSet));
+  st->print_cr("  _waiters = %d", _waiters);
+  st->print_cr("  _WaitSetLock = %d", _WaitSetLock);
+  st->print_cr("}");
+}
+#endif
--- a/src/hotspot/share/runtime/objectMonitor.hpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/objectMonitor.hpp	Wed Nov 20 09:10:02 2019 -0500
@@ -144,7 +144,7 @@
                         sizeof(ObjectMonitor *));
   void* volatile _owner;            // pointer to owning thread OR BasicLock
   volatile jlong _previous_owner_tid;  // thread id of the previous owner of the monitor
-  volatile intptr_t _recursions;    // recursion count, 0 for first entry
+  volatile intx _recursions;        // recursion count, 0 for first entry
   ObjectWaiter* volatile _EntryList;  // Threads blocked on entry or reentry.
                                       // The list is actually composed of WaitNodes,
                                       // acting as proxies for Threads.
@@ -237,7 +237,7 @@
   jint      waiters() const;
 
   jint      contentions() const;
-  intptr_t  recursions() const                                         { return _recursions; }
+  intx      recursions() const                                         { return _recursions; }
 
   // JVM/TI GetObjectMonitorUsage() needs this:
   ObjectWaiter* first_waiter()                                         { return _WaitSet; }
@@ -263,7 +263,7 @@
     // _recursions == 0 _WaitSet == NULL
     DEBUG_ONLY(stringStream ss;)
     assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, "
-           "recursions=" INTPTR_FORMAT, is_busy_to_string(&ss), _recursions);
+           "recursions=" INTX_FORMAT, is_busy_to_string(&ss), _recursions);
     _succ          = NULL;
     _EntryList     = NULL;
     _cxq           = NULL;
@@ -289,11 +289,14 @@
   void      notifyAll(TRAPS);
 
   void      print() const;
+#ifdef ASSERT
+  void      print_debug_style_on(outputStream* st) const;
+#endif
   void      print_on(outputStream* st) const;
 
 // Use the following at your own risk
-  intptr_t  complete_exit(TRAPS);
-  void      reenter(intptr_t recursions, TRAPS);
+  intx      complete_exit(TRAPS);
+  void      reenter(intx recursions, TRAPS);
 
  private:
   void      AddWaiter(ObjectWaiter* waiter);
--- a/src/hotspot/share/runtime/objectMonitor.inline.hpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp	Wed Nov 20 09:10:02 2019 -0500
@@ -59,7 +59,7 @@
   assert(Atomic::load(&_header).value() != 0, "must be non-zero");
   assert(_contentions == 0, "must be 0: contentions=%d", _contentions);
   assert(_waiters == 0, "must be 0: waiters=%d", _waiters);
-  assert(_recursions == 0, "must be 0: recursions=" INTPTR_FORMAT, _recursions);
+  assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions);
   assert(_object != NULL, "must be non-NULL");
   assert(_owner == NULL, "must be NULL: owner=" INTPTR_FORMAT, p2i(_owner));
 
--- a/src/hotspot/share/runtime/synchronizer.cpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/synchronizer.cpp	Wed Nov 20 09:10:02 2019 -0500
@@ -359,7 +359,7 @@
 //  4) reenter lock1 with original recursion count
 //  5) lock lock2
 // NOTE: must use heavy weight monitor to handle complete_exit/reenter()
-intptr_t ObjectSynchronizer::complete_exit(Handle obj, TRAPS) {
+intx ObjectSynchronizer::complete_exit(Handle obj, TRAPS) {
   if (UseBiasedLocking) {
     BiasedLocking::revoke(obj, THREAD);
     assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
@@ -371,7 +371,7 @@
 }
 
 // NOTE: must use heavy weight monitor to handle complete_exit/reenter()
-void ObjectSynchronizer::reenter(Handle obj, intptr_t recursion, TRAPS) {
+void ObjectSynchronizer::reenter(Handle obj, intx recursions, TRAPS) {
   if (UseBiasedLocking) {
     BiasedLocking::revoke(obj, THREAD);
     assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
@@ -379,7 +379,7 @@
 
   ObjectMonitor* monitor = inflate(THREAD, obj(), inflate_cause_vm_internal);
 
-  monitor->reenter(recursion, THREAD);
+  monitor->reenter(recursions, THREAD);
 }
 // -----------------------------------------------------------------------------
 // JNI locks on java objects
@@ -1140,7 +1140,7 @@
   guarantee(m->object() == NULL, "invariant");
   stringStream ss;
   guarantee((m->is_busy() | m->_recursions) == 0, "freeing in-use monitor: "
-            "%s, recursions=" INTPTR_FORMAT, m->is_busy_to_string(&ss),
+            "%s, recursions=" INTX_FORMAT, m->is_busy_to_string(&ss),
             m->_recursions);
   // _next_om is used for both per-thread in-use and free lists so
   // we have to remove 'm' from the in-use list first (as needed).
--- a/src/hotspot/share/runtime/synchronizer.hpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/synchronizer.hpp	Wed Nov 20 09:10:02 2019 -0500
@@ -92,8 +92,8 @@
   // used by classloading to free classloader object lock,
   // wait on an internal lock, and reclaim original lock
   // with original recursion count
-  static intptr_t complete_exit(Handle obj, TRAPS);
-  static void reenter (Handle obj, intptr_t recursion, TRAPS);
+  static intx complete_exit(Handle obj, TRAPS);
+  static void reenter (Handle obj, intx recursions, TRAPS);
 
   // thread-specific and global ObjectMonitor free list accessors
   static ObjectMonitor* om_alloc(Thread* self);
@@ -209,8 +209,8 @@
   void wait_uninterruptibly(TRAPS) { ObjectSynchronizer::wait_uninterruptibly(_obj, 0, CHECK); }
   // complete_exit gives up lock completely, returning recursion count
   // reenter reclaims lock with original recursion count
-  intptr_t complete_exit(TRAPS)  { return ObjectSynchronizer::complete_exit(_obj, THREAD); }
-  void reenter(intptr_t recursion, TRAPS)  { ObjectSynchronizer::reenter(_obj, recursion, CHECK); }
+  intx complete_exit(TRAPS)  { return ObjectSynchronizer::complete_exit(_obj, THREAD); }
+  void reenter(intx recursions, TRAPS)  { ObjectSynchronizer::reenter(_obj, recursions, CHECK); }
 };
 
 #endif // SHARE_RUNTIME_SYNCHRONIZER_HPP
--- a/src/hotspot/share/runtime/threadSMR.cpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/threadSMR.cpp	Wed Nov 20 09:10:02 2019 -0500
@@ -601,8 +601,6 @@
 }
 
 void ThreadsList::dec_nested_handle_cnt() {
-  // The decrement only needs to be MO_ACQ_REL since the reference
-  // counter is volatile (and the hazard ptr is already NULL).
   Atomic::dec(&_nested_handle_cnt);
 }
 
@@ -646,8 +644,6 @@
 }
 
 void ThreadsList::inc_nested_handle_cnt() {
-  // The increment needs to be MO_SEQ_CST so that the reference counter
-  // update is seen before the subsequent hazard ptr update.
   Atomic::inc(&_nested_handle_cnt);
 }
 
--- a/src/hotspot/share/runtime/vmStructs.cpp	Wed Nov 20 10:37:46 2019 +0100
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Wed Nov 20 09:10:02 2019 -0500
@@ -911,7 +911,7 @@
   unchecked_nonstatic_field(ObjectMonitor,     _owner,                                        sizeof(void *)) /* NOTE: no type */    \
   volatile_nonstatic_field(ObjectMonitor,      _contentions,                                  jint)                                  \
   volatile_nonstatic_field(ObjectMonitor,      _waiters,                                      jint)                                  \
-  volatile_nonstatic_field(ObjectMonitor,      _recursions,                                   intptr_t)                              \
+  volatile_nonstatic_field(ObjectMonitor,      _recursions,                                   intx)                                  \
   nonstatic_field(ObjectMonitor,               _next_om,                                      ObjectMonitor*)                        \
   volatile_nonstatic_field(BasicLock,          _displaced_header,                             markWord)                              \
   nonstatic_field(BasicObjectLock,             _lock,                                         BasicLock)                             \