8212681: Refactor IC locking to use a fine grained CompiledICLocker

Reviewed-by: coleenp, rehn, kvn
This commit is contained in:
Erik Österlund 2018-11-01 14:57:26 +01:00
parent 54d4acf73f
commit 97d3dc7902
23 changed files with 211 additions and 103 deletions

View File

@ -179,10 +179,10 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
}
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
method_holder->set_data(0);

View File

@ -69,10 +69,10 @@ void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, addre
#ifdef NEVER_CALLED
void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeLoadGot* method_loader = nativeLoadGot_at(stub);
NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/compiledIC.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_aarch64.hpp"
#include "oops/oop.inline.hpp"
@ -178,7 +179,8 @@ address NativeCall::destination() const {
// during code generation, where no patching lock is needed.
void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) {
assert(!assert_lock ||
(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()),
(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(addr_at(0)),
"concurrent code patching");
ResourceMark rm;

View File

@ -137,10 +137,10 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
}
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -197,10 +197,10 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
}
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + IC_pos_in_java_to_interp_stub);
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "code/compiledIC.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_ppc.hpp"
#include "oops/compressedOops.inline.hpp"
@ -94,7 +95,8 @@ address NativeCall::destination() const {
// during code generation, where no patching lock is needed.
void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) {
assert(!assert_lock ||
(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()),
(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(addr_at(0)),
"concurrent code patching");
ResourceMark rm;

View File

@ -127,10 +127,10 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
}
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub + NativeCall::get_IC_pos_in_java_to_interp_stub());
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());

View File

@ -124,10 +124,10 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
}
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeMovConstReg* method_holder = nativeMovConstReg_at(stub);
NativeJump* jump = nativeJump_at(method_holder->next_instruction_address());

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "code/codeCache.hpp"
#include "code/compiledIC.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_sparc.hpp"
#include "oops/oop.inline.hpp"
@ -189,8 +190,9 @@ void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) {
//
// Used in the runtime linkage of calls; see class CompiledIC.
void NativeCall::set_destination_mt_safe(address dest) {
assert(Patching_lock->is_locked() ||
SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
assert((Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) ||
CompiledICLocker::is_safe(addr_at(0)),
"concurrent code patching");
// set_destination uses set_long_at which does the ICache::invalidate
set_destination(dest);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -88,10 +88,10 @@ void CompiledPltStaticCall::set_to_interpreted(const methodHandle& callee, addre
#ifdef NEVER_CALLED
void CompiledPltStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");
assert(CompiledICLocker::is_safe(stub), "mt unsafe call");
// Creation also verifies the object.
NativeLoadGot* method_loader = nativeLoadGot_at(stub);
NativeGotJump* jump = nativeGotJump_at(method_loader->next_instruction_address());

View File

@ -177,7 +177,7 @@ void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, ad
}
void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) {
assert (CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "mt unsafe call");
assert(CompiledICLocker::is_safe(static_stub->addr()), "mt unsafe call");
// Reset stub.
address stub = static_stub->addr();
assert(stub != NULL, "stub not found");

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/compiledIC.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_x86.hpp"
#include "oops/oop.inline.hpp"
@ -257,8 +258,8 @@ void NativeCall::set_destination_mt_safe(address dest) {
debug_only(verify());
// Make sure patching code is locked. No two threads can patch at the same
// time but one may be executing this code.
assert(Patching_lock->is_locked() ||
SafepointSynchronize::is_at_safepoint(), "concurrent code patching");
assert(Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint() ||
CompiledICLocker::is_safe(instruction_address()), "concurrent code patching");
// Both C1 and C2 should now be generating code which aligns the patched address
// to be within a single cache line.
bool is_aligned = ((uintptr_t)displacement_address() + 0) / cache_line_size ==

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "code/codeBehaviours.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
CompiledICProtectionBehaviour* CompiledICProtectionBehaviour::_current = NULL;
bool DefaultICProtectionBehaviour::lock(CompiledMethod* method) {
if (CompiledIC_lock->owned_by_self()) {
return false;
}
CompiledIC_lock->lock();
return true;
}
void DefaultICProtectionBehaviour::unlock(CompiledMethod* method) {
CompiledIC_lock->unlock();
}
bool DefaultICProtectionBehaviour::is_safe(CompiledMethod* method) {
return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self();
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_CODE_CODEBEHAVIOURS_HPP
#define SHARE_CODE_CODEBEHAVIOURS_HPP
#include "memory/allocation.hpp"
class CompiledMethod;
class CompiledICProtectionBehaviour {
static CompiledICProtectionBehaviour* _current;
public:
virtual bool lock(CompiledMethod* method) = 0;
virtual void unlock(CompiledMethod* method) = 0;
virtual bool is_safe(CompiledMethod* method) = 0;
static CompiledICProtectionBehaviour* current() { return _current; }
static void set_current(CompiledICProtectionBehaviour* current) { _current = current; }
};
class DefaultICProtectionBehaviour: public CompiledICProtectionBehaviour, public CHeapObj<mtInternal> {
virtual bool lock(CompiledMethod* method);
virtual void unlock(CompiledMethod* method);
virtual bool is_safe(CompiledMethod* method);
};
#endif // SHARE_CODE_CODEBEHAVIOURS_HPP

View File

@ -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::cached_value() const {
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 @@ void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub
}
{
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 @@ void CompiledIC::set_ic_destination(ICStub* stub) {
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 @@ CompiledIC::CompiledIC(RelocIterator* iter)
}
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 @@ bool CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecod
// 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_megamorphic() const {
}
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_compiled() const {
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 @@ bool CompiledIC::is_call_to_interpreted() const {
}
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 @@ void CompiledIC::set_to_clean(bool in_use) {
// 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 @@ void CompiledIC::set_to_clean(bool in_use) {
}
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 @@ bool CompiledIC::is_clean() const {
}
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 CompiledIC::cleanup_call_site(virtual_call_Relocation* call_site, const Com
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_to_compiled(address entry) {
}
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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -59,8 +59,22 @@
// transition is made to a stub.
//
class CompiledIC;
class CompiledICProtectionBehaviour;
class CompiledMethod;
class ICStub;
class CompiledICLocker: public StackObj {
CompiledMethod* _method;
CompiledICProtectionBehaviour* _behaviour;
bool _locked;
public:
CompiledICLocker(CompiledMethod* method);
~CompiledICLocker();
static bool is_safe(CompiledMethod* method);
static bool is_safe(address code);
};
class CompiledICInfo : public StackObj {
private:
address _entry; // entry point for call

View File

@ -324,7 +324,7 @@ void CompiledMethod::clear_inline_caches() {
// Clear ICStubs of all compiled ICs
void CompiledMethod::clear_ic_stubs() {
assert_locked_or_safepoint(CompiledIC_lock);
assert(CompiledICLocker::is_safe(this), "mt unsafe call");
ResourceMark rm;
RelocIterator iter(this);
while(iter.next()) {
@ -546,7 +546,7 @@ bool CompiledMethod::unload_nmethod_caches(bool parallel, bool unloading_occurre
// Called to clean up after class unloading for live nmethods and from the sweeper
// for all methods.
bool CompiledMethod::cleanup_inline_caches_impl(bool parallel, bool unloading_occurred, bool clean_all) {
assert_locked_or_safepoint(CompiledIC_lock);
assert(CompiledICLocker::is_safe(this), "mt unsafe call");
bool postponed = false;
ResourceMark rm;

View File

@ -170,8 +170,9 @@ void InlineCacheBuffer_init() {
void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) {
MutexLockerEx ml(CompiledIC_lock->owned_by_self() ? NULL : CompiledIC_lock);
assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint");
assert (CompiledIC_lock->is_locked(), "");
assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call");
if (TraceICBuffer) {
tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT,
p2i(ic->instruction_address()), p2i(entry), p2i(cached_value));
@ -224,7 +225,9 @@ void InlineCacheBuffer::release_pending_icholders() {
// not safe to free them until them since they might be visible to
// another thread.
void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) {
MutexLockerEx mex(InlineCacheBuffer_lock);
MutexLockerEx mex1((CompiledIC_lock->owned_by_self() ||
SafepointSynchronize::is_at_safepoint()) ? NULL : CompiledIC_lock);
MutexLockerEx mex2(InlineCacheBuffer_lock);
icholder->set_next(_pending_released);
_pending_released = icholder;
_pending_count++;

View File

@ -953,7 +953,7 @@ void nmethod::fix_oop_relocations(address begin, address end, bool initialize_im
void nmethod::verify_clean_inline_caches() {
assert_locked_or_safepoint(CompiledIC_lock);
assert(CompiledICLocker::is_safe(this), "mt unsafe call");
ResourceMark rm;
RelocIterator iter(this, oops_reloc_begin());
@ -2115,14 +2115,11 @@ void nmethod::verify() {
void nmethod::verify_interrupt_point(address call_site) {
// Verify IC only when nmethod installation is finished.
if (!is_not_installed()) {
Thread *cur = Thread::current();
if (CompiledIC_lock->owner() == cur ||
((cur->is_VM_thread() || cur->is_ConcurrentGC_thread()) &&
SafepointSynchronize::is_at_safepoint())) {
if (CompiledICLocker::is_safe(this)) {
CompiledIC_at(this, call_site);
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
} else {
MutexLocker ml_verify (CompiledIC_lock);
CompiledICLocker ml_verify(this);
CompiledIC_at(this, call_site);
}
}
@ -2819,7 +2816,7 @@ void nmethod::print_calls(outputStream* st) {
switch (iter.type()) {
case relocInfo::virtual_call_type:
case relocInfo::opt_virtual_call_type: {
VerifyMutexLocker mc(CompiledIC_lock);
CompiledICLocker ml_verify(this);
CompiledIC_at(&iter)->print();
break;
}

View File

@ -30,6 +30,7 @@
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeBehaviours.hpp"
#include "code/codeCache.hpp"
#include "code/dependencies.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
@ -60,9 +61,9 @@
#include "prims/resolvedMethodTable.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/flags/flagSetting.hpp"
#include "runtime/flags/jvmFlagConstraintList.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
#include "runtime/java.hpp"
@ -640,6 +641,10 @@ void* Universe::non_oop_word() {
return (void*)_non_oop_bits;
}
static void initialize_global_behaviours() {
CompiledICProtectionBehaviour::set_current(new DefaultICProtectionBehaviour());
}
jint universe_init() {
assert(!Universe::_fully_initialized, "called after initialize_vtables");
guarantee(1 << LogHeapWordSize == sizeof(HeapWord),
@ -652,6 +657,8 @@ jint universe_init() {
JavaClasses::compute_hard_coded_offsets();
initialize_global_behaviours();
jint status = Universe::initialize_heap();
if (status != JNI_OK) {
return status;

View File

@ -346,38 +346,4 @@ class MutexUnlockerEx: StackObj {
}
};
#ifndef PRODUCT
//
// A special MutexLocker that allows:
// - reentrant locking
// - locking out of order
//
// Only to be used for verify code, where we can relax out dead-lock
// detection code a bit (unsafe, but probably ok). This code is NEVER to
// be included in a product version.
//
class VerifyMutexLocker: StackObj {
private:
Monitor * _mutex;
bool _reentrant;
public:
VerifyMutexLocker(Monitor * mutex) {
_mutex = mutex;
_reentrant = mutex->owned_by_self();
if (!_reentrant) {
// We temp. disable strict safepoint checking, while we require the lock
FlagSetting fs(StrictSafepointChecks, false);
_mutex->lock();
}
}
~VerifyMutexLocker() {
if (!_reentrant) {
_mutex->unlock();
}
}
};
#endif
#endif // SHARE_VM_RUNTIME_MUTEXLOCKER_HPP

View File

@ -1351,7 +1351,7 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
// grab lock, check for deoptimization and potentially patch caller
{
MutexLocker ml_patch(CompiledIC_lock);
CompiledICLocker ml(caller_nm);
// Lock blocks for safepoint during which both nmethods can change state.
@ -1382,7 +1382,7 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
}
}
} // unlock CompiledIC_lock
} // unlock CompiledICLocker
return callee_method;
}
@ -1585,11 +1585,13 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) {
JvmtiDynamicCodeEventCollector event_collector;
// Update inline cache to megamorphic. Skip update if we are called from interpreted.
{ MutexLocker ml_patch (CompiledIC_lock);
{
RegisterMap reg_map(thread, false);
frame caller_frame = thread->last_frame().sender(&reg_map);
CodeBlob* cb = caller_frame.cb();
CompiledMethod* caller_nm = cb->as_compiled_method_or_null();
CompiledICLocker ml(caller_nm);
if (cb->is_compiled()) {
CompiledIC* inline_cache = CompiledIC_before(((CompiledMethod*)cb), caller_frame.pc());
bool should_be_mono = false;
@ -1647,7 +1649,7 @@ methodHandle SharedRuntime::handle_ic_miss_helper(JavaThread *thread, TRAPS) {
} else {
fatal("Unimplemented");
}
} // Release CompiledIC_lock
} // Release CompiledICLocker
return callee_method;
}
@ -1731,8 +1733,7 @@ methodHandle SharedRuntime::reresolve_call_site(JavaThread *thread, TRAPS) {
// to a wrong method). It should not be performance critical, since the
// resolve is only done once.
bool is_nmethod = caller_nm->is_nmethod();
MutexLocker ml(CompiledIC_lock);
CompiledICLocker ml(caller_nm);
if (is_static_call) {
CompiledStaticCall* ssc = caller_nm->compiledStaticCall_at(call_addr);
ssc->set_to_clean();

View File

@ -673,8 +673,8 @@ void NMethodSweeper::release_compiled_method(CompiledMethod* nm) {
// Clean up any CompiledICHolders
{
ResourceMark rm;
MutexLocker ml_patch(CompiledIC_lock);
RelocIterator iter(nm);
CompiledICLocker ml(nm);
while (iter.next()) {
if (iter.type() == relocInfo::virtual_call_type) {
CompiledIC::cleanup_call_site(iter.virtual_call_reloc(), nm);
@ -701,7 +701,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_compiled_method(Compil
// But still remember to clean-up inline caches for alive nmethods
if (cm->is_alive()) {
// Clean inline caches that point to zombie/non-entrant/unloaded nmethods
MutexLocker cl(CompiledIC_lock);
CompiledICLocker ml(cm);
cm->cleanup_inline_caches();
SWEEP(cm);
}
@ -723,7 +723,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_compiled_method(Compil
// Clear ICStubs to prevent back patching stubs of zombie or flushed
// nmethods during the next safepoint (see ICStub::finalize).
{
MutexLocker cl(CompiledIC_lock);
CompiledICLocker ml(cm);
cm->clear_ic_stubs();
}
// Code cache state change is tracked in make_zombie()
@ -747,7 +747,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_compiled_method(Compil
}
} else {
// Still alive, clean up its inline caches
MutexLocker cl(CompiledIC_lock);
CompiledICLocker ml(cm);
cm->cleanup_inline_caches();
SWEEP(cm);
}
@ -757,7 +757,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_compiled_method(Compil
{
// Clean ICs of unloaded nmethods as well because they may reference other
// unloaded nmethods that may be flushed earlier in the sweeper cycle.
MutexLocker cl(CompiledIC_lock);
CompiledICLocker ml(cm);
cm->cleanup_inline_caches();
}
if (cm->is_osr_method()) {
@ -778,7 +778,7 @@ NMethodSweeper::MethodStateChange NMethodSweeper::process_compiled_method(Compil
possibly_flush((nmethod*)cm);
}
// Clean inline caches that point to zombie/non-entrant/unloaded nmethods
MutexLocker cl(CompiledIC_lock);
CompiledICLocker ml(cm);
cm->cleanup_inline_caches();
SWEEP(cm);
}