8213199: GC abstraction for Assembler::needs_explicit_null_check()

Reviewed-by: adinn, eosterlund
This commit is contained in:
Roman Kennke 2018-11-08 23:31:08 +01:00
parent 7724fd6d9b
commit 7c3f2b06f1
19 changed files with 56 additions and 30 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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; }

View File

@ -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.

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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));
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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();
}

View File

@ -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