< prev index next >

src/hotspot/share/runtime/thread.cpp

Print this page
rev 60137 : 8227745: Enable Escape Analysis for Better Performance in the Presence of JVMTI Agents
Reviewed-by: mdoerr, goetz
rev 60138 : 8227745: delta webrev.5 -> webrev.6

@@ -2382,11 +2382,11 @@
   // so check for other async requests.
   if (check_asyncs) {
     check_and_handle_async_exceptions();
   }
 
-  if (is_ea_obj_deopt_suspend()) {
+  if (is_obj_deopt_suspend()) {
     frame_anchor()->make_walkable(this);
     wait_for_object_deoptimization();
   }
 
   JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(this);)

@@ -2584,30 +2584,56 @@
 void JavaThread::wait_for_object_deoptimization() {
   assert(!has_last_Java_frame() || frame_anchor()->walkable(), "should have walkable stack");
   assert(this == Thread::current(), "invariant");
   JavaThreadState state = thread_state();
 
+  bool should_spin_wait = true;
   do {
     set_thread_state(_thread_blocked);
     set_suspend_equivalent();
+    {
     MonitorLocker ml(this, EscapeBarrier_lock, Monitor::_no_safepoint_check_flag);
-    if (is_ea_obj_deopt_suspend()) {
+      if (EscapeBarrier::deoptimizing_objects_for_all_threads() ||
+          (is_obj_deopt_suspend() && !should_spin_wait)) {
       ml.wait();
     }
-    if (handle_special_suspend_equivalent_condition()) {
-      MutexUnlocker mu(EscapeBarrier_lock, Monitor::_no_safepoint_check_flag);
-      java_suspend_self();
+      should_spin_wait = should_spin_wait && is_obj_deopt_suspend();
+    }
+    // Single deoptimization is typically very short. Microbenchmarks
+    // showed 5% better performance when spinning
+    if (should_spin_wait) {
+      // Inspired by HandshakeSpinYield
+      const jlong max_spin_time_ns = 100 /* us */ * (NANOUNITS / MICROUNITS);
+      const int free_cpus = os::active_processor_count() - 1;
+      jlong spin_time_ns = (5 /* us */ * (NANOUNITS / MICROUNITS)) * free_cpus; // zero on UP
+      spin_time_ns = spin_time_ns > max_spin_time_ns ? max_spin_time_ns : spin_time_ns;
+      jlong spin_start = os::javaTimeNanos();
+      while (is_obj_deopt_suspend()) {
+        os::naked_yield();
+        if ((os::javaTimeNanos() - spin_start) > spin_time_ns) {
+          should_spin_wait = false;
+          break;
+        }
+      }
     }
     set_thread_state_fence(state);
-  } while (is_ea_obj_deopt_suspend());
+
+    if (handle_special_suspend_equivalent_condition()) {
+      java_suspend_self_with_safepoint_check();
+    }
 
   // Since we are not using a regular thread-state transition helper here,
   // we must manually emit the instruction barrier after leaving a safe state.
   OrderAccess::cross_modify_fence();
   if (state != _thread_in_native) {
     SafepointMechanism::block_if_requested(this);
   }
+
+    // Check for another deopt suspend _after_ checking for safepont/handshake,
+    // or otherwise a stale value can be seen if the flag was changed with a
+    // handshake while the current thread was _thread_blocked above.
+  } while (is_obj_deopt_suspend());
 }
 
 #ifdef ASSERT
 // Verify the JavaThread has not yet been published in the Threads::list, and
 // hence doesn't need protection from concurrent access at this stage.

@@ -2635,11 +2661,11 @@
     thread->java_suspend_self_with_safepoint_check();
   } else {
     SafepointMechanism::block_if_requested(thread);
   }
 
-  if (thread->is_ea_obj_deopt_suspend()) {
+  if (thread->is_obj_deopt_suspend()) {
     thread->wait_for_object_deoptimization();
   }
 
   JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(thread);)
 }

@@ -4614,10 +4640,13 @@
     // Make sure that safepoint code disregard this thread. This is needed since
     // the thread might mess around with locks after this point. This can cause it
     // to do callbacks into the safepoint code. However, the safepoint code is not aware
     // of this thread since it is removed from the queue.
     p->set_terminated_value();
+
+    // Notify threads waiting in EscapeBarriers
+    EscapeBarrier::thread_removed(p);
   } // unlock Threads_lock
 
   // Since Events::log uses a lock, we grab it outside the Threads_lock
   Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p));
 }
< prev index next >