< prev index next >

src/hotspot/share/runtime/deoptimization.cpp

Print this page
rev 56251 : imported patch 8226705-v1
rev 56253 : [mq]: 8226705-v3-pat

@@ -155,61 +155,16 @@
   thread->inc_in_deopt_handler();
 
   return fetch_unroll_info_helper(thread, exec_mode);
 JRT_END
 
-
-// This is factored, since it is both called from a JRT_LEAF (deoptimization) and a JRT_ENTRY (uncommon_trap)
-Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread, int exec_mode) {
-
-  // Note: there is a safepoint safety issue here. No matter whether we enter
-  // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once
-  // the vframeArray is created.
-  //
-
-  // Allocate our special deoptimization ResourceMark
-  DeoptResourceMark* dmark = new DeoptResourceMark(thread);
-  assert(thread->deopt_mark() == NULL, "Pending deopt!");
-  thread->set_deopt_mark(dmark);
-
-  frame stub_frame = thread->last_frame(); // Makes stack walkable as side effect
-  RegisterMap map(thread, true);
-  RegisterMap dummy_map(thread, false);
-  // Now get the deoptee with a valid map
-  frame deoptee = stub_frame.sender(&map);
-  // Set the deoptee nmethod
-  assert(thread->deopt_compiled_method() == NULL, "Pending deopt!");
-  CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null();
-  thread->set_deopt_compiled_method(cm);
-
-  if (VerifyStack) {
-    thread->validate_frame_layout();
-  }
-
-  // Create a growable array of VFrames where each VFrame represents an inlined
-  // Java frame.  This storage is allocated with the usual system arena.
-  assert(deoptee.is_compiled_frame(), "Wrong frame type");
-  GrowableArray<compiledVFrame*>* chunk = new GrowableArray<compiledVFrame*>(10);
-  vframe* vf = vframe::new_vframe(&deoptee, &map, thread);
-  while (!vf->is_top()) {
-    assert(vf->is_compiled_frame(), "Wrong frame type");
-    chunk->push(compiledVFrame::cast(vf));
-    vf = vf->sender();
-  }
-  assert(vf->is_compiled_frame(), "Wrong frame type");
-  chunk->push(compiledVFrame::cast(vf));
-
-  bool realloc_failures = false;
-
 #if COMPILER2_OR_JVMCI
-  // Reallocate the non-escaping objects and restore their fields. Then
-  // relock objects if synchronization on them was eliminated.
-#if !INCLUDE_JVMCI
-  if (DoEscapeAnalysis || EliminateNestedLocks) {
-    if (EliminateAllocations) {
-#endif // INCLUDE_JVMCI
+static bool eliminate_allocations(JavaThread* thread, int exec_mode, CompiledMethod* compiled_method,
+                                  frame& deoptee, RegisterMap& map, GrowableArray<compiledVFrame*>* chunk) {
+  bool realloc_failures = false;
       assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames");
+
       GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
 
       // The flag return_oop() indicates call sites which return oop
       // in compiled code. Such sites include java method calls,
       // runtime calls (for example, used to allocate new objects/arrays

@@ -217,11 +172,11 @@
       // It is not guaranteed that we can get such information here only
       // by analyzing bytecode in deoptimized frames. This is why this flag
       // is set during method compilation (see Compile::Process_OopMap_Node()).
       // If the previous frame was popped or if we are dispatching an exception,
       // we don't have an oop result.
-      bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution() && (exec_mode == Unpack_deopt);
+  bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution() && (exec_mode == Deoptimization::Unpack_deopt);
       Handle return_value;
       if (save_oop_result) {
         // Reallocation may trigger GC. If deoptimization happened on return from
         // call which returns oop we need to save it since it is not in oopmap.
         oop result = deoptee.saved_oop_result(&map);

@@ -233,39 +188,39 @@
           tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, p2i(result), p2i(thread));
         }
       }
       if (objects != NULL) {
         JRT_BLOCK
-          realloc_failures = realloc_objects(thread, &deoptee, &map, objects, THREAD);
+      realloc_failures = Deoptimization::realloc_objects(thread, &deoptee, &map, objects, THREAD);
         JRT_END
-        bool skip_internal = (cm != NULL) && !cm->is_compiled_by_jvmci();
-        reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
+    bool skip_internal = (compiled_method != NULL) && !compiled_method->is_compiled_by_jvmci();
+    Deoptimization::reassign_fields(&deoptee, &map, objects, realloc_failures, skip_internal);
 #ifndef PRODUCT
         if (TraceDeoptimization) {
           ttyLocker ttyl;
           tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, p2i(thread));
-          print_objects(objects, realloc_failures);
+      Deoptimization::print_objects(objects, realloc_failures);
         }
 #endif
       }
       if (save_oop_result) {
         // Restore result.
         deoptee.set_saved_oop_result(&map, return_value());
       }
-#if !INCLUDE_JVMCI
-    }
-    if (EliminateLocks) {
-#endif // INCLUDE_JVMCI
+  return realloc_failures;
+}
+
+static void eliminate_locks(JavaThread* thread, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) {
 #ifndef PRODUCT
       bool first = true;
 #endif
       for (int i = 0; i < chunk->length(); i++) {
         compiledVFrame* cvf = chunk->at(i);
         assert (cvf->scope() != NULL,"expect only compiled java frames");
         GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
         if (monitors->is_nonempty()) {
-          relock_objects(monitors, thread, realloc_failures);
+      Deoptimization::relock_objects(monitors, thread, realloc_failures);
 #ifndef PRODUCT
           if (PrintDeoptimizationDetails) {
             ttyLocker ttyl;
             for (int j = 0; j < monitors->length(); j++) {
               MonitorInfo* mi = monitors->at(j);

@@ -284,14 +239,83 @@
             }
           }
 #endif // !PRODUCT
         }
       }
-#if !INCLUDE_JVMCI
+}
+#endif // COMPILER2_OR_JVMCI
+
+// This is factored, since it is both called from a JRT_LEAF (deoptimization) and a JRT_ENTRY (uncommon_trap)
+Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread* thread, int exec_mode) {
+
+  // Note: there is a safepoint safety issue here. No matter whether we enter
+  // via vanilla deopt or uncommon trap we MUST NOT stop at a safepoint once
+  // the vframeArray is created.
+  //
+
+  // Allocate our special deoptimization ResourceMark
+  DeoptResourceMark* dmark = new DeoptResourceMark(thread);
+  assert(thread->deopt_mark() == NULL, "Pending deopt!");
+  thread->set_deopt_mark(dmark);
+
+  frame stub_frame = thread->last_frame(); // Makes stack walkable as side effect
+  RegisterMap map(thread, true);
+  RegisterMap dummy_map(thread, false);
+  // Now get the deoptee with a valid map
+  frame deoptee = stub_frame.sender(&map);
+  // Set the deoptee nmethod
+  assert(thread->deopt_compiled_method() == NULL, "Pending deopt!");
+  CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null();
+  thread->set_deopt_compiled_method(cm);
+
+  if (VerifyStack) {
+    thread->validate_frame_layout();
+  }
+
+  // Create a growable array of VFrames where each VFrame represents an inlined
+  // Java frame.  This storage is allocated with the usual system arena.
+  assert(deoptee.is_compiled_frame(), "Wrong frame type");
+  GrowableArray<compiledVFrame*>* chunk = new GrowableArray<compiledVFrame*>(10);
+  vframe* vf = vframe::new_vframe(&deoptee, &map, thread);
+  while (!vf->is_top()) {
+    assert(vf->is_compiled_frame(), "Wrong frame type");
+    chunk->push(compiledVFrame::cast(vf));
+    vf = vf->sender();
+  }
+  assert(vf->is_compiled_frame(), "Wrong frame type");
+  chunk->push(compiledVFrame::cast(vf));
+
+  bool realloc_failures = false;
+
+#if COMPILER2_OR_JVMCI
+#if INCLUDE_JVMCI
+  bool jvmci_enabled = true;
+#else
+  bool jvmci_enabled = false;
+#endif
+
+  // Reallocate the non-escaping objects and restore their fields. Then
+  // relock objects if synchronization on them was eliminated.
+  if (jvmci_enabled || ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateAllocations)) {
+    realloc_failures = eliminate_allocations(thread, exec_mode, cm, deoptee, map, chunk);
     }
+#endif // COMPILER2_OR_JVMCI
+
+  // Revoke biases, done with in java state.
+  // No safepoints allowed after this
+  revoke_from_deopt_handler(thread, deoptee, &map);
+
+  // Ensure that no safepoint is taken after pointers have been stored
+  // in fields of rematerialized objects.  If a safepoint occurs from here on
+  // out the java state residing in the vframeArray will be missed.
+  // Locks may be rebaised in a safepoint.
+  NoSafepointVerifier no_safepoint;
+
+#if COMPILER2_OR_JVMCI
+  if (jvmci_enabled || ((DoEscapeAnalysis || EliminateNestedLocks) && EliminateLocks)) {
+    eliminate_locks(thread, chunk, realloc_failures);
   }
-#endif // INCLUDE_JVMCI
 #endif // COMPILER2_OR_JVMCI
 
   ScopeDesc* trap_scope = chunk->at(0)->scope();
   Handle exceptionObject;
   if (trap_scope->rethrow_exception()) {

@@ -303,15 +327,10 @@
     ScopeValue* topOfStack = expressions->top();
     exceptionObject = StackValue::create_stack_value(&deoptee, &map, topOfStack)->get_obj();
     guarantee(exceptionObject() != NULL, "exception oop can not be null");
   }
 
-  // Ensure that no safepoint is taken after pointers have been stored
-  // in fields of rematerialized objects.  If a safepoint occurs from here on
-  // out the java state residing in the vframeArray will be missed.
-  NoSafepointVerifier no_safepoint;
-
   vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures);
 #if COMPILER2_OR_JVMCI
   if (realloc_failures) {
     pop_frames_failed_reallocs(thread, array);
   }

@@ -777,14 +796,37 @@
 
 
   return bt;
 JRT_END
 
+class DeoptimizeMarkedTC : public ThreadClosure {
+ public:
+  virtual void do_thread(Thread* thread) {
+    assert(thread->is_Java_thread(), "must be");
+    JavaThread* jt = (JavaThread*)thread;
+    jt->deoptimize_marked_methods();
+  }
+};
+
+void Deoptimization::deoptimize_all_marked() {
+  ResourceMark rm;
+  DeoptimizationMarker dm;
 
-int Deoptimization::deoptimize_dependents() {
-  Threads::deoptimized_wrt_marked_nmethods();
-  return 0;
+  if (SafepointSynchronize::is_at_safepoint()) {
+    DeoptimizeMarkedTC deopt;
+    // Make the dependent methods not entrant
+    CodeCache::make_marked_nmethods_not_entrant();
+    Threads::java_threads_do(&deopt);
+  } else {
+    // Make the dependent methods not entrant
+    {
+      MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+      CodeCache::make_marked_nmethods_not_entrant();
+    }
+    DeoptimizeMarkedTC deopt;
+    Handshake::execute(&deopt);
+  }
 }
 
 Deoptimization::DeoptAction Deoptimization::_unloaded_action
   = Deoptimization::Action_reinterpret;
 

@@ -1395,18 +1437,11 @@
       objects_to_revoke->append(Handle(thread, mon_info->owner()));
     }
   }
 }
 
-
-void Deoptimization::revoke_biases_of_monitors(JavaThread* thread, frame fr, RegisterMap* map) {
-  if (!UseBiasedLocking) {
-    return;
-  }
-
-  GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
-
+static void get_monitors_from_stack(GrowableArray<Handle>* objects_to_revoke, JavaThread* thread, frame fr, RegisterMap* map) {
   // Unfortunately we don't have a RegisterMap available in most of
   // the places we want to call this routine so we need to walk the
   // stack again to update the register map.
   if (map == NULL || !map->update_map()) {
     StackFrameStream sfs(thread, true);

@@ -1426,15 +1461,24 @@
   while (!cvf->is_top()) {
     collect_monitors(cvf, objects_to_revoke);
     cvf = compiledVFrame::cast(cvf->sender());
   }
   collect_monitors(cvf, objects_to_revoke);
+}
 
-  if (SafepointSynchronize::is_at_safepoint()) {
-    BiasedLocking::revoke_at_safepoint(objects_to_revoke);
-  } else {
-    BiasedLocking::revoke(objects_to_revoke, thread);
+void Deoptimization::revoke_from_deopt_handler(JavaThread* thread, frame fr, RegisterMap* map) {
+  if (!UseBiasedLocking) {
+    return;
+  }
+  GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
+  get_monitors_from_stack(objects_to_revoke, thread, fr, map);
+
+  int len = objects_to_revoke->length();
+  for (int i = 0; i < len; i++) {
+    oop obj = (objects_to_revoke->at(i))();
+    BiasedLocking::revoke_own_lock(objects_to_revoke->at(i), thread);
+    assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
   }
 }
 
 
 void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {

@@ -1462,28 +1506,20 @@
   // Patch the compiled method so that when execution returns to it we will
   // deopt the execution state and return to the interpreter.
   fr.deoptimize(thread);
 }
 
-void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map) {
-  deoptimize(thread, fr, map, Reason_constraint);
-}
-
 void Deoptimization::deoptimize(JavaThread* thread, frame fr, RegisterMap *map, DeoptReason reason) {
   // Deoptimize only if the frame comes from compile code.
   // Do not deoptimize the frame which is already patched
   // during the execution of the loops below.
   if (!fr.is_compiled_frame() || fr.is_deoptimized_frame()) {
     return;
   }
   ResourceMark rm;
   DeoptimizationMarker dm;
-  if (UseBiasedLocking) {
-    revoke_biases_of_monitors(thread, fr, map);
-  }
   deoptimize_single_frame(thread, fr, reason);
-
 }
 
 #if INCLUDE_JVMCI
 address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* cm) {
   // there is no exception handler for this pc => deoptimize

@@ -1640,13 +1676,10 @@
               trap_request, p2i(fr.pc()), fr.pc() - fr.cb()->code_begin());
 
   {
     ResourceMark rm;
 
-    // Revoke biases of any monitors in the frame to ensure we can migrate them
-    revoke_biases_of_monitors(thread, fr, &reg_map);
-
     DeoptReason reason = trap_request_reason(trap_request);
     DeoptAction action = trap_request_action(trap_request);
 #if INCLUDE_JVMCI
     int debug_id = trap_request_debug_id(trap_request);
 #endif
< prev index next >