8043070: nmethod::verify_interrupt_point() shouldn't enter safepoint
authoriveresov
Mon, 20 Nov 2017 19:00:22 -0800
changeset 48007 ab3959df2115
parent 48006 e79838cf4613
child 48008 8fb080e5714b
8043070: nmethod::verify_interrupt_point() shouldn't enter safepoint Summary: Introduce not_installed state for nmethods Reviewed-by: dlong
src/hotspot/share/ci/ciEnv.cpp
src/hotspot/share/code/compiledMethod.cpp
src/hotspot/share/code/compiledMethod.hpp
src/hotspot/share/code/nmethod.cpp
src/hotspot/share/code/nmethod.hpp
src/hotspot/share/jvmci/jvmciEnv.cpp
src/hotspot/share/runtime/sweeper.cpp
src/hotspot/share/runtime/vmStructs.cpp
--- a/src/hotspot/share/ci/ciEnv.cpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/ci/ciEnv.cpp	Mon Nov 20 19:00:22 2017 -0800
@@ -1101,6 +1101,7 @@
         }
         method->method_holder()->add_osr_nmethod(nm);
       }
+      nm->make_in_use();
     }
   }  // safepoints are allowed again
 
--- a/src/hotspot/share/code/compiledMethod.cpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/code/compiledMethod.cpp	Mon Nov 20 19:00:22 2017 -0800
@@ -64,6 +64,8 @@
 const char* CompiledMethod::state() const {
   int state = get_state();
   switch (state) {
+  case not_installed:
+    return "not installed";
   case in_use:
     return "in use";
   case not_used:
--- a/src/hotspot/share/code/compiledMethod.hpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/code/compiledMethod.hpp	Mon Nov 20 19:00:22 2017 -0800
@@ -183,12 +183,14 @@
   bool  has_wide_vectors() const                  { return _has_wide_vectors; }
   void  set_has_wide_vectors(bool z)              { _has_wide_vectors = z; }
 
-  enum { in_use       = 0,   // executable nmethod
-         not_used     = 1,   // not entrant, but revivable
-         not_entrant  = 2,   // marked for deoptimization but activations may still exist,
+  enum { not_installed = -1, // in construction, only the owner doing the construction is
+                             // allowed to advance state
+         in_use        = 0,  // executable nmethod
+         not_used      = 1,  // not entrant, but revivable
+         not_entrant   = 2,  // marked for deoptimization but activations may still exist,
                              // will be transformed to zombie when all activations are gone
-         zombie       = 3,   // no activations exist, nmethod is ready for purge
-         unloaded     = 4    // there should be no activations, should not be called,
+         zombie        = 3,  // no activations exist, nmethod is ready for purge
+         unloaded      = 4   // there should be no activations, should not be called,
                              // will be transformed to zombie immediately
   };
 
--- a/src/hotspot/share/code/nmethod.cpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/code/nmethod.cpp	Mon Nov 20 19:00:22 2017 -0800
@@ -386,7 +386,7 @@
 
 // Fill in default values for various flag fields
 void nmethod::init_defaults() {
-  _state                      = in_use;
+  _state                      = not_installed;
   _has_flushed_dependencies   = 0;
   _lock_count                 = 0;
   _stack_traversal_mark       = 0;
@@ -445,6 +445,7 @@
     nm->log_new_nmethod();
   }
 
+  nm->make_in_use();
   return nm;
 }
 
@@ -1129,7 +1130,7 @@
 /**
  * Common functionality for both make_not_entrant and make_zombie
  */
-bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
+bool nmethod::make_not_entrant_or_zombie(int state) {
   assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
   assert(!is_zombie(), "should not already be a zombie");
 
@@ -2097,9 +2098,7 @@
 
 void nmethod::verify_interrupt_point(address call_site) {
   // Verify IC only when nmethod installation is finished.
-  bool is_installed = (method()->code() == this) // nmethod is in state 'in_use' and installed
-                      || !this->is_in_use();     // nmethod is installed, but not in 'in_use' state
-  if (is_installed) {
+  if (!is_not_installed()) {
     Thread *cur = Thread::current();
     if (CompiledIC_lock->owner() == cur ||
         ((cur->is_VM_thread() || cur->is_ConcurrentGC_thread()) &&
--- a/src/hotspot/share/code/nmethod.hpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/code/nmethod.hpp	Mon Nov 20 19:00:22 2017 -0800
@@ -124,7 +124,7 @@
   bool _unload_reported;
 
   // Protected by Patching_lock
-  volatile unsigned char _state;             // {in_use, not_entrant, zombie, unloaded}
+  volatile char _state;             // {not_installed, in_use, not_entrant, zombie, unloaded}
 
 #ifdef ASSERT
   bool _oops_are_stale;  // indicates that it's no longer safe to access oops section
@@ -216,7 +216,7 @@
   const char* reloc_string_for(u_char* begin, u_char* end);
   // Returns true if this thread changed the state of the nmethod or
   // false if another thread performed the transition.
-  bool make_not_entrant_or_zombie(unsigned int state);
+  bool make_not_entrant_or_zombie(int state);
   bool make_entrant() { Unimplemented(); return false; }
   void inc_decompile_count();
 
@@ -316,8 +316,9 @@
   address verified_entry_point() const            { return _verified_entry_point;    } // if klass is correct
 
   // flag accessing and manipulation
-  bool  is_in_use() const                         { return _state == in_use; }
-  bool  is_alive() const                          { unsigned char s = _state; return s < zombie; }
+  bool  is_not_installed() const                  { return _state == not_installed; }
+  bool  is_in_use() const                         { return _state <= in_use; }
+  bool  is_alive() const                          { return _state < zombie; }
   bool  is_not_entrant() const                    { return _state == not_entrant; }
   bool  is_zombie() const                         { return _state == zombie; }
   bool  is_unloaded() const                       { return _state == unloaded; }
@@ -328,6 +329,7 @@
   void set_rtm_state(RTMState state)              { _rtm_state = state; }
 #endif
 
+  void make_in_use()                              { _state = in_use; }
   // Make the nmethod non entrant. The nmethod will continue to be
   // alive.  It is used when an uncommon trap happens.  Returns true
   // if this thread changed the state of the nmethod or false if
--- a/src/hotspot/share/jvmci/jvmciEnv.cpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/jvmci/jvmciEnv.cpp	Mon Nov 20 19:00:22 2017 -0800
@@ -582,6 +582,7 @@
             InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm);
           }
         }
+        nm->make_in_use();
       }
       result = nm != NULL ? JVMCIEnv::ok :JVMCIEnv::cache_full;
     }
--- a/src/hotspot/share/runtime/sweeper.cpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/runtime/sweeper.cpp	Mon Nov 20 19:00:22 2017 -0800
@@ -699,7 +699,7 @@
 
 void NMethodSweeper::possibly_flush(nmethod* nm) {
   if (UseCodeCacheFlushing) {
-    if (!nm->is_locked_by_vm() && !nm->is_native_method()) {
+    if (!nm->is_locked_by_vm() && !nm->is_native_method() && !nm->is_not_installed()) {
       bool make_not_entrant = false;
 
       // Do not make native methods not-entrant
--- a/src/hotspot/share/runtime/vmStructs.cpp	Mon Nov 20 17:10:02 2017 -0500
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Mon Nov 20 19:00:22 2017 -0800
@@ -830,7 +830,7 @@
   nonstatic_field(nmethod,                     _osr_link,                                     nmethod*)                              \
   nonstatic_field(nmethod,                     _scavenge_root_link,                           nmethod*)                              \
   nonstatic_field(nmethod,                     _scavenge_root_state,                          jbyte)                                 \
-  nonstatic_field(nmethod,                     _state,                                        volatile unsigned char)                \
+  nonstatic_field(nmethod,                     _state,                                        volatile char)                         \
   nonstatic_field(nmethod,                     _exception_offset,                             int)                                   \
   nonstatic_field(nmethod,                     _orig_pc_offset,                               int)                                   \
   nonstatic_field(nmethod,                     _stub_offset,                                  int)                                   \
@@ -1351,7 +1351,7 @@
   declare_integer_type(long)                                              \
   declare_integer_type(char)                                              \
   declare_unsigned_integer_type(unsigned char)                            \
-  declare_unsigned_integer_type(volatile unsigned char)                   \
+  declare_unsigned_integer_type(volatile char)                            \
   declare_unsigned_integer_type(u_char)                                   \
   declare_unsigned_integer_type(unsigned int)                             \
   declare_unsigned_integer_type(uint)                                     \