8213199: GC abstraction for Assembler::needs_explicit_null_check()
Reviewed-by: adinn, eosterlund
This commit is contained in:
parent
7724fd6d9b
commit
7c3f2b06f1
@ -582,6 +582,7 @@ public:
|
||||
|
||||
virtual void null_check(Register reg, int offset = -1);
|
||||
static bool needs_explicit_null_check(intptr_t offset);
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
static address target_addr_for_insn(address insn_addr, unsigned insn);
|
||||
static address target_addr_for_insn(address insn_addr) {
|
||||
|
@ -358,6 +358,7 @@ public:
|
||||
void zero_memory(Register start, Register end, Register tmp);
|
||||
|
||||
static bool needs_explicit_null_check(intptr_t offset);
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
void arm_stack_overflow_check(int frame_size_in_bytes, Register tmp);
|
||||
void arm_stack_overflow_check(Register Rsize, Register tmp);
|
||||
@ -1095,4 +1096,3 @@ private:
|
||||
|
||||
|
||||
#endif // CPU_ARM_VM_MACROASSEMBLER_ARM_HPP
|
||||
|
||||
|
@ -659,6 +659,7 @@ class MacroAssembler: public Assembler {
|
||||
void get_vm_result_2(Register metadata_result);
|
||||
|
||||
static bool needs_explicit_null_check(intptr_t offset);
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
// Trap-instruction-based checks.
|
||||
// Range checks can be distinguished from zero checks as they check 32 bit,
|
||||
|
@ -772,6 +772,7 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
void null_check(Register reg, Register tmp = Z_R0, int64_t offset = -1);
|
||||
static bool needs_explicit_null_check(intptr_t offset); // Implemented in shared file ?!
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
// Klass oop manipulations if compressed.
|
||||
void encode_klass_not_null(Register dst, Register src = noreg);
|
||||
|
@ -575,6 +575,7 @@ class MacroAssembler : public Assembler {
|
||||
|
||||
void null_check(Register reg, int offset = -1);
|
||||
static bool needs_explicit_null_check(intptr_t offset);
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
// support for delayed instructions
|
||||
MacroAssembler* delayed() { Assembler::delayed(); return this; }
|
||||
|
@ -96,6 +96,7 @@ class MacroAssembler: public Assembler {
|
||||
|
||||
void null_check(Register reg, int offset = -1);
|
||||
static bool needs_explicit_null_check(intptr_t offset);
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
// Required platform-specific helpers for Label::patch_instructions.
|
||||
// They _shadow_ the declarations in AbstractAssembler, which are undefined.
|
||||
|
@ -2492,7 +2492,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
#endif
|
||||
{
|
||||
// Null pointer exception.
|
||||
if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr)) {
|
||||
if (MacroAssembler::uses_implicit_null_check((void*)addr)) {
|
||||
address stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
|
||||
if (stub != NULL) return Handle_Exception(exceptionInfo, stub);
|
||||
}
|
||||
|
@ -409,7 +409,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec
|
||||
// SIGSEGV-based implicit null check in compiled code.
|
||||
else if (sig == SIGSEGV && ImplicitNullChecks &&
|
||||
CodeCache::contains((void*) pc) &&
|
||||
!MacroAssembler::needs_explicit_null_check((intptr_t) info->si_addr)) {
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", pc);
|
||||
}
|
||||
@ -612,5 +612,3 @@ bool os::platform_print_native_stack(outputStream* st, void* context, char *buf,
|
||||
AixNativeCallstack::print_callstack_for_context(st, (const ucontext_t*)context, true, buf, (size_t) buf_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -580,7 +580,7 @@ JVM_handle_bsd_signal(int sig,
|
||||
// 64-bit Darwin may also use a SIGBUS (seen with compressed oops).
|
||||
// Catching SIGBUS here prevents the implicit SIGBUS NULL check below from
|
||||
// being called, so only do so if the implicit NULL check is not necessary.
|
||||
} else if (sig == SIGBUS && MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
} else if (sig == SIGBUS && !MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
#else
|
||||
} else if (sig == SIGBUS /* && info->si_code == BUS_OBJERR */) {
|
||||
#endif
|
||||
@ -655,7 +655,7 @@ JVM_handle_bsd_signal(int sig,
|
||||
}
|
||||
#endif // AMD64
|
||||
} else if ((sig == SIGSEGV || sig == SIGBUS) &&
|
||||
!MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null exception
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
|
||||
}
|
||||
|
@ -357,10 +357,15 @@ JVM_handle_linux_signal(int sig,
|
||||
}
|
||||
#endif
|
||||
|
||||
address addr = (address) info->si_addr;
|
||||
|
||||
// Make sure the high order byte is sign extended, as it may be masked away by the hardware.
|
||||
if ((uintptr_t(addr) & (uintptr_t(1) << 55)) != 0) {
|
||||
addr = address(uintptr_t(addr) | (uintptr_t(0xFF) << 56));
|
||||
}
|
||||
|
||||
// Handle ALL stack overflow variations here
|
||||
if (sig == SIGSEGV) {
|
||||
address addr = (address) info->si_addr;
|
||||
|
||||
// check if fault address is within thread stack
|
||||
if (thread->on_local_stack(addr)) {
|
||||
// stack overflow
|
||||
@ -456,7 +461,7 @@ JVM_handle_linux_signal(int sig,
|
||||
SharedRuntime::
|
||||
IMPLICIT_DIVIDE_BY_ZERO);
|
||||
} else if (sig == SIGSEGV &&
|
||||
!MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
MacroAssembler::uses_implicit_null_check((void*)addr)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null exception
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
|
||||
}
|
||||
|
@ -384,7 +384,8 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info,
|
||||
if (nm != NULL && nm->has_unsafe_access()) {
|
||||
unsafe_access = true;
|
||||
}
|
||||
} else if (sig == SIGSEGV && !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
} else if (sig == SIGSEGV &&
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null exception
|
||||
CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
|
||||
if (cb != NULL) {
|
||||
@ -682,4 +683,3 @@ int os::extra_bang_size_in_bytes() {
|
||||
// ARM does not require an additional stack bang.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,7 @@ JVM_handle_linux_signal(int sig,
|
||||
// SIGSEGV-based implicit null check in compiled code.
|
||||
else if (sig == SIGSEGV && ImplicitNullChecks &&
|
||||
CodeCache::contains((void*) pc) &&
|
||||
!MacroAssembler::needs_explicit_null_check((intptr_t) info->si_addr)) {
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc));
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ JVM_handle_linux_signal(int sig,
|
||||
|
||||
else if (sig == SIGSEGV && ImplicitNullChecks &&
|
||||
CodeCache::contains((void*) pc) &&
|
||||
!MacroAssembler::needs_explicit_null_check((intptr_t) info->si_addr)) {
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
if (TraceTraps) {
|
||||
tty->print_cr("trap: null_check at " INTPTR_FORMAT " (SIGSEGV)", p2i(pc));
|
||||
}
|
||||
|
@ -416,9 +416,9 @@ inline static bool checkFPFault(address pc, int code,
|
||||
return false;
|
||||
}
|
||||
|
||||
inline static bool checkNullPointer(address pc, intptr_t fault,
|
||||
inline static bool checkNullPointer(address pc, void* fault,
|
||||
JavaThread* thread, address* stub) {
|
||||
if (!MacroAssembler::needs_explicit_null_check(fault)) {
|
||||
if (MacroAssembler::uses_implicit_null_check(fault)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null
|
||||
// exception
|
||||
*stub =
|
||||
@ -586,7 +586,7 @@ JVM_handle_linux_signal(int sig,
|
||||
}
|
||||
|
||||
if ((sig == SIGSEGV) &&
|
||||
checkNullPointer(pc, (intptr_t)info->si_addr, thread, &stub)) {
|
||||
checkNullPointer(pc, info->si_addr, thread, &stub)) {
|
||||
break;
|
||||
}
|
||||
} while (0);
|
||||
|
@ -479,7 +479,7 @@ JVM_handle_linux_signal(int sig,
|
||||
}
|
||||
#endif // AMD64
|
||||
} else if (sig == SIGSEGV &&
|
||||
!MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null exception
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
}
|
||||
#endif // COMPILER2
|
||||
|
||||
else if (sig == SIGSEGV && info->si_code > 0 && !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
else if (sig == SIGSEGV && info->si_code > 0 && MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null exception
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
|
||||
}
|
||||
|
@ -579,7 +579,8 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
// QQQ It doesn't seem that we need to do this on x86 because we should be able
|
||||
// to return properly from the handler without this extra stuff on the back side.
|
||||
|
||||
else if (sig == SIGSEGV && info->si_code > 0 && !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
|
||||
else if (sig == SIGSEGV && info->si_code > 0 &&
|
||||
MacroAssembler::uses_implicit_null_check(info->si_addr)) {
|
||||
// Determination of interpreter/vtable stub/compiled code null exception
|
||||
stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/icache.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -307,21 +308,32 @@ const char* AbstractAssembler::code_string(const char* str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
|
||||
bool MacroAssembler::uses_implicit_null_check(void* address) {
|
||||
// Exception handler checks the nmethod's implicit null checks table
|
||||
// only when this method returns false.
|
||||
intptr_t int_address = reinterpret_cast<intptr_t>(address);
|
||||
intptr_t cell_header_size = Universe::heap()->cell_header_size();
|
||||
size_t region_size = os::vm_page_size() + cell_header_size;
|
||||
#ifdef _LP64
|
||||
if (UseCompressedOops && Universe::narrow_oop_base() != NULL) {
|
||||
assert (Universe::heap() != NULL, "java heap should be initialized");
|
||||
// The first page after heap_base is unmapped and
|
||||
// the 'offset' is equal to [heap_base + offset] for
|
||||
// narrow oop implicit null checks.
|
||||
uintptr_t base = (uintptr_t)Universe::narrow_oop_base();
|
||||
if ((uintptr_t)offset >= base) {
|
||||
// Normalize offset for the next check.
|
||||
offset = (intptr_t)(pointer_delta((void*)offset, (void*)base, 1));
|
||||
// A SEGV can legitimately happen in C2 code at address
|
||||
// (heap_base + offset) if Matcher::narrow_oop_use_complex_address
|
||||
// is configured to allow narrow oops field loads to be implicitly
|
||||
// null checked
|
||||
intptr_t start = ((intptr_t)Universe::narrow_oop_base()) - cell_header_size;
|
||||
intptr_t end = start + region_size;
|
||||
if (int_address >= start && int_address < end) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return offset < 0 || os::vm_page_size() <= offset;
|
||||
intptr_t start = -cell_header_size;
|
||||
intptr_t end = start + region_size;
|
||||
return int_address >= start && int_address < end;
|
||||
}
|
||||
|
||||
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
|
||||
// Check if offset is outside of [-cell_header_size, os::vm_page_size)
|
||||
return offset < -Universe::heap()->cell_header_size() ||
|
||||
offset >= os::vm_page_size();
|
||||
}
|
||||
|
@ -580,6 +580,11 @@ class CollectedHeap : public CHeapObj<mtInternal> {
|
||||
|
||||
virtual size_t obj_size(oop obj) const;
|
||||
|
||||
// Cells are memory slices allocated by the allocator. Objects are initialized
|
||||
// in cells. The cell itself may have a header, found at a negative offset of
|
||||
// oops. Usually, the size of the cell header is 0, but it may be larger.
|
||||
virtual ptrdiff_t cell_header_size() const { return 0; }
|
||||
|
||||
// Non product verification and debugging.
|
||||
#ifndef PRODUCT
|
||||
// Support for PromotionFailureALot. Return true if it's time to cause a
|
||||
|
Loading…
x
Reference in New Issue
Block a user