mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8229278: Improve hs_err location printing to assume less about GC internals
Reviewed-by: stefank, kbarrett
This commit is contained in:
parent
2750569c00
commit
855f16ef50
23 changed files with 243 additions and 127 deletions
|
@ -26,6 +26,7 @@
|
||||||
#include "gc/epsilon/epsilonMemoryPool.hpp"
|
#include "gc/epsilon/epsilonMemoryPool.hpp"
|
||||||
#include "gc/epsilon/epsilonThreadLocalData.hpp"
|
#include "gc/epsilon/epsilonThreadLocalData.hpp"
|
||||||
#include "gc/shared/gcArguments.hpp"
|
#include "gc/shared/gcArguments.hpp"
|
||||||
|
#include "gc/shared/locationPrinter.inline.hpp"
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
@ -305,6 +306,10 @@ void EpsilonHeap::print_on(outputStream *st) const {
|
||||||
MetaspaceUtils::print_on(st);
|
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 {
|
void EpsilonHeap::print_tracing_info() const {
|
||||||
print_heap_info(used());
|
print_heap_info(used());
|
||||||
print_metaspace_info();
|
print_metaspace_info();
|
||||||
|
|
|
@ -114,8 +114,8 @@ public:
|
||||||
virtual void unpin_object(JavaThread* thread, oop obj) { }
|
virtual void unpin_object(JavaThread* thread, oop obj) { }
|
||||||
|
|
||||||
// No support for block parsing.
|
// No support for block parsing.
|
||||||
virtual HeapWord* block_start(const void* addr) const { return NULL; }
|
HeapWord* block_start(const void* addr) const { return NULL; }
|
||||||
virtual bool block_is_obj(const HeapWord* addr) const { return false; }
|
bool block_is_obj(const HeapWord* addr) const { return false; }
|
||||||
|
|
||||||
// No GC threads
|
// No GC threads
|
||||||
virtual void print_gc_threads_on(outputStream* st) const {}
|
virtual void print_gc_threads_on(outputStream* st) const {}
|
||||||
|
@ -138,6 +138,7 @@ public:
|
||||||
|
|
||||||
virtual void print_on(outputStream* st) const;
|
virtual void print_on(outputStream* st) const;
|
||||||
virtual void print_tracing_info() const;
|
virtual void print_tracing_info() const;
|
||||||
|
virtual bool print_location(outputStream* st, void* addr) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void print_heap_info(size_t used) const;
|
void print_heap_info(size_t used) const;
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||||
#include "gc/shared/generationSpec.hpp"
|
#include "gc/shared/generationSpec.hpp"
|
||||||
#include "gc/shared/isGCActiveMark.hpp"
|
#include "gc/shared/isGCActiveMark.hpp"
|
||||||
|
#include "gc/shared/locationPrinter.inline.hpp"
|
||||||
#include "gc/shared/oopStorageParState.hpp"
|
#include "gc/shared/oopStorageParState.hpp"
|
||||||
#include "gc/shared/preservedMarks.inline.hpp"
|
#include "gc/shared/preservedMarks.inline.hpp"
|
||||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||||
|
@ -2490,6 +2491,10 @@ void G1CollectedHeap::print_all_rsets() {
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
|
|
||||||
|
bool G1CollectedHeap::print_location(outputStream* st, void* addr) const {
|
||||||
|
return BlockLocationPrinter<G1CollectedHeap>::print_location(st, addr);
|
||||||
|
}
|
||||||
|
|
||||||
G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
|
G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
|
||||||
|
|
||||||
size_t eden_used_bytes = _eden.used_bytes();
|
size_t eden_used_bytes = _eden.used_bytes();
|
||||||
|
|
|
@ -1211,11 +1211,11 @@ public:
|
||||||
// address "addr". We say "blocks" instead of "object" since some heaps
|
// 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
|
// may not pack objects densely; a chunk may either be an object or a
|
||||||
// non-object.
|
// 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
|
// Requires "addr" to be the start of a block, and returns "TRUE" iff
|
||||||
// the block is an object.
|
// 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)
|
// Section on thread-local allocation buffers (TLABs)
|
||||||
// See CollectedHeap for semantics.
|
// See CollectedHeap for semantics.
|
||||||
|
@ -1428,6 +1428,9 @@ public:
|
||||||
void print_cset_rsets() PRODUCT_RETURN;
|
void print_cset_rsets() PRODUCT_RETURN;
|
||||||
void print_all_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();
|
size_t pending_card_num();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "gc/shared/gcLocker.hpp"
|
#include "gc/shared/gcLocker.hpp"
|
||||||
#include "gc/shared/gcWhen.hpp"
|
#include "gc/shared/gcWhen.hpp"
|
||||||
#include "gc/shared/genArguments.hpp"
|
#include "gc/shared/genArguments.hpp"
|
||||||
|
#include "gc/shared/locationPrinter.inline.hpp"
|
||||||
#include "gc/shared/scavengableNMethods.hpp"
|
#include "gc/shared/scavengableNMethods.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "memory/metaspaceCounters.hpp"
|
#include "memory/metaspaceCounters.hpp"
|
||||||
|
@ -584,6 +585,10 @@ PSHeapSummary ParallelScavengeHeap::create_ps_heap_summary() {
|
||||||
return PSHeapSummary(heap_summary, used(), old_summary, old_space, young_summary, eden_space, from_space, to_space);
|
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 {
|
void ParallelScavengeHeap::print_on(outputStream* st) const {
|
||||||
young_gen()->print_on(st);
|
young_gen()->print_on(st);
|
||||||
old_gen()->print_on(st);
|
old_gen()->print_on(st);
|
||||||
|
|
|
@ -228,6 +228,9 @@ class ParallelScavengeHeap : public CollectedHeap {
|
||||||
PreGenGCValues get_pre_gc_values() const;
|
PreGenGCValues get_pre_gc_values() const;
|
||||||
void print_heap_change(const PreGenGCValues& 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 */);
|
void verify(VerifyOption option /* ignored */);
|
||||||
|
|
||||||
// Resize the young generation. The reserved space for the
|
// Resize the young generation. The reserved space for the
|
||||||
|
|
|
@ -402,28 +402,6 @@ class CollectedHeap : public CHeapObj<mtInternal> {
|
||||||
// over live objects.
|
// over live objects.
|
||||||
virtual void safe_object_iterate(ObjectClosure* cl) = 0;
|
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
|
// 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.
|
// time that any part of the heap was examined by a garbage collection.
|
||||||
virtual jlong millis_since_last_gc() = 0;
|
virtual jlong millis_since_last_gc() = 0;
|
||||||
|
@ -461,6 +439,9 @@ class CollectedHeap : public CHeapObj<mtInternal> {
|
||||||
|
|
||||||
virtual void print_on_error(outputStream* st) const;
|
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)
|
// Print all GC threads (other than the VM thread)
|
||||||
// used by this heap.
|
// used by this heap.
|
||||||
virtual void print_gc_threads_on(outputStream* st) const = 0;
|
virtual void print_gc_threads_on(outputStream* st) const = 0;
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "gc/shared/genCollectedHeap.hpp"
|
#include "gc/shared/genCollectedHeap.hpp"
|
||||||
#include "gc/shared/genOopClosures.inline.hpp"
|
#include "gc/shared/genOopClosures.inline.hpp"
|
||||||
#include "gc/shared/generationSpec.hpp"
|
#include "gc/shared/generationSpec.hpp"
|
||||||
|
#include "gc/shared/locationPrinter.inline.hpp"
|
||||||
#include "gc/shared/oopStorageParState.inline.hpp"
|
#include "gc/shared/oopStorageParState.inline.hpp"
|
||||||
#include "gc/shared/scavengableNMethods.hpp"
|
#include "gc/shared/scavengableNMethods.hpp"
|
||||||
#include "gc/shared/space.hpp"
|
#include "gc/shared/space.hpp"
|
||||||
|
@ -1260,6 +1261,10 @@ void GenCollectedHeap::gc_threads_do(ThreadClosure* tc) const {
|
||||||
void GenCollectedHeap::print_gc_threads_on(outputStream* st) const {
|
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 {
|
void GenCollectedHeap::print_tracing_info() const {
|
||||||
if (log_is_enabled(Debug, gc, heap, exit)) {
|
if (log_is_enabled(Debug, gc, heap, exit)) {
|
||||||
LogStreamHandle(Debug, gc, heap, exit) lsh;
|
LogStreamHandle(Debug, gc, heap, exit) lsh;
|
||||||
|
|
|
@ -260,13 +260,13 @@ public:
|
||||||
// address "addr". We say "blocks" instead of "object" since some heaps
|
// 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
|
// may not pack objects densely; a chunk may either be an object or a
|
||||||
// non-object.
|
// 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
|
// Requires "addr" to be the start of a block, and returns "TRUE" iff
|
||||||
// the block is an object. Assumes (and verifies in non-product
|
// the block is an object. Assumes (and verifies in non-product
|
||||||
// builds) that addr is in the allocated part of the heap and is
|
// builds) that addr is in the allocated part of the heap and is
|
||||||
// the start of a chunk.
|
// 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.
|
// Section on TLAB's.
|
||||||
virtual bool supports_tlab_allocation() const;
|
virtual bool supports_tlab_allocation() const;
|
||||||
|
@ -332,6 +332,9 @@ public:
|
||||||
virtual void gc_threads_do(ThreadClosure* tc) const;
|
virtual void gc_threads_do(ThreadClosure* tc) const;
|
||||||
virtual void print_tracing_info() 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;
|
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
|
// The functions below are helper functions that a subclass of
|
||||||
|
|
50
src/hotspot/share/gc/shared/locationPrinter.cpp
Normal file
50
src/hotspot/share/gc/shared/locationPrinter.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
48
src/hotspot/share/gc/shared/locationPrinter.hpp
Normal file
48
src/hotspot/share/gc/shared/locationPrinter.hpp
Normal file
|
@ -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
|
87
src/hotspot/share/gc/shared/locationPrinter.inline.hpp
Normal file
87
src/hotspot/share/gc/shared/locationPrinter.inline.hpp
Normal file
|
@ -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
|
|
@ -28,6 +28,7 @@
|
||||||
#include "gc/shared/gcArguments.hpp"
|
#include "gc/shared/gcArguments.hpp"
|
||||||
#include "gc/shared/gcTimer.hpp"
|
#include "gc/shared/gcTimer.hpp"
|
||||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||||
|
#include "gc/shared/locationPrinter.inline.hpp"
|
||||||
#include "gc/shared/memAllocator.hpp"
|
#include "gc/shared/memAllocator.hpp"
|
||||||
#include "gc/shared/plab.hpp"
|
#include "gc/shared/plab.hpp"
|
||||||
|
|
||||||
|
@ -1133,6 +1134,10 @@ bool ShenandoahHeap::block_is_obj(const HeapWord* addr) const {
|
||||||
return sp->block_is_obj(addr);
|
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() {
|
jlong ShenandoahHeap::millis_since_last_gc() {
|
||||||
double v = heuristics()->time_since_last_gc() * 1000;
|
double v = heuristics()->time_since_last_gc() * 1000;
|
||||||
assert(0 <= v && v <= max_jlong, "value should fit: %f", v);
|
assert(0 <= v && v <= max_jlong, "value should fit: %f", v);
|
||||||
|
|
|
@ -536,6 +536,7 @@ public:
|
||||||
// Used for parsing heap during error printing
|
// Used for parsing heap during error printing
|
||||||
HeapWord* block_start(const void* addr) const;
|
HeapWord* block_start(const void* addr) const;
|
||||||
bool block_is_obj(const HeapWord* 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
|
// Used for native heap walkers: heap dumpers, mostly
|
||||||
void object_iterate(ObjectClosure* cl);
|
void object_iterate(ObjectClosure* cl);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "gc/shared/gcHeapSummary.hpp"
|
#include "gc/shared/gcHeapSummary.hpp"
|
||||||
|
#include "gc/shared/locationPrinter.hpp"
|
||||||
#include "gc/shared/suspendibleThreadSet.hpp"
|
#include "gc/shared/suspendibleThreadSet.hpp"
|
||||||
#include "gc/z/zCollectedHeap.hpp"
|
#include "gc/z/zCollectedHeap.hpp"
|
||||||
#include "gc/z/zGlobals.hpp"
|
#include "gc/z/zGlobals.hpp"
|
||||||
|
@ -249,14 +250,6 @@ void ZCollectedHeap::safe_object_iterate(ObjectClosure* cl) {
|
||||||
_heap.object_iterate(cl, true /* visit_weaks */);
|
_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) {
|
void ZCollectedHeap::register_nmethod(nmethod* nm) {
|
||||||
ZNMethod::register_nmethod(nm);
|
ZNMethod::register_nmethod(nm);
|
||||||
}
|
}
|
||||||
|
@ -356,6 +349,16 @@ void ZCollectedHeap::print_tracing_info() const {
|
||||||
// Does nothing
|
// 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 */) {
|
void ZCollectedHeap::verify(VerifyOption option /* ignored */) {
|
||||||
_heap.verify();
|
_heap.verify();
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,9 +100,6 @@ public:
|
||||||
virtual void object_iterate(ObjectClosure* cl);
|
virtual void object_iterate(ObjectClosure* cl);
|
||||||
virtual void safe_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 register_nmethod(nmethod* nm);
|
||||||
virtual void unregister_nmethod(nmethod* nm);
|
virtual void unregister_nmethod(nmethod* nm);
|
||||||
virtual void flush_nmethod(nmethod* nm);
|
virtual void flush_nmethod(nmethod* nm);
|
||||||
|
@ -124,6 +121,7 @@ public:
|
||||||
virtual void print_extended_on(outputStream* st) const;
|
virtual void print_extended_on(outputStream* st) const;
|
||||||
virtual void print_gc_threads_on(outputStream* st) const;
|
virtual void print_gc_threads_on(outputStream* st) const;
|
||||||
virtual void print_tracing_info() const;
|
virtual void print_tracing_info() const;
|
||||||
|
virtual bool print_location(outputStream* st, void* addr) const;
|
||||||
|
|
||||||
virtual void prepare_for_verify();
|
virtual void prepare_for_verify();
|
||||||
virtual void verify(VerifyOption option /* ignored */);
|
virtual void verify(VerifyOption option /* ignored */);
|
||||||
|
|
|
@ -194,16 +194,6 @@ bool ZHeap::is_in(uintptr_t addr) const {
|
||||||
return false;
|
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 {
|
uint ZHeap::nconcurrent_worker_threads() const {
|
||||||
return _workers.nconcurrent();
|
return _workers.nconcurrent();
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,10 +107,6 @@ public:
|
||||||
bool is_in(uintptr_t addr) const;
|
bool is_in(uintptr_t addr) const;
|
||||||
uint32_t hash_oop(oop obj) 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
|
// Workers
|
||||||
uint nconcurrent_worker_threads() const;
|
uint nconcurrent_worker_threads() const;
|
||||||
uint nconcurrent_no_boost_worker_threads() const;
|
uint nconcurrent_no_boost_worker_threads() const;
|
||||||
|
|
|
@ -90,9 +90,6 @@ public:
|
||||||
|
|
||||||
bool is_in(uintptr_t addr) const;
|
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_marked() const;
|
||||||
bool is_object_live(uintptr_t addr) const;
|
bool is_object_live(uintptr_t addr) const;
|
||||||
bool is_object_strongly_live(uintptr_t addr) const;
|
bool is_object_strongly_live(uintptr_t addr) const;
|
||||||
|
|
|
@ -177,18 +177,6 @@ inline bool ZPage::is_in(uintptr_t addr) const {
|
||||||
return offset >= start() && offset < top();
|
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 {
|
inline bool ZPage::is_marked() const {
|
||||||
assert(is_relocatable(), "Invalid page state");
|
assert(is_relocatable(), "Invalid page state");
|
||||||
return _livemap.is_marked();
|
return _livemap.is_marked();
|
||||||
|
|
|
@ -173,35 +173,6 @@ void* oopDesc::load_oop_raw(oop obj, int offset) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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); }
|
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); }
|
void oopDesc::obj_field_put_raw(int offset, oop value) { RawAccess<>::oop_store_at(as_oop(), offset, value); }
|
||||||
|
|
|
@ -331,8 +331,6 @@ class oopDesc {
|
||||||
// for error reporting
|
// for error reporting
|
||||||
static void* load_klass_raw(oop obj);
|
static void* load_klass_raw(oop obj);
|
||||||
static void* load_oop_raw(oop obj, int offset);
|
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
|
#endif // SHARE_OOPS_OOP_HPP
|
||||||
|
|
|
@ -1082,37 +1082,10 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if addr points into Java heap.
|
// Check if addr points into Java heap.
|
||||||
if (Universe::heap()->is_in(addr)) {
|
if (Universe::heap()->print_location(st, 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));
|
|
||||||
return;
|
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);
|
bool accessible = is_readable_pointer(addr);
|
||||||
|
|
||||||
// Check if addr is a JNI handle.
|
// Check if addr is a JNI handle.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue