diff --git a/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp b/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp index a9ab86761ac..0fd6045d633 100644 --- a/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp +++ b/src/hotspot/share/gc/z/zVirtualMemoryManager.hpp @@ -33,6 +33,7 @@ using ZVirtualMemoryRegistry = ZRangeRegistry; class ZVirtualMemoryReserver { + friend class ZTest; friend class ZMapperTest; friend class ZVirtualMemoryManagerTest; diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index f22eef50858..3a69ff3cbb7 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -28,9 +28,10 @@ #include "gc/z/zGlobals.hpp" #include "gc/z/zHeap.hpp" #include "gc/z/zPage.inline.hpp" +#include "gc/z/zRangeRegistry.inline.hpp" #include "gc/z/zVirtualMemory.inline.hpp" #include "runtime/os.hpp" -#include "unittest.hpp" +#include "zunittest.hpp" using namespace testing; @@ -40,35 +41,21 @@ using namespace testing; #define CAPTURE(expression) CAPTURE1(expression) -class ZForwardingTest : public Test { +class ZForwardingTest : public ZTest { public: // Setup and tear down ZHeap* _old_heap; ZGenerationOld* _old_old; ZGenerationYoung* _old_young; - char* _reserved; - static size_t _page_offset; - - char* reserve_page_memory() { - // Probe for a free 2MB region inside the usable address range. - // Inspired by ZVirtualMemoryManager::reserve_contiguous. - const size_t unused = ZAddressOffsetMax - ZGranuleSize; - const size_t increment = MAX2(align_up(unused / 100, ZGranuleSize), ZGranuleSize); - - for (uintptr_t start = 0; start + ZGranuleSize <= ZAddressOffsetMax; start += increment) { - char* const reserved = os::attempt_reserve_memory_at((char*)ZAddressHeapBase + start, ZGranuleSize, mtTest); - if (reserved != nullptr) { - // Success - return reserved; - } - } - - // Failed - return nullptr; - } + ZAddressReserver _zaddress_reserver; + zoffset _page_offset; virtual void SetUp() { - ZGlobalsPointers::initialize(); + // Only run test on supported Windows versions + if (!is_os_supported()) { + GTEST_SKIP() << "OS not supported"; + } + _old_heap = ZHeap::_heap; ZHeap::_heap = (ZHeap*)os::malloc(sizeof(ZHeap), mtTest); @@ -84,36 +71,34 @@ public: ZGeneration::_old->_seqnum = 1; ZGeneration::_young->_seqnum = 2; - // Preconditions for reserve_free_granule() - ASSERT_NE(ZAddressHeapBase, 0u); - ASSERT_NE(ZAddressOffsetMax, 0u); - ASSERT_NE(ZGranuleSize, 0u); + _zaddress_reserver.SetUp(ZGranuleSize); + _page_offset = _zaddress_reserver.registry()->peek_low_address(); - _reserved = nullptr; + if (_page_offset == zoffset::invalid) { + GTEST_SKIP() << "Unable to reserve memory"; + } - // Find a suitable address for the testing page - char* reserved = reserve_page_memory(); - - ASSERT_NE(reserved, nullptr) << "Failed to reserve the page granule. Test needs tweaking"; - ASSERT_GE(reserved, (char*)ZAddressHeapBase); - ASSERT_LT(reserved, (char*)ZAddressHeapBase + ZAddressOffsetMax); - - _reserved = reserved; - - os::commit_memory((char*)_reserved, ZGranuleSize, false /* executable */); - - _page_offset = uintptr_t(_reserved) - ZAddressHeapBase; + char* const addr = (char*)untype(ZOffset::address_unsafe(_page_offset)); + os::commit_memory(addr, ZGranuleSize, /* executable */ false); } virtual void TearDown() { + if (!is_os_supported()) { + // Test skipped, nothing to cleanup + return; + } + os::free(ZHeap::_heap); ZHeap::_heap = _old_heap; ZGeneration::_old = _old_old; ZGeneration::_young = _old_young; - if (_reserved != nullptr) { - os::uncommit_memory((char*)_reserved, ZGranuleSize, false /* executable */); - os::release_memory((char*)_reserved, ZGranuleSize); + + if (_page_offset != zoffset::invalid) { + char* const addr = (char*)untype(ZOffset::address_unsafe(_page_offset)); + os::uncommit_memory(addr, ZGranuleSize, false /* executable */); } + + _zaddress_reserver.TearDown(); } // Helper functions @@ -219,7 +204,7 @@ public: } } - static void test(void (*function)(ZForwarding*), uint32_t size) { + void test(void (*function)(ZForwarding*), uint32_t size) { // Create page const ZVirtualMemory vmem(zoffset(_page_offset), ZPageSizeSmall); ZPage page(ZPageType::small, ZPageAge::eden, vmem, 0u); @@ -257,7 +242,7 @@ public: } // Run the given function with a few different input values. - static void test(void (*function)(ZForwarding*)) { + void test(void (*function)(ZForwarding*)) { test(function, 1); test(function, 2); test(function, 3); @@ -285,5 +270,3 @@ TEST_VM_F(ZForwardingTest, find_full) { TEST_VM_F(ZForwardingTest, find_every_other) { test(&ZForwardingTest::find_every_other); } - -size_t ZForwardingTest::_page_offset; diff --git a/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp b/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp index ea43859b051..1789d2e3b43 100644 --- a/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp +++ b/test/hotspot/gtest/gc/z/test_zMapper_windows.cpp @@ -34,8 +34,9 @@ using namespace testing; class ZMapperTest : public ZTest { private: - static constexpr size_t ReservationSize = 32 * M; + static constexpr size_t ReservationSize = 3 * ZGranuleSize; + ZAddressReserver _zaddress_reserver; ZVirtualMemoryReserver* _reserver; ZVirtualMemoryRegistry* _registry; @@ -46,9 +47,14 @@ public: GTEST_SKIP() << "OS not supported"; } - _reserver = (ZVirtualMemoryReserver*)os::malloc(sizeof(ZVirtualMemoryManager), mtTest); - _reserver = ::new (_reserver) ZVirtualMemoryReserver(ReservationSize); - _registry = &_reserver->_registry; + _zaddress_reserver.SetUp(ReservationSize); + _reserver = _zaddress_reserver.reserver(); + _registry = _zaddress_reserver.registry(); + + if (_reserver->reserved() < ReservationSize || !_registry->is_contiguous()) { + GTEST_SKIP() << "Fixture failed to reserve adequate memory, reserved " + << (_reserver->reserved() >> ZGranuleSizeShift) << " * ZGranuleSize"; + } } virtual void TearDown() { @@ -58,9 +64,9 @@ public: } // Best-effort cleanup - _reserver->unreserve_all(); - _reserver->~ZVirtualMemoryReserver(); - os::free(_reserver); + _registry = nullptr; + _reserver = nullptr; + _zaddress_reserver.TearDown(); } void test_unreserve() { diff --git a/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp b/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp index b6b827aa0b7..2b6fbc198ca 100644 --- a/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp +++ b/test/hotspot/gtest/gc/z/test_zVirtualMemoryManager.cpp @@ -56,6 +56,7 @@ class ZVirtualMemoryManagerTest : public ZTest { private: static constexpr size_t ReservationSize = 32 * M; + ZAddressReserver _zaddress_reserver; ZVirtualMemoryReserver* _reserver; ZVirtualMemoryRegistry* _registry; @@ -66,9 +67,14 @@ public: GTEST_SKIP() << "OS not supported"; } - _reserver = (ZVirtualMemoryReserver*)os::malloc(sizeof(ZVirtualMemoryManager), mtTest); - _reserver = ::new (_reserver) ZVirtualMemoryReserver(ReservationSize); - _registry = &_reserver->_registry; + _zaddress_reserver.SetUp(ReservationSize); + _reserver = _zaddress_reserver.reserver(); + _registry = _zaddress_reserver.registry(); + + if (_reserver->reserved() < ReservationSize || !_registry->is_contiguous()) { + GTEST_SKIP() << "Fixture failed to reserve adequate memory, reserved " + << (_reserver->reserved() >> ZGranuleSizeShift) << " * ZGranuleSize"; + } } virtual void TearDown() { @@ -77,10 +83,9 @@ public: return; } - // Best-effort cleanup - _reserver->unreserve_all(); - _reserver->~ZVirtualMemoryReserver(); - os::free(_reserver); + _registry = nullptr; + _reserver = nullptr; + _zaddress_reserver.TearDown(); } void test_reserve_discontiguous_and_coalesce() { @@ -112,11 +117,6 @@ public: // to separate the fetched memory from the memory left in the manager. This // used to fail because the memory was already split into two placeholders. - if (_reserver->reserved() < 4 * ZGranuleSize || !_registry->is_contiguous()) { - GTEST_SKIP() << "Fixture failed to reserve adequate memory, reserved " - << (_reserver->reserved() >> ZGranuleSizeShift) << " * ZGranuleSize"; - } - // Start at the offset we reserved. const zoffset base_offset = _registry->peek_low_address(); diff --git a/test/hotspot/gtest/gc/z/zunittest.hpp b/test/hotspot/gtest/gc/z/zunittest.hpp index c732b7d4f7e..a4586d51a0e 100644 --- a/test/hotspot/gtest/gc/z/zunittest.hpp +++ b/test/hotspot/gtest/gc/z/zunittest.hpp @@ -30,6 +30,7 @@ #include "gc/z/zNUMA.hpp" #include "gc/z/zRangeRegistry.hpp" #include "gc/z/zVirtualMemory.inline.hpp" +#include "gc/z/zVirtualMemoryManager.hpp" #include "runtime/os.hpp" #include "unittest.hpp" @@ -60,6 +61,50 @@ public: }; class ZTest : public testing::Test { +public: + class ZAddressReserver { + ZVirtualMemoryReserver* _reserver; + bool _active; + + public: + ZAddressReserver() + : _reserver(nullptr), + _active(false) {} + + ~ZAddressReserver() { + GTEST_EXPECT_FALSE(_active) << "ZAddressReserver deconstructed without calling TearDown"; + } + + void SetUp(size_t reservation_size) { + GTEST_EXPECT_TRUE(ZArguments::is_os_supported()) << "Should not use SetUp on unsupported systems"; + GTEST_EXPECT_FALSE(_active) << "SetUp called twice without a TearDown"; + _active = true; + + _reserver = (ZVirtualMemoryReserver*)os::malloc(sizeof(ZVirtualMemoryManager), mtTest); + _reserver = ::new (_reserver) ZVirtualMemoryReserver(reservation_size); + } + + void TearDown() { + GTEST_EXPECT_TRUE(_active) << "TearDown called without a preceding SetUp"; + _active = false; + + // Best-effort cleanup + _reserver->unreserve_all(); + _reserver->~ZVirtualMemoryReserver(); + os::free(_reserver); + } + + ZVirtualMemoryReserver* reserver() { + GTEST_EXPECT_TRUE(_active) << "Should only use HeapReserver while active"; + return _reserver; + } + + ZVirtualMemoryRegistry* registry() { + GTEST_EXPECT_TRUE(_active) << "Should only use HeapReserver while active"; + return &_reserver->_registry; + } + }; + private: ZAddressOffsetMaxSetter _zaddress_offset_max_setter; unsigned int _rand_seed;