Skip to content

Commit

Permalink
8340392: Handle OopStorage in location decoder
Browse files Browse the repository at this point in the history
Reviewed-by: kbarrett, dholmes
  • Loading branch information
shipilev committed Sep 23, 2024
1 parent f31f97d commit 0f253d1
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 1 deletion.
20 changes: 20 additions & 0 deletions src/hotspot/share/gc/shared/oopStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/gc/shared/oopStorage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ class OopStorage : public CHeapObjBase {
// 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.
Expand Down
2 changes: 2 additions & 0 deletions src/hotspot/share/gc/shared/oopStorage.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ class OopStorage::Block /* No base class, to avoid messing up alignment. */ {

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() {
Expand Down
17 changes: 17 additions & 0 deletions src/hotspot/share/gc/shared/oopStorageSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions src/hotspot/share/gc/shared/oopStorageSet.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -89,6 +90,8 @@ class OopStorageSet : public AllStatic {
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,
Expand Down
6 changes: 6 additions & 0 deletions src/hotspot/share/runtime/os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
84 changes: 83 additions & 1 deletion test/hotspot/gtest/gc/shared/test_oopStorageSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -83,6 +89,8 @@ class OopStorageSetTest : public ::testing::Test {
EnumRange<OopStorageSet::Id>(),
&OopStorageSet::fill_all);
}

class VM_PrintAtSafepoint;
};

TEST_VM_F(OopStorageSetTest, strong_iteration) {
Expand All @@ -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);
}
}
}

0 comments on commit 0f253d1

Please sign in to comment.