diff -r 71564a544d4c -r d6dc479bcdd3 src/hotspot/share/code/compiledIC.cpp --- 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