8212681: Refactor IC locking to use a fine grained CompiledICLocker
Reviewed-by: coleenp, rehn, kvn
This commit is contained in:
parent
54d4acf73f
commit
97d3dc7902
@ -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);
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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");
|
||||
|
@ -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 ==
|
||||
|
46
src/hotspot/share/code/codeBehaviours.cpp
Normal file
46
src/hotspot/share/code/codeBehaviours.cpp
Normal 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();
|
||||
}
|
50
src/hotspot/share/code/codeBehaviours.hpp
Normal file
50
src/hotspot/share/code/codeBehaviours.hpp
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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++;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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(®_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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user