diff a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp
--- a/src/hotspot/share/runtime/synchronizer.cpp
+++ b/src/hotspot/share/runtime/synchronizer.cpp
@@ -349,11 +349,11 @@
   }
 
   if (mark.has_monitor()) {
     ObjectMonitor* const mon = mark.monitor();
     assert(mon->object() == oop(obj), "invariant");
-    if (mon->owner() != current) return false;  // slow-path for IMS exception
+    if (!mon->is_owner(current)) return false;  // slow-path for IMS exception
 
     if (mon->first_waiter() != nullptr) {
       // We have one or more waiters. Since this is an inflated monitor
       // that we own, we can transfer one or more threads from the waitset
       // to the entrylist here and now, avoiding the slow-path.
@@ -399,11 +399,11 @@
       // Always go into runtime if the lock stack is full.
       return false;
     }
     if (lock_stack.try_recursive_enter(obj)) {
       // Recursive lock successful.
-      current->inc_held_monitor_count();
+      NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
       return true;
     }
   }
 
   const markWord mark = obj->mark();
@@ -414,20 +414,19 @@
     // the ObjectMonitor busy by setting the owner below. If we detect
     // that race we just bail out to the slow-path here.
     if (m->object_peek() == nullptr) {
       return false;
     }
-    JavaThread* const owner = static_cast<JavaThread*>(m->owner_raw());
 
     // Lock contention and Transactional Lock Elision (TLE) diagnostics
     // and observability
     // Case: light contention possibly amenable to TLE
     // Case: TLE inimical operations such as nested/recursive synchronization
 
-    if (owner == current) {
+    if (m->is_owner(current)) {
       m->_recursions++;
-      current->inc_held_monitor_count();
+      NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
       return true;
     }
 
     if (LockingMode != LM_LIGHTWEIGHT) {
       // This Java Monitor is inflated so obj's header will never be
@@ -440,13 +439,13 @@
       // recursive stack-locking in the displaced header in the BasicLock,
       // and last are the inflated Java Monitor (ObjectMonitor) checks.
       lock->set_displaced_header(markWord::unused_mark());
     }
 
-    if (owner == nullptr && m->try_set_owner_from(nullptr, current) == nullptr) {
+    if (!m->has_owner() && m->try_set_owner_from(nullptr, current) == nullptr) {
       assert(m->_recursions == 0, "invariant");
-      current->inc_held_monitor_count();
+      NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
       return true;
     }
   }
 
   // Note that we could inflate in quick_enter.
@@ -522,10 +521,13 @@
 void ObjectSynchronizer::enter_for(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
   // When called with locking_thread != Thread::current() some mechanism must synchronize
   // the locking_thread with respect to the current thread. Currently only used when
   // deoptimizing and re-locking locks. See Deoptimization::relock_objects
   assert(locking_thread == Thread::current() || locking_thread->is_obj_deopt_suspend(), "must be");
+
+  NOT_LOOM_MONITOR_SUPPORT(locking_thread->inc_held_monitor_count();)
+
   if (!enter_fast_impl(obj, lock, locking_thread)) {
     // Inflated ObjectMonitor::enter_for is required
 
     // An async deflation can race after the inflate_for() call and before
     // enter_for() can make the ObjectMonitor busy. enter_for() returns false
@@ -540,10 +542,13 @@
   }
 }
 
 void ObjectSynchronizer::enter(Handle obj, BasicLock* lock, JavaThread* current) {
   assert(current == Thread::current(), "must be");
+
+  NOT_LOOM_MONITOR_SUPPORT(current->inc_held_monitor_count();)
+
   if (!enter_fast_impl(obj, lock, current)) {
     // Inflated ObjectMonitor::enter is required
 
     // An async deflation can race after the inflate() call and before
     // enter() can make the ObjectMonitor busy. enter() returns false if
@@ -559,17 +564,14 @@
 
 // The interpreter and compiler assembly code tries to lock using the fast path
 // of this algorithm. Make sure to update that code if the following function is
 // changed. The implementation is extremely sensitive to race condition. Be careful.
 bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread* locking_thread) {
-
   if (obj->klass()->is_value_based()) {
     handle_sync_on_value_based_class(obj, locking_thread);
   }
 
-  locking_thread->inc_held_monitor_count();
-
   if (!useHeavyMonitors()) {
     if (LockingMode == LM_LIGHTWEIGHT) {
       // Fast-locking does not use the 'lock' argument.
       LockStack& lock_stack = locking_thread->lock_stack();
       if (lock_stack.is_full()) {
@@ -594,11 +596,11 @@
         // The least recently locked lock is chosen as it is the lock
         // with the longest critical section.
 
         log_info(monitorinflation)("LockStack capacity exceeded, inflating.");
         ObjectMonitor* monitor = inflate_for(locking_thread, lock_stack.bottom(), inflate_cause_vm_internal);
-        assert(monitor->owner() == Thread::current(), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT,
+        assert(monitor->is_owner(JavaThread::current()), "must be owner=" PTR_FORMAT " current=" PTR_FORMAT " mark=" PTR_FORMAT,
                p2i(monitor->owner()), p2i(Thread::current()), monitor->object()->mark_acquire().value());
         assert(!lock_stack.is_full(), "must have made room here");
       }
 
       markWord mark = obj()->mark_acquire();
@@ -628,10 +630,11 @@
       if (mark.is_unlocked()) {
         // Anticipate successful CAS -- the ST of the displaced mark must
         // be visible <= the ST performed by the CAS.
         lock->set_displaced_header(mark);
         if (mark == obj()->cas_set_mark(markWord::from_pointer(lock), mark)) {
+          LOOM_MONITOR_SUPPORT_ONLY(locking_thread->inc_held_monitor_count();)
           return true;
         }
       } else if (mark.has_locker() &&
                  locking_thread->is_lock_owned((address) mark.locker())) {
         assert(lock != mark.locker(), "must not re-lock the same lock");
@@ -655,11 +658,11 @@
 
   return false;
 }
 
 void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) {
-  current->dec_held_monitor_count();
+  NOT_LOOM_MONITOR_SUPPORT(current->dec_held_monitor_count();)
 
   if (!useHeavyMonitors()) {
     markWord mark = object->mark();
     if (LockingMode == LM_LIGHTWEIGHT) {
       // Fast-locking does not use the 'lock' argument.
@@ -720,10 +723,11 @@
       if (mark == markWord::from_pointer(lock)) {
         // If the object is stack-locked by the current thread, try to
         // swing the displaced header from the BasicLock back to the mark.
         assert(dhw.is_neutral(), "invariant");
         if (object->cas_set_mark(dhw, mark) == mark) {
+          LOOM_MONITOR_SUPPORT_ONLY(current->dec_held_monitor_count();)
           return;
         }
       }
     }
   } else if (VerifyHeavyMonitors) {
@@ -781,18 +785,20 @@
 // Internal VM locks on java objects
 // standard constructor, allows locking failures
 ObjectLocker::ObjectLocker(Handle obj, JavaThread* thread) {
   _thread = thread;
   _thread->check_for_valid_safepoint_state();
+  DEBUG_ONLY(_thread->inc_obj_locker_count();)
   _obj = obj;
 
   if (_obj() != nullptr) {
     ObjectSynchronizer::enter(_obj, &_lock, _thread);
   }
 }
 
 ObjectLocker::~ObjectLocker() {
+  DEBUG_ONLY(_thread->dec_obj_locker_count();)
   if (_obj() != nullptr) {
     ObjectSynchronizer::exit(_obj(), &_lock, _thread);
   }
 }
 
@@ -1148,11 +1154,11 @@
   markWord mark = read_stable_mark(obj);
 
   if (LockingMode == LM_LEGACY && mark.has_locker()) {
     // stack-locked so header points into owner's stack.
     // owning_thread_from_monitor_owner() may also return null here:
-    return Threads::owning_thread_from_monitor_owner(t_list, (address) mark.locker());
+    return Threads::owning_thread_from_stacklock(t_list, (address) mark.locker());
   }
 
   if (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked()) {
     // fast-locked so get owner from the object.
     // owning_thread_from_object() may also return null here:
@@ -1198,28 +1204,28 @@
     // target thread is suspended or when the target thread is
     // operating on itself. The current closures in use today are
     // only interested in an owned ObjectMonitor and ownership
     // cannot be dropped under the calling contexts so the
     // ObjectMonitor cannot be async deflated.
-    if (monitor->has_owner() && filter(monitor->owner_raw())) {
+    if (monitor->has_owner() && filter(monitor)) {
       assert(!monitor->is_being_async_deflated(), "Owned monitors should not be deflating");
 
       closure->do_monitor(monitor);
     }
   });
 }
 
 // Iterate ObjectMonitors where the owner == thread; this does NOT include
 // ObjectMonitors where owner is set to a stack-lock address in thread.
 void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure, JavaThread* thread) {
-  auto thread_filter = [&](void* owner) { return owner == thread; };
+  auto thread_filter = [&](ObjectMonitor* monitor) { return monitor->is_owner(thread); };
   return owned_monitors_iterate_filtered(closure, thread_filter);
 }
 
 // Iterate ObjectMonitors owned by any thread.
 void ObjectSynchronizer::owned_monitors_iterate(MonitorClosure* closure) {
-  auto all_filter = [&](void* owner) { return true; };
+  auto all_filter = [&](ObjectMonitor* monitor) { return true; };
   return owned_monitors_iterate_filtered(closure, all_filter);
 }
 
 static bool monitors_used_above_threshold(MonitorList* list) {
   if (MonitorUsedDeflationThreshold == 0) {  // disabled case is easy
@@ -1385,41 +1391,35 @@
   (void)inflate(Thread::current(), obj, inflate_cause_vm_internal);
 }
 
 ObjectMonitor* ObjectSynchronizer::inflate(Thread* current, oop obj, const InflateCause cause) {
   assert(current == Thread::current(), "must be");
-  if (LockingMode == LM_LIGHTWEIGHT && current->is_Java_thread()) {
-    return inflate_impl(JavaThread::cast(current), obj, cause);
-  }
-  return inflate_impl(nullptr, obj, cause);
+  return inflate_impl(current->is_Java_thread() ? JavaThread::cast(current) : nullptr, obj, cause);
 }
 
 ObjectMonitor* ObjectSynchronizer::inflate_for(JavaThread* thread, oop obj, const InflateCause cause) {
   assert(thread == Thread::current() || thread->is_obj_deopt_suspend(), "must be");
   return inflate_impl(thread, obj, cause);
 }
 
 ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oop object, const InflateCause cause) {
-  // The JavaThread* inflating_thread parameter is only used by LM_LIGHTWEIGHT and requires
-  // that the inflating_thread == Thread::current() or is suspended throughout the call by
-  // some other mechanism.
-  // Even with LM_LIGHTWEIGHT the thread might be nullptr when called from a non
-  // JavaThread. (As may still be the case from FastHashCode). However it is only
-  // important for the correctness of the LM_LIGHTWEIGHT algorithm that the thread
-  // is set when called from ObjectSynchronizer::enter from the owning thread,
+  // The JavaThread* inflating_thread requires that the inflating_thread == Thread::current() or
+  // is suspended throughout the call by some other mechanism.
+  // The thread might be nullptr when called from a non JavaThread. (As may still be
+  // the case from FastHashCode). However it is only important for correctness that the
+  // thread is set when called from ObjectSynchronizer::enter from the owning thread,
   // ObjectSynchronizer::enter_for from any thread, or ObjectSynchronizer::exit.
   EventJavaMonitorInflate event;
 
   for (;;) {
     const markWord mark = object->mark_acquire();
 
     // The mark can be in one of the following states:
-    // *  inflated     - Just return if using stack-locking.
-    //                   If using fast-locking and the ObjectMonitor owner
-    //                   is anonymous and the inflating_thread owns the
-    //                   object lock, then we make the inflating_thread
-    //                   the ObjectMonitor owner and remove the lock from
+    // *  inflated     - If the ObjectMonitor owner is anonymous and the
+    //                   inflating_thread owns the object lock, then we
+    //                   make the inflating_thread the ObjectMonitor owner.
+    //                   For LM_LIGHTWEIGHT we also remove the lock from
     //                   the inflating_thread's lock stack.
     // *  fast-locked  - Coerce it to inflated from fast-locked.
     // *  stack-locked - Coerce it to inflated from stack-locked.
     // *  INFLATING    - Busy wait for conversion from stack-locked to
     //                   inflated.
@@ -1428,15 +1428,25 @@
     // CASE: inflated
     if (mark.has_monitor()) {
       ObjectMonitor* inf = mark.monitor();
       markWord dmw = inf->header();
       assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
-      if (LockingMode == LM_LIGHTWEIGHT && inf->is_owner_anonymous() &&
-          inflating_thread != nullptr && inflating_thread->lock_stack().contains(object)) {
-        inf->set_owner_from_anonymous(inflating_thread);
-        size_t removed = inflating_thread->lock_stack().remove(object);
-        inf->set_recursions(removed - 1);
+      if (inf->is_owner_anonymous() && inflating_thread != nullptr) {
+        if (LockingMode == LM_LIGHTWEIGHT) {
+          if (inflating_thread->lock_stack().contains(object)) {
+            inf->set_owner_from_anonymous(inflating_thread);
+            size_t removed = inflating_thread->lock_stack().remove(object);
+            inf->set_recursions(removed - 1);
+          }
+        } else {
+          assert(LockingMode == LM_LEGACY, "invariant");
+          if (inflating_thread->is_lock_owned((address)inf->stack_locker())) {
+            inf->set_owner_from_BasicLock(inflating_thread);
+            // Decrement monitor count now since this monitor is okay for freezing
+            LOOM_MONITOR_SUPPORT_ONLY(inflating_thread->dec_held_monitor_count();)
+          }
+        }
       }
       return inf;
     }
 
     if (LockingMode != LM_LIGHTWEIGHT) {
@@ -1566,16 +1576,23 @@
       assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
 
       // Setup monitor fields to proper values -- prepare the monitor
       m->set_header(dmw);
 
-      // Optimization: if the mark.locker stack address is associated
-      // with this thread we could simply set m->_owner = current.
       // Note that a thread can inflate an object
       // that it has stack-locked -- as might happen in wait() -- directly
       // with CAS.  That is, we can avoid the xchg-nullptr .... ST idiom.
-      m->set_owner_from(nullptr, mark.locker());
+      if (inflating_thread != nullptr && inflating_thread->is_lock_owned((address)mark.locker())) {
+        m->set_owner_from(nullptr, inflating_thread);
+        // Decrement monitor count now since this monitor is okay for freezing
+        LOOM_MONITOR_SUPPORT_ONLY(inflating_thread->dec_held_monitor_count();)
+      } else {
+        // Use ANONYMOUS_OWNER to indicate that the owner is the BasicLock on the stack,
+        // and set the stack locker field in the monitor.
+        m->set_stack_locker(mark.locker());
+        m->set_owner_anonymous();  // second
+      }
       // TODO-FIXME: assert BasicLock->dhw != 0.
 
       // Must preserve store ordering. The monitor state must
       // be stable at the time of publishing the monitor address.
       guarantee(object->mark() == markWord::INFLATING(), "invariant");
@@ -1869,11 +1886,11 @@
 
  public:
   ReleaseJavaMonitorsClosure(JavaThread* thread) : _thread(thread) {}
   void do_monitor(ObjectMonitor* mid) {
     intx rec = mid->complete_exit(_thread);
-    _thread->dec_held_monitor_count(rec + 1);
+    _thread->dec_held_monitor_count(NOT_LOOM_MONITOR_SUPPORT((rec + 1)));
   }
 };
 
 // Release all inflated monitors owned by current thread.  Lightweight monitors are
 // ignored.  This is meant to be called during JNI thread detach which assumes
@@ -1909,10 +1926,11 @@
     case inflate_cause_wait:           return "Monitor Wait";
     case inflate_cause_notify:         return "Monitor Notify";
     case inflate_cause_hash_code:      return "Monitor Hash Code";
     case inflate_cause_jni_enter:      return "JNI Monitor Enter";
     case inflate_cause_jni_exit:       return "JNI Monitor Exit";
+    case inflate_cause_cont_freeze:    return "Continuation Freeze";
     default:
       ShouldNotReachHere();
   }
   return "Unknown";
 }
