java-topology/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

571 lines
22 KiB
C++

/*
* Copyright Amazon.com Inc. 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 "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahMarkBitMap.hpp"
#include "gc/shenandoah/shenandoahMarkBitMap.inline.hpp"
BEGIN_ALLOW_FORBIDDEN_FUNCTIONS
#include <iostream>
END_ALLOW_FORBIDDEN_FUNCTIONS
#include "memory/memRegion.hpp"
#include "unittest.hpp"
#include "utilities/ostream.hpp"
#include "utilities/vmassert_reinstall.hpp"
#include "utilities/vmassert_uninstall.hpp"
// These tests will all be skipped (unless Shenandoah becomes the default
// collector). To execute these tests, you must enable Shenandoah, which
// is done with:
//
// % make exploded-test TEST="gtest:ShenandoahOld*" CONF=release TEST_OPTS="JAVA_OPTIONS=-XX:+UseShenandoahGC -XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational"
//
// Please note that these 'unit' tests are really integration tests and rely
// on the JVM being initialized. These tests manipulate the state of the
// collector in ways that are not compatible with a normal collection run.
// If these tests take longer than the minimum time between gc intervals -
// or, more likely, if you have them paused in a debugger longer than this
// interval - you can expect trouble. These tests will also not run in a build
// with asserts enabled because they use APIs that expect to run on a safepoint.
#ifdef ASSERT
#define SKIP_IF_NOT_SHENANDOAH() \
std::cout << "skipped (debug build)\n"; \
return;
#else
#define SKIP_IF_NOT_SHENANDOAH() \
if (!UseShenandoahGC) { \
std::cout << "skipped\n"; \
return; \
}
#endif
static bool _success;
static size_t _assertion_failures;
#define MarkBitMapAssertEqual(a, b) EXPECT_EQ((a), (b)); if ((a) != (b)) { _assertion_failures++; }
#define MarkBitMapAssertTrue(a) EXPECT_TRUE((a)); if ((a) == 0) { _assertion_failures++; }
class ShenandoahMarkBitMapTest: public ::testing::Test {
protected:
static void verify_bitmap_is_empty(HeapWord *start, size_t words_in_heap, ShenandoahMarkBitMap* mbm) {
MarkBitMapAssertTrue(mbm->is_bitmap_clear_range(start, start + words_in_heap));
while (words_in_heap-- > 0) {
MarkBitMapAssertTrue(!mbm->is_marked(start));
MarkBitMapAssertTrue(!mbm->is_marked_weak(start));
MarkBitMapAssertTrue(!mbm->is_marked_strong(start));
start++;
}
}
static void verify_bitmap_is_weakly_marked(ShenandoahMarkBitMap* mbm,
HeapWord* weakly_marked_addresses[], size_t weakly_marked_objects) {
for (size_t i = 0; i < weakly_marked_objects; i++) {
HeapWord* obj_addr = weakly_marked_addresses[i];
MarkBitMapAssertTrue(mbm->is_marked(obj_addr));
MarkBitMapAssertTrue(mbm->is_marked_weak(obj_addr));
}
}
static void verify_bitmap_is_strongly_marked(ShenandoahMarkBitMap* mbm,
HeapWord* strongly_marked_addresses[], size_t strongly_marked_objects) {
for (size_t i = 0; i < strongly_marked_objects; i++) {
HeapWord* obj_addr = strongly_marked_addresses[i];
MarkBitMapAssertTrue(mbm->is_marked(obj_addr));
MarkBitMapAssertTrue(mbm->is_marked_strong(obj_addr));
}
}
static void verify_bitmap_all(ShenandoahMarkBitMap* mbm, HeapWord* all_marked_addresses[],
bool is_weakly_marked_object[], bool is_strongly_marked_object[], size_t all_marked_objects,
HeapWord* heap_memory, HeapWord* end_of_heap_memory) {
HeapWord* last_marked_addr = &heap_memory[-1];
for (size_t i = 0; i < all_marked_objects; i++) {
HeapWord* obj_addr = all_marked_addresses[i];
if (is_strongly_marked_object[i]) {
MarkBitMapAssertTrue(mbm->is_marked(obj_addr));
MarkBitMapAssertTrue(mbm->is_marked_strong(obj_addr));
}
if (is_weakly_marked_object[i]) {
MarkBitMapAssertTrue(mbm->is_marked(obj_addr));
MarkBitMapAssertTrue(mbm->is_marked_weak(obj_addr));
}
while (++last_marked_addr < obj_addr) {
MarkBitMapAssertTrue(!mbm->is_marked(last_marked_addr));
MarkBitMapAssertTrue(!mbm->is_marked_strong(last_marked_addr));
MarkBitMapAssertTrue(!mbm->is_marked_weak(last_marked_addr));
}
last_marked_addr = obj_addr;
}
while (++last_marked_addr < end_of_heap_memory) {
MarkBitMapAssertTrue(!mbm->is_marked(last_marked_addr));
MarkBitMapAssertTrue(!mbm->is_marked_strong(last_marked_addr));
MarkBitMapAssertTrue(!mbm->is_marked_weak(last_marked_addr));
}
HeapWord* next_marked = (HeapWord*) &heap_memory[0] - 1;
for (size_t i = 0; i < all_marked_objects; i++) {
next_marked = mbm->get_next_marked_addr(next_marked + 1, end_of_heap_memory);
MarkBitMapAssertTrue(mbm->is_marked(next_marked));
MarkBitMapAssertEqual(next_marked, all_marked_addresses[i]);
if (is_strongly_marked_object[i]) {
MarkBitMapAssertTrue(mbm->is_marked_strong(next_marked));
}
if (is_weakly_marked_object[i]) {
MarkBitMapAssertTrue(mbm->is_marked_weak(next_marked));
}
}
// We expect no more marked addresses to be found. Should return limit.
HeapWord* sentinel = mbm->get_next_marked_addr(next_marked + 1, end_of_heap_memory);
MarkBitMapAssertEqual(sentinel, end_of_heap_memory);
HeapWord* prev_marked = end_of_heap_memory + 1;
for (int i = (int) all_marked_objects - 1; i >= 0; i--) {
prev_marked = mbm->get_prev_marked_addr(&heap_memory[0], prev_marked - 1);
MarkBitMapAssertEqual(prev_marked, all_marked_addresses[i]);
MarkBitMapAssertTrue(mbm->is_marked(prev_marked));
if (is_strongly_marked_object[i]) {
MarkBitMapAssertTrue(mbm->is_marked_strong(prev_marked));
}
if (is_weakly_marked_object[i]) {
MarkBitMapAssertTrue(mbm->is_marked_weak(prev_marked));
}
}
// We expect no more marked addresses to be found. should return prev_marked.
sentinel = mbm->get_prev_marked_addr(&heap_memory[0], prev_marked - 1);
MarkBitMapAssertEqual(sentinel, prev_marked);
}
public:
static bool run_test() {
ShenandoahHeap* heap = ShenandoahHeap::heap();
size_t test_heap_size = MIN2(32 * M, heap->max_capacity());
size_t heap_size_words = test_heap_size / HeapWordSize;
HeapWord* my_heap_memory = heap->base();
HeapWord* end_of_my_heap = my_heap_memory + heap_size_words;
MemRegion heap_descriptor(my_heap_memory, heap_size_words);
_success = false;
_assertion_failures = 0;
size_t bitmap_page_size = UseLargePages ? os::large_page_size() : os::vm_page_size();
size_t bitmap_size_orig = ShenandoahMarkBitMap::compute_size(test_heap_size);
size_t bitmap_size = align_up(bitmap_size_orig, bitmap_page_size);
size_t bitmap_word_size = (bitmap_size + HeapWordSize - 1) / HeapWordSize;
HeapWord* my_bitmap_memory = NEW_C_HEAP_ARRAY(HeapWord, bitmap_word_size, mtGC);
MarkBitMapAssertTrue(my_bitmap_memory != nullptr);
if (my_bitmap_memory == nullptr) {
std::cout <<"Cannot run test because failed to allocate bitmap memory\n" << std::flush;
return false;
}
MemRegion bitmap_descriptor(my_bitmap_memory, bitmap_size / HeapWordSize);
ShenandoahMarkBitMap mbm(heap_descriptor, bitmap_descriptor);
mbm.clear_range_large(heap_descriptor);
verify_bitmap_is_empty((HeapWord*) my_heap_memory, heap_size_words, &mbm);
HeapWord* weakly_marked_addresses[] = {
(HeapWord*) &my_heap_memory[13],
(HeapWord*) &my_heap_memory[14],
(HeapWord*) &my_heap_memory[15],
(HeapWord*) &my_heap_memory[16],
(HeapWord*) &my_heap_memory[176],
(HeapWord*) &my_heap_memory[240],
(HeapWord*) &my_heap_memory[480],
(HeapWord*) &my_heap_memory[1360],
(HeapWord*) &my_heap_memory[1488],
(HeapWord*) &my_heap_memory[2416],
(HeapWord*) &my_heap_memory[5968],
(HeapWord*) &my_heap_memory[8191],
(HeapWord*) &my_heap_memory[8192],
(HeapWord*) &my_heap_memory[8193]
};
size_t weakly_marked_objects = sizeof(weakly_marked_addresses) / sizeof(HeapWord*);
for (size_t i = 0; i < weakly_marked_objects; i++) {
mbm.mark_weak(weakly_marked_addresses[i]);
}
HeapWord* next_marked = (HeapWord*) &my_heap_memory[0] - 1;
for (size_t i = 0; i < weakly_marked_objects; i++) {
next_marked = mbm.get_next_marked_addr(next_marked + 1, end_of_my_heap);
MarkBitMapAssertEqual(next_marked, weakly_marked_addresses[i]);
MarkBitMapAssertTrue(mbm.is_marked(next_marked));
MarkBitMapAssertTrue(mbm.is_marked_weak(next_marked));
MarkBitMapAssertTrue(!mbm.is_marked_strong(next_marked));
}
// We expect no more marked addresses to be found. Should return limit.
HeapWord* sentinel = mbm.get_next_marked_addr(next_marked + 1, end_of_my_heap);
HeapWord* heap_limit = end_of_my_heap;
MarkBitMapAssertEqual(sentinel, heap_limit);
HeapWord* prev_marked = end_of_my_heap + 1;;
for (int i = (int) weakly_marked_objects - 1; i >= 0; i--) {
// to be renamed get_prev_marked_addr()
prev_marked = mbm.get_prev_marked_addr(&my_heap_memory[0], prev_marked - 1);
MarkBitMapAssertEqual(prev_marked, weakly_marked_addresses[i]);
MarkBitMapAssertTrue(mbm.is_marked(prev_marked));
MarkBitMapAssertTrue(mbm.is_marked_weak(prev_marked));
MarkBitMapAssertTrue(!mbm.is_marked_strong(prev_marked));
}
// We expect no more marked addresses to be found. should return prev_marked.
sentinel = mbm.get_prev_marked_addr(&my_heap_memory[0], prev_marked - 1);
// MarkBitMapAssertEqual(sentinel, prev_marked);
MarkBitMapAssertEqual(sentinel, prev_marked);
verify_bitmap_is_weakly_marked(&mbm, weakly_marked_addresses, weakly_marked_objects);
HeapWord* strongly_marked_addresses[] = {
(HeapWord*) &my_heap_memory[8],
(HeapWord*) &my_heap_memory[24],
(HeapWord*) &my_heap_memory[32],
(HeapWord*) &my_heap_memory[56],
(HeapWord*) &my_heap_memory[64],
(HeapWord*) &my_heap_memory[168],
(HeapWord*) &my_heap_memory[232],
(HeapWord*) &my_heap_memory[248],
(HeapWord*) &my_heap_memory[256],
(HeapWord*) &my_heap_memory[257],
(HeapWord*) &my_heap_memory[258],
(HeapWord*) &my_heap_memory[259],
(HeapWord*) &my_heap_memory[488],
(HeapWord*) &my_heap_memory[1352],
(HeapWord*) &my_heap_memory[1496],
(HeapWord*) &my_heap_memory[2432],
(HeapWord*) &my_heap_memory[5960]
};
size_t strongly_marked_objects = sizeof(strongly_marked_addresses) / sizeof(HeapWord*);
for (size_t i = 0; i < strongly_marked_objects; i++) {
bool upgraded = false;
mbm.mark_strong(strongly_marked_addresses[i], upgraded);
MarkBitMapAssertTrue(!upgraded);
}
verify_bitmap_is_strongly_marked(&mbm, strongly_marked_addresses, strongly_marked_objects);
HeapWord* upgraded_weakly_marked_addresses[] = {
(HeapWord*) &my_heap_memory[240],
(HeapWord*) &my_heap_memory[1360],
};
size_t upgraded_weakly_marked_objects = sizeof(upgraded_weakly_marked_addresses) / sizeof(HeapWord *);
for (size_t i = 0; i < upgraded_weakly_marked_objects; i++) {
bool upgraded = false;
mbm.mark_strong(upgraded_weakly_marked_addresses[i], upgraded);
MarkBitMapAssertTrue(upgraded);
}
verify_bitmap_is_strongly_marked(&mbm, upgraded_weakly_marked_addresses, upgraded_weakly_marked_objects);
HeapWord* all_marked_addresses[] = {
(HeapWord*) &my_heap_memory[8], /* strongly marked */
(HeapWord*) &my_heap_memory[13], /* weakly marked */
(HeapWord*) &my_heap_memory[14], /* weakly marked */
(HeapWord*) &my_heap_memory[15], /* weakly marked */
(HeapWord*) &my_heap_memory[16], /* weakly marked */
(HeapWord*) &my_heap_memory[24], /* strongly marked */
(HeapWord*) &my_heap_memory[32], /* strongly marked */
(HeapWord*) &my_heap_memory[56], /* strongly marked */
(HeapWord*) &my_heap_memory[64], /* strongly marked */
(HeapWord*) &my_heap_memory[168], /* strongly marked */
(HeapWord*) &my_heap_memory[176], /* weakly marked */
(HeapWord*) &my_heap_memory[232], /* strongly marked */
(HeapWord*) &my_heap_memory[240], /* weakly marked upgraded to strongly marked */
(HeapWord*) &my_heap_memory[248], /* strongly marked */
(HeapWord*) &my_heap_memory[256], /* strongly marked */
(HeapWord*) &my_heap_memory[257], /* strongly marked */
(HeapWord*) &my_heap_memory[258], /* strongly marked */
(HeapWord*) &my_heap_memory[259], /* strongly marked */
(HeapWord*) &my_heap_memory[480], /* weakly marked */
(HeapWord*) &my_heap_memory[488], /* strongly marked */
(HeapWord*) &my_heap_memory[1352], /* strongly marked */
(HeapWord*) &my_heap_memory[1360], /* weakly marked upgraded to strongly marked */
(HeapWord*) &my_heap_memory[1488], /* weakly marked */
(HeapWord*) &my_heap_memory[1496], /* strongly marked */
(HeapWord*) &my_heap_memory[2416], /* weakly marked */
(HeapWord*) &my_heap_memory[2432], /* strongly marked */
(HeapWord*) &my_heap_memory[5960], /* strongly marked */
(HeapWord*) &my_heap_memory[5968], /* weakly marked */
(HeapWord*) &my_heap_memory[8191], /* weakly marked */
(HeapWord*) &my_heap_memory[8192], /* weakly marked */
(HeapWord*) &my_heap_memory[8193] /* weakly marked */
};
size_t all_marked_objects = sizeof(all_marked_addresses) / sizeof(HeapWord*);
bool is_weakly_marked_object[] = {
false,
true,
true,
true,
true,
false,
false,
false,
false,
false,
true,
false,
true,
false,
false,
false,
false,
false,
true,
false,
false,
true,
true,
false,
true,
false,
false,
true,
true,
true,
true
};
bool is_strongly_marked_object[] = {
true,
false,
false,
false,
false,
true,
true,
true,
true,
true,
false,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
true,
false,
true,
false,
true,
true,
false,
false,
false,
false
};
verify_bitmap_all(&mbm, all_marked_addresses, is_weakly_marked_object, is_strongly_marked_object, all_marked_objects,
my_heap_memory, end_of_my_heap);
MemRegion first_clear_region(&my_heap_memory[168], &my_heap_memory[256]);
mbm.clear_range_large(first_clear_region);
// Five objects are no longer marked
HeapWord* all_marked_addresses_after_first_clear[] = {
(HeapWord*) &my_heap_memory[8], /* strongly marked */
(HeapWord*) &my_heap_memory[13], /* weakly marked */
(HeapWord*) &my_heap_memory[14], /* weakly marked */
(HeapWord*) &my_heap_memory[15], /* weakly marked */
(HeapWord*) &my_heap_memory[16], /* weakly marked */
(HeapWord*) &my_heap_memory[24], /* strongly marked */
(HeapWord*) &my_heap_memory[32], /* strongly marked */
(HeapWord*) &my_heap_memory[56], /* strongly marked */
(HeapWord*) &my_heap_memory[64], /* strongly marked */
(HeapWord*) &my_heap_memory[256], /* strongly marked */
(HeapWord*) &my_heap_memory[257], /* strongly marked */
(HeapWord*) &my_heap_memory[258], /* strongly marked */
(HeapWord*) &my_heap_memory[259], /* strongly marked */
(HeapWord*) &my_heap_memory[480], /* weakly marked */
(HeapWord*) &my_heap_memory[488], /* strongly marked */
(HeapWord*) &my_heap_memory[1352], /* strongly marked */
(HeapWord*) &my_heap_memory[1360], /* weakly marked upgraded to strongly marked */
(HeapWord*) &my_heap_memory[1488], /* weakly marked */
(HeapWord*) &my_heap_memory[1496], /* strongly marked */
(HeapWord*) &my_heap_memory[2416], /* weakly marked */
(HeapWord*) &my_heap_memory[2432], /* strongly marked */
(HeapWord*) &my_heap_memory[5960], /* strongly marked */
(HeapWord*) &my_heap_memory[5968], /* weakly marked */
(HeapWord*) &my_heap_memory[8191], /* weakly marked */
(HeapWord*) &my_heap_memory[8192], /* weakly marked */
(HeapWord*) &my_heap_memory[8193] /* weakly marked */
};
size_t all_marked_objects_after_first_clear = sizeof(all_marked_addresses_after_first_clear) / sizeof(HeapWord*);
bool is_weakly_marked_object_after_first_clear[] = {
false,
true,
true,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
true,
true,
false,
true,
false,
false,
true,
true,
true,
true
};
bool is_strongly_marked_object_after_first_clear[] = {
true,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
true,
false,
true,
false,
true,
true,
false,
false,
false,
false
};
verify_bitmap_all(&mbm, all_marked_addresses_after_first_clear,
is_weakly_marked_object_after_first_clear, is_strongly_marked_object_after_first_clear,
all_marked_objects_after_first_clear, my_heap_memory, end_of_my_heap);
MemRegion second_clear_region(&my_heap_memory[1360], &my_heap_memory[2416]);
mbm.clear_range_large(second_clear_region);
// Five objects are no longer marked
HeapWord* all_marked_addresses_after_2nd_clear[] = {
(HeapWord*) &my_heap_memory[8], /* strongly marked */
(HeapWord*) &my_heap_memory[13], /* weakly marked */
(HeapWord*) &my_heap_memory[14], /* weakly marked */
(HeapWord*) &my_heap_memory[15], /* weakly marked */
(HeapWord*) &my_heap_memory[16], /* weakly marked */
(HeapWord*) &my_heap_memory[24], /* strongly marked */
(HeapWord*) &my_heap_memory[32], /* strongly marked */
(HeapWord*) &my_heap_memory[56], /* strongly marked */
(HeapWord*) &my_heap_memory[64], /* strongly marked */
(HeapWord*) &my_heap_memory[256], /* strongly marked */
(HeapWord*) &my_heap_memory[257], /* strongly marked */
(HeapWord*) &my_heap_memory[258], /* strongly marked */
(HeapWord*) &my_heap_memory[259], /* strongly marked */
(HeapWord*) &my_heap_memory[480], /* weakly marked */
(HeapWord*) &my_heap_memory[488], /* strongly marked */
(HeapWord*) &my_heap_memory[1352], /* strongly marked */
(HeapWord*) &my_heap_memory[2416], /* weakly marked */
(HeapWord*) &my_heap_memory[2432], /* strongly marked */
(HeapWord*) &my_heap_memory[5960], /* strongly marked */
(HeapWord*) &my_heap_memory[5968], /* weakly marked */
(HeapWord*) &my_heap_memory[8191], /* weakly marked */
(HeapWord*) &my_heap_memory[8192], /* weakly marked */
(HeapWord*) &my_heap_memory[8193] /* weakly marked */
};
size_t all_marked_objects_after_2nd_clear = sizeof(all_marked_addresses_after_2nd_clear) / sizeof(HeapWord*);
bool is_weakly_marked_object_after_2nd_clear[] = {
false,
true,
true,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false,
false,
true,
false,
false,
true,
true,
true,
true
};
bool is_strongly_marked_object_after_2nd_clear[] = {
true,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
true,
true,
false,
true,
true,
false,
true,
true,
false,
false,
false,
false
};
verify_bitmap_all(&mbm, all_marked_addresses_after_2nd_clear,
is_weakly_marked_object_after_2nd_clear, is_strongly_marked_object_after_2nd_clear,
all_marked_objects_after_2nd_clear, my_heap_memory, end_of_my_heap);
FREE_C_HEAP_ARRAY(HeapWord, my_bitmap_memory);
_success = true;
return true;
}
};
TEST_VM_F(ShenandoahMarkBitMapTest, minimum_test) {
SKIP_IF_NOT_SHENANDOAH();
bool result = ShenandoahMarkBitMapTest::run_test();
ASSERT_EQ(result, true);
ASSERT_EQ(_success, true);
ASSERT_EQ(_assertion_failures, (size_t) 0);
}