8229516: Thread.isInterrupted() always returns false after thread termination
authordholmes
Sun, 03 Nov 2019 18:02:29 -0500
changeset 58901 2700c409ff10
parent 58900 434329f6f456
child 58902 197238c30630
8229516: Thread.isInterrupted() always returns false after thread termination Reviewed-by: dnsimon, sspitsyn, dcubed, alanb
make/hotspot/symbols/symbols-unix
src/hotspot/os/windows/osThread_windows.cpp
src/hotspot/os/windows/osThread_windows.hpp
src/hotspot/share/aot/aotCodeHeap.cpp
src/hotspot/share/classfile/javaClasses.cpp
src/hotspot/share/classfile/javaClasses.hpp
src/hotspot/share/classfile/vmSymbols.cpp
src/hotspot/share/classfile/vmSymbols.hpp
src/hotspot/share/include/jvm.h
src/hotspot/share/jvmci/jvmciRuntime.cpp
src/hotspot/share/jvmci/jvmciRuntime.hpp
src/hotspot/share/jvmci/vmStructs_jvmci.cpp
src/hotspot/share/oops/oop.hpp
src/hotspot/share/oops/oop.inline.hpp
src/hotspot/share/opto/c2compiler.cpp
src/hotspot/share/opto/library_call.cpp
src/hotspot/share/prims/jvm.cpp
src/hotspot/share/prims/jvmtiEnv.cpp
src/hotspot/share/prims/jvmtiEnvBase.cpp
src/hotspot/share/runtime/osThread.cpp
src/hotspot/share/runtime/osThread.hpp
src/hotspot/share/runtime/thread.cpp
src/hotspot/share/runtime/vmStructs.cpp
src/java.base/share/classes/java/lang/Thread.java
src/java.base/share/native/libjava/Thread.c
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java
--- a/make/hotspot/symbols/symbols-unix	Sun Nov 03 14:07:43 2019 +0000
+++ b/make/hotspot/symbols/symbols-unix	Sun Nov 03 18:02:29 2019 -0500
@@ -142,7 +142,6 @@
 JVM_IsArrayClass
 JVM_IsConstructorIx
 JVM_IsInterface
-JVM_IsInterrupted
 JVM_IsPrimitiveClass
 JVM_IsSameClassPackage
 JVM_IsSupportedJNIVersion
--- a/src/hotspot/os/windows/osThread_windows.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/os/windows/osThread_windows.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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);
   }
 }
--- a/src/hotspot/os/windows/osThread_windows.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/os/windows/osThread_windows.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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
--- a/src/hotspot/share/aot/aotCodeHeap.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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);
--- a/src/hotspot/share/classfile/javaClasses.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/classfile/javaClasses.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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);
--- a/src/hotspot/share/classfile/javaClasses.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/classfile/javaClasses.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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);
--- a/src/hotspot/share/classfile/vmSymbols.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/classfile/vmSymbols.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -568,7 +568,6 @@
     if (!InlineClassNatives) return true;
     break;
   case vmIntrinsics::_currentThread:
-  case vmIntrinsics::_isInterrupted:
     if (!InlineThreadNatives) return true;
     break;
   case vmIntrinsics::_floatToRawIntBits:
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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;")                                \
--- a/src/hotspot/share/include/jvm.h	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/include/jvm.h	Sun Nov 03 18:02:29 2019 -0500
@@ -252,9 +252,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
--- a/src/hotspot/share/jvmci/jvmciRuntime.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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;
--- a/src/hotspot/share/jvmci/jvmciRuntime.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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);
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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) \
--- a/src/hotspot/share/oops/oop.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/oops/oop.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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;
--- a/src/hotspot/share/oops/oop.inline.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/oops/oop.inline.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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<MO_SEQ_CST>::load_at(as_oop(), offset); }
+inline void     oopDesc::bool_field_put_volatile(int offset, jboolean value) { HeapAccess<MO_SEQ_CST>::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); }
 
--- a/src/hotspot/share/opto/c2compiler.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/opto/c2compiler.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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:
--- a/src/hotspot/share/opto/library_call.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/opto/library_call.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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) {
--- a/src/hotspot/share/prims/jvm.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/prims/jvm.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -3065,21 +3065,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))
--- a/src/hotspot/share/prims/jvmtiEnv.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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;
--- a/src/hotspot/share/prims/jvmtiEnvBase.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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;
     }
   }
--- a/src/hotspot/share/runtime/osThread.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/runtime/osThread.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -30,7 +30,6 @@
   pd_initialize();
   set_start_proc(start_proc);
   set_start_parm(start_parm);
-  _interrupted = 0;
 }
 
 OSThread::~OSThread() {
--- a/src/hotspot/share/runtime/osThread.hpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/runtime/osThread.hpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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)
 
--- a/src/hotspot/share/runtime/thread.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/runtime/thread.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -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 JSR166. Unpark even if interrupt status already was set.
+  // For Windows _interrupt_event
+  osthread()->set_interrupted(true);
+
+  // For Thread.sleep
+  _SleepEvent->unpark();
+
+  // 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();
 }
 
--- a/src/hotspot/share/runtime/vmStructs.cpp	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/hotspot/share/runtime/vmStructs.cpp	Sun Nov 03 18:02:29 2019 -0500
@@ -786,7 +786,6 @@
   /* OSThread */                                                                                                                     \
   /************/                                                                                                                     \
                                                                                                                                      \
-  volatile_nonstatic_field(OSThread,           _interrupted,                                  jint)                                  \
   volatile_nonstatic_field(OSThread,           _state,                                        ThreadState)                           \
                                                                                                                                      \
   /************************/                                                                                                         \
--- a/src/java.base/share/classes/java/lang/Thread.java	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/java.base/share/classes/java/lang/Thread.java	Sun Nov 03 18:02:29 2019 -0500
@@ -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 @@
      *
      * <p> 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).
      *
-     * <p>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 <i>interrupted
      * status</i> of the thread is unaffected by this method.
      *
-     * <p>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);
 }
--- a/src/java.base/share/native/libjava/Thread.c	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/java.base/share/native/libjava/Thread.c	Sun Nov 03 18:02:29 2019 -0500
@@ -51,7 +51,6 @@
     {"sleep",            "(J)V",       (void *)&JVM_Sleep},
     {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},
     {"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},
@@ -68,3 +67,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
+}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/OSThread.java	Sun Nov 03 18:02:29 2019 -0500
@@ -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);
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotMethodSubstitutionTest.java	Sun Nov 03 18:02:29 2019 -0500
@@ -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")
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java	Sun Nov 03 18:02:29 2019 -0500
@@ -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");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Sun Nov 03 18:02:29 2019 -0500
@@ -441,7 +441,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 reflectionClass;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Sun Nov 03 14:07:43 2019 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Sun Nov 03 18:02:29 2019 -0500
@@ -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;
     }