--- old/make/hotspot/symbols/symbols-unix 2019-10-31 00:09:41.954296392 -0400 +++ new/make/hotspot/symbols/symbols-unix 2019-10-31 00:09:40.799283023 -0400 @@ -143,7 +143,6 @@ JVM_IsArrayClass JVM_IsConstructorIx JVM_IsInterface -JVM_IsInterrupted JVM_IsPrimitiveClass JVM_IsSameClassPackage JVM_IsSupportedJNIVersion --- old/src/hotspot/os/windows/osThread_windows.cpp 2019-10-31 00:09:45.741340227 -0400 +++ new/src/hotspot/os/windows/osThread_windows.cpp 2019-10-31 00:09:44.583326823 -0400 @@ -39,28 +39,15 @@ } } -// We need to specialize these to interact with the _interrupt_event. - -volatile bool OSThread::interrupted() { - return _interrupted != 0 && - (WaitForSingleObject(_interrupt_event, 0) == WAIT_OBJECT_0); -} +// We need to specialize this to interact with the _interrupt_event. void OSThread::set_interrupted(bool z) { if (z) { - _interrupted = 1; - // More than one thread can get here with the same value of osthread, - // resulting in multiple notifications. We do, however, want the store - // to interrupted() to be visible to other threads before we post - // the interrupt event. - OrderAccess::release(); SetEvent(_interrupt_event); } else { // We should only ever clear the interrupt if we are in fact interrupted, // and this can only be done by the current thread on itself. - assert(_interrupted == 1, "invariant for clearing interrupt state"); - _interrupted = 0; ResetEvent(_interrupt_event); } } --- old/src/hotspot/os/windows/osThread_windows.hpp 2019-10-31 00:09:49.276381144 -0400 +++ new/src/hotspot/os/windows/osThread_windows.hpp 2019-10-31 00:09:48.116367717 -0400 @@ -43,10 +43,7 @@ void set_thread_handle(HANDLE handle) { _thread_handle = handle; } HANDLE interrupt_event() const { return _interrupt_event; } void set_interrupt_event(HANDLE interrupt_event) { _interrupt_event = interrupt_event; } - // These are specialized on Windows to interact with the _interrupt_event. - // Also note that Windows does not skip these calls if we are interrupted - see - // LibraryCallKit::inline_native_isInterrupted - volatile bool interrupted(); + // This is specialized on Windows to interact with the _interrupt_event. void set_interrupted(bool z); #ifndef PRODUCT --- old/src/hotspot/share/aot/aotCodeHeap.cpp 2019-10-31 00:09:53.045424770 -0400 +++ new/src/hotspot/share/aot/aotCodeHeap.cpp 2019-10-31 00:09:51.897411482 -0400 @@ -450,7 +450,6 @@ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_post", address, JVMCIRuntime::write_barrier_post); #endif SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_identity_hash_code", address, JVMCIRuntime::identity_hash_code); - SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_thread_is_interrupted", address, JVMCIRuntime::thread_is_interrupted); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_exception_handler_for_pc", address, JVMCIRuntime::exception_handler_for_pc); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_test_deoptimize_call_int", address, JVMCIRuntime::test_deoptimize_call_int); SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_throw_and_post_jvmti_exception", address, JVMCIRuntime::throw_and_post_jvmti_exception); --- old/src/hotspot/share/classfile/javaClasses.cpp 2019-10-31 00:09:57.027470862 -0400 +++ new/src/hotspot/share/classfile/javaClasses.cpp 2019-10-31 00:09:55.791456555 -0400 @@ -56,6 +56,7 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" +#include "runtime/init.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" @@ -1634,6 +1635,7 @@ int java_lang_Thread::_inheritedAccessControlContext_offset = 0; int java_lang_Thread::_priority_offset = 0; int java_lang_Thread::_eetop_offset = 0; +int java_lang_Thread::_interrupted_offset = 0; int java_lang_Thread::_daemon_offset = 0; int java_lang_Thread::_stillborn_offset = 0; int java_lang_Thread::_stackSize_offset = 0; @@ -1649,6 +1651,7 @@ macro(_priority_offset, k, vmSymbols::priority_name(), int_signature, false); \ macro(_daemon_offset, k, vmSymbols::daemon_name(), bool_signature, false); \ macro(_eetop_offset, k, "eetop", long_signature, false); \ + macro(_interrupted_offset, k, "interrupted", bool_signature, false); \ macro(_stillborn_offset, k, "stillborn", bool_signature, false); \ macro(_stackSize_offset, k, "stackSize", long_signature, false); \ macro(_tid_offset, k, "tid", long_signature, false); \ @@ -1677,6 +1680,21 @@ java_thread->address_field_put(_eetop_offset, (address)thread); } +bool java_lang_Thread::interrupted(oop java_thread) { +#if INCLUDE_JFR + if (java_thread == NULL) { + // can happen from Jfr::on_vm_init leading to call of JavaThread::sleep + assert(!is_init_completed(), "should only happen during init"); + return false; + } +#endif + return java_thread->bool_field_volatile(_interrupted_offset); +} + +void java_lang_Thread::set_interrupted(oop java_thread, bool val) { + java_thread->bool_field_put_volatile(_interrupted_offset, val); +} + oop java_lang_Thread::name(oop java_thread) { return java_thread->obj_field(_name_offset); --- old/src/hotspot/share/classfile/javaClasses.hpp 2019-10-31 00:10:00.951516282 -0400 +++ new/src/hotspot/share/classfile/javaClasses.hpp 2019-10-31 00:09:59.814503121 -0400 @@ -373,6 +373,7 @@ static int _inheritedAccessControlContext_offset; static int _priority_offset; static int _eetop_offset; + static int _interrupted_offset; static int _daemon_offset; static int _stillborn_offset; static int _stackSize_offset; @@ -391,6 +392,9 @@ static JavaThread* thread(oop java_thread); // Set JavaThread for instance static void set_thread(oop java_thread, JavaThread* thread); + // Interrupted status + static bool interrupted(oop java_thread); + static void set_interrupted(oop java_thread, bool val); // Name static oop name(oop java_thread); static void set_name(oop java_thread, oop name); --- old/src/hotspot/share/classfile/vmSymbols.cpp 2019-10-31 00:10:04.737560105 -0400 +++ new/src/hotspot/share/classfile/vmSymbols.cpp 2019-10-31 00:10:03.621547187 -0400 @@ -568,7 +568,6 @@ if (!InlineClassNatives) return true; break; case vmIntrinsics::_currentThread: - case vmIntrinsics::_isInterrupted: if (!InlineThreadNatives) return true; break; case vmIntrinsics::_floatToRawIntBits: --- old/src/hotspot/share/classfile/vmSymbols.hpp 2019-10-31 00:10:08.637605247 -0400 +++ new/src/hotspot/share/classfile/vmSymbols.hpp 2019-10-31 00:10:07.477591820 -0400 @@ -862,9 +862,6 @@ do_intrinsic(_arraycopy, java_lang_System, arraycopy_name, arraycopy_signature, F_S) \ do_name( arraycopy_name, "arraycopy") \ do_signature(arraycopy_signature, "(Ljava/lang/Object;ILjava/lang/Object;II)V") \ - do_intrinsic(_isInterrupted, java_lang_Thread, isInterrupted_name, isInterrupted_signature, F_R) \ - do_name( isInterrupted_name, "isInterrupted") \ - do_signature(isInterrupted_signature, "(Z)Z") \ do_intrinsic(_currentThread, java_lang_Thread, currentThread_name, currentThread_signature, F_S) \ do_name( currentThread_name, "currentThread") \ do_signature(currentThread_signature, "()Ljava/lang/Thread;") \ --- old/src/hotspot/share/include/jvm.h 2019-10-31 00:10:12.447649348 -0400 +++ new/src/hotspot/share/include/jvm.h 2019-10-31 00:10:11.335636477 -0400 @@ -255,9 +255,6 @@ JVM_Interrupt(JNIEnv *env, jobject thread); JNIEXPORT jboolean JNICALL -JVM_IsInterrupted(JNIEnv *env, jobject thread, jboolean clearInterrupted); - -JNIEXPORT jboolean JNICALL JVM_HoldsLock(JNIEnv *env, jclass threadClass, jobject obj); JNIEXPORT void JNICALL --- old/src/hotspot/share/jvmci/jvmciRuntime.cpp 2019-10-31 00:10:16.282693738 -0400 +++ new/src/hotspot/share/jvmci/jvmciRuntime.cpp 2019-10-31 00:10:15.144680565 -0400 @@ -620,21 +620,6 @@ return (jint) obj->identity_hash(); JRT_END -JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted)) - Handle receiverHandle(thread, receiver); - // A nested ThreadsListHandle may require the Threads_lock which - // requires thread_in_vm which is why this method cannot be JRT_LEAF. - ThreadsListHandle tlh; - - JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); - if (receiverThread == NULL || (EnableThreadSMRExtraValidityChecks && !tlh.includes(receiverThread))) { - // The other thread may exit during this process, which is ok so return false. - return JNI_FALSE; - } else { - return (jint) receiverThread->is_interrupted(clear_interrupted != 0); - } -JRT_END - JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) deopt_caller(); return (jint) value; --- old/src/hotspot/share/jvmci/jvmciRuntime.hpp 2019-10-31 00:10:20.050737352 -0400 +++ new/src/hotspot/share/jvmci/jvmciRuntime.hpp 2019-10-31 00:10:18.892723949 -0400 @@ -309,7 +309,6 @@ static void dynamic_new_array_or_null(JavaThread* thread, oopDesc* element_mirror, jint length) { dynamic_new_array_common(thread, element_mirror, length, true); } static void dynamic_new_instance_or_null(JavaThread* thread, oopDesc* type_mirror) { dynamic_new_instance_common(thread, type_mirror, true); } - static jboolean thread_is_interrupted(JavaThread* thread, oopDesc* obj, jboolean clear_interrupted); static void vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3); static jint identity_hash_code(JavaThread* thread, oopDesc* obj); static address exception_handler_for_pc(JavaThread* thread); --- old/src/hotspot/share/jvmci/vmStructs_jvmci.cpp 2019-10-31 00:10:23.708779694 -0400 +++ new/src/hotspot/share/jvmci/vmStructs_jvmci.cpp 2019-10-31 00:10:22.573766556 -0400 @@ -263,8 +263,6 @@ \ static_field(os, _polling_page, address) \ \ - volatile_nonstatic_field(OSThread, _interrupted, jint) \ - \ static_field(StubRoutines, _verify_oop_count, jint) \ \ static_field(StubRoutines, _throw_delayed_StackOverflowError_entry, address) \ @@ -641,7 +639,6 @@ declare_function(JVMCIRuntime::dynamic_new_array_or_null) \ declare_function(JVMCIRuntime::dynamic_new_instance_or_null) \ \ - declare_function(JVMCIRuntime::thread_is_interrupted) \ declare_function(JVMCIRuntime::vm_message) \ declare_function(JVMCIRuntime::identity_hash_code) \ declare_function(JVMCIRuntime::exception_handler_for_pc) \ --- old/src/hotspot/share/oops/oop.hpp 2019-10-31 00:10:27.337821699 -0400 +++ new/src/hotspot/share/oops/oop.hpp 2019-10-31 00:10:26.218808747 -0400 @@ -173,6 +173,8 @@ jboolean bool_field(int offset) const; void bool_field_put(int offset, jboolean contents); + jboolean bool_field_volatile(int offset) const; + void bool_field_put_volatile(int offset, jboolean contents); jint int_field(int offset) const; jint int_field_raw(int offset) const; --- old/src/hotspot/share/oops/oop.inline.hpp 2019-10-31 00:10:30.757861285 -0400 +++ new/src/hotspot/share/oops/oop.inline.hpp 2019-10-31 00:10:29.655848530 -0400 @@ -301,9 +301,10 @@ inline jchar oopDesc::char_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } inline void oopDesc::char_field_put(int offset, jchar value) { HeapAccess<>::store_at(as_oop(), offset, value); } -inline jboolean oopDesc::bool_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } +inline jboolean oopDesc::bool_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } inline void oopDesc::bool_field_put(int offset, jboolean value) { HeapAccess<>::store_at(as_oop(), offset, jboolean(value & 1)); } - +inline jboolean oopDesc::bool_field_volatile(int offset) const { return HeapAccess::load_at(as_oop(), offset); } +inline void oopDesc::bool_field_put_volatile(int offset, jboolean value) { HeapAccess::store_at(as_oop(), offset, jboolean(value & 1)); } inline jshort oopDesc::short_field(int offset) const { return HeapAccess<>::load_at(as_oop(), offset); } inline void oopDesc::short_field_put(int offset, jshort value) { HeapAccess<>::store_at(as_oop(), offset, value); } --- old/src/hotspot/share/opto/c2compiler.cpp 2019-10-31 00:10:34.192901046 -0400 +++ new/src/hotspot/share/opto/c2compiler.cpp 2019-10-31 00:10:33.082888197 -0400 @@ -582,7 +582,6 @@ case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: case vmIntrinsics::_currentThread: - case vmIntrinsics::_isInterrupted: #ifdef JFR_HAVE_INTRINSICS case vmIntrinsics::_counterTime: case vmIntrinsics::_getClassId: --- old/src/hotspot/share/opto/library_call.cpp 2019-10-31 00:10:37.806942877 -0400 +++ new/src/hotspot/share/opto/library_call.cpp 2019-10-31 00:10:36.687929925 -0400 @@ -264,7 +264,6 @@ bool inline_native_classID(); bool inline_native_getEventWriter(); #endif - bool inline_native_isInterrupted(); bool inline_native_Class_query(vmIntrinsics::ID id); bool inline_native_subtype_check(); bool inline_native_getLength(); @@ -752,7 +751,6 @@ case vmIntrinsics::_onSpinWait: return inline_onspinwait(); case vmIntrinsics::_currentThread: return inline_native_currentThread(); - case vmIntrinsics::_isInterrupted: return inline_native_isInterrupted(); #ifdef JFR_HAVE_INTRINSICS case vmIntrinsics::_counterTime: return inline_native_time_funcs(CAST_FROM_FN_PTR(address, JFR_TIME_FUNCTION), "counterTime"); @@ -3041,128 +3039,6 @@ return true; } -//------------------------inline_native_isInterrupted------------------ -// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted); -bool LibraryCallKit::inline_native_isInterrupted() { - // Add a fast path to t.isInterrupted(clear_int): - // (t == Thread.current() && - // (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int))) - // ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int) - // So, in the common case that the interrupt bit is false, - // we avoid making a call into the VM. Even if the interrupt bit - // is true, if the clear_int argument is false, we avoid the VM call. - // However, if the receiver is not currentThread, we must call the VM, - // because there must be some locking done around the operation. - - // We only go to the fast case code if we pass two guards. - // Paths which do not pass are accumulated in the slow_region. - - enum { - no_int_result_path = 1, // t == Thread.current() && !TLS._osthread._interrupted - no_clear_result_path = 2, // t == Thread.current() && TLS._osthread._interrupted && !clear_int - slow_result_path = 3, // slow path: t.isInterrupted(clear_int) - PATH_LIMIT - }; - - // Ensure that it's not possible to move the load of TLS._osthread._interrupted flag - // out of the function. - insert_mem_bar(Op_MemBarCPUOrder); - - RegionNode* result_rgn = new RegionNode(PATH_LIMIT); - PhiNode* result_val = new PhiNode(result_rgn, TypeInt::BOOL); - - RegionNode* slow_region = new RegionNode(1); - record_for_igvn(slow_region); - - // (a) Receiving thread must be the current thread. - Node* rec_thr = argument(0); - Node* tls_ptr = NULL; - Node* cur_thr = generate_current_thread(tls_ptr); - - // Resolve oops to stable for CmpP below. - cur_thr = access_resolve(cur_thr, 0); - rec_thr = access_resolve(rec_thr, 0); - - Node* cmp_thr = _gvn.transform(new CmpPNode(cur_thr, rec_thr)); - Node* bol_thr = _gvn.transform(new BoolNode(cmp_thr, BoolTest::ne)); - - generate_slow_guard(bol_thr, slow_region); - - // (b) Interrupt bit on TLS must be false. - Node* p = basic_plus_adr(top()/*!oop*/, tls_ptr, in_bytes(JavaThread::osthread_offset())); - Node* osthread = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered); - p = basic_plus_adr(top()/*!oop*/, osthread, in_bytes(OSThread::interrupted_offset())); - - // Set the control input on the field _interrupted read to prevent it floating up. - Node* int_bit = make_load(control(), p, TypeInt::BOOL, T_INT, MemNode::unordered); - Node* cmp_bit = _gvn.transform(new CmpINode(int_bit, intcon(0))); - Node* bol_bit = _gvn.transform(new BoolNode(cmp_bit, BoolTest::ne)); - - IfNode* iff_bit = create_and_map_if(control(), bol_bit, PROB_UNLIKELY_MAG(3), COUNT_UNKNOWN); - - // First fast path: if (!TLS._interrupted) return false; - Node* false_bit = _gvn.transform(new IfFalseNode(iff_bit)); - result_rgn->init_req(no_int_result_path, false_bit); - result_val->init_req(no_int_result_path, intcon(0)); - - // drop through to next case - set_control( _gvn.transform(new IfTrueNode(iff_bit))); - -#ifndef _WINDOWS - // (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path. - Node* clr_arg = argument(1); - Node* cmp_arg = _gvn.transform(new CmpINode(clr_arg, intcon(0))); - Node* bol_arg = _gvn.transform(new BoolNode(cmp_arg, BoolTest::ne)); - IfNode* iff_arg = create_and_map_if(control(), bol_arg, PROB_FAIR, COUNT_UNKNOWN); - - // Second fast path: ... else if (!clear_int) return true; - Node* false_arg = _gvn.transform(new IfFalseNode(iff_arg)); - result_rgn->init_req(no_clear_result_path, false_arg); - result_val->init_req(no_clear_result_path, intcon(1)); - - // drop through to next case - set_control( _gvn.transform(new IfTrueNode(iff_arg))); -#else - // To return true on Windows you must read the _interrupted field - // and check the event state i.e. take the slow path. -#endif // _WINDOWS - - // (d) Otherwise, go to the slow path. - slow_region->add_req(control()); - set_control( _gvn.transform(slow_region)); - - if (stopped()) { - // There is no slow path. - result_rgn->init_req(slow_result_path, top()); - result_val->init_req(slow_result_path, top()); - } else { - // non-virtual because it is a private non-static - CallJavaNode* slow_call = generate_method_call(vmIntrinsics::_isInterrupted); - - Node* slow_val = set_results_for_java_call(slow_call); - // this->control() comes from set_results_for_java_call - - Node* fast_io = slow_call->in(TypeFunc::I_O); - Node* fast_mem = slow_call->in(TypeFunc::Memory); - - // These two phis are pre-filled with copies of of the fast IO and Memory - PhiNode* result_mem = PhiNode::make(result_rgn, fast_mem, Type::MEMORY, TypePtr::BOTTOM); - PhiNode* result_io = PhiNode::make(result_rgn, fast_io, Type::ABIO); - - result_rgn->init_req(slow_result_path, control()); - result_io ->init_req(slow_result_path, i_o()); - result_mem->init_req(slow_result_path, reset_memory()); - result_val->init_req(slow_result_path, slow_val); - - set_all_memory(_gvn.transform(result_mem)); - set_i_o( _gvn.transform(result_io)); - } - - C->set_has_split_ifs(true); // Has chance for split-if optimization - set_result(result_rgn, result_val); - return true; -} - //---------------------------load_mirror_from_klass---------------------------- // Given a klass oop, load its java mirror (a java.lang.Class oop). Node* LibraryCallKit::load_mirror_from_klass(Node* klass) { --- old/src/hotspot/share/prims/jvm.cpp 2019-10-31 00:10:41.721988193 -0400 +++ new/src/hotspot/share/prims/jvm.cpp 2019-10-31 00:10:40.599975206 -0400 @@ -3109,21 +3109,6 @@ JVM_END -JVM_ENTRY(jboolean, JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clear_interrupted)) - JVMWrapper("JVM_IsInterrupted"); - - ThreadsListHandle tlh(thread); - JavaThread* receiver = NULL; - bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL); - if (is_alive) { - // jthread refers to a live JavaThread. - return (jboolean) receiver->is_interrupted(clear_interrupted != 0); - } else { - return JNI_FALSE; - } -JVM_END - - // Return true iff the current thread has locked the object passed in JVM_ENTRY(jboolean, JVM_HoldsLock(JNIEnv* env, jclass threadClass, jobject obj)) --- old/src/hotspot/share/prims/jvmtiEnv.cpp 2019-10-31 00:10:45.372030442 -0400 +++ new/src/hotspot/share/prims/jvmtiEnv.cpp 2019-10-31 00:10:44.241017351 -0400 @@ -879,8 +879,7 @@ if (jts == _thread_in_native) { state |= JVMTI_THREAD_STATE_IN_NATIVE; } - OSThread* osThread = java_thread->osthread(); - if (osThread != NULL && osThread->interrupted()) { + if (java_thread->is_interrupted(false)) { state |= JVMTI_THREAD_STATE_INTERRUPTED; } } @@ -1092,7 +1091,6 @@ // thread - NOT pre-checked jvmtiError JvmtiEnv::InterruptThread(jthread thread) { - // TODO: this is very similar to JVM_Interrupt(); share code in future JavaThread* current_thread = JavaThread::current(); JavaThread* java_thread = NULL; ThreadsListHandle tlh(current_thread); @@ -1100,7 +1098,11 @@ if (err != JVMTI_ERROR_NONE) { return err; } - + // Really this should be a Java call to Thread.interrupt to ensure the same + // semantics, however historically this has not been done for some reason. + // So we continue with that (which means we don't interact with any Java-level + // Interruptible object) but we must set the Java-level interrupted state. + java_lang_Thread::set_interrupted(JNIHandles::resolve(thread), true); java_thread->interrupt(); return JVMTI_ERROR_NONE; --- old/src/hotspot/share/prims/jvmtiEnvBase.cpp 2019-10-31 00:10:49.035072841 -0400 +++ new/src/hotspot/share/prims/jvmtiEnvBase.cpp 2019-10-31 00:10:47.899059692 -0400 @@ -1214,8 +1214,7 @@ if (jts == _thread_in_native) { state |= JVMTI_THREAD_STATE_IN_NATIVE; } - OSThread* osThread = thr->osthread(); - if (osThread != NULL && osThread->interrupted()) { + if (thr->is_interrupted(false)) { state |= JVMTI_THREAD_STATE_INTERRUPTED; } } --- old/src/hotspot/share/runtime/osThread.cpp 2019-10-31 00:10:52.755115900 -0400 +++ new/src/hotspot/share/runtime/osThread.cpp 2019-10-31 00:10:51.611102658 -0400 @@ -30,7 +30,6 @@ pd_initialize(); set_start_proc(start_proc); set_start_parm(start_parm); - _interrupted = 0; } OSThread::~OSThread() { --- old/src/hotspot/share/runtime/osThread.hpp 2019-10-31 00:10:56.223156042 -0400 +++ new/src/hotspot/share/runtime/osThread.hpp 2019-10-31 00:10:55.119143263 -0400 @@ -62,12 +62,6 @@ OSThreadStartFunc _start_proc; // Thread start routine void* _start_parm; // Thread start routine parameter volatile ThreadState _state; // Thread state *hint* - volatile jint _interrupted; // Thread.isInterrupted state - - // Note: _interrupted must be jint, so that Java intrinsics can access it. - // The value stored there must be either 0 or 1. It must be possible - // for Java to emulate Thread.currentThread().isInterrupted() by performing - // the double indirection Thread::current()->_osthread->_interrupted. // Methods public: @@ -82,18 +76,14 @@ void set_start_proc(OSThreadStartFunc start_proc) { _start_proc = start_proc; } void* start_parm() const { return _start_parm; } void set_start_parm(void* start_parm) { _start_parm = start_parm; } - // These are specialized on Windows. + // This is specialized on Windows. #ifndef _WINDOWS - volatile bool interrupted() const { return _interrupted != 0; } - void set_interrupted(bool z) { _interrupted = z ? 1 : 0; } + void set_interrupted(bool z) { /* nothing to do */ } #endif // Printing void print_on(outputStream* st) const; void print() const; - // For java intrinsics: - static ByteSize interrupted_offset() { return byte_offset_of(OSThread, _interrupted); } - // Platform dependent stuff #include OS_HEADER(osThread) --- old/src/hotspot/share/runtime/thread.cpp 2019-10-31 00:10:59.906198673 -0400 +++ new/src/hotspot/share/runtime/thread.cpp 2019-10-31 00:10:58.763185442 -0400 @@ -1725,19 +1725,13 @@ void JavaThread::interrupt() { debug_only(check_for_dangling_thread_pointer(this);) - if (!osthread()->interrupted()) { - osthread()->set_interrupted(true); - // More than one thread can get here with the same value of osthread, - // resulting in multiple notifications. We do, however, want the store - // to interrupted() to be visible to other threads before we execute unpark(). - OrderAccess::fence(); - - // For JavaThread::sleep. Historically we only unpark if changing to the interrupted - // state, in contrast to the other events below. Not clear exactly why. - _SleepEvent->unpark(); - } + // For Windows _interrupt_event + osthread()->set_interrupted(true); + + // For Thread.sleep + _SleepEvent->unpark(); - // For JSR166. Unpark even if interrupt status already was set. + // For JSR166 LockSupport.park parker()->unpark(); // For ObjectMonitor and JvmtiRawMonitor @@ -1747,11 +1741,11 @@ bool JavaThread::is_interrupted(bool clear_interrupted) { debug_only(check_for_dangling_thread_pointer(this);) - bool interrupted = osthread()->interrupted(); + bool interrupted = java_lang_Thread::interrupted(threadObj()); // NOTE that since there is no "lock" around the interrupt and // is_interrupted operations, there is the possibility that the - // interrupted flag (in osThread) will be "false" but that the + // interrupted flag will be "false" but that the // low-level events will be in the signaled state. This is // intentional. The effect of this is that Object.wait() and // LockSupport.park() will appear to have a spurious wakeup, which @@ -1761,9 +1755,12 @@ // to JavaThread::sleep, so there is no early return. It has also been // recommended not to put the interrupted flag into the "event" // structure because it hides the issue. + // Also, because there is no lock, we must only clear the interrupt + // state if we are going to report that we were interrupted; otherwise + // an interrupt that happens just after we read the field would be lost. if (interrupted && clear_interrupted) { + java_lang_Thread::set_interrupted(threadObj(), false); osthread()->set_interrupted(false); - // consider thread->_SleepEvent->reset() ... optional optimization } return interrupted; @@ -2417,6 +2414,7 @@ // Interrupt thread so it will wake up from a potential wait()/sleep()/park() + java_lang_Thread::set_interrupted(threadObj(), true); this->interrupt(); } --- old/src/hotspot/share/runtime/vmStructs.cpp 2019-10-31 00:11:03.845244266 -0400 +++ new/src/hotspot/share/runtime/vmStructs.cpp 2019-10-31 00:11:02.693230932 -0400 @@ -786,7 +786,6 @@ /* OSThread */ \ /************/ \ \ - volatile_nonstatic_field(OSThread, _interrupted, jint) \ volatile_nonstatic_field(OSThread, _state, ThreadState) \ \ /************************/ \ --- old/src/java.base/share/classes/java/lang/Thread.java 2019-10-31 00:11:07.670288541 -0400 +++ new/src/java.base/share/classes/java/lang/Thread.java 2019-10-31 00:11:06.521275241 -0400 @@ -154,6 +154,9 @@ /* Whether or not the thread is a daemon thread. */ private boolean daemon = false; + /* Interrupt state of the thread - read/written directly by JVM */ + private volatile boolean interrupted; + /* Fields reserved for exclusive use by the JVM */ private boolean stillborn = false; private long eetop; @@ -971,10 +974,14 @@ * *

Interrupting a thread that is not alive need not have any effect. * + * @implNote In the JDK Reference Implementation, interruption of a thread + * that is not alive still records that the interrupt request was made and + * will report it via {@link #interrupted} and {@link #isInterrupted()}. + * * @throws SecurityException * if the current thread cannot modify this thread * - * @revised 6.0 + * @revised 6.0, 14 * @spec JSR-51 */ public void interrupt() { @@ -985,14 +992,15 @@ synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { - interrupt0(); // set interrupt status + interrupted = true; + interrupt0(); // inform VM of interrupt b.interrupt(this); return; } } } - - // set interrupt status + interrupted = true; + // inform VM of interrupt interrupt0(); } @@ -1004,45 +1012,38 @@ * interrupted again, after the first call had cleared its interrupted * status and before the second call had examined it). * - *

A thread interruption ignored because a thread was not alive - * at the time of the interrupt will be reflected by this method - * returning false. - * * @return {@code true} if the current thread has been interrupted; * {@code false} otherwise. * @see #isInterrupted() - * @revised 6.0 + * @revised 6.0, 14 */ public static boolean interrupted() { - return currentThread().isInterrupted(true); + Thread t = currentThread(); + boolean interrupted = t.interrupted; + // We may have been interrupted the moment after we read the field, + // so only clear the field if we saw that it was set and will return + // true; otherwise we could lose an interrupt. + if (interrupted) { + t.interrupted = false; + clearInterruptEvent(); + } + return interrupted; } /** * Tests whether this thread has been interrupted. The interrupted * status of the thread is unaffected by this method. * - *

A thread interruption ignored because a thread was not alive - * at the time of the interrupt will be reflected by this method - * returning false. - * * @return {@code true} if this thread has been interrupted; * {@code false} otherwise. * @see #interrupted() - * @revised 6.0 + * @revised 6.0, 14 */ public boolean isInterrupted() { - return isInterrupted(false); + return interrupted; } /** - * Tests if some Thread has been interrupted. The interrupted state - * is reset or not based on the value of ClearInterrupted that is - * passed. - */ - @HotSpotIntrinsicCandidate - private native boolean isInterrupted(boolean ClearInterrupted); - - /** * Tests if this thread is alive. A thread is alive if it has * been started and has not yet died. * @@ -2080,5 +2081,6 @@ private native void suspend0(); private native void resume0(); private native void interrupt0(); + private static native void clearInterruptEvent(); private native void setNativeName(String name); } --- old/src/java.base/share/native/libjava/Thread.c 2019-10-31 00:11:11.344331067 -0400 +++ new/src/java.base/share/native/libjava/Thread.c 2019-10-31 00:11:10.201317837 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2019, 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 @@ -52,7 +52,6 @@ {"currentThread", "()" THD, (void *)&JVM_CurrentThread}, {"countStackFrames", "()I", (void *)&JVM_CountStackFrames}, {"interrupt0", "()V", (void *)&JVM_Interrupt}, - {"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted}, {"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock}, {"getThreads", "()[" THD, (void *)&JVM_GetAllThreads}, {"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads}, @@ -69,3 +68,12 @@ { (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); } + +JNIEXPORT void JNICALL +Java_java_lang_Thread_clearInterruptEvent(JNIEnv *env, jclass cls) +{ +#if defined(_WIN32) + // Need to reset the interrupt event used by Process.waitFor + ResetEvent((HANDLE) JVM_GetThreadInterruptEvent()); +#endif +} --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java 2019-10-31 00:11:14.774370769 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java 2019-10-31 00:11:13.634357574 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2019, 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 @@ -31,7 +31,6 @@ // The OSThread class holds OS-specific thread information. It is equivalent // to the sys_thread_t structure of the classic JVM implementation. public class OSThread extends VMObject { - private static JIntField interruptedField; private static Field threadIdField; private static CIntegerField threadStateField; @@ -56,7 +55,6 @@ private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("OSThread"); - interruptedField = type.getJIntField("_interrupted"); threadIdField = type.getField("_thread_id"); threadStateField = type.getCIntegerField("_state"); @@ -75,10 +73,6 @@ super(addr); } - public boolean interrupted() { - return ((int)interruptedField.getValue(addr)) != 0; - } - public int threadId() { return threadIdField.getJInt(addr); } --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java 2019-10-31 00:11:18.261411131 -0400 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java 2019-10-31 00:11:17.122397947 -0400 @@ -28,12 +28,13 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import org.graalvm.compiler.nodes.IfNode; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; +import org.junit.Test; /** * Tests HotSpot specific {@link MethodSubstitution}s. @@ -133,13 +134,18 @@ @Test public void testThreadSubstitutions() { + GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig(); testGraph("currentThread"); - assertInGraph(testGraph("threadIsInterrupted", "isInterrupted", true), IfNode.class); - assertInGraph(testGraph("threadInterrupted", "isInterrupted", true), IfNode.class); + if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) { + assertInGraph(testGraph("threadIsInterrupted", "isInterrupted", true), IfNode.class); + assertInGraph(testGraph("threadInterrupted", "isInterrupted", true), IfNode.class); + } Thread currentThread = Thread.currentThread(); test("currentThread", currentThread); - test("threadIsInterrupted", currentThread); + if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) { + test("threadIsInterrupted", currentThread); + } } @SuppressWarnings("all") --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java 2019-10-31 00:11:21.738451377 -0400 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java 2019-10-31 00:11:20.587438054 -0400 @@ -315,7 +315,7 @@ public final int javaThreadAnchorOffset = getFieldOffset("JavaThread::_anchor", Integer.class, "JavaFrameAnchor"); public final int javaThreadShouldPostOnExceptionsFlagOffset = getFieldOffset("JavaThread::_should_post_on_exceptions_flag", Integer.class, "int", Integer.MIN_VALUE); public final int threadObjectOffset = getFieldOffset("JavaThread::_threadObj", Integer.class, "oop"); - public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*"); + public final int osThreadOffset = getFieldOffset("JavaThread::_osthread", Integer.class, "OSThread*", Integer.MAX_VALUE); public final int threadIsMethodHandleReturnOffset = getFieldOffset("JavaThread::_is_method_handle_return", Integer.class, "int"); public final int threadObjectResultOffset = getFieldOffset("JavaThread::_vm_result", Integer.class, "oop"); public final int jvmciCountersThreadOffset = getFieldOffset("JavaThread::_jvmci_counters", Integer.class, "jlong*"); @@ -419,7 +419,7 @@ public final int frameInterpreterFrameSenderSpOffset = getConstant("frame::interpreter_frame_sender_sp_offset", Integer.class, intRequiredOnAMD64); public final int frameInterpreterFrameLastSpOffset = getConstant("frame::interpreter_frame_last_sp_offset", Integer.class, intRequiredOnAMD64); - public final int osThreadInterruptedOffset = getFieldOffset("OSThread::_interrupted", Integer.class, "jint"); + public final int osThreadInterruptedOffset = getFieldOffset("OSThread::_interrupted", Integer.class, "jint", Integer.MAX_VALUE); public final long markWordHashShift = getConstant(markWordField("hash_shift"), Long.class); @@ -714,7 +714,6 @@ return true; } - public final long threadIsInterruptedAddress = getAddress("JVMCIRuntime::thread_is_interrupted"); public final long vmMessageAddress = getAddress("JVMCIRuntime::vm_message"); public final long identityHashCodeAddress = getAddress("JVMCIRuntime::identity_hash_code"); public final long exceptionHandlerForPcAddress = getAddress("JVMCIRuntime::exception_handler_for_pc"); --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java 2019-10-31 00:11:25.279492364 -0400 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java 2019-10-31 00:11:24.129479053 -0400 @@ -440,7 +440,10 @@ } }); - r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class); + if (config.osThreadInterruptedOffset != Integer.MAX_VALUE) { + r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class); + } + } public static final String aesEncryptName; --- old/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java 2019-10-31 00:11:28.835533525 -0400 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java 2019-10-31 00:11:27.682520179 -0400 @@ -308,11 +308,13 @@ @Fold public static int osThreadOffset(@InjectedParameter GraalHotSpotVMConfig config) { + assert config.osThreadOffset != Integer.MAX_VALUE; return config.osThreadOffset; } @Fold public static int osThreadInterruptedOffset(@InjectedParameter GraalHotSpotVMConfig config) { + assert config.osThreadInterruptedOffset != Integer.MAX_VALUE; return config.osThreadInterruptedOffset; }