8340392: Handle OopStorage in location decoder
Reviewed-by: kbarrett, dholmes
This commit is contained in:
parent
f31f97ddb6
commit
0f253d1103
@ -1135,6 +1135,26 @@ void OopStorage::BasicParState::report_num_dead() const {
|
||||
|
||||
const char* OopStorage::name() const { return _name; }
|
||||
|
||||
bool OopStorage::print_containing(const oop* addr, outputStream* st) {
|
||||
if (addr != nullptr) {
|
||||
Block* block = find_block_or_null(addr);
|
||||
if (block != nullptr && block->print_containing(addr, st)) {
|
||||
st->print(" in oop storage \"%s\"", name());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OopStorage::Block::print_containing(const oop* addr, outputStream* st) {
|
||||
if (contains(addr)) {
|
||||
st->print(PTR_FORMAT " is a pointer %u/%zu into block %zu",
|
||||
p2i(addr), get_index(addr), ARRAY_SIZE(_data), _active_index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
void OopStorage::print_on(outputStream* st) const {
|
||||
|
@ -213,6 +213,7 @@ public:
|
||||
// Debugging and logging support.
|
||||
const char* name() const;
|
||||
void print_on(outputStream* st) const PRODUCT_RETURN;
|
||||
bool print_containing(const oop* addr, outputStream* st);
|
||||
|
||||
// Provides access to storage internals, for unit testing.
|
||||
// Declare, but not define, the public class OopStorage::TestAccess.
|
||||
|
@ -196,6 +196,8 @@ public:
|
||||
|
||||
template<typename F> bool iterate(F f);
|
||||
template<typename F> bool iterate(F f) const;
|
||||
|
||||
bool print_containing(const oop* addr, outputStream* st);
|
||||
}; // class Block
|
||||
|
||||
inline OopStorage::Block* OopStorage::AllocationList::head() {
|
||||
|
@ -82,6 +82,23 @@ template OopStorage* OopStorageSet::get_storage(StrongId);
|
||||
template OopStorage* OopStorageSet::get_storage(WeakId);
|
||||
template OopStorage* OopStorageSet::get_storage(Id);
|
||||
|
||||
bool OopStorageSet::print_containing(const void* addr, outputStream* st) {
|
||||
if (addr != nullptr) {
|
||||
const void* aligned_addr = align_down(addr, alignof(oop));
|
||||
for (OopStorage* storage : Range<Id>()) {
|
||||
if (storage->print_containing((oop*) aligned_addr, st)) {
|
||||
if (aligned_addr != addr) {
|
||||
st->print_cr(" (unaligned)");
|
||||
} else {
|
||||
st->cr();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
|
||||
void OopStorageSet::verify_initialized(uint index) {
|
||||
|
@ -26,6 +26,7 @@
|
||||
#define SHARE_GC_SHARED_OOPSTORAGESET_HPP
|
||||
|
||||
#include "nmt/memTag.hpp"
|
||||
#include "oops/oop.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/enumIterator.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
@ -89,6 +90,8 @@ public:
|
||||
template <typename Closure>
|
||||
static void strong_oops_do(Closure* cl);
|
||||
|
||||
// Debugging: print location info, if in storage.
|
||||
static bool print_containing(const void* addr, outputStream* st);
|
||||
};
|
||||
|
||||
ENUMERATOR_VALUE_RANGE(OopStorageSet::StrongId,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/vtableStubs.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "jvm.h"
|
||||
#include "logging/log.hpp"
|
||||
@ -1317,6 +1318,11 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Ask if any OopStorage knows about this address.
|
||||
if (OopStorageSet::print_containing(addr, st)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Still nothing? If NMT is enabled, we can ask what it thinks...
|
||||
if (MemTracker::print_containing_region(addr, st)) {
|
||||
return;
|
||||
|
@ -23,15 +23,21 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/oopStorage.hpp"
|
||||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "gc/shared/oopStorageSet.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "runtime/interfaceSupport.inline.hpp"
|
||||
#include "runtime/vmOperations.hpp"
|
||||
#include "runtime/vmThread.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/enumIterator.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#include "unittest.hpp"
|
||||
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::Not;
|
||||
|
||||
class OopStorageSetTest : public ::testing::Test {
|
||||
protected:
|
||||
// Returns index of s in storages, or size if not found.
|
||||
@ -83,6 +89,8 @@ protected:
|
||||
EnumRange<OopStorageSet::Id>(),
|
||||
&OopStorageSet::fill_all);
|
||||
}
|
||||
|
||||
class VM_PrintAtSafepoint;
|
||||
};
|
||||
|
||||
TEST_VM_F(OopStorageSetTest, strong_iteration) {
|
||||
@ -96,3 +104,77 @@ TEST_VM_F(OopStorageSetTest, weak_iteration) {
|
||||
TEST_VM_F(OopStorageSetTest, all_iteration) {
|
||||
test_all_iteration();
|
||||
}
|
||||
|
||||
class OopStorageSetTest::VM_PrintAtSafepoint : public VM_GTestExecuteAtSafepoint {
|
||||
private:
|
||||
class PrintContainingClosure : public Closure {
|
||||
public:
|
||||
void do_oop(oop* addr) {
|
||||
// Direct slot hit.
|
||||
{
|
||||
stringStream ss;
|
||||
bool printed = OopStorageSet::print_containing(addr, &ss);
|
||||
ASSERT_TRUE(printed);
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("is a pointer"));
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("into block"));
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("in oop storage"));
|
||||
ASSERT_THAT(ss.freeze(), Not(HasSubstr("(unaligned)")));
|
||||
}
|
||||
|
||||
// Unaligned pointer to adjacent slot, should still be in oop storage range.
|
||||
{
|
||||
char* unaligned_addr = (char*)addr + 1;
|
||||
stringStream ss;
|
||||
bool printed = OopStorageSet::print_containing(unaligned_addr, &ss);
|
||||
ASSERT_TRUE(printed);
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("is a pointer"));
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("into block"));
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("in oop storage"));
|
||||
ASSERT_THAT(ss.freeze(), HasSubstr("(unaligned)"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
void doit() {
|
||||
PrintContainingClosure cl;
|
||||
for (OopStorage* storage : OopStorageSet::Range<OopStorageSet::Id>()) {
|
||||
storage->oops_do(&cl);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_VM_F(OopStorageSetTest, print_containing) {
|
||||
// nullptrs print nothing
|
||||
{
|
||||
stringStream ss;
|
||||
bool printed = OopStorageSet::print_containing(nullptr, &ss);
|
||||
ASSERT_FALSE(printed);
|
||||
EXPECT_STREQ("", ss.freeze());
|
||||
}
|
||||
|
||||
// Goofy values print nothing: unaligned out of storage pointer.
|
||||
{
|
||||
stringStream ss;
|
||||
bool printed = OopStorageSet::print_containing((char*)0x1, &ss);
|
||||
ASSERT_FALSE(printed);
|
||||
EXPECT_STREQ("", ss.freeze());
|
||||
}
|
||||
|
||||
// Goofy values print nothing: aligned out of storage pointer.
|
||||
{
|
||||
stringStream ss;
|
||||
bool printed = OopStorageSet::print_containing((char*)alignof(oop), &ss);
|
||||
ASSERT_FALSE(printed);
|
||||
EXPECT_STREQ("", ss.freeze());
|
||||
}
|
||||
|
||||
// All slot addresses should print well.
|
||||
{
|
||||
VM_PrintAtSafepoint op;
|
||||
{
|
||||
ThreadInVMfromNative invm(JavaThread::current());
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user