diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 6eeaa30..56df639 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -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) { diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index 3b137f6..543213b 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -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 - diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index d41a33d..12c2eaf 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -667,6 +667,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, diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 90afb7e..f33478e 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -779,6 +779,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); diff --git a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp index d795815..ce8c624 100644 --- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp +++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp @@ -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; } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 433f1ca..a48c9ac 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -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. diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 0b3b9d9..f4b5d8d 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -2509,7 +2509,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); } diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 8955d2f..3d84509 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -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); } @@ -624,5 +624,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; } - - diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index 56dadda..0e86b97 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -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); } diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 13b7214..9a30b7f 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -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(info->si_addr)) { // Determination of interpreter/vtable stub/compiled code null exception stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); } diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 930d9b2..aee36ca 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -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) { @@ -692,4 +693,3 @@ int os::extra_bang_size_in_bytes() { // ARM does not require an additional stack bang. return 0; } - diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 63ca308..507207c 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -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)); } diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 9d6e1d9..ba2b868 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -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)); } diff --git a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp index 984aa7c..35e1d3b 100644 --- a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp +++ b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp @@ -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 = @@ -600,7 +600,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); diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index e0de858..faf5679 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -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); } diff --git a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp index 9a8afe3..0aa2ade 100644 --- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp +++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp @@ -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); } diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index 18c7c6b..39337f1 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -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,25 @@ 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 cell_header_size = Universe::heap()->cell_header_size(); + HeapWord* start = (HeapWord*)-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)); - } + start += (uintptr_t)Universe::narrow_oop_base(); } #endif - return offset < 0 || os::vm_page_size() <= offset; + MemRegion implicit_null_range(start, (os::vm_page_size() + cell_header_size) / HeapWordSize); + return implicit_null_range.contains(address); +} + +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(); } diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index e43bb28..4919cd0 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -580,6 +580,11 @@ class CollectedHeap : public CHeapObj { 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