8229278: Improve hs_err location printing to assume less about GC internals
authoreosterlund
Wed, 28 Aug 2019 11:19:09 +0200
changeset 57903 5e2576c303a2
parent 57901 53ed0cf870b0
child 57904 4f38fcd65577
8229278: Improve hs_err location printing to assume less about GC internals Reviewed-by: stefank, kbarrett
src/hotspot/share/gc/epsilon/epsilonHeap.cpp
src/hotspot/share/gc/epsilon/epsilonHeap.hpp
src/hotspot/share/gc/g1/g1CollectedHeap.cpp
src/hotspot/share/gc/g1/g1CollectedHeap.hpp
src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
src/hotspot/share/gc/shared/collectedHeap.hpp
src/hotspot/share/gc/shared/genCollectedHeap.cpp
src/hotspot/share/gc/shared/genCollectedHeap.hpp
src/hotspot/share/gc/shared/locationPrinter.cpp
src/hotspot/share/gc/shared/locationPrinter.hpp
src/hotspot/share/gc/shared/locationPrinter.inline.hpp
src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
src/hotspot/share/gc/z/zCollectedHeap.cpp
src/hotspot/share/gc/z/zCollectedHeap.hpp
src/hotspot/share/gc/z/zHeap.cpp
src/hotspot/share/gc/z/zHeap.hpp
src/hotspot/share/gc/z/zPage.hpp
src/hotspot/share/gc/z/zPage.inline.hpp
src/hotspot/share/oops/oop.cpp
src/hotspot/share/oops/oop.hpp
src/hotspot/share/runtime/os.cpp
--- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -26,6 +26,7 @@
 #include "gc/epsilon/epsilonMemoryPool.hpp"
 #include "gc/epsilon/epsilonThreadLocalData.hpp"
 #include "gc/shared/gcArguments.hpp"
+#include "gc/shared/locationPrinter.inline.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
@@ -305,6 +306,10 @@
   MetaspaceUtils::print_on(st);
 }
 
+bool EpsilonHeap::print_location(outputStream* st, void* addr) const {
+  return BlockLocationPrinter<EpsilonHeap>::print_location(st, addr);
+}
+
 void EpsilonHeap::print_tracing_info() const {
   print_heap_info(used());
   print_metaspace_info();
--- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -114,8 +114,8 @@
   virtual void unpin_object(JavaThread* thread, oop obj) { }
 
   // No support for block parsing.
-  virtual HeapWord* block_start(const void* addr) const { return NULL;  }
-  virtual bool block_is_obj(const HeapWord* addr) const { return false; }
+  HeapWord* block_start(const void* addr) const { return NULL;  }
+  bool block_is_obj(const HeapWord* addr) const { return false; }
 
   // No GC threads
   virtual void print_gc_threads_on(outputStream* st) const {}
@@ -138,6 +138,7 @@
 
   virtual void print_on(outputStream* st) const;
   virtual void print_tracing_info() const;
+  virtual bool print_location(outputStream* st, void* addr) const;
 
 private:
   void print_heap_info(size_t used) const;
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -74,6 +74,7 @@
 #include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/generationSpec.hpp"
 #include "gc/shared/isGCActiveMark.hpp"
+#include "gc/shared/locationPrinter.inline.hpp"
 #include "gc/shared/oopStorageParState.hpp"
 #include "gc/shared/preservedMarks.inline.hpp"
 #include "gc/shared/suspendibleThreadSet.hpp"
@@ -2490,6 +2491,10 @@
 }
 #endif // PRODUCT
 
+bool G1CollectedHeap::print_location(outputStream* st, void* addr) const {
+  return BlockLocationPrinter<G1CollectedHeap>::print_location(st, addr);
+}
+
 G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
 
   size_t eden_used_bytes = _eden.used_bytes();
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -1211,11 +1211,11 @@
   // address "addr".  We say "blocks" instead of "object" since some heaps
   // may not pack objects densely; a chunk may either be an object or a
   // non-object.
-  virtual HeapWord* block_start(const void* addr) const;
+  HeapWord* block_start(const void* addr) const;
 
   // Requires "addr" to be the start of a block, and returns "TRUE" iff
   // the block is an object.
-  virtual bool block_is_obj(const HeapWord* addr) const;
+  bool block_is_obj(const HeapWord* addr) const;
 
   // Section on thread-local allocation buffers (TLABs)
   // See CollectedHeap for semantics.
@@ -1428,6 +1428,9 @@
   void print_cset_rsets() PRODUCT_RETURN;
   void print_all_rsets() PRODUCT_RETURN;
 
+  // Used to print information about locations in the hs_err file.
+  virtual bool print_location(outputStream* st, void* addr) const;
+
   size_t pending_card_num();
 };
 
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -41,6 +41,7 @@
 #include "gc/shared/gcLocker.hpp"
 #include "gc/shared/gcWhen.hpp"
 #include "gc/shared/genArguments.hpp"
+#include "gc/shared/locationPrinter.inline.hpp"
 #include "gc/shared/scavengableNMethods.hpp"
 #include "logging/log.hpp"
 #include "memory/metaspaceCounters.hpp"
@@ -584,6 +585,10 @@
   return PSHeapSummary(heap_summary, used(), old_summary, old_space, young_summary, eden_space, from_space, to_space);
 }
 
+bool ParallelScavengeHeap::print_location(outputStream* st, void* addr) const {
+  return BlockLocationPrinter<ParallelScavengeHeap>::print_location(st, addr);
+}
+
 void ParallelScavengeHeap::print_on(outputStream* st) const {
   young_gen()->print_on(st);
   old_gen()->print_on(st);
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -228,6 +228,9 @@
   PreGenGCValues get_pre_gc_values() const;
   void print_heap_change(const PreGenGCValues& pre_gc_values) const;
 
+  // Used to print information about locations in the hs_err file.
+  virtual bool print_location(outputStream* st, void* addr) const;
+
   void verify(VerifyOption option /* ignored */);
 
   // Resize the young generation.  The reserved space for the
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -402,28 +402,6 @@
   // over live objects.
   virtual void safe_object_iterate(ObjectClosure* cl) = 0;
 
-  // NOTE! There is no requirement that a collector implement these
-  // functions.
-  //
-  // A CollectedHeap is divided into a dense sequence of "blocks"; that is,
-  // each address in the (reserved) heap is a member of exactly
-  // one block.  The defining characteristic of a block is that it is
-  // possible to find its size, and thus to progress forward to the next
-  // block.  (Blocks may be of different sizes.)  Thus, blocks may
-  // represent Java objects, or they might be free blocks in a
-  // free-list-based heap (or subheap), as long as the two kinds are
-  // distinguishable and the size of each is determinable.
-
-  // Returns the address of the start of the "block" that contains the
-  // address "addr".  We say "blocks" instead of "object" since some heaps
-  // may not pack objects densely; a chunk may either be an object or a
-  // non-object.
-  virtual HeapWord* block_start(const void* addr) const = 0;
-
-  // Requires "addr" to be the start of a block, and returns "TRUE" iff
-  // the block is an object.
-  virtual bool block_is_obj(const HeapWord* addr) const = 0;
-
   // Returns the longest time (in ms) that has elapsed since the last
   // time that any part of the heap was examined by a garbage collection.
   virtual jlong millis_since_last_gc() = 0;
@@ -461,6 +439,9 @@
 
   virtual void print_on_error(outputStream* st) const;
 
+  // Used to print information about locations in the hs_err file.
+  virtual bool print_location(outputStream* st, void* addr) const = 0;
+
   // Print all GC threads (other than the VM thread)
   // used by this heap.
   virtual void print_gc_threads_on(outputStream* st) const = 0;
--- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -47,6 +47,7 @@
 #include "gc/shared/genCollectedHeap.hpp"
 #include "gc/shared/genOopClosures.inline.hpp"
 #include "gc/shared/generationSpec.hpp"
+#include "gc/shared/locationPrinter.inline.hpp"
 #include "gc/shared/oopStorageParState.inline.hpp"
 #include "gc/shared/scavengableNMethods.hpp"
 #include "gc/shared/space.hpp"
@@ -1260,6 +1261,10 @@
 void GenCollectedHeap::print_gc_threads_on(outputStream* st) const {
 }
 
+bool GenCollectedHeap::print_location(outputStream* st, void* addr) const {
+  return BlockLocationPrinter<GenCollectedHeap>::print_location(st, addr);
+}
+
 void GenCollectedHeap::print_tracing_info() const {
   if (log_is_enabled(Debug, gc, heap, exit)) {
     LogStreamHandle(Debug, gc, heap, exit) lsh;
--- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -260,13 +260,13 @@
   // address "addr".  We say "blocks" instead of "object" since some heaps
   // may not pack objects densely; a chunk may either be an object or a
   // non-object.
-  virtual HeapWord* block_start(const void* addr) const;
+  HeapWord* block_start(const void* addr) const;
 
   // Requires "addr" to be the start of a block, and returns "TRUE" iff
   // the block is an object. Assumes (and verifies in non-product
   // builds) that addr is in the allocated part of the heap and is
   // the start of a chunk.
-  virtual bool block_is_obj(const HeapWord* addr) const;
+  bool block_is_obj(const HeapWord* addr) const;
 
   // Section on TLAB's.
   virtual bool supports_tlab_allocation() const;
@@ -332,6 +332,9 @@
   virtual void gc_threads_do(ThreadClosure* tc) const;
   virtual void print_tracing_info() const;
 
+  // Used to print information about locations in the hs_err file.
+  virtual bool print_location(outputStream* st, void* addr) const;
+
   void print_heap_change(size_t young_prev_used, size_t old_prev_used) const;
 
   // The functions below are helper functions that a subclass of
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/locationPrinter.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/locationPrinter.hpp"
+#include "memory/universe.hpp"
+#include "runtime/os.hpp"
+#include "oops/klass.hpp"
+
+bool LocationPrinter::is_valid_obj(void* obj) {
+  if (!is_object_aligned(obj)) {
+    return false;
+  }
+  if (obj < (void*)os::min_page_size()) {
+    return false;
+  }
+
+  // We need at least the mark and the klass word in the committed region.
+  if (!os::is_readable_range(obj, (HeapWord*)obj + oopDesc::header_size())) {
+    return false;
+  }
+  if (!Universe::heap()->is_in(obj)) {
+    return false;
+  }
+
+  Klass* k = (Klass*)oopDesc::load_klass_raw((oopDesc*)obj);
+  return Klass::is_valid(k);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/locationPrinter.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_SHARED_LOCATIONPRINTER_HPP
+#define SHARE_GC_SHARED_LOCATIONPRINTER_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/oopsHierarchy.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class outputStream;
+
+class LocationPrinter : AllStatic {
+ public:
+  static bool is_valid_obj(void* addr);
+};
+
+template <typename CollectedHeapT>
+class BlockLocationPrinter : public LocationPrinter {
+  static oop base_oop_or_null(void* addr);
+
+public:
+  static bool print_location(outputStream* st, void* addr);
+};
+
+
+#endif // SHARE_GC_SHARED_LOCATIONPRINTER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/locationPrinter.inline.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_SHARED_LOCATIONPRINTER_INLINE_HPP
+#define SHARE_GC_SHARED_LOCATIONPRINTER_INLINE_HPP
+
+#include "gc/shared/locationPrinter.hpp"
+#include "oops/compressedOops.inline.hpp"
+#include "oops/oopsHierarchy.hpp"
+
+template <typename CollectedHeapT>
+oop BlockLocationPrinter<CollectedHeapT>::base_oop_or_null(void* addr) {
+  if (is_valid_obj(addr)) {
+    // We were just given an oop directly.
+    return oop(addr);
+  }
+
+  // Try to find addr using block_start.
+  HeapWord* p = CollectedHeapT::heap()->block_start(addr);
+  if (p != NULL && CollectedHeapT::heap()->block_is_obj(p)) {
+    if (!is_valid_obj(p)) {
+      return NULL;
+    }
+    return oop(p);
+  }
+
+  return NULL;
+}
+
+template <typename CollectedHeapT>
+bool BlockLocationPrinter<CollectedHeapT>::print_location(outputStream* st, void* addr) {
+  // Check if addr points into Java heap.
+  if (CollectedHeapT::heap()->is_in(addr)) {
+    oop o = base_oop_or_null(addr);
+    if (o != NULL) {
+      if ((void*)o == addr) {
+        st->print(INTPTR_FORMAT " is an oop: ", p2i(addr));
+      } else {
+        st->print(INTPTR_FORMAT " is pointing into object: " , p2i(addr));
+      }
+      o->print_on(st);
+      return true;
+    }
+  } else if (CollectedHeapT::heap()->is_in_reserved(addr)) {
+    st->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", p2i(addr));
+    return true;
+  }
+
+  // Compressed oop needs to be decoded first.
+#ifdef _LP64
+  if (UseCompressedOops && ((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) {
+    narrowOop narrow_oop = (narrowOop)(uintptr_t)addr;
+    oop o = CompressedOops::decode_raw(narrow_oop);
+
+    if (is_valid_obj((address)o)) {
+      st->print(UINT32_FORMAT " is a compressed pointer to object: ", narrow_oop);
+      o->print_on(st);
+      return true;
+    }
+  }
+#endif
+
+  return false;
+}
+
+#endif // SHARE_GC_SHARED_LOCATIONPRINTER_INLINE_HPP
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -28,6 +28,7 @@
 #include "gc/shared/gcArguments.hpp"
 #include "gc/shared/gcTimer.hpp"
 #include "gc/shared/gcTraceTime.inline.hpp"
+#include "gc/shared/locationPrinter.inline.hpp"
 #include "gc/shared/memAllocator.hpp"
 #include "gc/shared/plab.hpp"
 
@@ -1133,6 +1134,10 @@
   return sp->block_is_obj(addr);
 }
 
+bool ShenandoahHeap::print_location(outputStream* st, void* addr) const {
+  return BlockLocationPrinter<ShenandoahHeap>::print_location(st, addr);
+}
+
 jlong ShenandoahHeap::millis_since_last_gc() {
   double v = heuristics()->time_since_last_gc() * 1000;
   assert(0 <= v && v <= max_jlong, "value should fit: %f", v);
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -536,6 +536,7 @@
   // Used for parsing heap during error printing
   HeapWord* block_start(const void* addr) const;
   bool block_is_obj(const HeapWord* addr) const;
+  bool print_location(outputStream* st, void* addr) const;
 
   // Used for native heap walkers: heap dumpers, mostly
   void object_iterate(ObjectClosure* cl);
--- a/src/hotspot/share/gc/z/zCollectedHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/z/zCollectedHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -23,6 +23,7 @@
 
 #include "precompiled.hpp"
 #include "gc/shared/gcHeapSummary.hpp"
+#include "gc/shared/locationPrinter.hpp"
 #include "gc/shared/suspendibleThreadSet.hpp"
 #include "gc/z/zCollectedHeap.hpp"
 #include "gc/z/zGlobals.hpp"
@@ -249,14 +250,6 @@
   _heap.object_iterate(cl, true /* visit_weaks */);
 }
 
-HeapWord* ZCollectedHeap::block_start(const void* addr) const {
-  return (HeapWord*)_heap.block_start((uintptr_t)addr);
-}
-
-bool ZCollectedHeap::block_is_obj(const HeapWord* addr) const {
-  return _heap.block_is_obj((uintptr_t)addr);
-}
-
 void ZCollectedHeap::register_nmethod(nmethod* nm) {
   ZNMethod::register_nmethod(nm);
 }
@@ -356,6 +349,16 @@
   // Does nothing
 }
 
+bool ZCollectedHeap::print_location(outputStream* st, void* addr) const {
+  if (LocationPrinter::is_valid_obj(addr)) {
+    st->print(INTPTR_FORMAT " is a %s oop: ", p2i(addr),
+              ZAddress::is_good(reinterpret_cast<uintptr_t>(addr)) ? "good" : "bad");
+    cast_to_oop(addr)->print_on(st);
+    return true;
+  }
+  return false;
+}
+
 void ZCollectedHeap::verify(VerifyOption option /* ignored */) {
   _heap.verify();
 }
--- a/src/hotspot/share/gc/z/zCollectedHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/z/zCollectedHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -100,9 +100,6 @@
   virtual void object_iterate(ObjectClosure* cl);
   virtual void safe_object_iterate(ObjectClosure* cl);
 
-  virtual HeapWord* block_start(const void* addr) const;
-  virtual bool block_is_obj(const HeapWord* addr) const;
-
   virtual void register_nmethod(nmethod* nm);
   virtual void unregister_nmethod(nmethod* nm);
   virtual void flush_nmethod(nmethod* nm);
@@ -124,6 +121,7 @@
   virtual void print_extended_on(outputStream* st) const;
   virtual void print_gc_threads_on(outputStream* st) const;
   virtual void print_tracing_info() const;
+  virtual bool print_location(outputStream* st, void* addr) const;
 
   virtual void prepare_for_verify();
   virtual void verify(VerifyOption option /* ignored */);
--- a/src/hotspot/share/gc/z/zHeap.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/z/zHeap.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -194,16 +194,6 @@
   return false;
 }
 
-uintptr_t ZHeap::block_start(uintptr_t addr) const {
-  const ZPage* const page = _page_table.get(addr);
-  return page->block_start(addr);
-}
-
-bool ZHeap::block_is_obj(uintptr_t addr) const {
-  const ZPage* const page = _page_table.get(addr);
-  return page->block_is_obj(addr);
-}
-
 uint ZHeap::nconcurrent_worker_threads() const {
   return _workers.nconcurrent();
 }
--- a/src/hotspot/share/gc/z/zHeap.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/z/zHeap.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -107,10 +107,6 @@
   bool is_in(uintptr_t addr) const;
   uint32_t hash_oop(oop obj) const;
 
-  // Block
-  uintptr_t block_start(uintptr_t addr) const;
-  bool block_is_obj(uintptr_t addr) const;
-
   // Workers
   uint nconcurrent_worker_threads() const;
   uint nconcurrent_no_boost_worker_threads() const;
--- a/src/hotspot/share/gc/z/zPage.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/z/zPage.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -90,9 +90,6 @@
 
   bool is_in(uintptr_t addr) const;
 
-  uintptr_t block_start(uintptr_t addr) const;
-  bool block_is_obj(uintptr_t addr) const;
-
   bool is_marked() const;
   bool is_object_live(uintptr_t addr) const;
   bool is_object_strongly_live(uintptr_t addr) const;
--- a/src/hotspot/share/gc/z/zPage.inline.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/gc/z/zPage.inline.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -177,18 +177,6 @@
   return offset >= start() && offset < top();
 }
 
-inline uintptr_t ZPage::block_start(uintptr_t addr) const {
-  if (block_is_obj(addr)) {
-    return addr;
-  } else {
-    return ZAddress::good(top());
-  }
-}
-
-inline bool ZPage::block_is_obj(uintptr_t addr) const {
-  return ZAddress::offset(addr) < top();
-}
-
 inline bool ZPage::is_marked() const {
   assert(is_relocatable(), "Invalid page state");
   return _livemap.is_marked();
--- a/src/hotspot/share/oops/oop.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/oops/oop.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -173,35 +173,6 @@
   }
 }
 
-bool oopDesc::is_valid(oop obj) {
-  if (!is_object_aligned(obj)) return false;
-  if ((size_t)(oopDesc*)obj < os::min_page_size()) return false;
-
-  // We need at least the mark and the klass word in the committed region.
-  if (!os::is_readable_range(obj, (oopDesc*)obj + 1)) return false;
-  if (!Universe::heap()->is_in(obj)) return false;
-
-  Klass* k = (Klass*)load_klass_raw(obj);
-  return Klass::is_valid(k);
-}
-
-oop oopDesc::oop_or_null(address addr) {
-  if (is_valid(oop(addr))) {
-    // We were just given an oop directly.
-    return oop(addr);
-  }
-
-  // Try to find addr using block_start.
-  HeapWord* p = Universe::heap()->block_start(addr);
-  if (p != NULL && Universe::heap()->block_is_obj(p)) {
-    if (!is_valid(oop(p))) return NULL;
-    return oop(p);
-  }
-
-  // If we can't find it it just may mean that heap wasn't parsable.
-  return NULL;
-}
-
 oop oopDesc::obj_field_acquire(int offset) const                      { return HeapAccess<MO_ACQUIRE>::oop_load_at(as_oop(), offset); }
 
 void oopDesc::obj_field_put_raw(int offset, oop value)                { RawAccess<>::oop_store_at(as_oop(), offset, value); }
--- a/src/hotspot/share/oops/oop.hpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/oops/oop.hpp	Wed Aug 28 11:19:09 2019 +0200
@@ -331,8 +331,6 @@
   // for error reporting
   static void* load_klass_raw(oop obj);
   static void* load_oop_raw(oop obj, int offset);
-  static bool  is_valid(oop obj);
-  static oop   oop_or_null(address addr);
 };
 
 #endif // SHARE_OOPS_OOP_HPP
--- a/src/hotspot/share/runtime/os.cpp	Wed Aug 28 09:50:23 2019 +0200
+++ b/src/hotspot/share/runtime/os.cpp	Wed Aug 28 11:19:09 2019 +0200
@@ -1082,37 +1082,10 @@
   }
 
   // Check if addr points into Java heap.
-  if (Universe::heap()->is_in(addr)) {
-    oop o = oopDesc::oop_or_null(addr);
-    if (o != NULL) {
-      if ((HeapWord*)o == (HeapWord*)addr) {
-        st->print(INTPTR_FORMAT " is an oop: ", p2i(addr));
-      } else {
-        st->print(INTPTR_FORMAT " is pointing into object: " , p2i(addr));
-      }
-      ResourceMark rm;
-      o->print_on(st);
-      return;
-    }
-  } else if (Universe::heap()->is_in_reserved(addr)) {
-    st->print_cr(INTPTR_FORMAT " is an unallocated location in the heap", p2i(addr));
+  if (Universe::heap()->print_location(st, addr)) {
     return;
   }
 
-  // Compressed oop needs to be decoded first.
-#ifdef _LP64
-  if (UseCompressedOops && ((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) {
-    narrowOop narrow_oop = (narrowOop)(uintptr_t)addr;
-    oop o = CompressedOops::decode_raw(narrow_oop);
-
-    if (oopDesc::is_valid(o)) {
-      st->print(UINT32_FORMAT " is a compressed pointer to object: ", narrow_oop);
-      o->print_on(st);
-      return;
-    }
-  }
-#endif
-
   bool accessible = is_readable_pointer(addr);
 
   // Check if addr is a JNI handle.