8213199: GC abstraction for Assembler::needs_explicit_null_check()
authorrkennke
Thu, 08 Nov 2018 23:31:08 +0100
changeset 52462 4ad404da0088
parent 52461 b391c62e38b1
child 52463 52155b28cdb7
8213199: GC abstraction for Assembler::needs_explicit_null_check() Reviewed-by: adinn, eosterlund
src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp
src/hotspot/cpu/arm/macroAssembler_arm.hpp
src/hotspot/cpu/ppc/macroAssembler_ppc.hpp
src/hotspot/cpu/s390/macroAssembler_s390.hpp
src/hotspot/cpu/sparc/macroAssembler_sparc.hpp
src/hotspot/cpu/x86/macroAssembler_x86.hpp
src/hotspot/os/windows/os_windows.cpp
src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp
src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp
src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp
src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp
src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp
src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp
src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp
src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp
src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp
src/hotspot/share/asm/assembler.cpp
src/hotspot/share/gc/shared/collectedHeap.hpp
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -582,6 +582,7 @@
 
   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) {
--- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -358,6 +358,7 @@
   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 @@
 
 
 #endif // CPU_ARM_VM_MACROASSEMBLER_ARM_HPP
-
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -659,6 +659,7 @@
   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,
--- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -772,6 +772,7 @@
 
   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);
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -575,6 +575,7 @@
 
   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; }
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -96,6 +96,7 @@
 
   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.
--- a/src/hotspot/os/windows/os_windows.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os/windows/os_windows.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -2492,7 +2492,7 @@
 #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);
             }
--- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -409,7 +409,7 @@
       // 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 @@
   AixNativeCallstack::print_callstack_for_context(st, (const ucontext_t*)context, true, buf, (size_t) buf_size);
   return true;
 }
-
-
--- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -580,7 +580,7 @@
       // 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 @@
         }
 #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);
       }
--- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -357,10 +357,15 @@
     }
 #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 @@
                                               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);
       }
--- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -384,7 +384,8 @@
         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 @@
   // ARM does not require an additional stack bang.
   return 0;
 }
-
--- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -431,7 +431,7 @@
       // 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));
         }
--- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -418,7 +418,7 @@
 
       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));
         }
--- a/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/linux_sparc/os_linux_sparc.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -416,9 +416,9 @@
   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 @@
         }
 
         if ((sig == SIGSEGV) &&
-            checkNullPointer(pc, (intptr_t)info->si_addr, thread, &stub)) {
+            checkNullPointer(pc, info->si_addr, thread, &stub)) {
           break;
         }
       } while (0);
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -479,7 +479,7 @@
         }
 #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);
       }
--- a/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/solaris_sparc/os_solaris_sparc.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -505,7 +505,7 @@
       }
 #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);
       }
--- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -579,7 +579,8 @@
         // 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);
       }
--- a/src/hotspot/share/asm/assembler.cpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/share/asm/assembler.cpp	Thu Nov 08 23:31:08 2018 +0100
@@ -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 @@
   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();
+}
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp	Thu Nov 08 18:10:15 2018 -0300
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp	Thu Nov 08 23:31:08 2018 +0100
@@ -580,6 +580,11 @@
 
   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