8265934: Cleanup _suspend_flags and _special_runtime_exit_condition

Reviewed-by: rehn, dcubed, dholmes
This commit is contained in:
Patricio Chilano Mateo 2021-05-13 18:04:26 +00:00
parent f3c6cda476
commit 853ffdb25c
7 changed files with 129 additions and 138 deletions

View File

@ -2952,7 +2952,7 @@ JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable))
THROW_OOP(java_throwable);
} else {
// Use a VM_Operation to throw the exception.
Thread::send_async_exception(java_thread, java_throwable);
JavaThread::send_async_exception(java_thread, java_throwable);
}
} else {
// Either:

View File

@ -971,7 +971,7 @@ void ThreadSafepointState::handle_polling_page_exception() {
// If we have a pending async exception deoptimize the frame
// as otherwise we may never deliver it.
if (self->has_async_condition()) {
if (self->has_async_exception_condition()) {
ThreadInVMfromJava __tiv(self, false /* check asyncs */);
Deoptimization::deoptimize_frame(self, caller_fr.id());
}

View File

@ -265,8 +265,6 @@ Thread::Thread() {
set_allocated_bytes(0);
_current_pending_raw_monitor = NULL;
_suspend_flags = 0;
// thread-specific hashCode stream generator state - Marsaglia shift-xor form
_hashStateX = os::random();
_hashStateY = 842502087;
@ -541,27 +539,6 @@ void Thread::start(Thread* thread) {
os::start_thread(thread);
}
class InstallAsyncExceptionClosure : public HandshakeClosure {
Handle _throwable; // The Throwable thrown at the target Thread
public:
InstallAsyncExceptionClosure(Handle throwable) : HandshakeClosure("InstallAsyncException"), _throwable(throwable) {}
void do_thread(Thread* thr) {
JavaThread* target = thr->as_Java_thread();
// Note that this now allows multiple ThreadDeath exceptions to be
// thrown at a thread.
// The target thread has run and has not exited yet.
target->send_thread_stop(_throwable());
}
};
void Thread::send_async_exception(oop java_thread, oop java_throwable) {
Handle throwable(Thread::current(), java_throwable);
JavaThread* target = java_lang_Thread::thread(java_thread);
InstallAsyncExceptionClosure vm_stop(throwable);
Handshake::execute(&vm_stop, target);
}
// GC Support
bool Thread::claim_par_threads_do(uintx claim_token) {
uintx token = _threads_do_token;
@ -1045,7 +1022,9 @@ JavaThread::JavaThread() :
_Stalled(0),
_monitor_chunks(nullptr),
_special_runtime_exit_condition(_no_async_condition),
_suspend_flags(0),
_async_exception_condition(_no_async_condition),
_pending_async_exception(nullptr),
_thread_state(_thread_new),
@ -1606,13 +1585,14 @@ void JavaThread::remove_monitor_chunk(MonitorChunk* chunk) {
}
}
// JVM support.
// Asynchronous exceptions support
//
// Note: this function shouldn't block if it's called in
// _thread_in_native_trans state (such as from
// check_special_condition_for_native_trans()).
void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
if (has_last_Java_frame() && has_async_condition()) {
void JavaThread::check_and_handle_async_exceptions() {
if (has_last_Java_frame() && has_async_exception_condition()) {
// If we are at a polling page safepoint (not a poll return)
// then we must defer async exception because live registers
// will be clobbered by the exception path. Poll return is
@ -1636,7 +1616,7 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
}
}
JavaThread::AsyncRequests condition = clear_special_runtime_exit_condition();
AsyncExceptionCondition condition = clear_async_exception_condition();
if (condition == _no_async_condition) {
// Conditions have changed since has_special_runtime_exit_condition()
// was called:
@ -1668,15 +1648,14 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
ls.print_cr(" of type: %s", _pending_async_exception->klass()->external_name());
}
_pending_async_exception = NULL;
clear_has_async_exception();
// Clear condition from _suspend_flags since we have finished processing it.
clear_suspend_flag(_has_async_exception);
}
}
if (check_unsafe_error &&
condition == _async_unsafe_access_error && !has_pending_exception()) {
if (condition == _async_unsafe_access_error && !has_pending_exception()) {
// We may be at method entry which requires we save the do-not-unlock flag.
UnlockFlagSaver fs(this);
condition = _no_async_condition; // done
switch (thread_state()) {
case _thread_in_vm: {
JavaThread* THREAD = this;
@ -1700,9 +1679,7 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
}
}
assert(condition == _no_async_condition || has_pending_exception() ||
(!check_unsafe_error && condition == _async_unsafe_access_error),
"must have handled the async condition, if no exception");
assert(has_pending_exception(), "must have handled the async condition if no exception");
}
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
@ -1721,6 +1698,27 @@ void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
JFR_ONLY(SUSPEND_THREAD_CONDITIONAL(this);)
}
class InstallAsyncExceptionClosure : public HandshakeClosure {
Handle _throwable; // The Throwable thrown at the target Thread
public:
InstallAsyncExceptionClosure(Handle throwable) : HandshakeClosure("InstallAsyncException"), _throwable(throwable) {}
void do_thread(Thread* thr) {
JavaThread* target = thr->as_Java_thread();
// Note that this now allows multiple ThreadDeath exceptions to be
// thrown at a thread.
// The target thread has run and has not exited yet.
target->send_thread_stop(_throwable());
}
};
void JavaThread::send_async_exception(oop java_thread, oop java_throwable) {
Handle throwable(Thread::current(), java_throwable);
JavaThread* target = java_lang_Thread::thread(java_thread);
InstallAsyncExceptionClosure vm_stop(throwable);
Handshake::execute(&vm_stop, target);
}
void JavaThread::send_thread_stop(oop java_throwable) {
ResourceMark rm;
assert(is_handshake_safe_for(Thread::current()),
@ -1875,10 +1873,10 @@ void JavaThread::check_special_condition_for_native_trans(JavaThread *thread) {
// barrier, which will trap unsafe stack frames.
StackWatermarkSet::before_unwind(thread);
if (thread->has_async_exception()) {
if (thread->has_async_exception_condition(false /* check unsafe access error */)) {
// We are in _thread_in_native_trans state, don't handle unsafe
// access error since that may block.
thread->check_and_handle_async_exceptions(false);
thread->check_and_handle_async_exceptions();
}
}

View File

@ -215,20 +215,6 @@ class Thread: public ThreadShadow {
protected:
static void* allocate(size_t size, bool throw_excpt, MEMFLAGS flags = mtThread);
enum SuspendFlags {
// NOTE: avoid using the sign-bit as cc generates different test code
// when the sign-bit is used, and sometimes incorrectly - see CR 6398077
_has_async_exception = 0x00000001U, // there is a pending async exception
_trace_flag = 0x00000004U, // call tracing backend
_obj_deopt = 0x00000008U // suspend for object reallocation and relocking for JVMTI agent
};
// various suspension related flags - atomically updated
// overloaded for async exception checking in check_special_condition_for_native_trans.
volatile uint32_t _suspend_flags;
private:
DEBUG_ONLY(bool _suspendible_thread;)
@ -396,20 +382,6 @@ class Thread: public ThreadShadow {
os::set_native_thread_name(name);
}
bool has_async_exception() const { return (_suspend_flags & _has_async_exception) != 0; }
inline void set_suspend_flag(SuspendFlags f);
inline void clear_suspend_flag(SuspendFlags f);
inline void set_has_async_exception();
inline void clear_has_async_exception();
inline void set_trace_flag();
inline void clear_trace_flag();
inline void set_obj_deopt_flag();
inline void clear_obj_deopt_flag();
// Support for Unhandled Oop detection
// Add the field for both, fastdebug and debug, builds to keep
// Thread's fields layout the same.
@ -440,9 +412,6 @@ class Thread: public ThreadShadow {
void set_skip_gcalot(bool v) { _skip_gcalot = v; }
#endif
// Installs a pending exception to be inserted later
static void send_async_exception(oop thread_oop, oop java_throwable);
// Resource area
ResourceArea* resource_area() const { return _resource_area; }
void set_resource_area(ResourceArea* area) { _resource_area = area; }
@ -478,10 +447,6 @@ class Thread: public ThreadShadow {
JFR_ONLY(DEFINE_THREAD_LOCAL_ACCESSOR_JFR;)
bool is_trace_suspend() { return (_suspend_flags & _trace_flag) != 0; }
bool is_obj_deopt_suspend() { return (_suspend_flags & _obj_deopt) != 0; }
// For tracking the Jvmti raw monitor the thread is pending on.
JvmtiRawMonitor* current_pending_raw_monitor() {
return _current_pending_raw_monitor;
@ -807,14 +772,62 @@ class JavaThread: public Thread {
// allocated during deoptimization
// and by JNI_MonitorEnter/Exit
// Async. requests support
enum AsyncRequests {
enum SuspendFlags {
// NOTE: avoid using the sign-bit as cc generates different test code
// when the sign-bit is used, and sometimes incorrectly - see CR 6398077
_has_async_exception = 0x00000001U, // there is a pending async exception
_trace_flag = 0x00000004U, // call tracing backend
_obj_deopt = 0x00000008U // suspend for object reallocation and relocking for JVMTI agent
};
// various suspension related flags - atomically updated
// overloaded with async exceptions so that we do a single check when transitioning from native->Java
volatile uint32_t _suspend_flags;
inline void set_suspend_flag(SuspendFlags f);
inline void clear_suspend_flag(SuspendFlags f);
public:
inline void set_trace_flag();
inline void clear_trace_flag();
inline void set_obj_deopt_flag();
inline void clear_obj_deopt_flag();
bool is_trace_suspend() { return (_suspend_flags & _trace_flag) != 0; }
bool is_obj_deopt_suspend() { return (_suspend_flags & _obj_deopt) != 0; }
// Asynchronous exceptions support
private:
enum AsyncExceptionCondition {
_no_async_condition = 0,
_async_exception,
_async_unsafe_access_error
};
AsyncRequests _special_runtime_exit_condition; // Enum indicating pending async. request
oop _pending_async_exception;
AsyncExceptionCondition _async_exception_condition;
oop _pending_async_exception;
void set_async_exception_condition(AsyncExceptionCondition aec) { _async_exception_condition = aec; }
AsyncExceptionCondition clear_async_exception_condition() {
AsyncExceptionCondition x = _async_exception_condition;
_async_exception_condition = _no_async_condition;
return x;
}
public:
bool has_async_exception_condition(bool check_unsafe_access_error = true) {
return check_unsafe_access_error ? _async_exception_condition != _no_async_condition
: _async_exception_condition == _async_exception;
}
inline void set_pending_async_exception(oop e);
void set_pending_unsafe_access_error() {
// Don't overwrite an asynchronous exception sent by another thread
if (_async_exception_condition == _no_async_condition) {
set_async_exception_condition(_async_unsafe_access_error);
}
}
void check_and_handle_async_exceptions();
// Installs a pending exception to be inserted later
static void send_async_exception(oop thread_oop, oop java_throwable);
void send_thread_stop(oop throwable);
// Safepoint support
public: // Expose _thread_state for SafeFetchInt()
@ -1127,33 +1140,16 @@ class JavaThread: public Thread {
// current thread, i.e. reverts optimizations based on escape analysis.
void wait_for_object_deoptimization();
// Thread.stop support
void send_thread_stop(oop throwable);
AsyncRequests clear_special_runtime_exit_condition() {
AsyncRequests x = _special_runtime_exit_condition;
_special_runtime_exit_condition = _no_async_condition;
return x;
}
// Are any async conditions present?
bool has_async_condition() { return (_special_runtime_exit_condition != _no_async_condition); }
void check_and_handle_async_exceptions(bool check_unsafe_error = true);
// these next two are also used for self-suspension and async exception support
void handle_special_runtime_exit_condition(bool check_asyncs = true);
// Return true if JavaThread has an asynchronous condition or
// if external suspension is requested.
bool has_special_runtime_exit_condition() {
return (_special_runtime_exit_condition != _no_async_condition) ||
return (_async_exception_condition != _no_async_condition) ||
(_suspend_flags & (_obj_deopt JFR_ONLY(| _trace_flag))) != 0;
}
void set_pending_unsafe_access_error() { _special_runtime_exit_condition = _async_unsafe_access_error; }
inline void set_pending_async_exception(oop e);
// Fast-locking support
bool is_lock_owned(address adr) const;

View File

@ -36,40 +36,6 @@
#include "runtime/os.hpp"
#endif
inline void Thread::set_suspend_flag(SuspendFlags f) {
uint32_t flags;
do {
flags = _suspend_flags;
}
while (Atomic::cmpxchg(&_suspend_flags, flags, (flags | f)) != flags);
}
inline void Thread::clear_suspend_flag(SuspendFlags f) {
uint32_t flags;
do {
flags = _suspend_flags;
}
while (Atomic::cmpxchg(&_suspend_flags, flags, (flags & ~f)) != flags);
}
inline void Thread::set_has_async_exception() {
set_suspend_flag(_has_async_exception);
}
inline void Thread::clear_has_async_exception() {
clear_suspend_flag(_has_async_exception);
}
inline void Thread::set_trace_flag() {
set_suspend_flag(_trace_flag);
}
inline void Thread::clear_trace_flag() {
clear_suspend_flag(_trace_flag);
}
inline void Thread::set_obj_deopt_flag() {
set_suspend_flag(_obj_deopt);
}
inline void Thread::clear_obj_deopt_flag() {
clear_suspend_flag(_obj_deopt);
}
inline jlong Thread::cooked_allocated_bytes() {
jlong allocated_bytes = Atomic::load_acquire(&_allocated_bytes);
if (UseTLAB) {
@ -119,10 +85,41 @@ inline WXMode Thread::enable_wx(WXMode new_state) {
}
#endif // __APPLE__ && AARCH64
inline void JavaThread::set_suspend_flag(SuspendFlags f) {
uint32_t flags;
do {
flags = _suspend_flags;
}
while (Atomic::cmpxchg(&_suspend_flags, flags, (flags | f)) != flags);
}
inline void JavaThread::clear_suspend_flag(SuspendFlags f) {
uint32_t flags;
do {
flags = _suspend_flags;
}
while (Atomic::cmpxchg(&_suspend_flags, flags, (flags & ~f)) != flags);
}
inline void JavaThread::set_trace_flag() {
set_suspend_flag(_trace_flag);
}
inline void JavaThread::clear_trace_flag() {
clear_suspend_flag(_trace_flag);
}
inline void JavaThread::set_obj_deopt_flag() {
set_suspend_flag(_obj_deopt);
}
inline void JavaThread::clear_obj_deopt_flag() {
clear_suspend_flag(_obj_deopt);
}
inline void JavaThread::set_pending_async_exception(oop e) {
_pending_async_exception = e;
_special_runtime_exit_condition = _async_exception;
set_has_async_exception();
set_async_exception_condition(_async_exception);
// Set _suspend_flags too so we save a comparison in the transition from native to Java
// in the native wrappers. It will be cleared in check_and_handle_async_exceptions()
// when we actually install the exception.
set_suspend_flag(_has_async_exception);
}
inline JavaThreadState JavaThread::thread_state() const {

View File

@ -730,7 +730,6 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
nonstatic_field(ThreadShadow, _pending_exception, oop) \
nonstatic_field(ThreadShadow, _exception_file, const char*) \
nonstatic_field(ThreadShadow, _exception_line, int) \
volatile_nonstatic_field(Thread, _suspend_flags, uint32_t) \
nonstatic_field(Thread, _active_handles, JNIHandleBlock*) \
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
nonstatic_field(Thread, _allocated_bytes, jlong) \
@ -743,11 +742,12 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
nonstatic_field(JavaThread, _current_pending_monitor, ObjectMonitor*) \
nonstatic_field(JavaThread, _current_pending_monitor_is_from_java, bool) \
nonstatic_field(JavaThread, _current_waiting_monitor, ObjectMonitor*) \
volatile_nonstatic_field(JavaThread, _suspend_flags, uint32_t) \
nonstatic_field(JavaThread, _async_exception_condition, JavaThread::AsyncExceptionCondition) \
nonstatic_field(JavaThread, _pending_async_exception, oop) \
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \
nonstatic_field(JavaThread, _special_runtime_exit_condition, JavaThread::AsyncRequests) \
nonstatic_field(JavaThread, _saved_exception_pc, address) \
volatile_nonstatic_field(JavaThread, _thread_state, JavaThreadState) \
nonstatic_field(JavaThread, _osthread, OSThread*) \
@ -1983,7 +1983,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_toplevel_type(JavaThread*) \
declare_toplevel_type(JavaThread *const *const) \
declare_toplevel_type(java_lang_Class) \
declare_integer_type(JavaThread::AsyncRequests) \
declare_integer_type(JavaThread::AsyncExceptionCondition) \
declare_integer_type(JavaThread::TerminatedTypes) \
declare_toplevel_type(jbyte*) \
declare_toplevel_type(jbyte**) \
@ -2143,7 +2143,7 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
/* Thread::SuspendFlags enum */ \
/*****************************/ \
\
declare_constant(Thread::_has_async_exception) \
declare_constant(JavaThread::_has_async_exception) \
\
/*******************/ \
/* JavaThreadState */ \

View File

@ -55,8 +55,8 @@ public class Thread extends VMObject {
Type typeThread = db.lookupType("Thread");
Type typeJavaThread = db.lookupType("JavaThread");
suspendFlagsField = typeThread.getCIntegerField("_suspend_flags");
HAS_ASYNC_EXCEPTION = db.lookupIntConstant("Thread::_has_async_exception").intValue();
suspendFlagsField = typeJavaThread.getCIntegerField("_suspend_flags");
HAS_ASYNC_EXCEPTION = db.lookupIntConstant("JavaThread::_has_async_exception").intValue();
tlabFieldOffset = typeThread.getField("_tlab").getOffset();
activeHandlesField = typeThread.getAddressField("_active_handles");