Path: blob/master/test/hotspot/gtest/gc/shared/test_oopStorage.cpp
41152 views
/*1* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include "precompiled.hpp"24#include "gc/shared/oopStorage.inline.hpp"25#include "gc/shared/oopStorageParState.inline.hpp"26#include "gc/shared/workgroup.hpp"27#include "memory/allocation.inline.hpp"28#include "memory/resourceArea.hpp"29#include "metaprogramming/conditional.hpp"30#include "metaprogramming/enableIf.hpp"31#include "runtime/handles.inline.hpp"32#include "runtime/interfaceSupport.inline.hpp"33#include "runtime/mutex.hpp"34#include "runtime/mutexLocker.hpp"35#include "runtime/thread.hpp"36#include "runtime/vmOperations.hpp"37#include "runtime/vmThread.hpp"38#include "utilities/align.hpp"39#include "utilities/ostream.hpp"40#include "utilities/quickSort.hpp"41#include "unittest.hpp"4243// Access storage internals.44class OopStorage::TestAccess : public AllStatic {45public:46typedef OopStorage::Block Block;47typedef OopStorage::AllocationList AllocationList;48typedef OopStorage::ActiveArray ActiveArray;4950static ActiveArray& active_array(const OopStorage& storage) {51return *storage._active_array;52}5354static AllocationList& allocation_list(OopStorage& storage) {55return storage._allocation_list;56}5758static const AllocationList& allocation_list(const OopStorage& storage) {59return storage._allocation_list;60}6162static Mutex* allocation_mutex(const OopStorage& storage) {63return storage._allocation_mutex;64}6566static bool reduce_deferred_updates(OopStorage& storage) {67return storage.reduce_deferred_updates();68}6970static bool block_is_empty(const Block& block) {71return block.is_empty();72}7374static bool block_is_full(const Block& block) {75return block.is_full();76}7778static unsigned block_allocation_count(const Block& block) {79uintx bitmask = block.allocated_bitmask();80unsigned count = 0;81for ( ; bitmask != 0; bitmask >>= 1) {82if ((bitmask & 1) != 0) {83++count;84}85}86return count;87}8889static size_t memory_per_block() {90return Block::allocation_size();91}9293static void block_array_set_block_count(ActiveArray* blocks, size_t count) {94blocks->_block_count = count;95}96};9798typedef OopStorage::TestAccess TestAccess;99100// The "Oop" prefix is to avoid collision with similar opto names when101// building with precompiled headers, or for consistency with that102// workaround. There really should be an opto namespace.103typedef TestAccess::Block OopBlock;104typedef TestAccess::AllocationList AllocationList;105typedef TestAccess::ActiveArray ActiveArray;106107// Using EXPECT_EQ can't use NULL directly. Otherwise AIX build breaks.108const OopBlock* const NULL_BLOCK = NULL;109110static size_t list_length(const AllocationList& list) {111size_t result = 0;112for (const OopBlock* block = list.chead();113block != NULL;114block = list.next(*block)) {115++result;116}117return result;118}119120static void clear_list(AllocationList& list) {121OopBlock* next;122for (OopBlock* block = list.head(); block != NULL; block = next) {123next = list.next(*block);124list.unlink(*block);125}126}127128static bool is_list_empty(const AllocationList& list) {129return list.chead() == NULL;130}131132static bool process_deferred_updates(OopStorage& storage) {133MutexLocker ml(TestAccess::allocation_mutex(storage), Mutex::_no_safepoint_check_flag);134bool result = false;135while (TestAccess::reduce_deferred_updates(storage)) {136result = true;137}138return result;139}140141static void release_entry(OopStorage& storage, oop* entry, bool process_deferred = true) {142*entry = NULL;143storage.release(entry);144if (process_deferred) {145process_deferred_updates(storage);146}147}148149static size_t empty_block_count(const OopStorage& storage) {150const AllocationList& list = TestAccess::allocation_list(storage);151size_t count = 0;152for (const OopBlock* block = list.ctail();153(block != NULL) && block->is_empty();154++count, block = list.prev(*block))155{}156return count;157}158159static size_t active_count(const OopStorage& storage) {160return TestAccess::active_array(storage).block_count();161}162163static OopBlock* active_head(const OopStorage& storage) {164ActiveArray& ba = TestAccess::active_array(storage);165size_t count = ba.block_count();166if (count == 0) {167return NULL;168} else {169return ba.at(count - 1);170}171}172173class OopStorageTest : public ::testing::Test {174public:175OopStorageTest();176~OopStorageTest();177178OopStorage _storage;179180class CountingIterateClosure;181template<bool is_const> class VM_CountAtSafepoint;182};183184OopStorageTest::OopStorageTest() :185_storage("Test Storage", mtGC)186{ }187188OopStorageTest::~OopStorageTest() {189clear_list(TestAccess::allocation_list(_storage));190}191192class OopStorageTestWithAllocation : public OopStorageTest {193public:194OopStorageTestWithAllocation();195196static const size_t _max_entries = 1000;197oop* _entries[_max_entries];198};199200OopStorageTestWithAllocation::OopStorageTestWithAllocation() {201for (size_t i = 0; i < _max_entries; ++i) {202_entries[i] = _storage.allocate();203EXPECT_TRUE(_entries[i] != NULL);204EXPECT_EQ(i + 1, _storage.allocation_count());205}206};207208const size_t OopStorageTestWithAllocation::_max_entries;209210static bool is_allocation_list_sorted(const OopStorage& storage) {211// The allocation_list isn't strictly sorted. Rather, all empty212// blocks are segregated to the end of the list.213const AllocationList& list = TestAccess::allocation_list(storage);214const OopBlock* block = list.ctail();215for ( ; (block != NULL) && block->is_empty(); block = list.prev(*block)) {}216for ( ; block != NULL; block = list.prev(*block)) {217if (block->is_empty()) {218return false;219}220}221return true;222}223224static size_t total_allocation_count(const OopStorage& storage) {225size_t total_count = 0;226const ActiveArray& ba = TestAccess::active_array(storage);227size_t limit = active_count(storage);228for (size_t i = 0; i < limit; ++i) {229total_count += TestAccess::block_allocation_count(*ba.at(i));230}231return total_count;232}233234TEST_VM_F(OopStorageTest, allocate_one) {235EXPECT_EQ(0u, active_count(_storage));236EXPECT_TRUE(is_list_empty(TestAccess::allocation_list(_storage)));237238oop* ptr = _storage.allocate();239EXPECT_TRUE(ptr != NULL);240EXPECT_EQ(1u, _storage.allocation_count());241242EXPECT_EQ(1u, active_count(_storage));243EXPECT_EQ(1u, _storage.block_count());244EXPECT_EQ(1u, list_length(TestAccess::allocation_list(_storage)));245246EXPECT_EQ(0u, empty_block_count(_storage));247248const OopBlock* block = TestAccess::allocation_list(_storage).chead();249EXPECT_NE(block, (OopBlock*)NULL);250EXPECT_EQ(block, active_head(_storage));251EXPECT_FALSE(TestAccess::block_is_empty(*block));252EXPECT_FALSE(TestAccess::block_is_full(*block));253EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));254255release_entry(_storage, ptr);256EXPECT_EQ(0u, _storage.allocation_count());257258EXPECT_EQ(1u, active_count(_storage));259EXPECT_EQ(1u, _storage.block_count());260EXPECT_EQ(1u, list_length(TestAccess::allocation_list(_storage)));261262EXPECT_EQ(1u, empty_block_count(_storage));263264const OopBlock* new_block = TestAccess::allocation_list(_storage).chead();265EXPECT_EQ(block, new_block);266EXPECT_EQ(block, active_head(_storage));267EXPECT_TRUE(TestAccess::block_is_empty(*block));268EXPECT_FALSE(TestAccess::block_is_full(*block));269EXPECT_EQ(0u, TestAccess::block_allocation_count(*block));270}271272TEST_VM_F(OopStorageTest, allocation_count) {273static const size_t max_entries = 1000;274oop* entries[max_entries];275276AllocationList& allocation_list = TestAccess::allocation_list(_storage);277278EXPECT_EQ(0u, active_count(_storage));279EXPECT_EQ(0u, _storage.block_count());280EXPECT_TRUE(is_list_empty(allocation_list));281282size_t allocated = 0;283for ( ; allocated < max_entries; ++allocated) {284EXPECT_EQ(allocated, _storage.allocation_count());285if (active_count(_storage) != 0) {286EXPECT_EQ(1u, active_count(_storage));287EXPECT_EQ(1u, _storage.block_count());288const OopBlock& block = *TestAccess::active_array(_storage).at(0);289EXPECT_EQ(allocated, TestAccess::block_allocation_count(block));290if (TestAccess::block_is_full(block)) {291break;292} else {293EXPECT_FALSE(is_list_empty(allocation_list));294EXPECT_EQ(&block, allocation_list.chead());295}296}297entries[allocated] = _storage.allocate();298}299300EXPECT_EQ(allocated, _storage.allocation_count());301EXPECT_EQ(1u, active_count(_storage));302EXPECT_EQ(1u, _storage.block_count());303EXPECT_TRUE(is_list_empty(allocation_list));304const OopBlock& block = *TestAccess::active_array(_storage).at(0);305EXPECT_TRUE(TestAccess::block_is_full(block));306EXPECT_EQ(allocated, TestAccess::block_allocation_count(block));307308for (size_t i = 0; i < allocated; ++i) {309release_entry(_storage, entries[i]);310size_t remaining = allocated - (i + 1);311EXPECT_EQ(remaining, TestAccess::block_allocation_count(block));312EXPECT_EQ(remaining, _storage.allocation_count());313EXPECT_FALSE(is_list_empty(allocation_list));314}315}316317TEST_VM_F(OopStorageTest, allocate_many) {318static const size_t max_entries = 1000;319oop* entries[max_entries];320321AllocationList& allocation_list = TestAccess::allocation_list(_storage);322323EXPECT_EQ(0u, empty_block_count(_storage));324325entries[0] = _storage.allocate();326ASSERT_TRUE(entries[0] != NULL);327EXPECT_EQ(1u, active_count(_storage));328EXPECT_EQ(1u, _storage.block_count());329EXPECT_EQ(1u, list_length(allocation_list));330EXPECT_EQ(0u, empty_block_count(_storage));331332const OopBlock* block = TestAccess::active_array(_storage).at(0);333EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));334EXPECT_EQ(block, allocation_list.chead());335336for (size_t i = 1; i < max_entries; ++i) {337entries[i] = _storage.allocate();338EXPECT_EQ(i + 1, _storage.allocation_count());339ASSERT_TRUE(entries[i] != NULL);340EXPECT_EQ(0u, empty_block_count(_storage));341342if (block == NULL) {343ASSERT_FALSE(is_list_empty(allocation_list));344EXPECT_EQ(1u, list_length(allocation_list));345block = allocation_list.chead();346EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));347EXPECT_EQ(block, active_head(_storage));348} else if (TestAccess::block_is_full(*block)) {349EXPECT_TRUE(is_list_empty(allocation_list));350block = NULL;351} else {352EXPECT_FALSE(is_list_empty(allocation_list));353EXPECT_EQ(block, allocation_list.chead());354EXPECT_EQ(block, active_head(_storage));355}356}357358if (block != NULL) {359EXPECT_NE(0u, TestAccess::block_allocation_count(*block));360EXPECT_FALSE(is_list_empty(allocation_list));361EXPECT_EQ(block, allocation_list.chead());362EXPECT_EQ(block, active_head(_storage));363}364365for (size_t i = 0; i < max_entries; ++i) {366release_entry(_storage, entries[i]);367EXPECT_TRUE(is_allocation_list_sorted(_storage));368EXPECT_EQ(max_entries - (i + 1), total_allocation_count(_storage));369}370371EXPECT_EQ(active_count(_storage), list_length(allocation_list));372EXPECT_EQ(active_count(_storage), _storage.block_count());373EXPECT_EQ(active_count(_storage), empty_block_count(_storage));374for (const OopBlock* block = allocation_list.chead();375block != NULL;376block = allocation_list.next(*block)) {377EXPECT_TRUE(TestAccess::block_is_empty(*block));378}379}380381TEST_VM_F(OopStorageTestWithAllocation, random_release) {382static const size_t step = 11;383ASSERT_NE(0u, _max_entries % step); // max_entries and step are mutually prime384385EXPECT_EQ(0u, empty_block_count(_storage));386387AllocationList& allocation_list = TestAccess::allocation_list(_storage);388389EXPECT_EQ(_max_entries, total_allocation_count(_storage));390EXPECT_GE(1u, list_length(allocation_list));391392// Release all entries in "random" order.393size_t released = 0;394for (size_t i = 0; released < _max_entries; i = (i + step) % _max_entries) {395if (_entries[i] != NULL) {396release_entry(_storage, _entries[i]);397_entries[i] = NULL;398++released;399EXPECT_EQ(_max_entries - released, total_allocation_count(_storage));400EXPECT_TRUE(is_allocation_list_sorted(_storage));401}402}403404EXPECT_EQ(active_count(_storage), list_length(allocation_list));405EXPECT_EQ(active_count(_storage), _storage.block_count());406EXPECT_EQ(0u, total_allocation_count(_storage));407EXPECT_EQ(list_length(allocation_list), empty_block_count(_storage));408}409410TEST_VM_F(OopStorageTestWithAllocation, random_allocate_release) {411static const size_t release_step = 11;412static const size_t allocate_step = 5;413ASSERT_NE(0u, _max_entries % release_step); // max_entries and step are mutually prime414415EXPECT_EQ(0u, empty_block_count(_storage));416417AllocationList& allocation_list = TestAccess::allocation_list(_storage);418419EXPECT_EQ(_max_entries, total_allocation_count(_storage));420EXPECT_GE(1u, list_length(allocation_list));421422// Release all entries in "random" order, "randomly" interspersed423// with additional allocations.424size_t released = 0;425size_t total_released = 0;426for (size_t i = 0; released < _max_entries; i = (i + release_step) % _max_entries) {427if (_entries[i] != NULL) {428release_entry(_storage, _entries[i]);429_entries[i] = NULL;430++released;431++total_released;432EXPECT_EQ(_max_entries - released, total_allocation_count(_storage));433EXPECT_TRUE(is_allocation_list_sorted(_storage));434if (total_released % allocate_step == 0) {435_entries[i] = _storage.allocate();436--released;437EXPECT_EQ(_max_entries - released, total_allocation_count(_storage));438EXPECT_TRUE(is_allocation_list_sorted(_storage));439}440}441}442443EXPECT_EQ(active_count(_storage), list_length(allocation_list));444EXPECT_EQ(active_count(_storage), _storage.block_count());445EXPECT_EQ(0u, total_allocation_count(_storage));446EXPECT_EQ(list_length(allocation_list), empty_block_count(_storage));447}448449template<bool sorted>450class OopStorageTestBlockRelease : public OopStorageTestWithAllocation {451public:452void SetUp() {453size_t nrelease = _max_entries / 2;454oop** to_release = NEW_C_HEAP_ARRAY(oop*, nrelease, mtInternal);455456for (size_t i = 0; i < nrelease; ++i) {457to_release[i] = _entries[2 * i];458*to_release[i] = NULL;459}460if (sorted) {461QuickSort::sort(to_release, nrelease, PointerCompare(), false);462}463464_storage.release(to_release, nrelease);465EXPECT_EQ(_max_entries - nrelease, _storage.allocation_count());466467for (size_t i = 0; i < nrelease; ++i) {468release_entry(_storage, _entries[2 * i + 1], false);469EXPECT_EQ(_max_entries - nrelease - (i + 1), _storage.allocation_count());470}471EXPECT_TRUE(process_deferred_updates(_storage));472473EXPECT_EQ(_storage.block_count(), empty_block_count(_storage));474475FREE_C_HEAP_ARRAY(oop*, to_release);476}477478struct PointerCompare {479int operator()(const void* p, const void* q) const {480return (p < q) ? -1 : int(p != q);481}482};483};484485typedef OopStorageTestBlockRelease<true> OopStorageTestBlockReleaseSorted;486typedef OopStorageTestBlockRelease<false> OopStorageTestBlockReleaseUnsorted;487488TEST_VM_F(OopStorageTestBlockReleaseSorted, block_release) {}489TEST_VM_F(OopStorageTestBlockReleaseUnsorted, block_release) {}490491TEST_VM_F(OopStorageTest, bulk_allocation) {492static const size_t max_entries = 1000;493static const size_t zero = 0;494oop* entries[max_entries] = {};495496AllocationList& allocation_list = TestAccess::allocation_list(_storage);497498EXPECT_EQ(0u, empty_block_count(_storage));499size_t allocated = _storage.allocate(entries, max_entries);500ASSERT_NE(allocated, zero);501// ASSERT_LE would ODR-use the OopStorage constant.502size_t bulk_allocate_limit = OopStorage::bulk_allocate_limit;503ASSERT_LE(allocated, bulk_allocate_limit);504ASSERT_LE(allocated, max_entries);505for (size_t i = 0; i < allocated; ++i) {506EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(entries[i]));507}508for (size_t i = allocated; i < max_entries; ++i) {509EXPECT_EQ(NULL, entries[i]);510}511_storage.release(entries, allocated);512EXPECT_EQ(0u, _storage.allocation_count());513for (size_t i = 0; i < allocated; ++i) {514EXPECT_EQ(OopStorage::UNALLOCATED_ENTRY, _storage.allocation_status(entries[i]));515}516}517518#ifndef DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS519TEST_VM_F(OopStorageTest, invalid_pointer) {520{521char* mem = NEW_C_HEAP_ARRAY(char, 1000, mtInternal);522oop* ptr = reinterpret_cast<oop*>(align_down(mem + 250, sizeof(oop)));523// Predicate returns false for some malloc'ed block.524EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(ptr));525FREE_C_HEAP_ARRAY(char, mem);526}527528{529oop obj;530oop* ptr = &obj;531// Predicate returns false for some "random" location.532EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(ptr));533}534}535#endif // DISABLE_GARBAGE_ALLOCATION_STATUS_TESTS536537class OopStorageTest::CountingIterateClosure {538public:539size_t _const_count;540size_t _const_non_null;541size_t _non_const_count;542size_t _non_const_non_null;543544void do_oop(const oop* ptr) {545++_const_count;546if (*ptr != NULL) {547++_const_non_null;548}549}550551void do_oop(oop* ptr) {552++_non_const_count;553if (*ptr != NULL) {554++_non_const_non_null;555}556}557558CountingIterateClosure() :559_const_count(0),560_const_non_null(0),561_non_const_count(0),562_non_const_non_null(0)563{}564};565566template<bool is_const>567class OopStorageTest::VM_CountAtSafepoint : public VM_GTestExecuteAtSafepoint {568public:569typedef typename Conditional<is_const,570const OopStorage,571OopStorage>::type Storage;572573VM_CountAtSafepoint(Storage* storage, CountingIterateClosure* cl) :574_storage(storage), _cl(cl)575{}576577void doit() { _storage->oops_do(_cl); }578579private:580Storage* _storage;581CountingIterateClosure* _cl;582};583584TEST_VM_F(OopStorageTest, simple_iterate) {585// Dummy oop value.586intptr_t dummy_oop_value = 0xbadbeaf;587oop dummy_oop = reinterpret_cast<oopDesc*>(&dummy_oop_value);588589const size_t max_entries = 1000;590oop* entries[max_entries];591592size_t allocated = 0;593size_t entries_with_values = 0;594for (size_t i = 0; i < max_entries; i += 10) {595for ( ; allocated < i; ++allocated) {596entries[allocated] = _storage.allocate();597ASSERT_TRUE(entries[allocated] != NULL);598if ((allocated % 3) != 0) {599*entries[allocated] = dummy_oop;600++entries_with_values;601}602}603604{605CountingIterateClosure cl;606VM_CountAtSafepoint<false> op(&_storage, &cl);607{608ThreadInVMfromNative invm(JavaThread::current());609VMThread::execute(&op);610}611EXPECT_EQ(allocated, cl._non_const_count);612EXPECT_EQ(entries_with_values, cl._non_const_non_null);613EXPECT_EQ(0u, cl._const_count);614EXPECT_EQ(0u, cl._const_non_null);615}616617{618CountingIterateClosure cl;619VM_CountAtSafepoint<true> op(&_storage, &cl);620{621ThreadInVMfromNative invm(JavaThread::current());622VMThread::execute(&op);623}624EXPECT_EQ(allocated, cl._const_count);625EXPECT_EQ(entries_with_values, cl._const_non_null);626EXPECT_EQ(0u, cl._non_const_count);627EXPECT_EQ(0u, cl._non_const_non_null);628}629}630631while (allocated > 0) {632release_entry(_storage, entries[--allocated], false);633}634process_deferred_updates(_storage);635}636637class OopStorageTestIteration : public OopStorageTestWithAllocation {638public:639static const size_t _max_workers = 2;640unsigned char _states[_max_workers][_max_entries];641642static const unsigned char mark_released = 1u << 0;643static const unsigned char mark_invalid = 1u << 1;644static const unsigned char mark_const = 1u << 2;645static const unsigned char mark_non_const = 1u << 3;646647virtual void SetUp() {648OopStorageTestWithAllocation::SetUp();649650memset(_states, 0, sizeof(_states));651652size_t initial_release = 0;653for ( ; empty_block_count(_storage) < 2; ++initial_release) {654ASSERT_GT(_max_entries, initial_release);655release_entry(_storage, _entries[initial_release]);656_states[0][initial_release] = mark_released;657}658659for (size_t i = initial_release; i < _max_entries; i += 3) {660release_entry(_storage, _entries[i], false);661_states[0][i] = mark_released;662}663process_deferred_updates(_storage);664}665666class VerifyState;667class VerifyFn;668template<bool is_const> class VM_Verify;669670class VerifyClosure;671class VM_VerifyUsingOopsDo;672};673674const unsigned char OopStorageTestIteration::mark_released;675const unsigned char OopStorageTestIteration::mark_invalid;676const unsigned char OopStorageTestIteration::mark_const;677const unsigned char OopStorageTestIteration::mark_non_const;678679class OopStorageTestIteration::VerifyState {680public:681unsigned char _expected_mark;682const oop* const* _entries;683unsigned char (&_states)[_max_workers][_max_entries];684685VerifyState(unsigned char expected_mark,686const oop* const* entries,687unsigned char (&states)[_max_workers][_max_entries]) :688_expected_mark(expected_mark),689_entries(entries),690_states(states)691{ }692693bool update(const oop* ptr, uint worker_id, unsigned char mark) const {694size_t index = 0;695bool found = find_entry(ptr, &index);696EXPECT_TRUE(found);697EXPECT_GT(_max_entries, index);698EXPECT_GT(_max_workers, worker_id);699if (!found) {700return false;701} else if (index >= _max_entries) {702return false;703} else if (worker_id >= _max_workers) {704return false;705} else {706EXPECT_EQ(0, _states[worker_id][index]);707if (_states[worker_id][index] != 0) {708_states[worker_id][index] |= mark_invalid;709return false;710} else {711_states[worker_id][index] |= mark;712return true;713}714}715}716717void check() const {718for (size_t i = 0; i < _max_entries; ++i) {719unsigned char mark = 0;720for (size_t w = 0; w < _max_workers; ++w) {721if (mark == 0) {722mark = _states[w][i];723} else {724EXPECT_EQ(0u, _states[w][i]);725}726}727if (mark == 0) {728EXPECT_NE(0u, mark);729} else if ((mark & mark_released) != 0) {730EXPECT_EQ(mark_released, mark);731} else {732EXPECT_EQ(_expected_mark, mark);733}734}735}736737private:738bool find_entry(const oop* ptr, size_t* index) const {739for (size_t i = 0; i < _max_entries; ++i) {740if (ptr == _entries[i]) {741*index = i;742return true;743}744}745return false;746}747};748749class OopStorageTestIteration::VerifyFn {750public:751VerifyFn(VerifyState* state, uint worker_id = 0) :752_state(state),753_worker_id(worker_id)754{}755756bool operator()( oop* ptr) const {757return _state->update(ptr, _worker_id, mark_non_const);758}759760bool operator()(const oop* ptr) const {761return _state->update(ptr, _worker_id, mark_const);762}763764private:765VerifyState* _state;766uint _worker_id;767};768769class OopStorageTestIteration::VerifyClosure {770public:771VerifyClosure(VerifyState* state, uint worker_id = 0) :772_state(state),773_worker_id(worker_id)774{}775776void do_oop(oop* ptr) {777_state->update(ptr, _worker_id, mark_non_const);778}779780void do_oop(const oop* ptr) {781_state->update(ptr, _worker_id, mark_const);782}783784private:785VerifyState* _state;786uint _worker_id;787};788789const size_t OopStorageTestIteration::_max_workers;790791template<bool is_const>792class OopStorageTestIteration::VM_Verify : public VM_GTestExecuteAtSafepoint {793public:794typedef typename Conditional<is_const,795const OopStorage,796OopStorage>::type Storage;797798VM_Verify(Storage* storage, VerifyState* vstate) :799_storage(storage), _vstate(vstate), _result(false)800{}801802void doit() {803VerifyFn verifier(_vstate);804_result = _storage->iterate_safepoint(verifier);805}806807bool result() const { return _result; }808809private:810Storage* _storage;811VerifyState* _vstate;812bool _result;813};814815class OopStorageTestIteration::VM_VerifyUsingOopsDo : public VM_GTestExecuteAtSafepoint {816public:817VM_VerifyUsingOopsDo(OopStorage* storage, VerifyState* vstate) :818_storage(storage), _vstate(vstate)819{}820821void doit() {822VerifyClosure verifier(_vstate);823_storage->oops_do(&verifier);824}825826private:827OopStorage* _storage;828VerifyState* _vstate;829};830831TEST_VM_F(OopStorageTestIteration, iterate_safepoint) {832VerifyState vstate(mark_non_const, _entries, _states);833VM_Verify<false> op(&_storage, &vstate);834{835ThreadInVMfromNative invm(JavaThread::current());836VMThread::execute(&op);837}838EXPECT_TRUE(op.result());839vstate.check();840}841842TEST_VM_F(OopStorageTestIteration, const_iterate_safepoint) {843VerifyState vstate(mark_const, _entries, _states);844VM_Verify<true> op(&_storage, &vstate);845{846ThreadInVMfromNative invm(JavaThread::current());847VMThread::execute(&op);848}849EXPECT_TRUE(op.result());850vstate.check();851}852853TEST_VM_F(OopStorageTestIteration, oops_do) {854VerifyState vstate(mark_non_const, _entries, _states);855VM_VerifyUsingOopsDo op(&_storage, &vstate);856{857ThreadInVMfromNative invm(JavaThread::current());858VMThread::execute(&op);859}860vstate.check();861}862863class OopStorageTestParIteration : public OopStorageTestIteration {864public:865WorkGang* workers();866867class VM_ParStateVerify;868869template<bool concurrent, bool is_const> class Task;870template<bool concurrent, bool is_const> class TaskUsingOopsDo;871872private:873static WorkGang* _workers;874};875876WorkGang* OopStorageTestParIteration::_workers = NULL;877878WorkGang* OopStorageTestParIteration::workers() {879if (_workers == NULL) {880_workers = new WorkGang("OopStorageTestParIteration workers",881_max_workers,882false,883false);884_workers->initialize_workers();885_workers->update_active_workers(_max_workers);886}887return _workers;888}889890template<bool concurrent, bool is_const>891class OopStorageTestParIteration::Task : public AbstractGangTask {892typedef OopStorage::ParState<concurrent, is_const> StateType;893894typedef typename Conditional<is_const,895const OopStorage,896OopStorage>::type Storage;897898public:899Task(const char* name, Storage* storage, VerifyState* vstate) :900AbstractGangTask(name),901_state(storage),902_vstate(vstate)903{}904905virtual void work(uint worker_id) {906VerifyFn verifier(_vstate, worker_id);907_state.iterate(verifier);908}909910private:911StateType _state;912VerifyState* _vstate;913};914915template<bool concurrent, bool is_const>916class OopStorageTestParIteration::TaskUsingOopsDo : public AbstractGangTask {917public:918TaskUsingOopsDo(const char* name, OopStorage* storage, VerifyState* vstate) :919AbstractGangTask(name),920_state(storage),921_vstate(vstate)922{}923924virtual void work(uint worker_id) {925VerifyClosure verifier(_vstate, worker_id);926_state.oops_do(&verifier);927}928929private:930OopStorage::ParState<concurrent, is_const> _state;931VerifyState* _vstate;932};933934class OopStorageTestParIteration::VM_ParStateVerify : public VM_GTestExecuteAtSafepoint {935public:936VM_ParStateVerify(WorkGang* workers, AbstractGangTask* task) :937_workers(workers), _task(task)938{}939940void doit() {941_workers->run_task(_task);942}943944private:945WorkGang* _workers;946AbstractGangTask* _task;947};948949TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_iterate) {950VerifyState vstate(mark_non_const, _entries, _states);951Task<false, false> task("test", &_storage, &vstate);952VM_ParStateVerify op(workers(), &task);953{954ThreadInVMfromNative invm(JavaThread::current());955VMThread::execute(&op);956}957vstate.check();958}959960TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_const_iterate) {961VerifyState vstate(mark_const, _entries, _states);962Task<false, true> task("test", &_storage, &vstate);963VM_ParStateVerify op(workers(), &task);964{965ThreadInVMfromNative invm(JavaThread::current());966VMThread::execute(&op);967}968vstate.check();969}970971TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_oops_do) {972VerifyState vstate(mark_non_const, _entries, _states);973TaskUsingOopsDo<false, false> task("test", &_storage, &vstate);974VM_ParStateVerify op(workers(), &task);975{976ThreadInVMfromNative invm(JavaThread::current());977VMThread::execute(&op);978}979vstate.check();980}981982TEST_VM_F(OopStorageTestParIteration, par_state_safepoint_const_oops_do) {983VerifyState vstate(mark_const, _entries, _states);984TaskUsingOopsDo<false, true> task("test", &_storage, &vstate);985VM_ParStateVerify op(workers(), &task);986{987ThreadInVMfromNative invm(JavaThread::current());988VMThread::execute(&op);989}990vstate.check();991}992993TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_iterate) {994VerifyState vstate(mark_non_const, _entries, _states);995Task<true, false> task("test", &_storage, &vstate);996workers()->run_task(&task);997vstate.check();998}9991000TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_const_iterate) {1001VerifyState vstate(mark_const, _entries, _states);1002Task<true, true> task("test", &_storage, &vstate);1003workers()->run_task(&task);1004vstate.check();1005}10061007TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_oops_do) {1008VerifyState vstate(mark_non_const, _entries, _states);1009TaskUsingOopsDo<true, false> task("test", &_storage, &vstate);1010workers()->run_task(&task);1011vstate.check();1012}10131014TEST_VM_F(OopStorageTestParIteration, par_state_concurrent_const_oops_do) {1015VerifyState vstate(mark_const, _entries, _states);1016TaskUsingOopsDo<true, true> task("test", &_storage, &vstate);1017workers()->run_task(&task);1018vstate.check();1019}10201021TEST_VM_F(OopStorageTestWithAllocation, delete_empty_blocks) {1022size_t initial_active_size = active_count(_storage);1023EXPECT_EQ(initial_active_size, _storage.block_count());1024ASSERT_LE(3u, initial_active_size); // Need at least 3 blocks for test10251026for (size_t i = 0; empty_block_count(_storage) < 3; ++i) {1027ASSERT_GT(_max_entries, i);1028release_entry(_storage, _entries[i]);1029}10301031EXPECT_EQ(initial_active_size, active_count(_storage));1032EXPECT_EQ(initial_active_size, _storage.block_count());1033EXPECT_EQ(3u, empty_block_count(_storage));1034{1035ThreadInVMfromNative invm(JavaThread::current());1036while (_storage.delete_empty_blocks()) {}1037}1038EXPECT_EQ(0u, empty_block_count(_storage));1039EXPECT_EQ(initial_active_size - 3, active_count(_storage));1040EXPECT_EQ(initial_active_size - 3, _storage.block_count());1041}10421043TEST_VM_F(OopStorageTestWithAllocation, allocation_status) {1044oop* retained = _entries[200];1045oop* released = _entries[300];1046oop* garbage = reinterpret_cast<oop*>(1024 * 1024);1047release_entry(_storage, released);10481049EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(retained));1050EXPECT_EQ(OopStorage::UNALLOCATED_ENTRY, _storage.allocation_status(released));1051EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(garbage));10521053for (size_t i = 0; i < _max_entries; ++i) {1054if ((_entries[i] != retained) && (_entries[i] != released)) {1055// Leave deferred release updates to block deletion.1056release_entry(_storage, _entries[i], false);1057}1058}10591060{1061ThreadInVMfromNative invm(JavaThread::current());1062while (_storage.delete_empty_blocks()) {}1063}1064EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(retained));1065EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(released));1066EXPECT_EQ(OopStorage::INVALID_ENTRY, _storage.allocation_status(garbage));1067}10681069TEST_VM_F(OopStorageTest, usage_info) {1070size_t goal_blocks = 5;1071oop* entries[1000];1072size_t allocated = 0;10731074EXPECT_EQ(0u, _storage.block_count());1075// There is non-block overhead, so always some usage.1076EXPECT_LT(0u, _storage.total_memory_usage());10771078while (_storage.block_count() < goal_blocks) {1079size_t this_count = _storage.block_count();1080while (_storage.block_count() == this_count) {1081ASSERT_GT(ARRAY_SIZE(entries), allocated);1082entries[allocated] = _storage.allocate();1083ASSERT_TRUE(entries[allocated] != NULL);1084++allocated;1085}1086EXPECT_NE(0u, _storage.block_count());1087EXPECT_NE(0u, _storage.total_memory_usage());1088}10891090EXPECT_LT(TestAccess::memory_per_block() * _storage.block_count(),1091_storage.total_memory_usage());1092}10931094#ifndef PRODUCT10951096TEST_VM_F(OopStorageTestWithAllocation, print_storage) {1097// Release the first 1/21098for (size_t i = 0; i < (_max_entries / 2); ++i) {1099// Deferred updates don't affect print output.1100release_entry(_storage, _entries[i], false);1101_entries[i] = NULL;1102}1103// Release every other remaining1104for (size_t i = _max_entries / 2; i < _max_entries; i += 2) {1105// Deferred updates don't affect print output.1106release_entry(_storage, _entries[i], false);1107_entries[i] = NULL;1108}11091110size_t expected_entries = _max_entries / 4;1111EXPECT_EQ(expected_entries, _storage.allocation_count());11121113size_t entries_per_block = BitsPerWord;1114size_t expected_blocks = (_max_entries + entries_per_block - 1) / entries_per_block;1115EXPECT_EQ(expected_blocks, _storage.block_count());11161117double expected_usage = (100.0 * expected_entries) / (expected_blocks * entries_per_block);11181119{1120ResourceMark rm;1121stringStream expected_st;1122expected_st.print("Test Storage: " SIZE_FORMAT1123" entries in " SIZE_FORMAT1124" blocks (%.F%%), " SIZE_FORMAT " bytes",1125expected_entries,1126expected_blocks,1127expected_usage,1128_storage.total_memory_usage());1129stringStream st;1130_storage.print_on(&st);1131EXPECT_STREQ(expected_st.as_string(), st.as_string());1132}1133}11341135#endif // !PRODUCT11361137class OopStorageBlockCollectionTest : public ::testing::Test {1138protected:1139OopStorageBlockCollectionTest() {1140for (size_t i = 0; i < nvalues; ++i) {1141values[i] = OopBlock::new_block(pseudo_owner());1142}1143}11441145~OopStorageBlockCollectionTest() {1146for (size_t i = 0; i < nvalues; ++i) {1147OopBlock::delete_block(*values[i]);1148}1149}11501151public:1152static const size_t nvalues = 10;1153OopBlock* values[nvalues];11541155private:1156// The only thing we actually care about is the address of the owner.1157static const size_t pseudo_owner_size = sizeof(OopStorage) / sizeof(void*);1158static const void* const _pseudo_owner[pseudo_owner_size];1159static const OopStorage* pseudo_owner() {1160return reinterpret_cast<const OopStorage*>(&_pseudo_owner);1161}1162};11631164const size_t OopStorageBlockCollectionTest::nvalues;1165const void* const OopStorageBlockCollectionTest::_pseudo_owner[] = {};11661167class OopStorageAllocationListTest : public OopStorageBlockCollectionTest {};11681169TEST_F(OopStorageAllocationListTest, empty_list) {1170AllocationList list;11711172EXPECT_TRUE(is_list_empty(list));1173EXPECT_EQ(NULL_BLOCK, list.head());1174EXPECT_EQ(NULL_BLOCK, list.chead());1175EXPECT_EQ(NULL_BLOCK, list.ctail());1176}11771178TEST_F(OopStorageAllocationListTest, push_back) {1179AllocationList list;11801181for (size_t i = 0; i < nvalues; ++i) {1182list.push_back(*values[i]);1183EXPECT_FALSE(is_list_empty(list));1184EXPECT_EQ(list.ctail(), values[i]);1185}11861187EXPECT_EQ(list.chead(), list.head());1188EXPECT_EQ(list.chead(), values[0]);1189EXPECT_EQ(list.ctail(), values[nvalues - 1]);11901191const OopBlock* block = list.chead();1192for (size_t i = 0; i < nvalues; ++i) {1193EXPECT_EQ(block, values[i]);1194block = list.next(*block);1195}1196EXPECT_EQ(NULL_BLOCK, block);11971198block = list.ctail();1199for (size_t i = 0; i < nvalues; ++i) {1200EXPECT_EQ(block, values[nvalues - i - 1]);1201block = list.prev(*block);1202}1203EXPECT_EQ(NULL_BLOCK, block);12041205clear_list(list);1206}12071208TEST_F(OopStorageAllocationListTest, push_front) {1209AllocationList list;12101211for (size_t i = 0; i < nvalues; ++i) {1212list.push_front(*values[i]);1213EXPECT_FALSE(is_list_empty(list));1214EXPECT_EQ(list.head(), values[i]);1215}12161217EXPECT_EQ(list.chead(), list.head());1218EXPECT_EQ(list.chead(), values[nvalues - 1]);1219EXPECT_EQ(list.ctail(), values[0]);12201221const OopBlock* block = list.chead();1222for (size_t i = 0; i < nvalues; ++i) {1223EXPECT_EQ(block, values[nvalues - i - 1]);1224block = list.next(*block);1225}1226EXPECT_EQ(NULL_BLOCK, block);12271228block = list.ctail();1229for (size_t i = 0; i < nvalues; ++i) {1230EXPECT_EQ(block, values[i]);1231block = list.prev(*block);1232}1233EXPECT_EQ(NULL_BLOCK, block);12341235clear_list(list);1236}12371238class OopStorageAllocationListTestWithList : public OopStorageAllocationListTest {1239public:1240OopStorageAllocationListTestWithList() : list() {1241for (size_t i = 0; i < nvalues; ++i) {1242list.push_back(*values[i]);1243}1244}12451246~OopStorageAllocationListTestWithList() {1247clear_list(list);1248}12491250AllocationList list;1251};12521253TEST_F(OopStorageAllocationListTestWithList, unlink_front) {1254EXPECT_EQ(list.chead(), values[0]);1255EXPECT_EQ(list.ctail(), values[nvalues - 1]);12561257list.unlink(*values[0]);1258EXPECT_EQ(NULL_BLOCK, list.next(*values[0]));1259EXPECT_EQ(NULL_BLOCK, list.prev(*values[0]));1260EXPECT_EQ(list.chead(), values[1]);1261EXPECT_EQ(list.ctail(), values[nvalues - 1]);12621263const OopBlock* block = list.chead();1264for (size_t i = 1; i < nvalues; ++i) {1265EXPECT_EQ(block, values[i]);1266block = list.next(*block);1267}1268EXPECT_EQ(NULL_BLOCK, block);1269}12701271TEST_F(OopStorageAllocationListTestWithList, unlink_back) {1272EXPECT_EQ(list.chead(), values[0]);12731274list.unlink(*values[nvalues - 1]);1275EXPECT_EQ(NULL_BLOCK, list.next(*values[nvalues - 1]));1276EXPECT_EQ(NULL_BLOCK, list.prev(*values[nvalues - 1]));1277EXPECT_EQ(list.chead(), values[0]);1278EXPECT_EQ(list.ctail(), values[nvalues - 2]);12791280const OopBlock* block = list.chead();1281for (size_t i = 0; i < nvalues - 1; ++i) {1282EXPECT_EQ(block, values[i]);1283block = list.next(*block);1284}1285EXPECT_EQ(NULL_BLOCK, block);1286}12871288TEST_F(OopStorageAllocationListTestWithList, unlink_middle) {1289EXPECT_EQ(list.chead(), values[0]);12901291size_t index = nvalues / 2;12921293list.unlink(*values[index]);1294EXPECT_EQ(NULL_BLOCK, list.next(*values[index]));1295EXPECT_EQ(NULL_BLOCK, list.prev(*values[index]));1296EXPECT_EQ(list.chead(), values[0]);1297EXPECT_EQ(list.ctail(), values[nvalues - 1]);12981299const OopBlock* block = list.chead();1300for (size_t i = 0; i < index; ++i) {1301EXPECT_EQ(block, values[i]);1302block = list.next(*block);1303}1304for (size_t i = index + 1; i < nvalues; ++i) {1305EXPECT_EQ(block, values[i]);1306block = list.next(*block);1307}1308EXPECT_EQ(NULL_BLOCK, block);1309}13101311TEST_F(OopStorageAllocationListTest, single) {1312AllocationList list;13131314list.push_back(*values[0]);1315EXPECT_EQ(NULL_BLOCK, list.next(*values[0]));1316EXPECT_EQ(NULL_BLOCK, list.prev(*values[0]));1317EXPECT_EQ(list.chead(), values[0]);1318EXPECT_EQ(list.ctail(), values[0]);13191320list.unlink(*values[0]);1321EXPECT_EQ(NULL_BLOCK, list.next(*values[0]));1322EXPECT_EQ(NULL_BLOCK, list.prev(*values[0]));1323EXPECT_EQ(NULL_BLOCK, list.chead());1324EXPECT_EQ(NULL_BLOCK, list.ctail());1325}13261327class OopStorageActiveArrayTest : public OopStorageBlockCollectionTest {};13281329TEST_F(OopStorageActiveArrayTest, empty_array) {1330ActiveArray* a = ActiveArray::create(nvalues);13311332EXPECT_EQ(nvalues, a->size());1333EXPECT_EQ(0u, a->block_count_acquire());1334TestAccess::block_array_set_block_count(a, 2);1335EXPECT_EQ(2u, a->block_count_acquire());1336TestAccess::block_array_set_block_count(a, 0);1337a->increment_refcount();1338a->increment_refcount();1339EXPECT_FALSE(a->decrement_refcount());1340EXPECT_TRUE(a->decrement_refcount());13411342ActiveArray::destroy(a);1343}13441345TEST_F(OopStorageActiveArrayTest, push) {1346ActiveArray* a = ActiveArray::create(nvalues - 1);13471348for (size_t i = 0; i < nvalues - 1; ++i) {1349EXPECT_TRUE(a->push(values[i]));1350EXPECT_EQ(i + 1, a->block_count_acquire());1351EXPECT_EQ(values[i], a->at(i));1352}1353EXPECT_FALSE(a->push(values[nvalues - 1]));13541355TestAccess::block_array_set_block_count(a, 0);1356ActiveArray::destroy(a);1357}13581359class OopStorageActiveArrayTestWithArray : public OopStorageActiveArrayTest {1360public:1361OopStorageActiveArrayTestWithArray() : a(ActiveArray::create(nvalues)) {1362for (size_t i = 0; i < nvalues; ++i) {1363a->push(values[i]);1364}1365}13661367~OopStorageActiveArrayTestWithArray() {1368TestAccess::block_array_set_block_count(a, 0);1369ActiveArray::destroy(a);1370}13711372ActiveArray* a;1373};13741375TEST_F(OopStorageActiveArrayTestWithArray, remove0) {1376a->remove(values[0]);1377EXPECT_EQ(nvalues - 1, a->block_count_acquire());1378EXPECT_EQ(values[nvalues - 1], a->at(0));1379for (size_t i = 1; i < nvalues - 1; ++i) {1380EXPECT_EQ(values[i], a->at(i));1381}1382}13831384TEST_F(OopStorageActiveArrayTestWithArray, remove3) {1385a->remove(values[3]);1386EXPECT_EQ(nvalues - 1, a->block_count_acquire());1387for (size_t i = 0; i < 3; ++i) {1388EXPECT_EQ(values[i], a->at(i));1389}1390EXPECT_EQ(values[nvalues - 1], a->at(3));1391for (size_t i = 4; i < nvalues - 1; ++i) {1392EXPECT_EQ(values[i], a->at(i));1393}1394}13951396TEST_F(OopStorageActiveArrayTestWithArray, remove_last) {1397a->remove(values[nvalues - 1]);1398EXPECT_EQ(nvalues - 1, a->block_count_acquire());1399for (size_t i = 0; i < nvalues - 1; ++i) {1400EXPECT_EQ(values[i], a->at(i));1401}1402}140314041405