< 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"

*** 738,10 ***
--- 739,105 ---
        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::safe_load_mark(oop object) {
+   for (;;) {
+     const markWord mark = object->mark_acquire();
+ 
+     // 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
+     // *  INFLATING    - busy wait for conversion to complete
+     // *  Neutral      - 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: inflation in progress - inflating over a stack-lock.
+     // Some other thread is converting from stack-locked to inflated.
+     // Only that thread can complete inflation -- other threads must wait.
+     // The INFLATING value is transient.
+     // Currently, we spin/yield/park and poll the markword, waiting for inflation to finish.
+     // We could always eliminate polling by parking the thread on some auxiliary list.
+     if (mark == markWord::INFLATING()) {
+       read_stable_mark(object);
+       continue;
+     }
+ 
+     // CASE: stack-locked
+     // Could be stack-locked either by this thread or by some other thread.
+     if (mark.has_locker()) {
+       markWord cmp = object->cas_set_mark(markWord::INFLATING(), mark);
+       if (cmp != mark) {
+         continue;       // Interference -- just retry
+       }
+ 
+       // We've successfully installed INFLATING (0) into the mark-word.
+       // This is the only case where 0 will appear in a mark-word.
+       // Only the singular thread that successfully swings the mark-word
+       // to 0 can perform (or more precisely, complete) inflation.
+ 
+       // 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.
+       guarantee(object->mark() == markWord::INFLATING(), "invariant");
+       // Release semantics so that above set_object() is seen first.
+       object->release_set_mark(mark);
+ 
+       return dmw;
+     }
+ 
+     // CASE: neutral
+     // Catch if the object's header is not neutral (not locked and
+     // not marked is what we care about here).
+     assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
+     return mark;
+   }
+ }
+ 
+ markWord ObjectSynchronizer::stable_mark(const oop obj) {
+   markWord mark = read_stable_mark(obj);
+   if (!mark.is_neutral() && !mark.is_marked()) {
+     if (mark.has_monitor()) {
+       ObjectMonitor* monitor = mark.monitor();
+       mark = monitor->header();
+       assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
+     } else if (SafepointSynchronize::is_at_safepoint() || Thread::current()->is_lock_owned((address) mark.locker())) {
+       // This is a stack lock owned by the calling thread so fetch the
+       // displaced markWord from the BasicLock on the stack.
+       assert(mark.has_displaced_mark_helper(), "must be displaced header here");
+       mark = mark.displaced_mark_helper();
+       assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
+     } else {
+       mark = safe_load_mark(obj);
+       assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value());
+       assert(!mark.is_marked(), "no forwarded objects here");
+     }
+   }
+   return mark;
+ }
+ 
  // hashCode() generation :
  //
  // Possibilities:
  // * MD5Digest of {obj,stw_random}
  // * CRC32 of {obj,stw_random} or any linear-feedback shift register function.

*** 1350,10 ***
--- 1446,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()
  // by the VMThread.
  size_t ObjectSynchronizer::deflate_idle_monitors() {
    Thread* current = Thread::current();

*** 1402,12 ***
--- 1508,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 >