< 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

@@ -1637,11 +1637,11 @@
   set_callee_target(NULL);
   set_vm_result(NULL);
   set_vm_result_2(NULL);
   set_vframe_array_head(NULL);
   set_vframe_array_last(NULL);
-  set_deferred_locals(NULL);
+  set_deferred_updates(NULL);
   set_deopt_mark(NULL);
   set_deopt_compiled_method(NULL);
   set_monitor_chunks(NULL);
   _on_thread_list = false;
   _thread_state = _thread_new;

@@ -1864,21 +1864,21 @@
     old_array->set_unroll_block(NULL);
     delete old_info;
     delete old_array;
   }
 
-  GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred = deferred_locals();
+  GrowableArray<jvmtiDeferredLocalVariableSet*>* deferred = JvmtiDeferredUpdates::deferred_locals(this);
   if (deferred != NULL) {
     // This can only happen if thread is destroyed before deoptimization occurs.
     assert(deferred->length() != 0, "empty array!");
     do {
       jvmtiDeferredLocalVariableSet* dlv = deferred->at(0);
       deferred->remove_at(0);
       // individual jvmtiDeferredLocalVariableSet are CHeapObj's
       delete dlv;
     } while (deferred->length() != 0);
-    delete deferred;
+    delete deferred_updates();
   }
 
   // All Java related clean up happens in exit
   ThreadSafepointState::destroy(this);
   if (_thread_stat != NULL) delete _thread_stat;

@@ -2382,10 +2382,15 @@
   // so check for other async requests.
   if (check_asyncs) {
     check_and_handle_async_exceptions();
   }
 
+  if (is_obj_deopt_suspend()) {
+    frame_anchor()->make_walkable(this);
+    wait_for_object_deoptimization();
+  }
+
   JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(this);)
 }
 
 void JavaThread::send_thread_stop(oop java_throwable)  {
   ResourceMark rm;

@@ -2574,10 +2579,63 @@
   if (state != _thread_in_native) {
     SafepointMechanism::block_if_requested(this);
   }
 }
 
+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 (EscapeBarrier::deoptimizing_objects_for_all_threads() ||
+          (is_obj_deopt_suspend() && !should_spin_wait)) {
+        ml.wait();
+      }
+      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);
+
+    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.
 void JavaThread::verify_not_published() {
   // Cannot create a ThreadsListHandle here and check !tlh.includes(this)

@@ -2603,10 +2661,14 @@
     thread->java_suspend_self_with_safepoint_check();
   } else {
     SafepointMechanism::block_if_requested(thread);
   }
 
+  if (thread->is_obj_deopt_suspend()) {
+    thread->wait_for_object_deoptimization();
+  }
+
   JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(thread);)
 }
 
 // Slow path when the native==>VM/Java barriers detect a safepoint is in
 // progress or when _suspend_flags is non-zero.

@@ -2980,11 +3042,11 @@
   }
 
   assert(vframe_array_head() == NULL, "deopt in progress at a safepoint!");
   // If we have deferred set_locals there might be oops waiting to be
   // written
-  GrowableArray<jvmtiDeferredLocalVariableSet*>* list = deferred_locals();
+  GrowableArray<jvmtiDeferredLocalVariableSet*>* list = JvmtiDeferredUpdates::deferred_locals(this);
   if (list != NULL) {
     for (int i = 0; i < list->length(); i++) {
       list->at(i)->oops_do(f);
     }
   }

@@ -4542,10 +4604,13 @@
   // Maintain fast thread list
   ThreadsSMRSupport::add_thread(p);
 
   // Possible GC point.
   Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p));
+
+  // Make new thread known to active EscapeBarrier
+  EscapeBarrier::thread_added(p);
 }
 
 void Threads::remove(JavaThread* p, bool is_daemon) {
 
   // Reclaim the ObjectMonitors from the om_in_use_list and om_free_list of the moribund thread.

@@ -4575,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 >