8203466: intermittent crash at jdk.internal.misc.Unsafe::getObjectVolatile (native)
authorcoleenp
Tue, 18 Sep 2018 08:27:01 -0400
changeset 51784 fbec908e2783
parent 51783 4482acfef2a5
child 51785 05b05af6c160
8203466: intermittent crash at jdk.internal.misc.Unsafe::getObjectVolatile (native) Summary: Store rsi, rdi on thread local memory, store r15 in r9, for the stubs that have gc barriers Reviewed-by: dlong, eosterlund
src/hotspot/cpu/x86/stubGenerator_x86_64.cpp
src/hotspot/os_cpu/windows_x86/thread_windows_x86.hpp
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Tue Sep 18 13:32:40 2018 +0200
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp	Tue Sep 18 08:27:01 2018 -0400
@@ -1171,6 +1171,8 @@
   // Registers r9 and r10 are used to save rdi and rsi on Windows, which latter
   // are non-volatile.  r9 and r10 should not be used by the caller.
   //
+  DEBUG_ONLY(bool regs_in_thread;)
+
   void setup_arg_regs(int nargs = 3) {
     const Register saved_rdi = r9;
     const Register saved_rsi = r10;
@@ -1191,9 +1193,11 @@
     assert(c_rarg0 == rdi && c_rarg1 == rsi && c_rarg2 == rdx && c_rarg3 == rcx,
            "unexpected argument registers");
 #endif
+    DEBUG_ONLY(regs_in_thread = false;)
   }
 
   void restore_arg_regs() {
+    assert(!regs_in_thread, "wrong call to restore_arg_regs");
     const Register saved_rdi = r9;
     const Register saved_rsi = r10;
 #ifdef _WIN64
@@ -1202,6 +1206,38 @@
 #endif
   }
 
+  // This is used in places where r10 is a scratch register, and can
+  // be adapted if r9 is needed also.
+  void setup_arg_regs_using_thread() {
+    const Register saved_r15 = r9;
+#ifdef _WIN64
+    __ mov(saved_r15, r15);  // r15 is callee saved and needs to be restored
+    __ get_thread(r15_thread);
+    assert(c_rarg0 == rcx && c_rarg1 == rdx && c_rarg2 == r8 && c_rarg3 == r9,
+           "unexpected argument registers");
+    __ movptr(Address(r15_thread, in_bytes(JavaThread::windows_saved_rdi_offset())), rdi);
+    __ movptr(Address(r15_thread, in_bytes(JavaThread::windows_saved_rsi_offset())), rsi);
+
+    __ mov(rdi, rcx); // c_rarg0
+    __ mov(rsi, rdx); // c_rarg1
+    __ mov(rdx, r8);  // c_rarg2
+#else
+    assert(c_rarg0 == rdi && c_rarg1 == rsi && c_rarg2 == rdx && c_rarg3 == rcx,
+           "unexpected argument registers");
+#endif
+    DEBUG_ONLY(regs_in_thread = true;)
+  }
+
+  void restore_arg_regs_using_thread() {
+    assert(regs_in_thread, "wrong call to restore_arg_regs");
+    const Register saved_r15 = r9;
+#ifdef _WIN64
+    __ get_thread(r15_thread);
+    __ movptr(rsi, Address(r15_thread, in_bytes(JavaThread::windows_saved_rsi_offset())));
+    __ movptr(rdi, Address(r15_thread, in_bytes(JavaThread::windows_saved_rdi_offset())));
+    __ mov(r15, saved_r15);  // r15 is callee saved and needs to be restored
+#endif
+  }
 
   // Copy big chunks forward
   //
@@ -1829,8 +1865,8 @@
       BLOCK_COMMENT("Entry:");
     }
 
-    setup_arg_regs(); // from => rdi, to => rsi, count => rdx
-                      // r9 and r10 may be used to save non-volatile registers
+    setup_arg_regs_using_thread(); // from => rdi, to => rsi, count => rdx
+                                   // r9 is used to save r15_thread
 
     DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT;
     if (dest_uninitialized) {
@@ -1870,7 +1906,7 @@
 
   __ BIND(L_exit);
     bs->arraycopy_epilogue(_masm, decorators, type, from, to, dword_count);
-    restore_arg_regs();
+    restore_arg_regs_using_thread();
     inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
     __ vzeroupper();
     __ xorptr(rax, rax); // return 0
@@ -1923,8 +1959,8 @@
     }
 
     array_overlap_test(nooverlap_target, Address::times_4);
-    setup_arg_regs(); // from => rdi, to => rsi, count => rdx
-                      // r9 and r10 may be used to save non-volatile registers
+    setup_arg_regs_using_thread(); // from => rdi, to => rsi, count => rdx
+                                   // r9 is used to save r15_thread
 
     DecoratorSet decorators = IN_HEAP | IS_ARRAY;
     if (dest_uninitialized) {
@@ -1963,7 +1999,7 @@
     if (is_oop) {
       __ jmp(L_exit);
     }
-    restore_arg_regs();
+    restore_arg_regs_using_thread();
     inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
     __ xorptr(rax, rax); // return 0
     __ vzeroupper();
@@ -1975,7 +2011,7 @@
 
   __ BIND(L_exit);
     bs->arraycopy_epilogue(_masm, decorators, type, from, to, dword_count);
-    restore_arg_regs();
+    restore_arg_regs_using_thread();
     inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
     __ xorptr(rax, rax); // return 0
     __ vzeroupper();
@@ -2026,8 +2062,8 @@
       BLOCK_COMMENT("Entry:");
     }
 
-    setup_arg_regs(); // from => rdi, to => rsi, count => rdx
-                      // r9 and r10 may be used to save non-volatile registers
+    setup_arg_regs_using_thread(); // from => rdi, to => rsi, count => rdx
+                                     // r9 is used to save r15_thread
     // 'from', 'to' and 'qword_count' are now valid
 
     DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT;
@@ -2058,7 +2094,7 @@
     if (is_oop) {
       __ jmp(L_exit);
     } else {
-      restore_arg_regs();
+      restore_arg_regs_using_thread();
       inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free
       __ xorptr(rax, rax); // return 0
       __ vzeroupper();
@@ -2071,7 +2107,7 @@
 
     __ BIND(L_exit);
     bs->arraycopy_epilogue(_masm, decorators, type, from, to, qword_count);
-    restore_arg_regs();
+    restore_arg_regs_using_thread();
     if (is_oop) {
       inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
     } else {
@@ -2119,8 +2155,8 @@
     }
 
     array_overlap_test(nooverlap_target, Address::times_8);
-    setup_arg_regs(); // from => rdi, to => rsi, count => rdx
-                      // r9 and r10 may be used to save non-volatile registers
+    setup_arg_regs_using_thread(); // from => rdi, to => rsi, count => rdx
+                                   // r9 is used to save r15_thread
     // 'from', 'to' and 'qword_count' are now valid
 
     DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT;
@@ -2147,7 +2183,7 @@
     if (is_oop) {
       __ jmp(L_exit);
     } else {
-      restore_arg_regs();
+      restore_arg_regs_using_thread();
       inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free
       __ xorptr(rax, rax); // return 0
       __ vzeroupper();
@@ -2160,7 +2196,7 @@
 
     __ BIND(L_exit);
     bs->arraycopy_epilogue(_masm, decorators, type, from, to, qword_count);
-    restore_arg_regs();
+    restore_arg_regs_using_thread();
     if (is_oop) {
       inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
     } else {
@@ -2276,11 +2312,22 @@
     enum {
       saved_r13_offset,
       saved_r14_offset,
+      saved_r10_offset,
       saved_rbp_offset
     };
     __ subptr(rsp, saved_rbp_offset * wordSize);
     __ movptr(Address(rsp, saved_r13_offset * wordSize), r13);
     __ movptr(Address(rsp, saved_r14_offset * wordSize), r14);
+    __ movptr(Address(rsp, saved_r10_offset * wordSize), r10);
+
+#ifdef ASSERT
+      Label L2;
+      __ get_thread(r14);
+      __ cmpptr(r15_thread, r14);
+      __ jcc(Assembler::equal, L2);
+      __ stop("StubRoutines::call_stub: r15_thread is modified by call");
+      __ bind(L2);
+#endif // ASSERT
 
     // check that int operands are properly extended to size_t
     assert_clean_int(length, rax);
@@ -2372,6 +2419,7 @@
     __ BIND(L_done);
     __ movptr(r13, Address(rsp, saved_r13_offset * wordSize));
     __ movptr(r14, Address(rsp, saved_r14_offset * wordSize));
+    __ movptr(r10, Address(rsp, saved_r10_offset * wordSize));
     restore_arg_regs();
     inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); // Update counter after rscratch1 is free
     __ leave(); // required for proper stackwalking of RuntimeStub frame
@@ -5197,9 +5245,9 @@
     BLOCK_COMMENT("Entry:");
     __ enter(); // required for proper stackwalking of RuntimeStub frame
 
-       setup_arg_regs(4); // x => rdi, len => rsi, z => rdx
-                          // zlen => rcx
-                          // r9 and r10 may be used to save non-volatile registers
+    setup_arg_regs(4); // x => rdi, len => rsi, z => rdx
+                       // zlen => rcx
+                       // r9 and r10 may be used to save non-volatile registers
     __ movptr(r8, rdx);
     __ square_to_len(x, len, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx, rax);
 
--- a/src/hotspot/os_cpu/windows_x86/thread_windows_x86.hpp	Tue Sep 18 13:32:40 2018 +0200
+++ b/src/hotspot/os_cpu/windows_x86/thread_windows_x86.hpp	Tue Sep 18 08:27:01 2018 -0400
@@ -26,8 +26,15 @@
 #define OS_CPU_WINDOWS_X86_VM_THREAD_WINDOWS_X86_HPP
 
  private:
+  // On windows, in the stubGenerator, there's nowhere to save callee saved regs
+  address          _windows_saved_rsi;
+  address          _windows_saved_rdi;
+
   void pd_initialize() {
     _anchor.clear();
+
+    _windows_saved_rsi = NULL;
+    _windows_saved_rdi = NULL;
   }
 
   frame pd_last_frame();
@@ -52,6 +59,8 @@
 
    bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava);
 
+  static ByteSize windows_saved_rsi_offset() { return byte_offset_of(JavaThread, _windows_saved_rsi); }
+  static ByteSize windows_saved_rdi_offset() { return byte_offset_of(JavaThread, _windows_saved_rdi); }
 private:
   bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava);