< prev index next >

src/hotspot/share/runtime/deoptimization.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

@@ -283,23 +283,25 @@
   JavaThread* deoptee_thread = chunk->at(0)->thread();
   CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null();
   RegisterMap map(chunk->at(0)->register_map());
   bool deoptimized_objects = false;
 
-  // Reallocate the non-escaping objects and restore their fields. Then
-  // relock objects if synchronization on them was eliminated.
-  if (DoEscapeAnalysis && EliminateAllocations) {
+  bool const jvmci_enabled = JVMCI_ONLY(UseJVMCICompiler) NOT_JVMCI(false);
+
+  // Reallocate the non-escaping objects and restore their fields.
+  if (jvmci_enabled COMPILER2_PRESENT(|| (DoEscapeAnalysis && EliminateAllocations))) {
     realloc_failures = eliminate_allocations(thread, Unpack_none, cm, deoptee, map, chunk, deoptimized_objects);
   }
 
   // Revoke biases of objects with eliminated locks in the given frame.
   Deoptimization::revoke_for_object_deoptimization(deoptee_thread, deoptee, &map, thread);
 
   // MonitorInfo structures used in eliminate_locks are not GC safe.
   NoSafepointVerifier no_safepoint;
 
-  if ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateLocks) {
+  // Now relock objects if synchronization on them was eliminated.
+  if (jvmci_enabled COMPILER2_PRESENT(|| ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateLocks))) {
     eliminate_locks(thread, chunk, realloc_failures, deoptee, Unpack_none, deoptimized_objects);
   }
   return deoptimized_objects;
 }
 #endif // COMPILER2_OR_JVMCI

@@ -1637,14 +1639,14 @@
 
   int len = objects_to_revoke->length();
   for (int i = 0; i < len; i++) {
     oop obj = (objects_to_revoke->at(i))();
     markWord mark = obj->mark();
-    if (!mark.has_bias_pattern()
-        || mark.is_biased_anonymously() // eliminated locking does not bias an object if it wasn't before
-        || !obj->klass()->prototype_header().has_bias_pattern() // bulk revoke ignores eliminated monitors
-        || (obj->klass()->prototype_header().bias_epoch() != mark.bias_epoch())) { // bulk rebias ignores eliminated monitors
+    if (!mark.has_bias_pattern() ||
+        mark.is_biased_anonymously() || // eliminated locking does not bias an object if it wasn't before
+        !obj->klass()->prototype_header().has_bias_pattern() || // bulk revoke ignores eliminated monitors
+        (obj->klass()->prototype_header().bias_epoch() != mark.bias_epoch())) { // bulk rebias ignores eliminated monitors
       // We reach here regularly if there's just eliminated locking on obj.
       // We must not call BiasedLocking::revoke_own_lock() in this case, as we would hit assertions, because it is a
       // prerequisite that there has to be non-eliminated locking on obj by deoptee_thread.
       // Luckily we don't have to revoke here, because obj has to be a  non-escaping obj and can be relocked without
       // revoking the bias. See Deoptimization::relock_objects().

@@ -2705,47 +2707,10 @@
     #undef PRINT_STAT_LINE
     if (xtty != NULL)  xtty->tail("statistics");
   }
 }
 
-#ifdef ASSERT
-// Revert optimizations based on escape analysis.
-void Deoptimization::deoptimize_objects_alot_loop() {
-  JavaThread* ct = JavaThread::current();
-  HandleMark hm(ct);
-  if (DeoptimizeObjectsALotThreadCount == 1) {
-    // Revert everything at once
-    while (!ct->is_terminated()) {
-      { // Begin new scope for escape barrier
-        HandleMarkCleaner hmc(ct);
-        ResourceMark rm(ct);
-        EscapeBarrier eb(ct, true);
-        eb.deoptimize_objects_all_threads();
-      }
-      // Now sleep after the escape barriers destructor resumed the java threads.
-      ct->sleep(DeoptimizeObjectsALotInterval);
-    }
-  } else {
-    // Revert everything for one deoptee_thread which gets selected round robin
-    JavaThread* deoptee_thread = NULL;
-    while (!ct->is_terminated()) {
-      { // Begin new scope for escape barrier
-        HandleMarkCleaner hmc(ct);
-        ResourceMark rm(ct);
-        ThreadsListHandle tlh;
-        int idx = (1 + tlh.list()->find_index_of_JavaThread(deoptee_thread)) % tlh.list()->length();
-        deoptee_thread = tlh.list()->thread_at(idx);
-        EscapeBarrier eb(ct, deoptee_thread, true);
-        eb.deoptimize_objects(100);
-      }
-      // Now sleep after the escape barriers destructor resumed deoptee_thread.
-      ct->sleep(DeoptimizeObjectsALotInterval);
-    }
-  }
-}
-#endif // !ASSERT
-
 // Returns true iff objects were reallocated and relocked because of access through JVMTI
 bool EscapeBarrier::objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) {
   // first/oldest update holds the flag
   GrowableArray<jvmtiDeferredLocalVariableSet*>* list = JvmtiDeferredUpdates::deferred_locals(thread);
   bool result = false;

@@ -2758,14 +2723,18 @@
     }
   }
   return result;
 }
 
-// Deoptimize frames with non escaping objects. Deoptimize objects with optimizations based on
-// escape analysis. Do it for all frames within the given depth and continue from there until the
-// entry frame is reached, because thread local objects passed as arguments might escape from callee
-// frames within the given depth.
+// Object references of frames up to the given depth are about to be accessed. Frames with
+// optimizations based on escape state that is potentially changed by the accesses need to be
+// deoptimized and the referenced objects need to be reallocated and relocked.
+// Up to depth this is done for frames with not escaping objects in scope. For deeper frames it is
+// done only, if they pass not escaping objects as arguments, because they potentially escape from
+// callee frames within the given depth.
+// The search for deeper frames is ended if an entry frame is found, because arguments to
+// native methods are considered to escape globally.
 bool EscapeBarrier::deoptimize_objects(int depth) {
   if (barrier_active() && deoptee_thread()->has_last_Java_frame()) {
     ResourceMark rm(calling_thread());
     HandleMark   hm;
     RegisterMap  reg_map(deoptee_thread());

@@ -2779,17 +2748,19 @@
         bool should_deopt = cur_depth <= depth ? cvf->not_global_escape_in_scope() : cvf->arg_escape();
         if (should_deopt && !deoptimize_objects(cvf->fr().id())) {
           // reallocation of scalar replaced objects failed, because heap is exhausted
           return false;
         }
-      }
 
-      // move to next physical frame
+        // move to top frame
       while(!vf->is_top()) {
         cur_depth++;
         vf = vf->sender();
       }
+      }
+
+      // move to next physical frame
       cur_depth++;
       vf = vf->sender();
     }
   }
   return true;

@@ -2810,15 +2781,16 @@
           compiledVFrame* cvf = compiledVFrame::cast(vf);
           if ((cvf->not_global_escape_in_scope() || cvf->arg_escape()) &&
               !deoptimize_objects_internal(jt, cvf->fr().id())) {
             return false; // reallocation failure
           }
-        }
-        // move to next physical frame
+          // move to top frame
         while(!vf->is_top()) {
           vf = vf->sender();
         }
+        }
+        // move to next physical frame
         vf = vf->sender();
       }
     }
   }
   return true; // success

@@ -2831,11 +2803,11 @@
   JavaThread* _excluded_thread;
  public:
   EscapeBarrierSuspendHandshake(JavaThread* excluded_thread, const char* name) : HandshakeClosure(name), _excluded_thread(excluded_thread) { }
   void do_thread(Thread* th) {
     if (th->is_Java_thread() && !th->is_hidden_from_external_view() && (th != _excluded_thread)) {
-      th->set_ea_obj_deopt_flag();
+      th->set_obj_deopt_flag();
     }
   }
 };
 
 void EscapeBarrier::sync_and_suspend_one() {

@@ -2846,29 +2818,26 @@
   // Sync with other threads that might be doing deoptimizations
   {
     // Need to switch to _thread_blocked for the wait() call
     ThreadBlockInVM tbivm(_calling_thread);
     MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);
-    while (_self_deoptimization_in_progress || _deoptee_thread->is_ea_obj_deopt_suspend()) {
+    while (_self_deoptimization_in_progress || _deoptee_thread->is_obj_deopt_suspend()) {
       ml.wait();
     }
 
     if (self_deopt()) {
       _self_deoptimization_in_progress = true;
       return;
     }
 
     // set suspend flag for target thread
-    _deoptee_thread->set_ea_obj_deopt_flag();
+    _deoptee_thread->set_obj_deopt_flag();
   }
 
   // suspend target thread
-  uint32_t debug_bits = 0;
-  if (!_deoptee_thread->is_thread_fully_suspended(false, &debug_bits)) {
     EscapeBarrierSuspendHandshake sh(NULL, "EscapeBarrierSuspendOne");
-    Handshake::execute(&sh, _deoptee_thread);
-  }
+  Handshake::execute_direct(&sh, _deoptee_thread);
   assert(!_deoptee_thread->has_last_Java_frame() || _deoptee_thread->frame_anchor()->walkable(),
          "stack should be walkable now");
 }
 
 void EscapeBarrier::sync_and_suspend_all() {

@@ -2884,11 +2853,11 @@
 
     bool deopt_in_progress;
     do {
       deopt_in_progress = _self_deoptimization_in_progress;
       for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
-        deopt_in_progress = (deopt_in_progress || jt->is_ea_obj_deopt_suspend());
+        deopt_in_progress = (deopt_in_progress || jt->is_obj_deopt_suspend());
         if (deopt_in_progress) {
           break;
         }
       }
       if (deopt_in_progress) {

@@ -2918,11 +2887,11 @@
   MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);
   if (self_deopt()) {
     assert(_self_deoptimization_in_progress, "incorrect synchronization");
     _self_deoptimization_in_progress = false;
   } else {
-    _deoptee_thread->clear_ea_obj_deopt_flag();
+    _deoptee_thread->clear_obj_deopt_flag();
   }
   ml.notify_all();
 }
 
 void EscapeBarrier::resume_all() {

@@ -2931,23 +2900,31 @@
   MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);
   assert(_self_deoptimization_in_progress, "incorrect synchronization");
   _deoptimizing_objects_for_all_threads = false;
   _self_deoptimization_in_progress = false;
   for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
-    jt->clear_ea_obj_deopt_flag();
+    jt->clear_obj_deopt_flag();
   }
   ml.notify_all();
 }
 
 void EscapeBarrier::thread_added(JavaThread* jt) {
   if (!jt->is_hidden_from_external_view()) {
     MutexLocker ml(EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);
     if (_deoptimizing_objects_for_all_threads) {
-      jt->set_ea_obj_deopt_flag();
-    } else {
-      jt->clear_ea_obj_deopt_flag();
+      jt->set_obj_deopt_flag();
+    }
     }
+}
+
+void EscapeBarrier::thread_removed(JavaThread* jt) {
+  MonitorLocker ml(EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);
+  if (jt->is_obj_deopt_suspend()) {
+    // jt terminated before it self suspended.
+    // Other threads might be waiting to perform deoptimizations for it.
+    jt->clear_obj_deopt_flag();
+    ml.notify_all();
   }
 }
 
 // Remember that objects were reallocated and relocked for the compiled frame with the given id
 static void set_objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) {
< prev index next >