8076185: Provide SafeFetchX implementation for zero
authordholmes
Tue, 31 Mar 2015 05:30:36 -0400
changeset 30129 351788433103
parent 30128 b5e4e8a58b0b
child 30130 386d3e9878bc
8076185: Provide SafeFetchX implementation for zero Summary: Implement SafeFetchX for zero using setjmp/longjmp and Posix TLS Reviewed-by: sgehwolf, dholmes Contributed-by: thomas.stuefe@gmail.com
hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp
hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp
hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp
hotspot/src/share/vm/runtime/stubRoutines.hpp
--- a/hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp	Tue Mar 31 02:11:09 2015 +0000
+++ b/hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp	Tue Mar 31 05:30:36 2015 -0400
@@ -45,6 +45,18 @@
 #include "opto/runtime.hpp"
 #endif
 
+// For SafeFetch we need POSIX tls and setjmp
+#include <setjmp.h>
+#include <pthread.h>
+static pthread_key_t g_jmpbuf_key;
+
+// return the currently active jump buffer for this thread
+//  - if there is any, NULL otherwise. Called from
+//    zero signal handlers.
+extern sigjmp_buf* get_jmp_buf_for_continuation() {
+  return (sigjmp_buf*) pthread_getspecific(g_jmpbuf_key);
+}
+
 // Declaration and definition of StubGenerator (no .hpp file).
 // For a more detailed description of the stub routine structure
 // see the comment in stubRoutines.hpp
@@ -176,17 +188,55 @@
       StubRoutines::_oop_arraycopy;
   }
 
-  // NYI: SafeFetch for Zero isn't actually safe.
   static int SafeFetch32(int *adr, int errValue) {
+
+    // set up a jump buffer; anchor the pointer to the jump buffer in tls; then
+    // do the pointer access. If pointer is invalid, we crash; in signal
+    // handler, we retrieve pointer to jmp buffer from tls, and jump back.
+    //
+    // Note: the jump buffer itself - which can get pretty large depending on
+    // the architecture - lives on the stack and that is fine, because we will
+    // not rewind the stack: either we crash, in which case signal handler
+    // frame is below us, or we don't crash, in which case it does not matter.
+    sigjmp_buf jb;
+    if (sigsetjmp(jb, 1)) {
+      // we crashed. clean up tls and return default value.
+      pthread_setspecific(g_jmpbuf_key, NULL);
+      return errValue;
+    } else {
+      // preparation phase
+      pthread_setspecific(g_jmpbuf_key, &jb);
+    }
+
     int value = errValue;
     value = *adr;
+
+    // all went well. clean tls.
+    pthread_setspecific(g_jmpbuf_key, NULL);
+
     return value;
   }
 
   static intptr_t SafeFetchN(intptr_t *adr, intptr_t errValue) {
+
+    sigjmp_buf jb;
+    if (sigsetjmp(jb, 1)) {
+      // we crashed. clean up tls and return default value.
+      pthread_setspecific(g_jmpbuf_key, NULL);
+      return errValue;
+    } else {
+      // preparation phase
+      pthread_setspecific(g_jmpbuf_key, &jb);
+    }
+
     intptr_t value = errValue;
     value = *adr;
+
+    // all went well. clean tls.
+    pthread_setspecific(g_jmpbuf_key, NULL);
+
     return value;
+
   }
 
   void generate_initial() {
@@ -241,6 +291,7 @@
     generate_arraycopy_stubs();
 
     // Safefetch stubs.
+    pthread_key_create(&g_jmpbuf_key, NULL);
     StubRoutines::_safefetch32_entry = CAST_FROM_FN_PTR(address, StubGenerator::SafeFetch32);
     StubRoutines::_safefetch32_fault_pc = NULL;
     StubRoutines::_safefetch32_continuation_pc = NULL;
--- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp	Tue Mar 31 02:11:09 2015 +0000
+++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp	Tue Mar 31 05:30:36 2015 -0400
@@ -59,6 +59,10 @@
 #include "utilities/events.hpp"
 #include "utilities/vmError.hpp"
 
+// See stubGenerator_zero.cpp
+#include <setjmp.h>
+extern sigjmp_buf* get_jmp_buf_for_continuation();
+
 address os::current_stack_pointer() {
   address dummy = (address) &dummy;
   return dummy;
@@ -134,6 +138,14 @@
 
   SignalHandlerMark shm(t);
 
+  // handle SafeFetch faults
+  if (sig == SIGSEGV || sig == SIGBUS) {
+    sigjmp_buf* const pjb = get_jmp_buf_for_continuation();
+    if (pjb) {
+      siglongjmp(*pjb, 1);
+    }
+  }
+
   // Note: it's not uncommon that JNI code uses signal/sigset to
   // install then restore certain signal handler (e.g. to temporarily
   // block SIGPIPE, or have a SIGILL handler when detecting CPU
--- a/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp	Tue Mar 31 02:11:09 2015 +0000
+++ b/hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp	Tue Mar 31 05:30:36 2015 -0400
@@ -54,6 +54,10 @@
 #include "utilities/events.hpp"
 #include "utilities/vmError.hpp"
 
+// See stubGenerator_zero.cpp
+#include <setjmp.h>
+extern sigjmp_buf* get_jmp_buf_for_continuation();
+
 address os::current_stack_pointer() {
   address dummy = (address) &dummy;
   return dummy;
@@ -125,6 +129,14 @@
 
   SignalHandlerMark shm(t);
 
+  // handle SafeFetch faults
+  if (sig == SIGSEGV || sig == SIGBUS) {
+    sigjmp_buf* const pjb = get_jmp_buf_for_continuation();
+    if (pjb) {
+      siglongjmp(*pjb, 1);
+    }
+  }
+
   // Note: it's not uncommon that JNI code uses signal/sigset to
   // install then restore certain signal handler (e.g. to temporarily
   // block SIGPIPE, or have a SIGILL handler when detecting CPU
--- a/hotspot/src/share/vm/runtime/stubRoutines.hpp	Tue Mar 31 02:11:09 2015 +0000
+++ b/hotspot/src/share/vm/runtime/stubRoutines.hpp	Tue Mar 31 05:30:36 2015 -0400
@@ -451,14 +451,10 @@
 
 // returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated)
 inline bool CanUseSafeFetch32() {
-  // All platforms have the stub but ZERO isn't safe.
-  assert(StubRoutines::SafeFetch32_stub() != NULL, "should have generated stub");
-  return NOT_ZERO(true) ZERO_ONLY(false);
+  return StubRoutines::SafeFetch32_stub() ? true : false;
 }
 
-inline bool CanUseSafeFetchN()  {
-  // All platforms have the stub but ZERO isn't safe.
-  assert(StubRoutines::SafeFetchN_stub() != NULL, "should have generated stub");
-  return NOT_ZERO(true) ZERO_ONLY(false);
+inline bool CanUseSafeFetchN() {
+  return StubRoutines::SafeFetchN_stub() ? true : false;
 }
 #endif // SHARE_VM_RUNTIME_STUBROUTINES_HPP