mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
Merge
This commit is contained in:
commit
9935440ede
20 changed files with 226 additions and 91 deletions
|
@ -296,6 +296,18 @@ void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* a
|
||||||
Node* dest_offset = ac->in(ArrayCopyNode::DestPos);
|
Node* dest_offset = ac->in(ArrayCopyNode::DestPos);
|
||||||
Node* length = ac->in(ArrayCopyNode::Length);
|
Node* length = ac->in(ArrayCopyNode::Length);
|
||||||
|
|
||||||
|
if (bt == T_OBJECT) {
|
||||||
|
// BarrierSetC2::clone sets the offsets via BarrierSetC2::arraycopy_payload_base_offset
|
||||||
|
// which 8-byte aligns them to allow for word size copies. Make sure the offsets point
|
||||||
|
// to the first element in the array when cloning object arrays. Otherwise, load
|
||||||
|
// barriers are applied to parts of the header.
|
||||||
|
assert(src_offset == dest_offset, "should be equal");
|
||||||
|
assert((src_offset->get_long() == arrayOopDesc::base_offset_in_bytes(T_OBJECT) && UseCompressedClassPointers) ||
|
||||||
|
(src_offset->get_long() == arrayOopDesc::length_offset_in_bytes() && !UseCompressedClassPointers),
|
||||||
|
"unexpected offset for object array clone");
|
||||||
|
src_offset = phase->longcon(arrayOopDesc::base_offset_in_bytes(T_OBJECT));
|
||||||
|
dest_offset = src_offset;
|
||||||
|
}
|
||||||
Node* payload_src = phase->basic_plus_adr(src, src_offset);
|
Node* payload_src = phase->basic_plus_adr(src, src_offset);
|
||||||
Node* payload_dst = phase->basic_plus_adr(dest, dest_offset);
|
Node* payload_dst = phase->basic_plus_adr(dest, dest_offset);
|
||||||
|
|
||||||
|
|
|
@ -307,8 +307,8 @@ address PhaseMacroExpand::basictype2arraycopy(BasicType t,
|
||||||
bool disjoint_bases,
|
bool disjoint_bases,
|
||||||
const char* &name,
|
const char* &name,
|
||||||
bool dest_uninitialized) {
|
bool dest_uninitialized) {
|
||||||
const TypeInt* src_offset_inttype = _igvn.find_int_type(src_offset);;
|
const TypeInt* src_offset_inttype = _igvn.find_int_type(src_offset);
|
||||||
const TypeInt* dest_offset_inttype = _igvn.find_int_type(dest_offset);;
|
const TypeInt* dest_offset_inttype = _igvn.find_int_type(dest_offset);
|
||||||
|
|
||||||
bool aligned = false;
|
bool aligned = false;
|
||||||
bool disjoint = disjoint_bases;
|
bool disjoint = disjoint_bases;
|
||||||
|
|
|
@ -2122,7 +2122,32 @@ WB_ENTRY(void, WB_AsyncHandshakeWalkStack(JNIEnv* env, jobject wb, jobject threa
|
||||||
}
|
}
|
||||||
WB_END
|
WB_END
|
||||||
|
|
||||||
//Some convenience methods to deal with objects from java
|
static volatile int _emulated_lock = 0;
|
||||||
|
|
||||||
|
WB_ENTRY(void, WB_LockAndBlock(JNIEnv* env, jobject wb, jboolean suspender))
|
||||||
|
JavaThread* self = JavaThread::current();
|
||||||
|
|
||||||
|
{
|
||||||
|
// Before trying to acquire the lock transition into a safepoint safe state.
|
||||||
|
// Otherwise if either suspender or suspendee blocks for a safepoint
|
||||||
|
// in ~ThreadBlockInVM the other one could loop forever trying to acquire
|
||||||
|
// the lock without allowing the safepoint to progress.
|
||||||
|
ThreadBlockInVM tbivm(self);
|
||||||
|
|
||||||
|
// We will deadlock here if we are 'suspender' and 'suspendee'
|
||||||
|
// suspended in ~ThreadBlockInVM. This verifies we only suspend
|
||||||
|
// at the right place.
|
||||||
|
while (Atomic::cmpxchg(&_emulated_lock, 0, 1) != 0) {}
|
||||||
|
assert(_emulated_lock == 1, "Must be locked");
|
||||||
|
|
||||||
|
// Sleep much longer in suspendee to force situation where
|
||||||
|
// 'suspender' is waiting above to acquire lock.
|
||||||
|
os::naked_short_sleep(suspender ? 1 : 10);
|
||||||
|
}
|
||||||
|
Atomic::store(&_emulated_lock, 0);
|
||||||
|
WB_END
|
||||||
|
|
||||||
|
// Some convenience methods to deal with objects from java
|
||||||
int WhiteBox::offset_for_field(const char* field_name, oop object,
|
int WhiteBox::offset_for_field(const char* field_name, oop object,
|
||||||
Symbol* signature_symbol) {
|
Symbol* signature_symbol) {
|
||||||
assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
|
assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
|
||||||
|
@ -2613,6 +2638,7 @@ static JNINativeMethod methods[] = {
|
||||||
{CC"handshakeReadMonitors", CC"(Ljava/lang/Thread;)Z", (void*)&WB_HandshakeReadMonitors },
|
{CC"handshakeReadMonitors", CC"(Ljava/lang/Thread;)Z", (void*)&WB_HandshakeReadMonitors },
|
||||||
{CC"handshakeWalkStack", CC"(Ljava/lang/Thread;Z)I", (void*)&WB_HandshakeWalkStack },
|
{CC"handshakeWalkStack", CC"(Ljava/lang/Thread;Z)I", (void*)&WB_HandshakeWalkStack },
|
||||||
{CC"asyncHandshakeWalkStack", CC"(Ljava/lang/Thread;)V", (void*)&WB_AsyncHandshakeWalkStack },
|
{CC"asyncHandshakeWalkStack", CC"(Ljava/lang/Thread;)V", (void*)&WB_AsyncHandshakeWalkStack },
|
||||||
|
{CC"lockAndBlock", CC"(Z)V", (void*)&WB_LockAndBlock},
|
||||||
{CC"checkThreadObjOfTerminatingThread", CC"(Ljava/lang/Thread;)V", (void*)&WB_CheckThreadObjOfTerminatingThread },
|
{CC"checkThreadObjOfTerminatingThread", CC"(Ljava/lang/Thread;)V", (void*)&WB_CheckThreadObjOfTerminatingThread },
|
||||||
{CC"verifyFrames", CC"(ZZ)V", (void*)&WB_VerifyFrames },
|
{CC"verifyFrames", CC"(ZZ)V", (void*)&WB_VerifyFrames },
|
||||||
{CC"addCompilerDirective", CC"(Ljava/lang/String;)I",
|
{CC"addCompilerDirective", CC"(Ljava/lang/String;)I",
|
||||||
|
|
|
@ -77,6 +77,7 @@ class HandshakeOperation : public CHeapObj<mtThread> {
|
||||||
int32_t pending_threads() { return Atomic::load(&_pending_threads); }
|
int32_t pending_threads() { return Atomic::load(&_pending_threads); }
|
||||||
const char* name() { return _handshake_cl->name(); }
|
const char* name() { return _handshake_cl->name(); }
|
||||||
bool is_async() { return _handshake_cl->is_async(); }
|
bool is_async() { return _handshake_cl->is_async(); }
|
||||||
|
bool is_suspend() { return _handshake_cl->is_suspend(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncHandshakeOperation : public HandshakeOperation {
|
class AsyncHandshakeOperation : public HandshakeOperation {
|
||||||
|
@ -376,6 +377,7 @@ void Handshake::execute(HandshakeClosure* hs_cl, JavaThread* target) {
|
||||||
// Check for pending handshakes to avoid possible deadlocks where our
|
// Check for pending handshakes to avoid possible deadlocks where our
|
||||||
// target is trying to handshake us.
|
// target is trying to handshake us.
|
||||||
if (SafepointMechanism::should_process(self)) {
|
if (SafepointMechanism::should_process(self)) {
|
||||||
|
// Will not suspend here.
|
||||||
ThreadBlockInVM tbivm(self);
|
ThreadBlockInVM tbivm(self);
|
||||||
}
|
}
|
||||||
hsy.process();
|
hsy.process();
|
||||||
|
@ -425,11 +427,19 @@ bool HandshakeState::operation_pending(HandshakeOperation* op) {
|
||||||
return _queue.contains(mo);
|
return _queue.contains(mo);
|
||||||
}
|
}
|
||||||
|
|
||||||
HandshakeOperation* HandshakeState::get_op_for_self() {
|
static bool no_suspend_filter(HandshakeOperation* op) {
|
||||||
|
return !op->is_suspend();
|
||||||
|
}
|
||||||
|
|
||||||
|
HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend) {
|
||||||
assert(_handshakee == Thread::current(), "Must be called by self");
|
assert(_handshakee == Thread::current(), "Must be called by self");
|
||||||
assert(_lock.owned_by_self(), "Lock must be held");
|
assert(_lock.owned_by_self(), "Lock must be held");
|
||||||
return _queue.peek();
|
if (allow_suspend) {
|
||||||
};
|
return _queue.peek();
|
||||||
|
} else {
|
||||||
|
return _queue.peek(no_suspend_filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool non_self_queue_filter(HandshakeOperation* op) {
|
static bool non_self_queue_filter(HandshakeOperation* op) {
|
||||||
return !op->is_async();
|
return !op->is_async();
|
||||||
|
@ -441,6 +451,11 @@ bool HandshakeState::have_non_self_executable_operation() {
|
||||||
return _queue.contains(non_self_queue_filter);
|
return _queue.contains(non_self_queue_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HandshakeState::has_a_non_suspend_operation() {
|
||||||
|
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
|
||||||
|
return _queue.contains(no_suspend_filter);
|
||||||
|
}
|
||||||
|
|
||||||
HandshakeOperation* HandshakeState::get_op() {
|
HandshakeOperation* HandshakeState::get_op() {
|
||||||
assert(_handshakee != Thread::current(), "Must not be called by self");
|
assert(_handshakee != Thread::current(), "Must not be called by self");
|
||||||
assert(_lock.owned_by_self(), "Lock must be held");
|
assert(_lock.owned_by_self(), "Lock must be held");
|
||||||
|
@ -454,25 +469,22 @@ void HandshakeState::remove_op(HandshakeOperation* op) {
|
||||||
assert(ret == op, "Popped op must match requested op");
|
assert(ret == op, "Popped op must match requested op");
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HandshakeState::process_by_self() {
|
bool HandshakeState::process_by_self(bool allow_suspend) {
|
||||||
assert(Thread::current() == _handshakee, "should call from _handshakee");
|
assert(Thread::current() == _handshakee, "should call from _handshakee");
|
||||||
assert(!_handshakee->is_terminated(), "should not be a terminated thread");
|
assert(!_handshakee->is_terminated(), "should not be a terminated thread");
|
||||||
assert(_handshakee->thread_state() != _thread_blocked, "should not be in a blocked state");
|
assert(_handshakee->thread_state() != _thread_blocked, "should not be in a blocked state");
|
||||||
assert(_handshakee->thread_state() != _thread_in_native, "should not be in native");
|
assert(_handshakee->thread_state() != _thread_in_native, "should not be in native");
|
||||||
ThreadInVMForHandshake tivm(_handshakee);
|
|
||||||
{
|
|
||||||
// Handshakes cannot safely safepoint.
|
|
||||||
// The exception to this rule is the asynchronous suspension handshake.
|
|
||||||
// It by-passes the NSV by manually doing the transition.
|
|
||||||
NoSafepointVerifier nsv;
|
|
||||||
return process_self_inner();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HandshakeState::process_self_inner() {
|
ThreadInVMForHandshake tivm(_handshakee);
|
||||||
|
// Handshakes cannot safely safepoint.
|
||||||
|
// The exception to this rule is the asynchronous suspension handshake.
|
||||||
|
// It by-passes the NSV by manually doing the transition.
|
||||||
|
NoSafepointVerifier nsv;
|
||||||
|
|
||||||
while (has_operation()) {
|
while (has_operation()) {
|
||||||
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
|
MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag);
|
||||||
HandshakeOperation* op = get_op_for_self();
|
|
||||||
|
HandshakeOperation* op = get_op_for_self(allow_suspend);
|
||||||
if (op != NULL) {
|
if (op != NULL) {
|
||||||
assert(op->_target == NULL || op->_target == Thread::current(), "Wrong thread");
|
assert(op->_target == NULL || op->_target == Thread::current(), "Wrong thread");
|
||||||
bool async = op->is_async();
|
bool async = op->is_async();
|
||||||
|
@ -621,6 +633,7 @@ class ThreadSelfSuspensionHandshake : public AsyncHandshakeClosure {
|
||||||
assert(current == Thread::current(), "Must be self executed.");
|
assert(current == Thread::current(), "Must be self executed.");
|
||||||
current->handshake_state()->do_self_suspend();
|
current->handshake_state()->do_self_suspend();
|
||||||
}
|
}
|
||||||
|
virtual bool is_suspend() { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HandshakeState::suspend_with_handshake() {
|
bool HandshakeState::suspend_with_handshake() {
|
||||||
|
@ -667,8 +680,15 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
bool HandshakeState::suspend() {
|
bool HandshakeState::suspend() {
|
||||||
|
JavaThread* self = JavaThread::current();
|
||||||
SuspendThreadHandshake st;
|
SuspendThreadHandshake st;
|
||||||
Handshake::execute(&st, _handshakee);
|
Handshake::execute(&st, _handshakee);
|
||||||
|
if (_handshakee == self) {
|
||||||
|
// If target is the current thread we need to call this to do the
|
||||||
|
// actual suspend since Handshake::execute() above only installed
|
||||||
|
// the asynchronous handshake.
|
||||||
|
SafepointMechanism::process_if_requested(self);
|
||||||
|
}
|
||||||
return st.did_suspend();
|
return st.did_suspend();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ class HandshakeClosure : public ThreadClosure, public CHeapObj<mtThread> {
|
||||||
virtual ~HandshakeClosure() {}
|
virtual ~HandshakeClosure() {}
|
||||||
const char* name() const { return _name; }
|
const char* name() const { return _name; }
|
||||||
virtual bool is_async() { return false; }
|
virtual bool is_async() { return false; }
|
||||||
|
virtual bool is_suspend() { return false; }
|
||||||
virtual void do_thread(Thread* thread) = 0;
|
virtual void do_thread(Thread* thread) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -92,15 +93,8 @@ class HandshakeState {
|
||||||
bool possibly_can_process_handshake();
|
bool possibly_can_process_handshake();
|
||||||
bool can_process_handshake();
|
bool can_process_handshake();
|
||||||
|
|
||||||
// Returns false if the JavaThread finished all its handshake operations.
|
|
||||||
// If the method returns true there is still potential work to be done,
|
|
||||||
// but we need to check for a safepoint before.
|
|
||||||
// (This is due to a suspension handshake which put the JavaThread in blocked
|
|
||||||
// state so a safepoint may be in-progress.)
|
|
||||||
bool process_self_inner();
|
|
||||||
|
|
||||||
bool have_non_self_executable_operation();
|
bool have_non_self_executable_operation();
|
||||||
HandshakeOperation* get_op_for_self();
|
HandshakeOperation* get_op_for_self(bool allow_suspend);
|
||||||
HandshakeOperation* get_op();
|
HandshakeOperation* get_op();
|
||||||
void remove_op(HandshakeOperation* op);
|
void remove_op(HandshakeOperation* op);
|
||||||
|
|
||||||
|
@ -123,10 +117,14 @@ class HandshakeState {
|
||||||
bool has_operation() {
|
bool has_operation() {
|
||||||
return !_queue.is_empty();
|
return !_queue.is_empty();
|
||||||
}
|
}
|
||||||
|
bool has_a_non_suspend_operation();
|
||||||
|
|
||||||
bool operation_pending(HandshakeOperation* op);
|
bool operation_pending(HandshakeOperation* op);
|
||||||
|
|
||||||
bool process_by_self();
|
// If the method returns true we need to check for a possible safepoint.
|
||||||
|
// This is due to a suspension handshake which put the JavaThread in blocked
|
||||||
|
// state so a safepoint may be in-progress.
|
||||||
|
bool process_by_self(bool allow_suspend);
|
||||||
|
|
||||||
enum ProcessResult {
|
enum ProcessResult {
|
||||||
_no_operation = 0,
|
_no_operation = 0,
|
||||||
|
|
|
@ -243,8 +243,10 @@ template <typename PRE_PROC>
|
||||||
class ThreadBlockInVMPreprocess : public ThreadStateTransition {
|
class ThreadBlockInVMPreprocess : public ThreadStateTransition {
|
||||||
private:
|
private:
|
||||||
PRE_PROC& _pr;
|
PRE_PROC& _pr;
|
||||||
|
bool _allow_suspend;
|
||||||
public:
|
public:
|
||||||
ThreadBlockInVMPreprocess(JavaThread* thread, PRE_PROC& pr) : ThreadStateTransition(thread), _pr(pr) {
|
ThreadBlockInVMPreprocess(JavaThread* thread, PRE_PROC& pr, bool allow_suspend = true)
|
||||||
|
: ThreadStateTransition(thread), _pr(pr), _allow_suspend(allow_suspend) {
|
||||||
assert(thread->thread_state() == _thread_in_vm, "coming from wrong thread state");
|
assert(thread->thread_state() == _thread_in_vm, "coming from wrong thread state");
|
||||||
thread->check_possible_safepoint();
|
thread->check_possible_safepoint();
|
||||||
// Once we are blocked vm expects stack to be walkable
|
// Once we are blocked vm expects stack to be walkable
|
||||||
|
@ -257,9 +259,9 @@ class ThreadBlockInVMPreprocess : public ThreadStateTransition {
|
||||||
// Change to transition state and ensure it is seen by the VM thread.
|
// Change to transition state and ensure it is seen by the VM thread.
|
||||||
_thread->set_thread_state_fence(_thread_blocked_trans);
|
_thread->set_thread_state_fence(_thread_blocked_trans);
|
||||||
|
|
||||||
if (SafepointMechanism::should_process(_thread)) {
|
if (SafepointMechanism::should_process(_thread, _allow_suspend)) {
|
||||||
_pr(_thread);
|
_pr(_thread);
|
||||||
SafepointMechanism::process_if_requested(_thread);
|
SafepointMechanism::process_if_requested(_thread, _allow_suspend);
|
||||||
}
|
}
|
||||||
|
|
||||||
_thread->set_thread_state(_thread_in_vm);
|
_thread->set_thread_state(_thread_in_vm);
|
||||||
|
@ -289,7 +291,7 @@ class ThreadBlockInVM {
|
||||||
ThreadBlockInVMPreprocess<InFlightMutexRelease> _tbivmpp;
|
ThreadBlockInVMPreprocess<InFlightMutexRelease> _tbivmpp;
|
||||||
public:
|
public:
|
||||||
ThreadBlockInVM(JavaThread* thread, Mutex** in_flight_mutex_addr = NULL)
|
ThreadBlockInVM(JavaThread* thread, Mutex** in_flight_mutex_addr = NULL)
|
||||||
: _ifmr(in_flight_mutex_addr), _tbivmpp(thread, _ifmr) {}
|
: _ifmr(in_flight_mutex_addr), _tbivmpp(thread, _ifmr, /* allow_suspend= */ false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debug class instantiated in JRT_ENTRY macro.
|
// Debug class instantiated in JRT_ENTRY macro.
|
||||||
|
|
|
@ -76,29 +76,6 @@ void SafepointMechanism::default_initialize() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafepointMechanism::process(JavaThread *thread) {
|
|
||||||
bool need_rechecking;
|
|
||||||
do {
|
|
||||||
if (global_poll()) {
|
|
||||||
// Any load in ::block() must not pass the global poll load.
|
|
||||||
// Otherwise we might load an old safepoint counter (for example).
|
|
||||||
OrderAccess::loadload();
|
|
||||||
SafepointSynchronize::block(thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The call to on_safepoint fixes the thread's oops and the first few frames.
|
|
||||||
//
|
|
||||||
// The call has been carefully placed here to cater to a few situations:
|
|
||||||
// 1) After we exit from block after a global poll
|
|
||||||
// 2) After a thread races with the disarming of the global poll and transitions from native/blocked
|
|
||||||
// 3) Before the handshake code is run
|
|
||||||
StackWatermarkSet::on_safepoint(thread);
|
|
||||||
|
|
||||||
need_rechecking = thread->handshake_state()->has_operation() && thread->handshake_state()->process_by_self();
|
|
||||||
|
|
||||||
} while (need_rechecking);
|
|
||||||
}
|
|
||||||
|
|
||||||
uintptr_t SafepointMechanism::compute_poll_word(bool armed, uintptr_t stack_watermark) {
|
uintptr_t SafepointMechanism::compute_poll_word(bool armed, uintptr_t stack_watermark) {
|
||||||
if (armed) {
|
if (armed) {
|
||||||
log_debug(stackbarrier)("Computed armed for tid %d", Thread::current()->osthread()->thread_id());
|
log_debug(stackbarrier)("Computed armed for tid %d", Thread::current()->osthread()->thread_id());
|
||||||
|
@ -134,12 +111,31 @@ void SafepointMechanism::update_poll_values(JavaThread* thread) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafepointMechanism::process_if_requested_slow(JavaThread *thread) {
|
void SafepointMechanism::process(JavaThread *thread, bool allow_suspend) {
|
||||||
// Read global poll and has_handshake after local poll
|
// Read global poll and has_handshake after local poll
|
||||||
OrderAccess::loadload();
|
OrderAccess::loadload();
|
||||||
|
|
||||||
// local poll already checked, if used.
|
// local poll already checked, if used.
|
||||||
process(thread);
|
bool need_rechecking;
|
||||||
|
do {
|
||||||
|
if (global_poll()) {
|
||||||
|
// Any load in ::block() must not pass the global poll load.
|
||||||
|
// Otherwise we might load an old safepoint counter (for example).
|
||||||
|
OrderAccess::loadload();
|
||||||
|
SafepointSynchronize::block(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The call to on_safepoint fixes the thread's oops and the first few frames.
|
||||||
|
//
|
||||||
|
// The call has been carefully placed here to cater to a few situations:
|
||||||
|
// 1) After we exit from block after a global poll
|
||||||
|
// 2) After a thread races with the disarming of the global poll and transitions from native/blocked
|
||||||
|
// 3) Before the handshake code is run
|
||||||
|
StackWatermarkSet::on_safepoint(thread);
|
||||||
|
|
||||||
|
need_rechecking = thread->handshake_state()->has_operation() && thread->handshake_state()->process_by_self(allow_suspend);
|
||||||
|
} while (need_rechecking);
|
||||||
|
|
||||||
update_poll_values(thread);
|
update_poll_values(thread);
|
||||||
OrderAccess::cross_modify_fence();
|
OrderAccess::cross_modify_fence();
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,9 @@ class SafepointMechanism : public AllStatic {
|
||||||
|
|
||||||
static inline bool global_poll();
|
static inline bool global_poll();
|
||||||
|
|
||||||
static void process(JavaThread *thread);
|
static void process(JavaThread *thread, bool allow_suspend);
|
||||||
static void process_if_requested_slow(JavaThread *thread);
|
|
||||||
|
static inline bool should_process_no_suspend(JavaThread* thread);
|
||||||
|
|
||||||
static void default_initialize();
|
static void default_initialize();
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ class SafepointMechanism : public AllStatic {
|
||||||
static uintptr_t compute_poll_word(bool armed, uintptr_t stack_watermark);
|
static uintptr_t compute_poll_word(bool armed, uintptr_t stack_watermark);
|
||||||
|
|
||||||
const static intptr_t _poll_bit = 1;
|
const static intptr_t _poll_bit = 1;
|
||||||
public:
|
public:
|
||||||
static inline bool local_poll_armed(JavaThread* thread);
|
static inline bool local_poll_armed(JavaThread* thread);
|
||||||
static intptr_t poll_bit() { return _poll_bit; }
|
static intptr_t poll_bit() { return _poll_bit; }
|
||||||
|
|
||||||
|
@ -79,10 +80,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// Call this method to see if this thread should block for a safepoint or process handshake.
|
// Call this method to see if this thread should block for a safepoint or process handshake.
|
||||||
static inline bool should_process(JavaThread* thread);
|
static inline bool should_process(JavaThread* thread, bool allow_suspend = true);
|
||||||
|
|
||||||
// Processes a pending requested operation.
|
// Processes a pending requested operation.
|
||||||
static inline void process_if_requested(JavaThread* thread);
|
static inline void process_if_requested(JavaThread* thread, bool allow_suspend = true);
|
||||||
static inline void process_if_requested_with_exit_check(JavaThread* thread, bool check_asyncs);
|
static inline void process_if_requested_with_exit_check(JavaThread* thread, bool check_asyncs);
|
||||||
// Compute what the poll values should be and install them.
|
// Compute what the poll values should be and install them.
|
||||||
static void update_poll_values(JavaThread* thread);
|
static void update_poll_values(JavaThread* thread);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "runtime/safepointMechanism.hpp"
|
#include "runtime/safepointMechanism.hpp"
|
||||||
|
|
||||||
#include "runtime/atomic.hpp"
|
#include "runtime/atomic.hpp"
|
||||||
|
#include "runtime/handshake.hpp"
|
||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
|
|
||||||
|
@ -61,11 +62,29 @@ bool SafepointMechanism::global_poll() {
|
||||||
return (SafepointSynchronize::_state != SafepointSynchronize::_not_synchronized);
|
return (SafepointSynchronize::_state != SafepointSynchronize::_not_synchronized);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SafepointMechanism::should_process(JavaThread* thread) {
|
bool SafepointMechanism::should_process_no_suspend(JavaThread* thread) {
|
||||||
return local_poll_armed(thread);
|
if (global_poll() || thread->handshake_state()->has_a_non_suspend_operation()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// We ignore suspend requests if any and just check before returning if we need
|
||||||
|
// to fix the thread's oops and first few frames due to a possible safepoint.
|
||||||
|
StackWatermarkSet::on_safepoint(thread);
|
||||||
|
update_poll_values(thread);
|
||||||
|
OrderAccess::cross_modify_fence();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SafepointMechanism::process_if_requested(JavaThread* thread) {
|
bool SafepointMechanism::should_process(JavaThread* thread, bool allow_suspend) {
|
||||||
|
if (!local_poll_armed(thread)) {
|
||||||
|
return false;
|
||||||
|
} else if (allow_suspend) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return should_process_no_suspend(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SafepointMechanism::process_if_requested(JavaThread* thread, bool allow_suspend) {
|
||||||
|
|
||||||
// Macos/aarch64 should be in the right state for safepoint (e.g.
|
// Macos/aarch64 should be in the right state for safepoint (e.g.
|
||||||
// deoptimization needs WXWrite). Crashes caused by the wrong state rarely
|
// deoptimization needs WXWrite). Crashes caused by the wrong state rarely
|
||||||
|
@ -77,7 +96,7 @@ void SafepointMechanism::process_if_requested(JavaThread* thread) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (local_poll_armed(thread)) {
|
if (local_poll_armed(thread)) {
|
||||||
process_if_requested_slow(thread);
|
process(thread, allow_suspend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,16 +28,16 @@ package java.lang.annotation;
|
||||||
/**
|
/**
|
||||||
* Indicates the contexts in which an annotation interface is applicable. The
|
* Indicates the contexts in which an annotation interface is applicable. The
|
||||||
* declaration contexts and type contexts in which an annotation interface may
|
* declaration contexts and type contexts in which an annotation interface may
|
||||||
* be applicable are specified in JLS 9.6.4.1, and denoted in source code by
|
* be applicable are specified in JLS {@jls 9.6.4.1}, and denoted in source code by
|
||||||
* enum constants of {@link ElementType java.lang.annotation.ElementType}.
|
* enum constants of {@link ElementType java.lang.annotation.ElementType}.
|
||||||
*
|
*
|
||||||
* <p>If an {@code @Target} meta-annotation is not present on an annotation
|
* <p>If an {@code @Target} meta-annotation is not present on an annotation
|
||||||
* interface {@code T}, then an annotation of type {@code T} may be written as
|
* interface {@code T}, then an annotation of type {@code T} may be written as
|
||||||
* a modifier for any declaration except a type parameter declaration.
|
* a modifier for any declaration.
|
||||||
*
|
*
|
||||||
* <p>If an {@code @Target} meta-annotation is present, the compiler will enforce
|
* <p>If an {@code @Target} meta-annotation is present, the compiler will enforce
|
||||||
* the usage restrictions indicated by {@code ElementType}
|
* the usage restrictions indicated by {@code ElementType}
|
||||||
* enum constants, in line with JLS 9.7.4.
|
* enum constants, in line with JLS {@jls 9.7.4}.
|
||||||
*
|
*
|
||||||
* <p>For example, this {@code @Target} meta-annotation indicates that the
|
* <p>For example, this {@code @Target} meta-annotation indicates that the
|
||||||
* declared interface is itself a meta-annotation interface. It can only be
|
* declared interface is itself a meta-annotation interface. It can only be
|
||||||
|
|
|
@ -113,7 +113,7 @@ Jvm* AppLauncher::createJvmLauncher() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
SysInfo::setEnvVariable(libEnvVarName, SysInfo::getEnvVariable(
|
SysInfo::setEnvVariable(libEnvVarName, SysInfo::getEnvVariable(
|
||||||
std::nothrow, libEnvVarName) + _T(";") + appDirPath);
|
std::nothrow, libEnvVarName) + FileUtils::pathSeparator + appDirPath);
|
||||||
|
|
||||||
std::unique_ptr<Jvm> jvm(new Jvm());
|
std::unique_ptr<Jvm> jvm(new Jvm());
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,15 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8155643
|
* @bug 8155643 8268125 8270461
|
||||||
* @summary Test Object.clone() intrinsic if ReduceInitialCardMarks is disabled.
|
* @summary Test Object.clone() intrinsic.
|
||||||
*
|
*
|
||||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-ReduceInitialCardMarks
|
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-ReduceInitialCardMarks
|
||||||
* -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
|
* -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
|
||||||
* compiler.arraycopy.TestObjectArrayClone
|
* compiler.arraycopy.TestObjectArrayClone
|
||||||
*
|
* @run main/othervm -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
|
||||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions
|
* compiler.arraycopy.TestObjectArrayClone
|
||||||
|
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedClassPointers -Xmx128m
|
||||||
* -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
|
* -XX:CompileCommand=compileonly,compiler.arraycopy.TestObjectArrayClone::testClone*
|
||||||
* compiler.arraycopy.TestObjectArrayClone
|
* compiler.arraycopy.TestObjectArrayClone
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,9 +31,9 @@ import sun.hotspot.WhiteBox;
|
||||||
* @summary Check if VM can kill thread which doesn't reach safepoint.
|
* @summary Check if VM can kill thread which doesn't reach safepoint.
|
||||||
* @bug 8219584 8227528
|
* @bug 8219584 8227528
|
||||||
* @library /testlibrary /test/lib
|
* @library /testlibrary /test/lib
|
||||||
* @build TestAbortVMOnSafepointTimeout
|
* @build sun.hotspot.WhiteBox
|
||||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestAbortVMOnSafepointTimeout
|
* @run driver TestAbortVMOnSafepointTimeout
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TestAbortVMOnSafepointTimeout {
|
public class TestAbortVMOnSafepointTimeout {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -28,8 +28,7 @@
|
||||||
* @library /test/lib
|
* @library /test/lib
|
||||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.misc
|
* java.base/jdk.internal.misc
|
||||||
* @compile LargeClassTest.java
|
* @run driver LargeClassTest
|
||||||
* @run main LargeClassTest
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -85,9 +85,4 @@ public class TestThreadDumpSMRInfo {
|
||||||
|
|
||||||
System.out.println("Test PASSED.");
|
System.out.println("Test PASSED.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usage() {
|
|
||||||
System.err.println("Usage: java TestThreadDumpSMRInfo [-v]");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -44,6 +44,7 @@ public class DuplAttributesTest {
|
||||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(test);
|
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(test);
|
||||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||||
output.shouldContain("java.lang.ClassFormatError: Multiple " + result);
|
output.shouldContain("java.lang.ClassFormatError: Multiple " + result);
|
||||||
|
output.shouldNotHaveExitValue(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) throws Throwable {
|
public static void main(String args[]) throws Throwable {
|
||||||
|
|
|
@ -57,6 +57,7 @@ public class HandshakeTimeoutTest {
|
||||||
"HandshakeTimeoutTest$Test");
|
"HandshakeTimeoutTest$Test");
|
||||||
|
|
||||||
OutputAnalyzer output = ProcessTools.executeProcess(pb);
|
OutputAnalyzer output = ProcessTools.executeProcess(pb);
|
||||||
|
output.shouldNotHaveExitValue(0);
|
||||||
output.reportDiagnosticSummary();
|
output.reportDiagnosticSummary();
|
||||||
// In rare cases the target wakes up and performs the handshake at the same time as we timeout.
|
// In rare cases the target wakes up and performs the handshake at the same time as we timeout.
|
||||||
// Therefore it's not certain the timeout will find any thread.
|
// Therefore it's not certain the timeout will find any thread.
|
||||||
|
|
58
test/hotspot/jtreg/runtime/handshake/SuspendBlocked.java
Normal file
58
test/hotspot/jtreg/runtime/handshake/SuspendBlocked.java
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test SuspendBlocked
|
||||||
|
* @bug 8270085
|
||||||
|
* @library /test/lib
|
||||||
|
* @build SuspendBlocked
|
||||||
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
|
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI SuspendBlocked
|
||||||
|
*/
|
||||||
|
|
||||||
|
import jdk.test.lib.Asserts;
|
||||||
|
import sun.hotspot.WhiteBox;
|
||||||
|
|
||||||
|
public class SuspendBlocked {
|
||||||
|
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
Thread suspend_thread = new Thread(() -> run_loop());
|
||||||
|
suspend_thread.start();
|
||||||
|
WhiteBox wb = WhiteBox.getWhiteBox();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
suspend_thread.suspend();
|
||||||
|
wb.lockAndBlock(/* suspender= */ true);
|
||||||
|
suspend_thread.resume();
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
suspend_thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void run_loop() {
|
||||||
|
WhiteBox wb = WhiteBox.getWhiteBox();
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
wb.lockAndBlock(/* suspender= */ false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import jdk.test.lib.Utils;
|
||||||
import jdk.test.lib.process.ProcessTools;
|
import jdk.test.lib.process.ProcessTools;
|
||||||
import jdk.test.lib.process.OutputAnalyzer;
|
import jdk.test.lib.process.OutputAnalyzer;
|
||||||
|
|
||||||
|
@ -154,6 +155,7 @@ public class TestCheckedJniExceptionCheck {
|
||||||
|
|
||||||
// Check warnings appear where they should, with start/end statements in output...
|
// Check warnings appear where they should, with start/end statements in output...
|
||||||
static void checkOuputForCorrectWarnings(OutputAnalyzer oa) throws RuntimeException {
|
static void checkOuputForCorrectWarnings(OutputAnalyzer oa) throws RuntimeException {
|
||||||
|
oa.shouldHaveExitValue(0);
|
||||||
List<String> lines = oa.asLines();
|
List<String> lines = oa.asLines();
|
||||||
int expectedWarnings = 0;
|
int expectedWarnings = 0;
|
||||||
int warningCount = 0;
|
int warningCount = 0;
|
||||||
|
@ -175,12 +177,10 @@ public class TestCheckedJniExceptionCheck {
|
||||||
oa.reportDiagnosticSummary();
|
oa.reportDiagnosticSummary();
|
||||||
throw new RuntimeException("Unexpected warning at line " + lineNo);
|
throw new RuntimeException("Unexpected warning at line " + lineNo);
|
||||||
}
|
}
|
||||||
}
|
} else if (line.startsWith(EXPECT_WARNING_START)) {
|
||||||
else if (line.startsWith(EXPECT_WARNING_START)) {
|
|
||||||
String countStr = line.substring(EXPECT_WARNING_START.length() + 1);
|
String countStr = line.substring(EXPECT_WARNING_START.length() + 1);
|
||||||
expectedWarnings = Integer.parseInt(countStr);
|
expectedWarnings = Integer.parseInt(countStr);
|
||||||
}
|
} else if (line.startsWith(EXPECT_WARNING_END)) {
|
||||||
else if (line.startsWith(EXPECT_WARNING_END)) {
|
|
||||||
if (warningCount != expectedWarnings) {
|
if (warningCount != expectedWarnings) {
|
||||||
oa.reportDiagnosticSummary();
|
oa.reportDiagnosticSummary();
|
||||||
throw new RuntimeException("Missing warning at line " + lineNo);
|
throw new RuntimeException("Missing warning at line " + lineNo);
|
||||||
|
@ -189,6 +189,9 @@ public class TestCheckedJniExceptionCheck {
|
||||||
expectedWarnings = 0;
|
expectedWarnings = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!testStartLine) {
|
||||||
|
throw new RuntimeException("Missing test start line after " + lineNo + " lines");
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
System.out.println("Output looks good...");
|
System.out.println("Output looks good...");
|
||||||
oa.reportDiagnosticSummary();
|
oa.reportDiagnosticSummary();
|
||||||
|
@ -203,7 +206,8 @@ public class TestCheckedJniExceptionCheck {
|
||||||
|
|
||||||
// launch and check output
|
// launch and check output
|
||||||
checkOuputForCorrectWarnings(ProcessTools.executeTestJvm("-Xcheck:jni",
|
checkOuputForCorrectWarnings(ProcessTools.executeTestJvm("-Xcheck:jni",
|
||||||
"TestCheckedJniExceptionCheck"));
|
"-Djava.library.path=" + Utils.TEST_NATIVE_PATH,
|
||||||
|
"TestCheckedJniExceptionCheck"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -608,6 +608,8 @@ public class WhiteBox {
|
||||||
public native boolean handshakeReadMonitors(Thread t);
|
public native boolean handshakeReadMonitors(Thread t);
|
||||||
public native void asyncHandshakeWalkStack(Thread t);
|
public native void asyncHandshakeWalkStack(Thread t);
|
||||||
|
|
||||||
|
public native void lockAndBlock(boolean suspender);
|
||||||
|
|
||||||
// Returns true on linux if library has the noexecstack flag set.
|
// Returns true on linux if library has the noexecstack flag set.
|
||||||
public native boolean checkLibSpecifiesNoexecstack(String libfilename);
|
public native boolean checkLibSpecifiesNoexecstack(String libfilename);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue