< prev index next >

src/hotspot/share/runtime/synchronizer.cpp

Print this page
@@ -23,10 +23,11 @@
   */
  
  #include "precompiled.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "jfr/jfrEvents.hpp"
+ #include "gc/shared/suspendibleThreadSet.hpp"
  #include "logging/log.hpp"
  #include "logging/logStream.hpp"
  #include "memory/allocation.inline.hpp"
  #include "memory/padded.hpp"
  #include "memory/resourceArea.hpp"

@@ -729,11 +730,11 @@
    DEFINE_PAD_MINUS_SIZE(2, OM_CACHE_LINE_SIZE, sizeof(volatile int));
  };
  
  static SharedGlobals GVars;
  
- static markWord read_stable_mark(oop obj) {
+ markWord ObjectSynchronizer::read_stable_mark(oop obj) {
    markWord mark = obj->mark_acquire();
    if (!mark.is_being_inflated()) {
      return mark;       // normal fast-path return
    }
  

@@ -789,10 +790,77 @@
        SpinPause();       // SMP-polite spinning
      }
    }
  }
  
+ // Safely load a mark word from an object, even with racing stack-locking or monitor inflation.
+ // The protocol is a partial inflation-protocol: it installs INFLATING into the object's mark
+ // word in order to prevent an stack-locks or inflations from interferring (or detect such
+ // interference and retry), but then, instead of creating and installing a monitor, simply
+ // read and return the real mark word.
+ markWord ObjectSynchronizer::stable_mark(oop object) {
+   for (;;) {
+     const markWord mark = read_stable_mark(object);
+     assert(!mark.is_being_inflated(), "read_stable_mark must prevent inflating mark");
+ 
+     // The mark can be in one of the following states:
+     // *  Inflated     - just return mark from inflated monitor
+     // *  Stack-locked - coerce it to inflating, and then return displaced mark
+     // *  Neutral      - return mark
+     // *  Marked       - return mark
+ 
+     // CASE: inflated
+     if (mark.has_monitor()) {
+       ObjectMonitor* inf = mark.monitor();
+       markWord dmw = inf->header();
+       assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
+       return dmw;
+     }
+ 
+     // CASE: stack-locked
+     // Could be stack-locked either by this thread or by some other thread.
+     if (mark.has_locker()) {
+       BasicLock* lock = mark.locker();
+       if (Thread::current()->is_lock_owned((address)lock)) {
+         // If locked by this thread, it is safe to access the displaced header.
+         markWord dmw = lock->displaced_header();
+         assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
+         return dmw;
+       }
+ 
+       // Otherwise, attempt to temporarily install INFLATING into the mark-word,
+       // to prevent inflation or unlocking by competing thread.
+       markWord cmp = object->cas_set_mark(markWord::INFLATING(), mark);
+       if (cmp != mark) {
+         continue;       // Interference -- just retry
+       }
+ 
+       // fetch the displaced mark from the owner's stack.
+       // The owner can't die or unwind past the lock while our INFLATING
+       // object is in the mark.  Furthermore the owner can't complete
+       // an unlock on the object, either.
+       markWord dmw = mark.displaced_mark_helper();
+       // Catch if the object's header is not neutral (not locked and
+       // not marked is what we care about here).
+       assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value());
+ 
+       // Must preserve store ordering. The monitor state must
+       // be stable at the time of publishing the monitor address.
+       assert(object->mark() == markWord::INFLATING(), "invariant");
+       // Release semantics so that above set_object() is seen first.
+       object->release_set_mark(mark);
+ 
+       return dmw;
+     }
+ 
+     // CASE: neutral or marked (for GC)
+     // Catch if the object's header is not neutral or marked (it must not be locked).
+     assert(mark.is_neutral() || mark.is_marked(), "invariant: header=" INTPTR_FORMAT, mark.value());
+     return mark;
+   }
+ }
+ 
  // hashCode() generation :
  //
  // Possibilities:
  // * MD5Digest of {obj,stw_random}
  // * CRC32 of {obj,stw_random} or any linear-feedback shift register function.

@@ -1457,10 +1525,20 @@
      log_trace(monitorinflation)("HandshakeForDeflation::do_thread: thread="
                                  INTPTR_FORMAT, p2i(thread));
    }
  };
  
+ class VM_RendezvousGCThreads : public VM_Operation {
+ public:
+   bool evaluate_at_safepoint() const override { return false; }
+   VMOp_Type type() const override { return VMOp_RendezvousGCThreads; }
+   void doit() override {
+     SuspendibleThreadSet::synchronize();
+     SuspendibleThreadSet::desynchronize();
+   };
+ };
+ 
  // This function is called by the MonitorDeflationThread to deflate
  // ObjectMonitors. It is also called via do_final_audit_and_print_stats()
  // and VM_ThreadDump::doit() by the VMThread.
  size_t ObjectSynchronizer::deflate_idle_monitors(ObjectMonitorsHashtable* table) {
    Thread* current = Thread::current();

@@ -1509,12 +1587,17 @@
                       _in_use_list.count(), _in_use_list.max());
        }
  
        // A JavaThread needs to handshake in order to safely free the
        // ObjectMonitors that were deflated in this cycle.
+       // Also, we sync and desync GC threads around the handshake, so that they can
+       // safely read the mark-word and look-through to the object-monitor, without
+       // being afraid that the object-monitor is going away.
        HandshakeForDeflation hfd_hc;
        Handshake::execute(&hfd_hc);
+       VM_RendezvousGCThreads sync_gc;
+       VMThread::execute(&sync_gc);
  
        if (ls != NULL) {
          ls->print_cr("after handshaking: in_use_list stats: ceiling="
                       SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT,
                       in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max());
< prev index next >