8340392: Handle OopStorage in location decoder

Reviewed-by: kbarrett, dholmes
This commit is contained in:
Aleksey Shipilev 2024-09-23 07:02:59 +00:00
parent f31f97ddb6
commit 0f253d1103
7 changed files with 132 additions and 1 deletions

View File

@ -1135,6 +1135,26 @@ void OopStorage::BasicParState::report_num_dead() const {
const char* OopStorage::name() const { return _name; } 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 #ifndef PRODUCT
void OopStorage::print_on(outputStream* st) const { void OopStorage::print_on(outputStream* st) const {

View File

@ -213,6 +213,7 @@ public:
// Debugging and logging support. // Debugging and logging support.
const char* name() const; const char* name() const;
void print_on(outputStream* st) const PRODUCT_RETURN; void print_on(outputStream* st) const PRODUCT_RETURN;
bool print_containing(const oop* addr, outputStream* st);
// Provides access to storage internals, for unit testing. // Provides access to storage internals, for unit testing.
// Declare, but not define, the public class OopStorage::TestAccess. // Declare, but not define, the public class OopStorage::TestAccess.

View File

@ -196,6 +196,8 @@ public:
template<typename F> bool iterate(F f); template<typename F> bool iterate(F f);
template<typename F> bool iterate(F f) const; template<typename F> bool iterate(F f) const;
bool print_containing(const oop* addr, outputStream* st);
}; // class Block }; // class Block
inline OopStorage::Block* OopStorage::AllocationList::head() { inline OopStorage::Block* OopStorage::AllocationList::head() {

View File

@ -82,6 +82,23 @@ template OopStorage* OopStorageSet::get_storage(StrongId);
template OopStorage* OopStorageSet::get_storage(WeakId); template OopStorage* OopStorageSet::get_storage(WeakId);
template OopStorage* OopStorageSet::get_storage(Id); 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 #ifdef ASSERT
void OopStorageSet::verify_initialized(uint index) { void OopStorageSet::verify_initialized(uint index) {

View File

@ -26,6 +26,7 @@
#define SHARE_GC_SHARED_OOPSTORAGESET_HPP #define SHARE_GC_SHARED_OOPSTORAGESET_HPP
#include "nmt/memTag.hpp" #include "nmt/memTag.hpp"
#include "oops/oop.hpp"
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
#include "utilities/enumIterator.hpp" #include "utilities/enumIterator.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
@ -89,6 +90,8 @@ public:
template <typename Closure> template <typename Closure>
static void strong_oops_do(Closure* cl); 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, ENUMERATOR_VALUE_RANGE(OopStorageSet::StrongId,

View File

@ -32,6 +32,7 @@
#include "code/codeCache.hpp" #include "code/codeCache.hpp"
#include "code/vtableStubs.hpp" #include "code/vtableStubs.hpp"
#include "gc/shared/gcVMOperations.hpp" #include "gc/shared/gcVMOperations.hpp"
#include "gc/shared/oopStorageSet.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "jvm.h" #include "jvm.h"
#include "logging/log.hpp" #include "logging/log.hpp"
@ -1317,6 +1318,11 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) {
} }
#endif #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... // Still nothing? If NMT is enabled, we can ask what it thinks...
if (MemTracker::print_containing_region(addr, st)) { if (MemTracker::print_containing_region(addr, st)) {
return; return;

View File

@ -23,15 +23,21 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorage.inline.hpp"
#include "gc/shared/oopStorageSet.hpp" #include "gc/shared/oopStorageSet.hpp"
#include "memory/allocation.inline.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/debug.hpp"
#include "utilities/enumIterator.hpp" #include "utilities/enumIterator.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp" #include "utilities/macros.hpp"
#include "unittest.hpp" #include "unittest.hpp"
using ::testing::HasSubstr;
using ::testing::Not;
class OopStorageSetTest : public ::testing::Test { class OopStorageSetTest : public ::testing::Test {
protected: protected:
// Returns index of s in storages, or size if not found. // Returns index of s in storages, or size if not found.
@ -83,6 +89,8 @@ protected:
EnumRange<OopStorageSet::Id>(), EnumRange<OopStorageSet::Id>(),
&OopStorageSet::fill_all); &OopStorageSet::fill_all);
} }
class VM_PrintAtSafepoint;
}; };
TEST_VM_F(OopStorageSetTest, strong_iteration) { TEST_VM_F(OopStorageSetTest, strong_iteration) {
@ -96,3 +104,77 @@ TEST_VM_F(OopStorageSetTest, weak_iteration) {
TEST_VM_F(OopStorageSetTest, all_iteration) { TEST_VM_F(OopStorageSetTest, all_iteration) {
test_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);
}
}
}