# HG changeset patch # User kzhaldyb # Date 1472490912 -10800 # Node ID 94ffc131534fbe97779e79fe183f2e8feb895157 # Parent 5189925f9ece35a40757e32a305db4f5300ca014 8164230: Convert TestCodeCacheRemSet_test to GTest Reviewed-by: mgerdin, dfazunen diff -r 5189925f9ece -r 94ffc131534f hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp --- a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Mon Aug 22 16:43:56 2016 +0300 +++ b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.cpp Mon Aug 29 20:15:12 2016 +0300 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "code/nmethod.hpp" +#include "gc/g1/g1CodeRootSetTable.hpp" #include "gc/g1/g1CodeCacheRemSet.hpp" #include "gc/g1/heapRegion.hpp" #include "memory/heap.hpp" @@ -33,58 +34,13 @@ #include "utilities/hashtable.inline.hpp" #include "utilities/stack.inline.hpp" -class CodeRootSetTable : public Hashtable { - friend class G1CodeRootSetTest; - typedef HashtableEntry Entry; - - static CodeRootSetTable* volatile _purge_list; - - CodeRootSetTable* _purge_next; - - unsigned int compute_hash(nmethod* nm) { - uintptr_t hash = (uintptr_t)nm; - return hash ^ (hash >> 7); // code heap blocks are 128byte aligned - } - - void remove_entry(Entry* e, Entry* previous); - Entry* new_entry(nmethod* nm); - - public: - CodeRootSetTable(int size) : Hashtable(size, sizeof(Entry)), _purge_next(NULL) {} - ~CodeRootSetTable(); - - // Needs to be protected locks - bool add(nmethod* nm); - bool remove(nmethod* nm); +G1CodeRootSetTable* volatile G1CodeRootSetTable::_purge_list = NULL; - // Can be called without locking - bool contains(nmethod* nm); - - int entry_size() const { return BasicHashtable::entry_size(); } - - void copy_to(CodeRootSetTable* new_table); - void nmethods_do(CodeBlobClosure* blk); - - template - int remove_if(CB& should_remove); - - static void purge_list_append(CodeRootSetTable* tbl); - static void purge(); - - static size_t static_mem_size() { - return sizeof(_purge_list); - } - - size_t mem_size(); -}; - -CodeRootSetTable* volatile CodeRootSetTable::_purge_list = NULL; - -size_t CodeRootSetTable::mem_size() { - return sizeof(CodeRootSetTable) + (entry_size() * number_of_entries()) + (sizeof(HashtableBucket) * table_size()); +size_t G1CodeRootSetTable::mem_size() { + return sizeof(G1CodeRootSetTable) + (entry_size() * number_of_entries()) + (sizeof(HashtableBucket) * table_size()); } -CodeRootSetTable::Entry* CodeRootSetTable::new_entry(nmethod* nm) { +G1CodeRootSetTable::Entry* G1CodeRootSetTable::new_entry(nmethod* nm) { unsigned int hash = compute_hash(nm); Entry* entry = (Entry*) new_entry_free_list(); if (entry == NULL) { @@ -96,7 +52,7 @@ return entry; } -void CodeRootSetTable::remove_entry(Entry* e, Entry* previous) { +void G1CodeRootSetTable::remove_entry(Entry* e, Entry* previous) { int index = hash_to_index(e->hash()); assert((e == bucket(index)) == (previous == NULL), "if e is the first entry then previous should be null"); @@ -108,7 +64,7 @@ free_entry(e); } -CodeRootSetTable::~CodeRootSetTable() { +G1CodeRootSetTable::~G1CodeRootSetTable() { for (int index = 0; index < table_size(); ++index) { for (Entry* e = bucket(index); e != NULL; ) { Entry* to_remove = e; @@ -125,7 +81,7 @@ } } -bool CodeRootSetTable::add(nmethod* nm) { +bool G1CodeRootSetTable::add(nmethod* nm) { if (!contains(nm)) { Entry* e = new_entry(nm); int index = hash_to_index(e->hash()); @@ -135,7 +91,7 @@ return false; } -bool CodeRootSetTable::contains(nmethod* nm) { +bool G1CodeRootSetTable::contains(nmethod* nm) { int index = hash_to_index(compute_hash(nm)); for (Entry* e = bucket(index); e != NULL; e = e->next()) { if (e->literal() == nm) { @@ -145,7 +101,7 @@ return false; } -bool CodeRootSetTable::remove(nmethod* nm) { +bool G1CodeRootSetTable::remove(nmethod* nm) { int index = hash_to_index(compute_hash(nm)); Entry* previous = NULL; for (Entry* e = bucket(index); e != NULL; previous = e, e = e->next()) { @@ -157,7 +113,7 @@ return false; } -void CodeRootSetTable::copy_to(CodeRootSetTable* new_table) { +void G1CodeRootSetTable::copy_to(G1CodeRootSetTable* new_table) { for (int index = 0; index < table_size(); ++index) { for (Entry* e = bucket(index); e != NULL; e = e->next()) { new_table->add(e->literal()); @@ -166,7 +122,7 @@ new_table->copy_freelist(this); } -void CodeRootSetTable::nmethods_do(CodeBlobClosure* blk) { +void G1CodeRootSetTable::nmethods_do(CodeBlobClosure* blk) { for (int index = 0; index < table_size(); ++index) { for (Entry* e = bucket(index); e != NULL; e = e->next()) { blk->do_code_blob(e->literal()); @@ -175,7 +131,7 @@ } template -int CodeRootSetTable::remove_if(CB& should_remove) { +int G1CodeRootSetTable::remove_if(CB& should_remove) { int num_removed = 0; for (int index = 0; index < table_size(); ++index) { Entry* previous = NULL; @@ -198,52 +154,52 @@ delete _table; } -CodeRootSetTable* G1CodeRootSet::load_acquire_table() { - return (CodeRootSetTable*) OrderAccess::load_ptr_acquire(&_table); +G1CodeRootSetTable* G1CodeRootSet::load_acquire_table() { + return (G1CodeRootSetTable*) OrderAccess::load_ptr_acquire(&_table); } void G1CodeRootSet::allocate_small_table() { - CodeRootSetTable* temp = new CodeRootSetTable(SmallSize); + G1CodeRootSetTable* temp = new G1CodeRootSetTable(SmallSize); OrderAccess::release_store_ptr(&_table, temp); } -void CodeRootSetTable::purge_list_append(CodeRootSetTable* table) { +void G1CodeRootSetTable::purge_list_append(G1CodeRootSetTable* table) { for (;;) { table->_purge_next = _purge_list; - CodeRootSetTable* old = (CodeRootSetTable*) Atomic::cmpxchg_ptr(table, &_purge_list, table->_purge_next); + G1CodeRootSetTable* old = (G1CodeRootSetTable*) Atomic::cmpxchg_ptr(table, &_purge_list, table->_purge_next); if (old == table->_purge_next) { break; } } } -void CodeRootSetTable::purge() { - CodeRootSetTable* table = _purge_list; +void G1CodeRootSetTable::purge() { + G1CodeRootSetTable* table = _purge_list; _purge_list = NULL; while (table != NULL) { - CodeRootSetTable* to_purge = table; + G1CodeRootSetTable* to_purge = table; table = table->_purge_next; delete to_purge; } } void G1CodeRootSet::move_to_large() { - CodeRootSetTable* temp = new CodeRootSetTable(LargeSize); + G1CodeRootSetTable* temp = new G1CodeRootSetTable(LargeSize); _table->copy_to(temp); - CodeRootSetTable::purge_list_append(_table); + G1CodeRootSetTable::purge_list_append(_table); OrderAccess::release_store_ptr(&_table, temp); } void G1CodeRootSet::purge() { - CodeRootSetTable::purge(); + G1CodeRootSetTable::purge(); } size_t G1CodeRootSet::static_mem_size() { - return CodeRootSetTable::static_mem_size(); + return G1CodeRootSetTable::static_mem_size(); } void G1CodeRootSet::add(nmethod* method) { @@ -278,7 +234,7 @@ } bool G1CodeRootSet::contains(nmethod* method) { - CodeRootSetTable* table = load_acquire_table(); // contains() may be called outside of lock, so ensure mem sync. + G1CodeRootSetTable* table = load_acquire_table(); // contains() may be called outside of lock, so ensure mem sync. if (table != NULL) { return table->contains(method); } @@ -348,67 +304,3 @@ clear(); } } - -#ifndef PRODUCT - -class G1CodeRootSetTest { - public: - static void test() { - { - G1CodeRootSet set1; - assert(set1.is_empty(), "Code root set must be initially empty but is not."); - - assert(G1CodeRootSet::static_mem_size() == sizeof(void*), - "The code root set's static memory usage is incorrect, " SIZE_FORMAT " bytes", G1CodeRootSet::static_mem_size()); - - set1.add((nmethod*)1); - assert(set1.length() == 1, "Added exactly one element, but set contains " - SIZE_FORMAT " elements", set1.length()); - - const size_t num_to_add = (size_t)G1CodeRootSet::Threshold + 1; - - for (size_t i = 1; i <= num_to_add; i++) { - set1.add((nmethod*)1); - } - assert(set1.length() == 1, - "Duplicate detection should not have increased the set size but " - "is " SIZE_FORMAT, set1.length()); - - for (size_t i = 2; i <= num_to_add; i++) { - set1.add((nmethod*)(uintptr_t)(i)); - } - assert(set1.length() == num_to_add, - "After adding in total " SIZE_FORMAT " distinct code roots, they " - "need to be in the set, but there are only " SIZE_FORMAT, - num_to_add, set1.length()); - - assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); - - size_t num_popped = 0; - for (size_t i = 1; i <= num_to_add; i++) { - bool removed = set1.remove((nmethod*)i); - if (removed) { - num_popped += 1; - } else { - break; - } - } - assert(num_popped == num_to_add, - "Managed to pop " SIZE_FORMAT " code roots, but only " SIZE_FORMAT " " - "were added", num_popped, num_to_add); - assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable"); - - G1CodeRootSet::purge(); - - assert(CodeRootSetTable::_purge_list == NULL, "should have purged old small tables"); - - } - - } -}; - -void TestCodeCacheRemSet_test() { - G1CodeRootSetTest::test(); -} - -#endif diff -r 5189925f9ece -r 94ffc131534f hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.hpp --- a/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.hpp Mon Aug 22 16:43:56 2016 +0300 +++ b/hotspot/src/share/vm/gc/g1/g1CodeCacheRemSet.hpp Mon Aug 29 20:15:12 2016 +0300 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/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 @@ -28,7 +28,7 @@ #include "memory/allocation.hpp" class CodeBlobClosure; -class CodeRootSetTable; +class G1CodeRootSetTable; class HeapRegion; class nmethod; @@ -42,8 +42,8 @@ const static size_t Threshold = 24; const static size_t LargeSize = 512; - CodeRootSetTable* _table; - CodeRootSetTable* load_acquire_table(); + G1CodeRootSetTable* _table; + G1CodeRootSetTable* load_acquire_table(); size_t _length; diff -r 5189925f9ece -r 94ffc131534f hotspot/src/share/vm/gc/g1/g1CodeRootSetTable.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/gc/g1/g1CodeRootSetTable.hpp Mon Aug 29 20:15:12 2016 +0300 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2016, Oracle and/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. + */ + +#ifndef SHARE_VM_GC_G1_G1CODEROOTSETTABLE_HPP +#define SHARE_VM_GC_G1_G1CODEROOTSETTABLE_HPP + +#include "utilities/hashtable.hpp" + +class nmethod; + +class G1CodeRootSetTable : public Hashtable { + friend class G1CodeRootSetTest; + typedef HashtableEntry Entry; + + static G1CodeRootSetTable* volatile _purge_list; + + G1CodeRootSetTable* _purge_next; + + unsigned int compute_hash(nmethod* nm) { + uintptr_t hash = (uintptr_t)nm; + return hash ^ (hash >> 7); // code heap blocks are 128byte aligned + } + + void remove_entry(Entry* e, Entry* previous); + Entry* new_entry(nmethod* nm); + + public: + G1CodeRootSetTable(int size) : Hashtable(size, sizeof(Entry)), _purge_next(NULL) {} + ~G1CodeRootSetTable(); + + // Needs to be protected by locks + bool add(nmethod* nm); + bool remove(nmethod* nm); + + // Can be called without locking + bool contains(nmethod* nm); + + int entry_size() const { return BasicHashtable::entry_size(); } + + void copy_to(G1CodeRootSetTable* new_table); + void nmethods_do(CodeBlobClosure* blk); + + template + int remove_if(CB& should_remove); + + static void purge_list_append(G1CodeRootSetTable* tbl); + static void purge(); + + static size_t static_mem_size() { + return sizeof(_purge_list); + } + + size_t mem_size(); +}; + +#endif /* SHARE_VM_GC_G1_G1CODEROOTSETTABLE_HPP */ diff -r 5189925f9ece -r 94ffc131534f hotspot/src/share/vm/utilities/internalVMTests.cpp --- a/hotspot/src/share/vm/utilities/internalVMTests.cpp Mon Aug 22 16:43:56 2016 +0300 +++ b/hotspot/src/share/vm/utilities/internalVMTests.cpp Mon Aug 29 20:15:12 2016 +0300 @@ -89,7 +89,6 @@ #if INCLUDE_ALL_GCS run_unit_test(TestG1BiasedArray_test); run_unit_test(TestBufferingOopClosure_test); - run_unit_test(TestCodeCacheRemSet_test); if (UseG1GC) { run_unit_test(FreeRegionList_test); run_unit_test(IHOP_test); diff -r 5189925f9ece -r 94ffc131534f hotspot/test/native/gc/g1/test_g1CodeCacheRemSet.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/native/gc/g1/test_g1CodeCacheRemSet.cpp Mon Aug 29 20:15:12 2016 +0300 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/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 "precompiled.hpp" +#include "gc/g1/g1CodeRootSetTable.hpp" +#include "gc/g1/g1CodeCacheRemSet.hpp" +#include "unittest.hpp" + +class G1CodeRootSetTest : public ::testing::Test { + public: + + size_t threshold() { + return G1CodeRootSet::Threshold; + } + + G1CodeRootSetTable* purge_list() { + return G1CodeRootSetTable::_purge_list; + } +}; + +TEST_VM_F(G1CodeRootSetTest, g1_code_cache_rem_set) { + G1CodeRootSet root_set; + + ASSERT_TRUE(root_set.is_empty()) << "Code root set must be initially empty " + "but is not."; + + ASSERT_EQ(G1CodeRootSet::static_mem_size(), sizeof (void*)) << + "The code root set's static memory usage is incorrect, " + << G1CodeRootSet::static_mem_size() << " bytes"; + + root_set.add((nmethod*) 1); + ASSERT_EQ(root_set.length(), (size_t) 1) << "Added exactly one element, but" + " set contains " << root_set.length() << " elements"; + + const size_t num_to_add = (size_t) threshold() + 1; + + for (size_t i = 1; i <= num_to_add; i++) { + root_set.add((nmethod*) 1); + } + ASSERT_EQ(root_set.length(), (size_t) 1) + << "Duplicate detection should not have increased the set size but " + << "is " << root_set.length(); + + for (size_t i = 2; i <= num_to_add; i++) { + root_set.add((nmethod*) (uintptr_t) (i)); + } + + ASSERT_EQ(root_set.length(), num_to_add) + << "After adding in total " << num_to_add << " distinct code roots, " + "they need to be in the set, but there are only " << root_set.length(); + + ASSERT_NE(purge_list(), (G1CodeRootSetTable*) NULL) + << "should have grown to large hashtable"; + + size_t num_popped = 0; + for (size_t i = 1; i <= num_to_add; i++) { + bool removed = root_set.remove((nmethod*) i); + if (removed) { + num_popped += 1; + } else { + break; + } + } + ASSERT_EQ(num_popped, num_to_add) + << "Managed to pop " << num_popped << " code roots, but only " + << num_to_add << " were added"; + ASSERT_NE(purge_list(), (G1CodeRootSetTable*) NULL) + << "should have grown to large hashtable"; + + G1CodeRootSet::purge(); + + ASSERT_EQ(purge_list(), (G1CodeRootSetTable*) NULL) + << "should have purged old small tables"; +}