mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 09:34:38 +02:00
8274379: Allow process of unsafe access errors in check_special_condition_for_native_trans
Reviewed-by: rehn, dholmes
This commit is contained in:
parent
b870468bdc
commit
0d80f6cf82
7 changed files with 42 additions and 74 deletions
|
@ -2961,7 +2961,7 @@ JVM_ENTRY(void, JVM_StopThread(JNIEnv* env, jobject jthread, jobject throwable))
|
||||||
THROW_OOP(java_throwable);
|
THROW_OOP(java_throwable);
|
||||||
} else {
|
} else {
|
||||||
// Use a VM_Operation to throw the exception.
|
// Use a VM_Operation to throw the exception.
|
||||||
JavaThread::send_async_exception(java_thread, java_throwable);
|
JavaThread::send_async_exception(receiver, java_throwable);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Either:
|
// Either:
|
||||||
|
|
|
@ -1072,7 +1072,7 @@ JvmtiEnv::StopThread(JavaThread* java_thread, jobject exception) {
|
||||||
oop e = JNIHandles::resolve_external_guard(exception);
|
oop e = JNIHandles::resolve_external_guard(exception);
|
||||||
NULL_CHECK(e, JVMTI_ERROR_NULL_POINTER);
|
NULL_CHECK(e, JVMTI_ERROR_NULL_POINTER);
|
||||||
|
|
||||||
JavaThread::send_async_exception(java_thread->threadObj(), e);
|
JavaThread::send_async_exception(java_thread, e);
|
||||||
|
|
||||||
return JVMTI_ERROR_NONE;
|
return JVMTI_ERROR_NONE;
|
||||||
|
|
||||||
|
|
|
@ -131,7 +131,6 @@ class SafepointSynchronize : AllStatic {
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case _thread_in_vm:
|
case _thread_in_vm:
|
||||||
case _thread_in_Java: // From compiled code
|
case _thread_in_Java: // From compiled code
|
||||||
case _thread_in_native_trans:
|
|
||||||
case _thread_blocked_trans:
|
case _thread_blocked_trans:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -1001,8 +1001,10 @@ JavaThread::JavaThread() :
|
||||||
_monitor_chunks(nullptr),
|
_monitor_chunks(nullptr),
|
||||||
|
|
||||||
_suspend_flags(0),
|
_suspend_flags(0),
|
||||||
_async_exception_condition(_no_async_condition),
|
|
||||||
_pending_async_exception(nullptr),
|
_pending_async_exception(nullptr),
|
||||||
|
#ifdef ASSERT
|
||||||
|
_is_unsafe_access_error(false),
|
||||||
|
#endif
|
||||||
|
|
||||||
_thread_state(_thread_new),
|
_thread_state(_thread_new),
|
||||||
_saved_exception_pc(nullptr),
|
_saved_exception_pc(nullptr),
|
||||||
|
@ -1572,9 +1574,6 @@ void JavaThread::remove_monitor_chunk(MonitorChunk* chunk) {
|
||||||
|
|
||||||
// Asynchronous exceptions 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() {
|
void JavaThread::check_and_handle_async_exceptions() {
|
||||||
if (has_last_Java_frame() && has_async_exception_condition()) {
|
if (has_last_Java_frame() && has_async_exception_condition()) {
|
||||||
// If we are at a polling page safepoint (not a poll return)
|
// If we are at a polling page safepoint (not a poll return)
|
||||||
|
@ -1600,21 +1599,12 @@ void JavaThread::check_and_handle_async_exceptions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncExceptionCondition condition = clear_async_exception_condition();
|
if (!clear_async_exception_condition()) {
|
||||||
if (condition == _no_async_condition) {
|
|
||||||
// Conditions have changed since has_special_runtime_exit_condition()
|
|
||||||
// was called:
|
|
||||||
// - if we were here only because of an external suspend request,
|
|
||||||
// then that was taken care of above (or cancelled) so we are done
|
|
||||||
// - if we were here because of another async request, then it has
|
|
||||||
// been cleared between the has_special_runtime_exit_condition()
|
|
||||||
// and now so again we are done
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for pending async. exception
|
|
||||||
if (_pending_async_exception != NULL) {
|
if (_pending_async_exception != NULL) {
|
||||||
// Only overwrite an already pending exception, if it is not a threadDeath.
|
// Only overwrite an already pending exception if it is not a threadDeath.
|
||||||
if (!has_pending_exception() || !pending_exception()->is_a(vmClasses::ThreadDeath_klass())) {
|
if (!has_pending_exception() || !pending_exception()->is_a(vmClasses::ThreadDeath_klass())) {
|
||||||
|
|
||||||
// We cannot call Exceptions::_throw(...) here because we cannot block
|
// We cannot call Exceptions::_throw(...) here because we cannot block
|
||||||
|
@ -1631,25 +1621,23 @@ void JavaThread::check_and_handle_async_exceptions() {
|
||||||
}
|
}
|
||||||
ls.print_cr(" of type: %s", _pending_async_exception->klass()->external_name());
|
ls.print_cr(" of type: %s", _pending_async_exception->klass()->external_name());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Always null out the _pending_async_exception oop here since the async condition was
|
||||||
|
// already cleared above and thus considered handled.
|
||||||
_pending_async_exception = NULL;
|
_pending_async_exception = NULL;
|
||||||
// Clear condition from _suspend_flags since we have finished processing it.
|
} else {
|
||||||
clear_suspend_flag(_has_async_exception);
|
assert(_is_unsafe_access_error, "must be");
|
||||||
}
|
DEBUG_ONLY(_is_unsafe_access_error = false);
|
||||||
}
|
|
||||||
|
|
||||||
if (condition == _async_unsafe_access_error && !has_pending_exception()) {
|
|
||||||
// We may be at method entry which requires we save the do-not-unlock flag.
|
// We may be at method entry which requires we save the do-not-unlock flag.
|
||||||
UnlockFlagSaver fs(this);
|
UnlockFlagSaver fs(this);
|
||||||
switch (thread_state()) {
|
switch (thread_state()) {
|
||||||
case _thread_in_vm: {
|
case _thread_in_vm: {
|
||||||
JavaThread* THREAD = this;
|
JavaThread* THREAD = this;
|
||||||
Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation");
|
Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation");
|
||||||
return;
|
// We might have blocked in a ThreadBlockInVM wrapper in the call above so make sure we process pending
|
||||||
}
|
// suspend requests and object reallocation operations if any since we might be going to Java after this.
|
||||||
case _thread_in_native: {
|
SafepointMechanism::process_if_requested_with_exit_check(this, true /* check asyncs */);
|
||||||
ThreadInVMfromNative tiv(this);
|
|
||||||
JavaThread* THREAD = this;
|
|
||||||
Exceptions::throw_unsafe_access_internal_error(THREAD, __FILE__, __LINE__, "a fault occurred in an unsafe memory access operation");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case _thread_in_Java: {
|
case _thread_in_Java: {
|
||||||
|
@ -1662,8 +1650,6 @@ void JavaThread::check_and_handle_async_exceptions() {
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(has_pending_exception(), "must have handled the async condition if no exception");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
|
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
|
||||||
|
@ -1696,9 +1682,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void JavaThread::send_async_exception(oop java_thread, oop java_throwable) {
|
void JavaThread::send_async_exception(JavaThread* target, oop java_throwable) {
|
||||||
Handle throwable(Thread::current(), java_throwable);
|
Handle throwable(Thread::current(), java_throwable);
|
||||||
JavaThread* target = java_lang_Thread::thread(java_thread);
|
|
||||||
InstallAsyncExceptionClosure vm_stop(throwable);
|
InstallAsyncExceptionClosure vm_stop(throwable);
|
||||||
Handshake::execute(&vm_stop, target);
|
Handshake::execute(&vm_stop, target);
|
||||||
}
|
}
|
||||||
|
@ -1847,21 +1832,17 @@ void JavaThread::check_special_condition_for_native_trans(JavaThread *thread) {
|
||||||
assert(thread->thread_state() == _thread_in_native_trans, "wrong state");
|
assert(thread->thread_state() == _thread_in_native_trans, "wrong state");
|
||||||
assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native->Java transition");
|
assert(!thread->has_last_Java_frame() || thread->frame_anchor()->walkable(), "Unwalkable stack in native->Java transition");
|
||||||
|
|
||||||
|
thread->set_thread_state(_thread_in_vm);
|
||||||
|
|
||||||
// Enable WXWrite: called directly from interpreter native wrapper.
|
// Enable WXWrite: called directly from interpreter native wrapper.
|
||||||
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
|
MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, thread));
|
||||||
|
|
||||||
SafepointMechanism::process_if_requested_with_exit_check(thread, false /* check asyncs */);
|
SafepointMechanism::process_if_requested_with_exit_check(thread, true /* check asyncs */);
|
||||||
|
|
||||||
// After returning from native, it could be that the stack frames are not
|
// After returning from native, it could be that the stack frames are not
|
||||||
// yet safe to use. We catch such situations in the subsequent stack watermark
|
// yet safe to use. We catch such situations in the subsequent stack watermark
|
||||||
// barrier, which will trap unsafe stack frames.
|
// barrier, which will trap unsafe stack frames.
|
||||||
StackWatermarkSet::before_unwind(thread);
|
StackWatermarkSet::before_unwind(thread);
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
|
@ -802,37 +802,21 @@ class JavaThread: public Thread {
|
||||||
|
|
||||||
// Asynchronous exceptions support
|
// Asynchronous exceptions support
|
||||||
private:
|
private:
|
||||||
enum AsyncExceptionCondition {
|
|
||||||
_no_async_condition = 0,
|
|
||||||
_async_exception,
|
|
||||||
_async_unsafe_access_error
|
|
||||||
};
|
|
||||||
AsyncExceptionCondition _async_exception_condition;
|
|
||||||
oop _pending_async_exception;
|
oop _pending_async_exception;
|
||||||
|
#ifdef ASSERT
|
||||||
|
bool _is_unsafe_access_error;
|
||||||
|
#endif
|
||||||
|
|
||||||
void set_async_exception_condition(AsyncExceptionCondition aec) { _async_exception_condition = aec; }
|
inline bool clear_async_exception_condition();
|
||||||
AsyncExceptionCondition clear_async_exception_condition() {
|
|
||||||
AsyncExceptionCondition x = _async_exception_condition;
|
|
||||||
_async_exception_condition = _no_async_condition;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool has_async_exception_condition(bool check_unsafe_access_error = true) {
|
bool has_async_exception_condition() {
|
||||||
return check_unsafe_access_error ? _async_exception_condition != _no_async_condition
|
return (_suspend_flags & _has_async_exception) != 0;
|
||||||
: _async_exception_condition == _async_exception;
|
|
||||||
}
|
}
|
||||||
inline void set_pending_async_exception(oop e);
|
inline void set_pending_async_exception(oop e);
|
||||||
void set_pending_unsafe_access_error() {
|
inline void set_pending_unsafe_access_error();
|
||||||
// Don't overwrite an asynchronous exception sent by another thread
|
static void send_async_exception(JavaThread* jt, oop java_throwable);
|
||||||
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);
|
void send_thread_stop(oop throwable);
|
||||||
|
void check_and_handle_async_exceptions();
|
||||||
|
|
||||||
// Safepoint support
|
// Safepoint support
|
||||||
public: // Expose _thread_state for SafeFetchInt()
|
public: // Expose _thread_state for SafeFetchInt()
|
||||||
|
@ -1177,8 +1161,7 @@ class JavaThread: public Thread {
|
||||||
// Return true if JavaThread has an asynchronous condition or
|
// Return true if JavaThread has an asynchronous condition or
|
||||||
// if external suspension is requested.
|
// if external suspension is requested.
|
||||||
bool has_special_runtime_exit_condition() {
|
bool has_special_runtime_exit_condition() {
|
||||||
return (_async_exception_condition != _no_async_condition) ||
|
return (_suspend_flags & (_has_async_exception | _obj_deopt JFR_ONLY(| _trace_flag))) != 0;
|
||||||
(_suspend_flags & (_obj_deopt JFR_ONLY(| _trace_flag))) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast-locking support
|
// Fast-locking support
|
||||||
|
|
|
@ -122,15 +122,22 @@ inline void JavaThread::clear_obj_deopt_flag() {
|
||||||
clear_suspend_flag(_obj_deopt);
|
clear_suspend_flag(_obj_deopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool JavaThread::clear_async_exception_condition() {
|
||||||
|
bool ret = has_async_exception_condition();
|
||||||
|
clear_suspend_flag(_has_async_exception);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
inline void JavaThread::set_pending_async_exception(oop e) {
|
inline void JavaThread::set_pending_async_exception(oop e) {
|
||||||
_pending_async_exception = e;
|
_pending_async_exception = e;
|
||||||
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);
|
set_suspend_flag(_has_async_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void JavaThread::set_pending_unsafe_access_error() {
|
||||||
|
set_suspend_flag(_has_async_exception);
|
||||||
|
DEBUG_ONLY(_is_unsafe_access_error = true);
|
||||||
|
}
|
||||||
|
|
||||||
inline JavaThreadState JavaThread::thread_state() const {
|
inline JavaThreadState JavaThread::thread_state() const {
|
||||||
#if defined(PPC64) || defined (AARCH64)
|
#if defined(PPC64) || defined (AARCH64)
|
||||||
// Use membars when accessing volatile _thread_state. See
|
// Use membars when accessing volatile _thread_state. See
|
||||||
|
|
|
@ -717,7 +717,6 @@
|
||||||
nonstatic_field(JavaThread, _current_pending_monitor_is_from_java, bool) \
|
nonstatic_field(JavaThread, _current_pending_monitor_is_from_java, bool) \
|
||||||
volatile_nonstatic_field(JavaThread, _current_waiting_monitor, ObjectMonitor*) \
|
volatile_nonstatic_field(JavaThread, _current_waiting_monitor, ObjectMonitor*) \
|
||||||
volatile_nonstatic_field(JavaThread, _suspend_flags, uint32_t) \
|
volatile_nonstatic_field(JavaThread, _suspend_flags, uint32_t) \
|
||||||
nonstatic_field(JavaThread, _async_exception_condition, JavaThread::AsyncExceptionCondition) \
|
|
||||||
nonstatic_field(JavaThread, _pending_async_exception, oop) \
|
nonstatic_field(JavaThread, _pending_async_exception, oop) \
|
||||||
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
|
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
|
||||||
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
|
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
|
||||||
|
@ -1951,7 +1950,6 @@
|
||||||
declare_toplevel_type(JavaThread*) \
|
declare_toplevel_type(JavaThread*) \
|
||||||
declare_toplevel_type(JavaThread *const *const) \
|
declare_toplevel_type(JavaThread *const *const) \
|
||||||
declare_toplevel_type(java_lang_Class) \
|
declare_toplevel_type(java_lang_Class) \
|
||||||
declare_integer_type(JavaThread::AsyncExceptionCondition) \
|
|
||||||
declare_integer_type(JavaThread::TerminatedTypes) \
|
declare_integer_type(JavaThread::TerminatedTypes) \
|
||||||
declare_toplevel_type(jbyte*) \
|
declare_toplevel_type(jbyte*) \
|
||||||
declare_toplevel_type(jbyte**) \
|
declare_toplevel_type(jbyte**) \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue