8076185: Provide SafeFetchX implementation for zero
Implement SafeFetchX for zero using setjmp/longjmp and Posix TLS Reviewed-by: sgehwolf, dholmes
This commit is contained in:
parent
38c3337610
commit
1afbc04d56
@ -45,6 +45,18 @@
|
|||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
#endif
|
#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).
|
// Declaration and definition of StubGenerator (no .hpp file).
|
||||||
// For a more detailed description of the stub routine structure
|
// For a more detailed description of the stub routine structure
|
||||||
// see the comment in stubRoutines.hpp
|
// see the comment in stubRoutines.hpp
|
||||||
@ -176,17 +188,55 @@ class StubGenerator: public StubCodeGenerator {
|
|||||||
StubRoutines::_oop_arraycopy;
|
StubRoutines::_oop_arraycopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NYI: SafeFetch for Zero isn't actually safe.
|
|
||||||
static int SafeFetch32(int *adr, int errValue) {
|
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;
|
int value = errValue;
|
||||||
value = *adr;
|
value = *adr;
|
||||||
|
|
||||||
|
// all went well. clean tls.
|
||||||
|
pthread_setspecific(g_jmpbuf_key, NULL);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static intptr_t SafeFetchN(intptr_t *adr, intptr_t errValue) {
|
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;
|
intptr_t value = errValue;
|
||||||
value = *adr;
|
value = *adr;
|
||||||
|
|
||||||
|
// all went well. clean tls.
|
||||||
|
pthread_setspecific(g_jmpbuf_key, NULL);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_initial() {
|
void generate_initial() {
|
||||||
@ -241,6 +291,7 @@ class StubGenerator: public StubCodeGenerator {
|
|||||||
generate_arraycopy_stubs();
|
generate_arraycopy_stubs();
|
||||||
|
|
||||||
// Safefetch stubs.
|
// Safefetch stubs.
|
||||||
|
pthread_key_create(&g_jmpbuf_key, NULL);
|
||||||
StubRoutines::_safefetch32_entry = CAST_FROM_FN_PTR(address, StubGenerator::SafeFetch32);
|
StubRoutines::_safefetch32_entry = CAST_FROM_FN_PTR(address, StubGenerator::SafeFetch32);
|
||||||
StubRoutines::_safefetch32_fault_pc = NULL;
|
StubRoutines::_safefetch32_fault_pc = NULL;
|
||||||
StubRoutines::_safefetch32_continuation_pc = NULL;
|
StubRoutines::_safefetch32_continuation_pc = NULL;
|
||||||
|
@ -59,6 +59,10 @@
|
|||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.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 os::current_stack_pointer() {
|
||||||
address dummy = (address) &dummy;
|
address dummy = (address) &dummy;
|
||||||
return dummy;
|
return dummy;
|
||||||
@ -134,6 +138,14 @@ JVM_handle_bsd_signal(int sig,
|
|||||||
|
|
||||||
SignalHandlerMark shm(t);
|
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
|
// Note: it's not uncommon that JNI code uses signal/sigset to
|
||||||
// install then restore certain signal handler (e.g. to temporarily
|
// install then restore certain signal handler (e.g. to temporarily
|
||||||
// block SIGPIPE, or have a SIGILL handler when detecting CPU
|
// block SIGPIPE, or have a SIGILL handler when detecting CPU
|
||||||
|
@ -54,6 +54,10 @@
|
|||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/vmError.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 os::current_stack_pointer() {
|
||||||
address dummy = (address) &dummy;
|
address dummy = (address) &dummy;
|
||||||
return dummy;
|
return dummy;
|
||||||
@ -125,6 +129,14 @@ JVM_handle_linux_signal(int sig,
|
|||||||
|
|
||||||
SignalHandlerMark shm(t);
|
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
|
// Note: it's not uncommon that JNI code uses signal/sigset to
|
||||||
// install then restore certain signal handler (e.g. to temporarily
|
// install then restore certain signal handler (e.g. to temporarily
|
||||||
// block SIGPIPE, or have a SIGILL handler when detecting CPU
|
// block SIGPIPE, or have a SIGILL handler when detecting CPU
|
||||||
|
@ -451,14 +451,10 @@ inline intptr_t SafeFetchN(intptr_t* adr, intptr_t errValue) {
|
|||||||
|
|
||||||
// returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated)
|
// returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated)
|
||||||
inline bool CanUseSafeFetch32() {
|
inline bool CanUseSafeFetch32() {
|
||||||
// All platforms have the stub but ZERO isn't safe.
|
return StubRoutines::SafeFetch32_stub() ? true : false;
|
||||||
assert(StubRoutines::SafeFetch32_stub() != NULL, "should have generated stub");
|
|
||||||
return NOT_ZERO(true) ZERO_ONLY(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool CanUseSafeFetchN() {
|
inline bool CanUseSafeFetchN() {
|
||||||
// All platforms have the stub but ZERO isn't safe.
|
return StubRoutines::SafeFetchN_stub() ? true : false;
|
||||||
assert(StubRoutines::SafeFetchN_stub() != NULL, "should have generated stub");
|
|
||||||
return NOT_ZERO(true) ZERO_ONLY(false);
|
|
||||||
}
|
}
|
||||||
#endif // SHARE_VM_RUNTIME_STUBROUTINES_HPP
|
#endif // SHARE_VM_RUNTIME_STUBROUTINES_HPP
|
||||||
|
Loading…
x
Reference in New Issue
Block a user