# HG changeset patch # User dholmes # Date 1427794236 14400 # Node ID 3517884331033dd254e30dc8178710fc77dff162 # Parent b5e4e8a58b0b8f121248d258a917a729df92b315 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 diff -r b5e4e8a58b0b -r 351788433103 hotspot/src/cpu/zero/vm/stubGenerator_zero.cpp --- 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 +#include +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; diff -r b5e4e8a58b0b -r 351788433103 hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp --- 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 +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 diff -r b5e4e8a58b0b -r 351788433103 hotspot/src/os_cpu/linux_zero/vm/os_linux_zero.cpp --- 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 +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 diff -r b5e4e8a58b0b -r 351788433103 hotspot/src/share/vm/runtime/stubRoutines.hpp --- 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