src/share/vm/runtime/synchronizer.cpp

Print this page

        

@@ -82,10 +82,12 @@
       HOTSPOT_MONITOR_WAIT(jtid,                                           \
                            (uintptr_t)(monitor), bytes, len, (millis));    \
     }                                                                      \
   }
 
+#define HOTSPOT_MONITOR_PROBE_notify HOTSPOT_MONITOR_NOTIFY
+#define HOTSPOT_MONITOR_PROBE_notifyAll HOTSPOT_MONITOR_NOTIFYALL
 #define HOTSPOT_MONITOR_PROBE_waited HOTSPOT_MONITOR_WAITED
 
 #define DTRACE_MONITOR_PROBE(probe, monitor, obj, thread)                  \
   {                                                                        \
     if (DTraceMonitorProbes) {                                             \

@@ -142,11 +144,66 @@
 // returns false -- to indicate the call needs the services of the slow-path.
 // A no-loitering ordinance is in effect for code in the quick_* family
 // operators: safepoints or indefinite blocking (blocking that might span a
 // safepoint) are forbidden. Generally the thread_state() is _in_Java upon
 // entry.
+//
+// An interesting optimization is to have the JIT recognize the following
+// common idiom:
+//   synchronized (someobj) { .... ; notify(); }
+// That is, we find a notify() or notifyAll() call that immediately precedes
+// the monitorexit operation.  In that case the JIT could fuse the operations
+// into a single notifyAndExit() runtime primitive.
 
+bool ObjectSynchronizer::quick_notify(oopDesc * obj, Thread * Self, bool All) {
+  assert(!SafepointSynchronize::is_at_safepoint(), "invariant");
+  assert(Self->is_Java_thread(), "invariant");
+  assert(((JavaThread *) Self)->thread_state() == _thread_in_Java, "invariant");
+  No_Safepoint_Verifier nsv;
+  if (obj == NULL) return false;
+  const markOop mark = obj->mark();
+
+  if (mark->has_locker() && Self->is_lock_owned((address)mark->locker())) {
+    // Degenerate notify
+    // stack-locked by caller so by definition the implied waitset is empty.
+    return true;
+  }
+
+  if (mark->has_monitor()) {
+    ObjectMonitor * const mon = mark->monitor();
+    assert(mon->object() == obj, "invariant");
+    if (mon->owner() != Self) return false;
+
+    // As long as the object is unbiased and doesn't require safepoint revocation
+    // and is owned by the caller we can transfer a thread or threads from
+    // the waitset to the entrylist here and now, avoiding the slow-path.
+    // That is, the only case where the slow-path is mandatory is
+    // when the object is biased or we need to throw IMSX exceptions.
+    if (mon->first_waiter() != NULL) {
+      if (All) {
+        DTRACE_MONITOR_PROBE(notifyAll, mon, obj, Self);
+      } else {
+        DTRACE_MONITOR_PROBE(notify, mon, obj, Self);
+      }
+      int tally = 0;
+      for (;;) {
+        if (mon->first_waiter() == NULL) break;
+        mon->INotify(Self);
+        ++tally;
+        if (!All) break;
+      }
+      if (ObjectMonitor::_sync_Notifications != NULL) {
+        ObjectMonitor::_sync_Notifications->inc(tally);
+      }
+    }
+    return true;
+  }
+
+  return false;  // revert to slow-path
+}
+
+
 // The LockNode emitted directly at the synchronization site would have
 // been too big if it were to have included support for the cases of inflated
 // recursive enter and exit, so they go here instead.
 // Note that we can't safely call AsyncPrintJavaStack() from within
 // quick_enter() as our thread state remains _in_Java.