src/hotspot/share/code/compiledIC.cpp
changeset 52384 d6dc479bcdd3
parent 51314 82adcc8ad853
child 52857 7e268f863ff0
--- a/src/hotspot/share/code/compiledIC.cpp	Fri Nov 02 07:58:22 2018 +0100
+++ b/src/hotspot/share/code/compiledIC.cpp	Thu Nov 01 14:57:26 2018 +0100
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/systemDictionary.hpp"
+#include "code/codeBehaviours.hpp"
 #include "code/codeCache.hpp"
 #include "code/compiledIC.hpp"
 #include "code/icBuffer.hpp"
@@ -47,12 +48,35 @@
 // Every time a compiled IC is changed or its type is being accessed,
 // either the CompiledIC_lock must be set or we must be at a safe point.
 
+CompiledICLocker::CompiledICLocker(CompiledMethod* method)
+  : _method(method),
+    _behaviour(CompiledICProtectionBehaviour::current()),
+    _locked(_behaviour->lock(_method)){
+}
+
+CompiledICLocker::~CompiledICLocker() {
+  if (_locked) {
+    _behaviour->unlock(_method);
+  }
+}
+
+bool CompiledICLocker::is_safe(CompiledMethod* method) {
+  return CompiledICProtectionBehaviour::current()->is_safe(method);
+}
+
+bool CompiledICLocker::is_safe(address code) {
+  CodeBlob* cb = CodeCache::find_blob_unsafe(code);
+  assert(cb != NULL && cb->is_compiled(), "must be compiled");
+  CompiledMethod* cm = cb->as_compiled_method();
+  return CompiledICProtectionBehaviour::current()->is_safe(cm);
+}
+
 //-----------------------------------------------------------------------------
 // Low-level access to an inline cache. Private, since they might not be
 // MT-safe to use.
 
 void* CompiledIC::cached_value() const {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   assert (!is_optimized(), "an optimized virtual call does not have a cached metadata");
 
   if (!is_in_transition_state()) {
@@ -69,7 +93,7 @@
 
 void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub, void* cache, bool is_icholder) {
   assert(entry_point != NULL, "must set legal entry point");
-  assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   assert (!is_optimized() || cache == NULL, "an optimized virtual call does not have a cached metadata");
   assert (cache == NULL || cache != (Metadata*)badOopVal, "invalid metadata");
 
@@ -101,11 +125,9 @@
   }
 
   {
-    MutexLockerEx pl(SafepointSynchronize::is_at_safepoint() ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
-#ifdef ASSERT
     CodeBlob* cb = CodeCache::find_blob_unsafe(_call->instruction_address());
+    MutexLockerEx pl(CompiledICLocker::is_safe(cb->as_compiled_method()) ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
     assert(cb != NULL && cb->is_compiled(), "must be compiled");
-#endif
     _call->set_destination_mt_safe(entry_point);
   }
 
@@ -130,23 +152,23 @@
 
 
 address CompiledIC::ic_destination() const {
- assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
- if (!is_in_transition_state()) {
-   return _call->destination();
- } else {
-   return InlineCacheBuffer::ic_destination_for((CompiledIC *)this);
- }
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
+  if (!is_in_transition_state()) {
+    return _call->destination();
+  } else {
+    return InlineCacheBuffer::ic_destination_for((CompiledIC *)this);
+  }
 }
 
 
 bool CompiledIC::is_in_transition_state() const {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   return InlineCacheBuffer::contains(_call->destination());;
 }
 
 
 bool CompiledIC::is_icholder_call() const {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   return !_is_optimized && is_icholder_entry(ic_destination());
 }
 
@@ -216,7 +238,7 @@
 }
 
 bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS) {
-  assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic");
   assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?");
 
@@ -270,7 +292,7 @@
 
 // true if destination is megamorphic stub
 bool CompiledIC::is_megamorphic() const {
-  assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   assert(!is_optimized(), "an optimized call cannot be megamorphic");
 
   // Cannot rely on cached_value. It is either an interface or a method.
@@ -278,7 +300,7 @@
 }
 
 bool CompiledIC::is_call_to_compiled() const {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
 
   // Use unsafe, since an inline cache might point to a zombie method. However, the zombie
   // method is guaranteed to still exist, since we only remove methods after all inline caches
@@ -304,7 +326,7 @@
 
 
 bool CompiledIC::is_call_to_interpreted() const {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   // Call to interpreter if destination is either calling to a stub (if it
   // is optimized), or calling to an I2C blob
   bool is_call_to_interpreted = false;
@@ -329,7 +351,7 @@
 }
 
 void CompiledIC::set_to_clean(bool in_use) {
-  assert(SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->is_locked() , "MT-unsafe call");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   if (TraceInlineCacheClearing || TraceICs) {
     tty->print_cr("IC@" INTPTR_FORMAT ": set to clean", p2i(instruction_address()));
     print();
@@ -339,7 +361,7 @@
 
   // A zombie transition will always be safe, since the metadata has already been set to NULL, so
   // we only need to patch the destination
-  bool safe_transition = _call->is_safe_for_patching() || !in_use || is_optimized() || SafepointSynchronize::is_at_safepoint();
+  bool safe_transition = _call->is_safe_for_patching() || !in_use || is_optimized() || CompiledICLocker::is_safe(_method);
 
   if (safe_transition) {
     // Kill any leftover stub we might have too
@@ -363,7 +385,7 @@
 }
 
 bool CompiledIC::is_clean() const {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   bool is_clean = false;
   address dest = ic_destination();
   is_clean = dest == _call->get_resolve_call_stub(is_optimized());
@@ -372,7 +394,7 @@
 }
 
 void CompiledIC::set_to_monomorphic(CompiledICInfo& info) {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
+  assert(CompiledICLocker::is_safe(_method), "mt unsafe call");
   // Updating a cache to the wrong entry can cause bugs that are very hard
   // to track down - if cache entry gets invalid - we just clean it. In
   // this way it is always the same code path that is responsible for
@@ -555,14 +577,9 @@
 
 void CompiledStaticCall::set_to_clean(bool in_use) {
   // in_use is unused but needed to match template function in CompiledMethod
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+  assert(CompiledICLocker::is_safe(instruction_address()), "mt unsafe call");
   // Reset call site
   MutexLockerEx pl(SafepointSynchronize::is_at_safepoint() ? NULL : Patching_lock, Mutex::_no_safepoint_check_flag);
-#ifdef ASSERT
-  CodeBlob* cb = CodeCache::find_blob_unsafe(instruction_address());
-  assert(cb != NULL && cb->is_compiled(), "must be compiled");
-#endif
-
   set_destination_mt_safe(resolve_call_stub());
 
   // Do not reset stub here:  It is too expensive to call find_stub.
@@ -606,7 +623,7 @@
 }
 
 void CompiledStaticCall::set(const StaticCallInfo& info) {
-  assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
+  assert(CompiledICLocker::is_safe(instruction_address()), "mt unsafe call");
   MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
   // Updating a cache to the wrong entry can cause bugs that are very hard
   // to track down - if cache entry gets invalid - we just clean it. In