--- old/src/share/vm/opto/chaitin.cpp 2014-11-06 00:05:08.454893823 +0300 +++ new/src/share/vm/opto/chaitin.cpp 2014-11-06 00:05:08.406893821 +0300 @@ -374,7 +374,6 @@ Compile::TracePhase tp("computeLive", &timers[_t_computeLive]); _live = NULL; // Mark live as being not available rm.reset_to_mark(); // Reclaim working storage - IndexSet::reset_memory(C, &live_arena); ifg.init(_lrg_map.max_lrg_id()); // Empty IFG gather_lrg_masks( false ); // Collect LRG masks live.compute(_lrg_map.max_lrg_id()); // Compute liveness @@ -392,7 +391,6 @@ // Since some live range stretched, I need to recompute live _live = NULL; rm.reset_to_mark(); // Reclaim working storage - IndexSet::reset_memory(C, &live_arena); ifg.init(_lrg_map.max_lrg_id()); gather_lrg_masks(false); live.compute(_lrg_map.max_lrg_id()); @@ -431,7 +429,6 @@ Compile::TracePhase tp("computeLive", &timers[_t_computeLive]); _live = NULL; rm.reset_to_mark(); // Reclaim working storage - IndexSet::reset_memory(C, &live_arena); ifg.init(_lrg_map.max_lrg_id()); gather_lrg_masks( true ); live.compute(_lrg_map.max_lrg_id()); @@ -469,7 +466,6 @@ Compile::TracePhase tp("computeLive", &timers[_t_computeLive]); _live = NULL; rm.reset_to_mark(); // Reclaim working storage - IndexSet::reset_memory(C, &live_arena); ifg.init(_lrg_map.max_lrg_id()); // Build a new interference graph gather_lrg_masks( true ); // Collect intersect mask live.compute(_lrg_map.max_lrg_id()); // Compute LIVE @@ -539,7 +535,6 @@ Compile::TracePhase tp("computeLive", &timers[_t_computeLive]); _live = NULL; rm.reset_to_mark(); // Reclaim working storage - IndexSet::reset_memory(C, &live_arena); ifg.init(_lrg_map.max_lrg_id()); // Create LiveRanGe array. @@ -660,8 +655,7 @@ // Done! _live = NULL; - _ifg = NULL; - C->set_indexSet_arena(NULL); // ResourceArea is at end of scope + _ifg = NULL; } void PhaseChaitin::de_ssa() { --- old/src/share/vm/opto/coalesce.cpp 2014-11-06 00:05:08.646893827 +0300 +++ new/src/share/vm/opto/coalesce.cpp 2014-11-06 00:05:08.594893826 +0300 @@ -607,6 +607,86 @@ ifg->lrgs(lr2)._copy_bias = lr1; } +//------------------------------lrg_union-------------------------------------- +// Compute the union of all elements of one and two which interfere with +// the RegMask mask. If the degree of the union becomes exceeds +// fail_degree, the union bails out. The destination set is cleared before +// the union is performed. + +uint lrg_union(IndexSet& dst, uint lr1, uint lr2, + const uint fail_degree, + const PhaseIFG *ifg, + const RegMask &mask ) { + IndexSet *one = ifg->neighbors(lr1); + IndexSet *two = ifg->neighbors(lr2); + LRG &lrg1 = ifg->lrgs(lr1); + LRG &lrg2 = ifg->lrgs(lr2); +#ifdef ASSERT +// assert(_max_elements == one->_max_elements, "max element mismatch"); +// check_watch("union destination"); +// one->check_watch("union source"); +// two->check_watch("union source"); +#endif + + // Compute the degree of the combined live-range. The combined + // live-range has the union of the original live-ranges' neighbors set as + // well as the neighbors of all intermediate copies, minus those neighbors + // that can not use the intersected allowed-register-set. + + // Copy the larger set. Insert the smaller set into the larger. + if (two->count() > one->count()) { + IndexSet *temp = one; + one = two; + two = temp; + } + + dst.clear(); + + // Used to compute degree of register-only interferences. Infinite-stack + // neighbors do not alter colorability, as they can always color to some + // other color. (A variant of the Briggs assertion) + uint reg_degree = 0; + + uint element; + // Load up the combined interference set with the neighbors of one + IndexSetIterator elements(one); + while ((element = elements.next()) != 0) { + LRG &lrg = ifg->lrgs(element); + if (mask.overlap(lrg.mask())) { + dst.insert(element); + if( !lrg.mask().is_AllStack() ) { + reg_degree += lrg1.compute_degree(lrg); + if( reg_degree >= fail_degree ) return reg_degree; + } else { + // !!!!! Danger! No update to reg_degree despite having a neighbor. + // A variant of the Briggs assertion. + // Not needed if I simplify during coalesce, ala George/Appel. + assert( lrg.lo_degree(), "" ); + } + } + } + // Add neighbors of two as well + IndexSetIterator elements2(two); + while ((element = elements2.next()) != 0) { + LRG &lrg = ifg->lrgs(element); + if (mask.overlap(lrg.mask())) { + if (dst.insert(element)) { + if( !lrg.mask().is_AllStack() ) { + reg_degree += lrg2.compute_degree(lrg); + if( reg_degree >= fail_degree ) return reg_degree; + } else { + // !!!!! Danger! No update to reg_degree despite having a neighbor. + // A variant of the Briggs assertion. + // Not needed if I simplify during coalesce, ala George/Appel. + assert( lrg.lo_degree(), "" ); + } + } + } + } + + return reg_degree; +} + // See if I can coalesce a series of multiple copies together. I need the // final dest copy and the original src copy. They can be the same Node. // Compute the compatible register masks. @@ -690,7 +770,7 @@ } // Union the two interference sets together into '_ulr' - uint reg_degree = _ulr.lrg_union( lr1, lr2, rm_size, _phc._ifg, rm ); + uint reg_degree = lrg_union( _ulr, lr1, lr2, rm_size, _phc._ifg, rm ); if( reg_degree >= rm_size ) { record_bias( _phc._ifg, lr1, lr2 ); @@ -736,11 +816,14 @@ // _ulr.dump(); //} - // Replace n_lr1 with the new combined live range. _ulr will use - // n_lr1's old memory on the next iteration. n_lr2 is cleared to - // send its internal memory to the free list. - _ulr.swap(n_lr1); + // Replace n_lr1 with the new combined live range. + // _ulr should be clean on the next iteration. + n_lr1->set_from(&_ulr); _ulr.clear(); + + // TODO: Do we need to clear n_lr2 here? Previous + // IndexSet implementation freed the underlying blocks, + // but now we only clear the bitmap, is this redundant? n_lr2->clear(); lrgs(lr1).set_degree( _phc._ifg->effective_degree(lr1) ); --- old/src/share/vm/opto/compile.cpp 2014-11-06 00:05:08.826893831 +0300 +++ new/src/share/vm/opto/compile.cpp 2014-11-06 00:05:08.774893829 +0300 @@ -455,8 +455,6 @@ compile->set_type_hwm(NULL); compile->set_type_last_size(0); compile->set_last_tf(NULL, NULL); - compile->set_indexSet_arena(NULL); - compile->set_indexSet_free_block_list(NULL); compile->init_type_arena(); Type::Initialize(compile); _compile->set_scratch_buffer_blob(NULL); --- old/src/share/vm/opto/compile.hpp 2014-11-06 00:05:09.022893835 +0300 +++ new/src/share/vm/opto/compile.hpp 2014-11-06 00:05:08.970893834 +0300 @@ -483,8 +483,6 @@ int _frame_slots; // Size of total frame in stack slots CodeOffsets _code_offsets; // Offsets into the code for various interesting entries RegMask _FIRST_STACK_mask; // All stack slots usable for spills (depends on frame layout) - Arena* _indexSet_arena; // control IndexSet allocation within PhaseChaitin - void* _indexSet_free_block_list; // free list of IndexSet bit blocks int _interpreter_frame_size; uint _node_bundling_limit; @@ -968,8 +966,6 @@ int frame_size_in_words() const; // frame_slots in units of the polymorphic 'words' int frame_size_in_bytes() const { return _frame_slots << LogBytesPerInt; } RegMask& FIRST_STACK_mask() { return _FIRST_STACK_mask; } - Arena* indexSet_arena() { return _indexSet_arena; } - void* indexSet_free_block_list() { return _indexSet_free_block_list; } uint node_bundling_limit() { return _node_bundling_limit; } Bundle* node_bundling_base() { return _node_bundling_base; } void set_node_bundling_limit(uint n) { _node_bundling_limit = n; } @@ -987,8 +983,6 @@ void set_matcher(Matcher* m) { _matcher = m; } //void set_regalloc(PhaseRegAlloc* ra) { _regalloc = ra; } - void set_indexSet_arena(Arena* a) { _indexSet_arena = a; } - void set_indexSet_free_block_list(void* p) { _indexSet_free_block_list = p; } // Remember if this compilation changes hardware mode to 24-bit precision void set_24_bit_selection_and_mode(bool selection, bool mode) { --- old/src/share/vm/opto/indexSet.cpp 2014-11-06 00:05:09.202893839 +0300 +++ new/src/share/vm/opto/indexSet.cpp 2014-11-06 00:05:09.154893838 +0300 @@ -23,358 +23,13 @@ */ #include "precompiled.hpp" -#include "memory/allocation.inline.hpp" -#include "opto/chaitin.hpp" -#include "opto/compile.hpp" #include "opto/indexSet.hpp" -#include "opto/regmask.hpp" - -// This file defines the IndexSet class, a set of sparse integer indices. -// This data structure is used by the compiler in its liveness analysis and -// during register allocation. It also defines an iterator for this class. - -//-------------------------------- Initializations ------------------------------ - -IndexSet::BitBlock IndexSet::_empty_block = IndexSet::BitBlock(); - -#ifdef ASSERT -// Initialize statistics counters -julong IndexSet::_alloc_new = 0; -julong IndexSet::_alloc_total = 0; - -julong IndexSet::_total_bits = 0; -julong IndexSet::_total_used_blocks = 0; -julong IndexSet::_total_unused_blocks = 0; - -// Per set, or all sets operation tracing -int IndexSet::_serial_count = 1; -#endif - -// What is the first set bit in a 5 bit integer? -const uint8_t IndexSetIterator::_first_bit[32] = { - 0, 0, 1, 0, - 2, 0, 1, 0, - 3, 0, 1, 0, - 2, 0, 1, 0, - 4, 0, 1, 0, - 2, 0, 1, 0, - 3, 0, 1, 0, - 2, 0, 1, 0 -}; - -// What is the second set bit in a 5 bit integer? -const uint8_t IndexSetIterator::_second_bit[32] = { - 5, 5, 5, 1, - 5, 2, 2, 1, - 5, 3, 3, 1, - 3, 2, 2, 1, - 5, 4, 4, 1, - 4, 2, 2, 1, - 4, 3, 3, 1, - 3, 2, 2, 1 -}; - -// I tried implementing the IndexSetIterator with a window_size of 8 and -// didn't seem to get a noticeable speedup. I am leaving in the tables -// in case we want to switch back. - -/*const byte IndexSetIterator::_first_bit[256] = { - 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, - 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 -}; - -const byte IndexSetIterator::_second_bit[256] = { - 8, 8, 8, 1, 8, 2, 2, 1, 8, 3, 3, 1, 3, 2, 2, 1, - 8, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 8, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, - 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 8, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, - 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, - 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 8, 7, 7, 1, 7, 2, 2, 1, 7, 3, 3, 1, 3, 2, 2, 1, - 7, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 7, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, - 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 7, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, - 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, - 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, - 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1 -};*/ - -//---------------------------- IndexSet::populate_free_list() ----------------------------- -// Populate the free BitBlock list with a batch of BitBlocks. The BitBlocks -// are 32 bit aligned. - -void IndexSet::populate_free_list() { - Compile *compile = Compile::current(); - BitBlock *free = (BitBlock*)compile->indexSet_free_block_list(); - - char *mem = (char*)arena()->Amalloc_4(sizeof(BitBlock) * - bitblock_alloc_chunk_size + 32); - - // Align the pointer to a 32 bit boundary. - BitBlock *new_blocks = (BitBlock*)(((uintptr_t)mem + 32) & ~0x001F); - - // Add the new blocks to the free list. - for (int i = 0; i < bitblock_alloc_chunk_size; i++) { - new_blocks->set_next(free); - free = new_blocks; - new_blocks++; - } - - compile->set_indexSet_free_block_list(free); - -#ifdef ASSERT - if (CollectIndexSetStatistics) { - inc_stat_counter(&_alloc_new, bitblock_alloc_chunk_size); - } -#endif -} - - -//---------------------------- IndexSet::alloc_block() ------------------------ -// Allocate a BitBlock from the free list. If the free list is empty, -// prime it. - -IndexSet::BitBlock *IndexSet::alloc_block() { -#ifdef ASSERT - if (CollectIndexSetStatistics) { - inc_stat_counter(&_alloc_total, 1); - } -#endif - Compile *compile = Compile::current(); - BitBlock* free_list = (BitBlock*)compile->indexSet_free_block_list(); - if (free_list == NULL) { - populate_free_list(); - free_list = (BitBlock*)compile->indexSet_free_block_list(); - } - BitBlock *block = free_list; - compile->set_indexSet_free_block_list(block->next()); - - block->clear(); - return block; -} - -//---------------------------- IndexSet::alloc_block_containing() ------------- -// Allocate a new BitBlock and put it into the position in the _blocks array -// corresponding to element. - -IndexSet::BitBlock *IndexSet::alloc_block_containing(uint element) { - BitBlock *block = alloc_block(); - uint bi = get_block_index(element); - _blocks[bi] = block; - return block; -} - -//---------------------------- IndexSet::free_block() ------------------------- -// Add a BitBlock to the free list. - -void IndexSet::free_block(uint i) { - debug_only(check_watch("free block", i)); - assert(i < _max_blocks, "block index too large"); - BitBlock *block = _blocks[i]; - assert(block != &_empty_block, "cannot free the empty block"); - block->set_next((IndexSet::BitBlock*)Compile::current()->indexSet_free_block_list()); - Compile::current()->set_indexSet_free_block_list(block); - set_block(i,&_empty_block); -} - -//------------------------------lrg_union-------------------------------------- -// Compute the union of all elements of one and two which interfere with -// the RegMask mask. If the degree of the union becomes exceeds -// fail_degree, the union bails out. The underlying set is cleared before -// the union is performed. - -uint IndexSet::lrg_union(uint lr1, uint lr2, - const uint fail_degree, - const PhaseIFG *ifg, - const RegMask &mask ) { - IndexSet *one = ifg->neighbors(lr1); - IndexSet *two = ifg->neighbors(lr2); - LRG &lrg1 = ifg->lrgs(lr1); - LRG &lrg2 = ifg->lrgs(lr2); -#ifdef ASSERT - assert(_max_elements == one->_max_elements, "max element mismatch"); - check_watch("union destination"); - one->check_watch("union source"); - two->check_watch("union source"); -#endif - - // Compute the degree of the combined live-range. The combined - // live-range has the union of the original live-ranges' neighbors set as - // well as the neighbors of all intermediate copies, minus those neighbors - // that can not use the intersected allowed-register-set. - - // Copy the larger set. Insert the smaller set into the larger. - if (two->count() > one->count()) { - IndexSet *temp = one; - one = two; - two = temp; - } - - clear(); - - // Used to compute degree of register-only interferences. Infinite-stack - // neighbors do not alter colorability, as they can always color to some - // other color. (A variant of the Briggs assertion) - uint reg_degree = 0; - - uint element; - // Load up the combined interference set with the neighbors of one - IndexSetIterator elements(one); - while ((element = elements.next()) != 0) { - LRG &lrg = ifg->lrgs(element); - if (mask.overlap(lrg.mask())) { - insert(element); - if( !lrg.mask().is_AllStack() ) { - reg_degree += lrg1.compute_degree(lrg); - if( reg_degree >= fail_degree ) return reg_degree; - } else { - // !!!!! Danger! No update to reg_degree despite having a neighbor. - // A variant of the Briggs assertion. - // Not needed if I simplify during coalesce, ala George/Appel. - assert( lrg.lo_degree(), "" ); - } - } - } - // Add neighbors of two as well - IndexSetIterator elements2(two); - while ((element = elements2.next()) != 0) { - LRG &lrg = ifg->lrgs(element); - if (mask.overlap(lrg.mask())) { - if (insert(element)) { - if( !lrg.mask().is_AllStack() ) { - reg_degree += lrg2.compute_degree(lrg); - if( reg_degree >= fail_degree ) return reg_degree; - } else { - // !!!!! Danger! No update to reg_degree despite having a neighbor. - // A variant of the Briggs assertion. - // Not needed if I simplify during coalesce, ala George/Appel. - assert( lrg.lo_degree(), "" ); - } - } - } - } - - return reg_degree; -} - -//---------------------------- IndexSet() ----------------------------- -// A deep copy constructor. This is used when you need a scratch copy of this set. - -IndexSet::IndexSet (IndexSet *set) { -#ifdef ASSERT - _serial_number = _serial_count++; - set->check_watch("copied", _serial_number); - check_watch("initialized by copy", set->_serial_number); - _max_elements = set->_max_elements; -#endif - _count = set->_count; - _max_blocks = set->_max_blocks; - if (_max_blocks <= preallocated_block_list_size) { - _blocks = _preallocated_block_list; - } else { - _blocks = - (IndexSet::BitBlock**) arena()->Amalloc_4(sizeof(IndexSet::BitBlock**) * _max_blocks); - } - for (uint i = 0; i < _max_blocks; i++) { - BitBlock *block = set->_blocks[i]; - if (block == &_empty_block) { - set_block(i, &_empty_block); - } else { - BitBlock *new_block = alloc_block(); - memcpy(new_block->words(), block->words(), sizeof(uint32_t) * words_per_block); - set_block(i, new_block); - } - } -} - -//---------------------------- IndexSet::initialize() ----------------------------- -// Prepare an IndexSet for use. - -void IndexSet::initialize(uint max_elements) { -#ifdef ASSERT - _serial_number = _serial_count++; - check_watch("initialized", max_elements); - _max_elements = max_elements; -#endif - _count = 0; - _max_blocks = (max_elements + bits_per_block - 1) / bits_per_block; - - if (_max_blocks <= preallocated_block_list_size) { - _blocks = _preallocated_block_list; - } else { - _blocks = (IndexSet::BitBlock**) arena()->Amalloc_4(sizeof(IndexSet::BitBlock**) * _max_blocks); - } - for (uint i = 0; i < _max_blocks; i++) { - set_block(i, &_empty_block); - } -} - -//---------------------------- IndexSet::initialize()------------------------------ -// Prepare an IndexSet for use. If it needs to allocate its _blocks array, it does -// so from the Arena passed as a parameter. BitBlock allocation is still done from -// the static Arena which was set with reset_memory(). - -void IndexSet::initialize(uint max_elements, Arena *arena) { -#ifdef ASSERT - _serial_number = _serial_count++; - check_watch("initialized2", max_elements); - _max_elements = max_elements; -#endif // ASSERT - _count = 0; - _max_blocks = (max_elements + bits_per_block - 1) / bits_per_block; - - if (_max_blocks <= preallocated_block_list_size) { - _blocks = _preallocated_block_list; - } else { - _blocks = (IndexSet::BitBlock**) arena->Amalloc_4(sizeof(IndexSet::BitBlock**) * _max_blocks); - } - for (uint i = 0; i < _max_blocks; i++) { - set_block(i, &_empty_block); - } -} - -//---------------------------- IndexSet::swap() ----------------------------- -// Exchange two IndexSets. - -void IndexSet::swap(IndexSet *set) { -#ifdef ASSERT - assert(_max_elements == set->_max_elements, "must have same universe size to swap"); - check_watch("swap", set->_serial_number); - set->check_watch("swap", _serial_number); -#endif - - for (uint i = 0; i < _max_blocks; i++) { - BitBlock *temp = _blocks[i]; - set_block(i, set->_blocks[i]); - set->set_block(i, temp); - } - uint temp = _count; - _count = set->_count; - set->_count = temp; -} //---------------------------- IndexSet::dump() ----------------------------- // Print this set. Used for debugging. #ifndef PRODUCT -void IndexSet::dump() const { +void IndexSet::dump() { IndexSetIterator elements(this); tty->print("{"); @@ -385,193 +40,3 @@ tty->print_cr("}"); } #endif - -#ifdef ASSERT -//---------------------------- IndexSet::tally_iteration_statistics() ----------------------------- -// Update block/bit counts to reflect that this set has been iterated over. - -void IndexSet::tally_iteration_statistics() const { - inc_stat_counter(&_total_bits, count()); - - for (uint i = 0; i < _max_blocks; i++) { - if (_blocks[i] != &_empty_block) { - inc_stat_counter(&_total_used_blocks, 1); - } else { - inc_stat_counter(&_total_unused_blocks, 1); - } - } -} - -//---------------------------- IndexSet::print_statistics() ----------------------------- -// Print statistics about IndexSet usage. - -void IndexSet::print_statistics() { - julong total_blocks = _total_used_blocks + _total_unused_blocks; - tty->print_cr ("Accumulated IndexSet usage statistics:"); - tty->print_cr ("--------------------------------------"); - tty->print_cr (" Iteration:"); - tty->print_cr (" blocks visited: " UINT64_FORMAT, total_blocks); - tty->print_cr (" blocks empty: %4.2f%%", 100.0*(double)_total_unused_blocks/total_blocks); - tty->print_cr (" bit density (bits/used blocks): %4.2f", (double)_total_bits/_total_used_blocks); - tty->print_cr (" bit density (bits/all blocks): %4.2f", (double)_total_bits/total_blocks); - tty->print_cr (" Allocation:"); - tty->print_cr (" blocks allocated: " UINT64_FORMAT, _alloc_new); - tty->print_cr (" blocks used/reused: " UINT64_FORMAT, _alloc_total); -} - -//---------------------------- IndexSet::verify() ----------------------------- -// Expensive test of IndexSet sanity. Ensure that the count agrees with the -// number of bits in the blocks. Make sure the iterator is seeing all elements -// of the set. Meant for use during development. - -void IndexSet::verify() const { - assert(!member(0), "zero cannot be a member"); - uint count = 0; - uint i; - for (i = 1; i < _max_elements; i++) { - if (member(i)) { - count++; - assert(count <= _count, "_count is messed up"); - } - } - - IndexSetIterator elements(this); - count = 0; - while ((i = elements.next()) != 0) { - count++; - assert(member(i), "returned a non member"); - assert(count <= _count, "iterator returned wrong number of elements"); - } -} -#endif - -//---------------------------- IndexSetIterator() ----------------------------- -// Create an iterator for a set. If empty blocks are detected when iterating -// over the set, these blocks are replaced. - -IndexSetIterator::IndexSetIterator(IndexSet *set) { -#ifdef ASSERT - if (CollectIndexSetStatistics) { - set->tally_iteration_statistics(); - } - set->check_watch("traversed", set->count()); -#endif - if (set->is_empty()) { - _current = 0; - _next_word = IndexSet::words_per_block; - _next_block = 1; - _max_blocks = 1; - - // We don't need the following values when we iterate over an empty set. - // The commented out code is left here to document that the omission - // is intentional. - // - //_value = 0; - //_words = NULL; - //_blocks = NULL; - //_set = NULL; - } else { - _current = 0; - _value = 0; - _next_block = 0; - _next_word = IndexSet::words_per_block; - - _max_blocks = set->_max_blocks; - _words = NULL; - _blocks = set->_blocks; - _set = set; - } -} - -//---------------------------- IndexSetIterator(const) ----------------------------- -// Iterate over a constant IndexSet. - -IndexSetIterator::IndexSetIterator(const IndexSet *set) { -#ifdef ASSERT - if (CollectIndexSetStatistics) { - set->tally_iteration_statistics(); - } - // We don't call check_watch from here to avoid bad recursion. - // set->check_watch("traversed const", set->count()); -#endif - if (set->is_empty()) { - _current = 0; - _next_word = IndexSet::words_per_block; - _next_block = 1; - _max_blocks = 1; - - // We don't need the following values when we iterate over an empty set. - // The commented out code is left here to document that the omission - // is intentional. - // - //_value = 0; - //_words = NULL; - //_blocks = NULL; - //_set = NULL; - } else { - _current = 0; - _value = 0; - _next_block = 0; - _next_word = IndexSet::words_per_block; - - _max_blocks = set->_max_blocks; - _words = NULL; - _blocks = set->_blocks; - _set = NULL; - } -} - -//---------------------------- List16Iterator::advance_and_next() ----------------------------- -// Advance to the next non-empty word in the set being iterated over. Return the next element -// if there is one. If we are done, return 0. This method is called from the next() method -// when it gets done with a word. - -uint IndexSetIterator::advance_and_next() { - // See if there is another non-empty word in the current block. - for (uint wi = _next_word; wi < (unsigned)IndexSet::words_per_block; wi++) { - if (_words[wi] != 0) { - // Found a non-empty word. - _value = ((_next_block - 1) * IndexSet::bits_per_block) + (wi * IndexSet::bits_per_word); - _current = _words[wi]; - - _next_word = wi+1; - - return next(); - } - } - - // We ran out of words in the current block. Advance to next non-empty block. - for (uint bi = _next_block; bi < _max_blocks; bi++) { - if (_blocks[bi] != &IndexSet::_empty_block) { - // Found a non-empty block. - - _words = _blocks[bi]->words(); - for (uint wi = 0; wi < (unsigned)IndexSet::words_per_block; wi++) { - if (_words[wi] != 0) { - // Found a non-empty word. - _value = (bi * IndexSet::bits_per_block) + (wi * IndexSet::bits_per_word); - _current = _words[wi]; - - _next_block = bi+1; - _next_word = wi+1; - - return next(); - } - } - - // All of the words in the block were empty. Replace - // the block with the empty block. - if (_set) { - _set->free_block(bi); - } - } - } - - // These assignments make redundant calls to next on a finished iterator - // faster. Probably not necessary. - _next_block = _max_blocks; - _next_word = IndexSet::words_per_block; - - // No more words. - return 0; -} --- old/src/share/vm/opto/indexSet.hpp 2014-11-06 00:05:09.382893843 +0300 +++ new/src/share/vm/opto/indexSet.hpp 2014-11-06 00:05:09.330893842 +0300 @@ -35,357 +35,90 @@ // during register allocation. //-------------------------------- class IndexSet ---------------------------- -// An IndexSet is a piece-wise bitvector. At the top level, we have an array -// of pointers to bitvector chunks called BitBlocks. Each BitBlock has a fixed -// size and is allocated from a shared free list. The bits which are set in -// each BitBlock correspond to the elements of the set. +// An IndexSet is an adapter for high-performance BitMap implementation in +// VM utility classes. See JDK-8059461 for performance investigation. class IndexSet : public ResourceObj { friend class IndexSetIterator; - public: - // When we allocate an IndexSet, it starts off with an array of top level block - // pointers of a set length. This size is intended to be large enough for the - // majority of IndexSets. In the cases when this size is not large enough, - // a separately allocated array is used. - - // The length of the preallocated top level block array - enum { preallocated_block_list_size = 16 }; - - // Elements of a IndexSet get decomposed into three fields. The highest order - // bits are the block index, which tell which high level block holds the element. - // Within that block, the word index indicates which word holds the element. - // Finally, the bit index determines which single bit within that word indicates - // membership of the element in the set. - - // The lengths of the index bitfields - enum { bit_index_length = 5, - word_index_length = 3, - block_index_length = 8 // not used - }; - - // Derived constants used for manipulating the index bitfields - enum { - bit_index_offset = 0, // not used - word_index_offset = bit_index_length, - block_index_offset = bit_index_length + word_index_length, - - bits_per_word = 1 << bit_index_length, - words_per_block = 1 << word_index_length, - bits_per_block = bits_per_word * words_per_block, - - bit_index_mask = right_n_bits(bit_index_length), - word_index_mask = right_n_bits(word_index_length) - }; - - // These routines are used for extracting the block, word, and bit index - // from an element. - static uint get_block_index(uint element) { - return element >> block_index_offset; - } - static uint get_word_index(uint element) { - return mask_bits(element >> word_index_offset,word_index_mask); - } - static uint get_bit_index(uint element) { - return mask_bits(element,bit_index_mask); - } - - //------------------------------ class BitBlock ---------------------------- - // The BitBlock class is a segment of a bitvector set. - - class BitBlock : public ResourceObj { - friend class IndexSetIterator; - friend class IndexSet; - - private: - // All of BitBlocks fields and methods are declared private. We limit - // access to IndexSet and IndexSetIterator. - - // A BitBlock is composed of some number of 32 bit words. When a BitBlock - // is not in use by any IndexSet, it is stored on a free list. The next field - // is used by IndexSet to mainting this free list. - - union { - uint32_t _words[words_per_block]; - BitBlock *_next; - } _data; - - // accessors - uint32_t* words() { return _data._words; } - void set_next(BitBlock *next) { _data._next = next; } - BitBlock *next() { return _data._next; } - - // Operations. A BitBlock supports four simple operations, - // clear(), member(), insert(), and remove(). These methods do - // not assume that the block index has been masked out. - - void clear() { - memset(words(), 0, sizeof(uint32_t) * words_per_block); - } - - bool member(uint element) { - uint word_index = IndexSet::get_word_index(element); - uint bit_index = IndexSet::get_bit_index(element); - - return ((words()[word_index] & (uint32_t)(0x1 << bit_index)) != 0); - } - - bool insert(uint element) { - uint word_index = IndexSet::get_word_index(element); - uint bit_index = IndexSet::get_bit_index(element); - - uint32_t bit = (0x1 << bit_index); - uint32_t before = words()[word_index]; - words()[word_index] = before | bit; - return ((before & bit) != 0); - } - - bool remove(uint element) { - uint word_index = IndexSet::get_word_index(element); - uint bit_index = IndexSet::get_bit_index(element); - - uint32_t bit = (0x1 << bit_index); - uint32_t before = words()[word_index]; - words()[word_index] = before & ~bit; - return ((before & bit) != 0); - } - }; - - //-------------------------- BitBlock allocation --------------------------- - private: - - // All IndexSets share an arena from which they allocate BitBlocks. Unused - // BitBlocks are placed on a free list. - - // The number of BitBlocks to allocate at a time - enum { bitblock_alloc_chunk_size = 50 }; - - static Arena *arena() { return Compile::current()->indexSet_arena(); } - - static void populate_free_list(); - - public: - - // Invalidate the current free BitBlock list and begin allocation - // from a new arena. It is essential that this method is called whenever - // the Arena being used for BitBlock allocation is reset. - static void reset_memory(Compile* compile, Arena *arena) { - compile->set_indexSet_free_block_list(NULL); - compile->set_indexSet_arena(arena); - - // This should probably be done in a static initializer - _empty_block.clear(); - } - - private: - friend class BitBlock; - // A distinguished BitBlock which always remains empty. When a new IndexSet is - // created, all of its top level BitBlock pointers are initialized to point to - // this. - static BitBlock _empty_block; - //-------------------------- Members ------------------------------------------ + private: - // The number of elements in the set - uint _count; - - // Our top level array of bitvector segments - BitBlock **_blocks; - - BitBlock *_preallocated_block_list[preallocated_block_list_size]; - - // The number of top level array entries in use - uint _max_blocks; - - // Our assertions need to know the maximum number allowed in the set -#ifdef ASSERT - uint _max_elements; -#endif + // Underlying BitMap where we store the values + BitMap _map; - // The next IndexSet on the free list (not used at same time as count) + // The next IndexSet on the free list IndexSet *_next; - public: //-------------------------- Free list operations ------------------------------ // Individual IndexSets can be placed on a free list. This is done in PhaseLive. + public: IndexSet *next() { -#ifdef ASSERT - if( VerifyOpto ) { - check_watch("removed from free list?", ((_next == NULL) ? 0 : _next->_serial_number)); - } -#endif return _next; } void set_next(IndexSet *next) { -#ifdef ASSERT - if( VerifyOpto ) { - check_watch("put on free list?", ((next == NULL) ? 0 : next->_serial_number)); - } -#endif _next = next; } - private: - //-------------------------- Utility methods ----------------------------------- - - // Get the block which holds element - BitBlock *get_block_containing(uint element) const { - assert(element < _max_elements, "element out of bounds"); - return _blocks[get_block_index(element)]; - } - - // Set a block in the top level array - void set_block(uint index, BitBlock *block) { -#ifdef ASSERT - if( VerifyOpto ) - check_watch("set block", index); -#endif - _blocks[index] = block; - } - - // Get a BitBlock from the free list - BitBlock *alloc_block(); - - // Get a BitBlock from the free list and place it in the top level array - BitBlock *alloc_block_containing(uint element); - - // Free a block from the top level array, placing it on the free BitBlock list - void free_block(uint i); - public: //-------------------------- Primitive set operations -------------------------- void clear() { -#ifdef ASSERT - if( VerifyOpto ) - check_watch("clear"); -#endif - _count = 0; - for (uint i = 0; i < _max_blocks; i++) { - BitBlock *block = _blocks[i]; - if (block != &_empty_block) { - free_block(i); - } - } + _map.clear(); } - uint count() const { return _count; } + uint count() const { + return _map.count_one_bits(); + } - bool is_empty() const { return _count == 0; } + bool is_empty() const { + return _map.is_empty(); + } bool member(uint element) const { - return get_block_containing(element)->member(element); + return _map.at(element); } bool insert(uint element) { -#ifdef ASSERT - if( VerifyOpto ) - check_watch("insert", element); -#endif if (element == 0) { return 0; } - BitBlock *block = get_block_containing(element); - if (block == &_empty_block) { - block = alloc_block_containing(element); - } - bool present = block->insert(element); - if (!present) { - _count++; - } - return !present; + return _map.set_bit_with_result(element); } bool remove(uint element) { -#ifdef ASSERT - if( VerifyOpto ) - check_watch("remove", element); -#endif - - BitBlock *block = get_block_containing(element); - bool present = block->remove(element); - if (present) { - _count--; - } - return present; + return _map.clear_bit_with_result(element); } - //-------------------------- Compound set operations ------------------------ - // Compute the union of all elements of one and two which interfere - // with the RegMask mask. If the degree of the union becomes - // exceeds fail_degree, the union bails out. The underlying set is - // cleared before the union is performed. - uint lrg_union(uint lr1, uint lr2, - const uint fail_degree, - const class PhaseIFG *ifg, - const RegMask &mask); - - //------------------------- Construction, initialization ----------------------- IndexSet() {} // This constructor is used for making a deep copy of a IndexSet. - IndexSet(IndexSet *set); + IndexSet(IndexSet *set) { + _map = BitMap(set->_map.size()); + _map.set_from(set->_map); + }; // Perform initialization on a IndexSet - void initialize(uint max_element); - - // Initialize a IndexSet. If the top level BitBlock array needs to be - // allocated, do it from the proffered arena. BitBlocks are still allocated - // from the static Arena member. - void initialize(uint max_element, Arena *arena); - - // Exchange two sets - void swap(IndexSet *set); - - //-------------------------- Debugging and statistics -------------------------- - -#ifndef PRODUCT - // Output a IndexSet for debugging - void dump() const; -#endif + void initialize(uint max_element) { + _map = BitMap(max_element); + }; -#ifdef ASSERT - void tally_iteration_statistics() const; + // Initialize a IndexSet in resource arena. + void initialize_in_resource_arena(uint max_element) { + _map = BitMap(max_element, true); + }; - // BitBlock allocation statistics - static julong _alloc_new; - static julong _alloc_total; - - // Block density statistics - static julong _total_bits; - static julong _total_used_blocks; - static julong _total_unused_blocks; - - // Sanity tests - void verify() const; - - static int _serial_count; - int _serial_number; - - // Check to see if the serial number of the current set is the one we're tracing. - // If it is, print a message. - void check_watch(const char *operation, uint operand) const { - if (IndexSetWatch != 0) { - if (IndexSetWatch == -1 || _serial_number == IndexSetWatch) { - tty->print_cr("IndexSet %d : %s ( %d )", _serial_number, operation, operand); - } - } + // Overwrite current IndexSet with another set + void set_from(IndexSet *set) { + _map.set_from(set->_map); } - void check_watch(const char *operation) const { - if (IndexSetWatch != 0) { - if (IndexSetWatch == -1 || _serial_number == IndexSetWatch) { - tty->print_cr("IndexSet %d : %s", _serial_number, operation); - } - } - } - - public: - static void print_statistics(); +#ifndef PRODUCT + void dump(); #endif }; @@ -393,79 +126,18 @@ //-------------------------------- class IndexSetIterator -------------------- // An iterator for IndexSets. -class IndexSetIterator VALUE_OBJ_CLASS_SPEC { +class IndexSetIterator { friend class IndexSet; - public: - - // We walk over the bits in a word in chunks of size window_size. - enum { window_size = 5, - window_mask = right_n_bits(window_size), - table_size = (1 << window_size) }; - - // For an integer of length window_size, what is the first set bit? - static const uint8_t _first_bit[table_size]; - - // For an integer of length window_size, what is the second set bit? - static const uint8_t _second_bit[table_size]; - - private: - // The current word we are inspecting - uint32_t _current; - - // What element number are we currently on? - uint _value; - - // The index of the next word we will inspect - uint _next_word; - - // A pointer to the contents of the current block - uint32_t *_words; - - // The index of the next block we will inspect - uint _next_block; - - // A pointer to the blocks in our set - IndexSet::BitBlock **_blocks; - - // The number of blocks in the set - uint _max_blocks; - - // If the iterator was created from a non-const set, we replace - // non-canonical empty blocks with the _empty_block pointer. If - // _set is NULL, we do no replacement. - IndexSet *_set; - - // Advance to the next non-empty word and return the next - // element in the set. - uint advance_and_next(); - + BitMapIterator iter; public: + IndexSetIterator(IndexSet *set) : iter(&(set->_map)) {} - // If an iterator is built from a constant set then empty blocks - // are not canonicalized. - IndexSetIterator(IndexSet *set); - IndexSetIterator(const IndexSet *set); - - // Return the next element of the set. Return 0 when done. - uint next() { - uint current = _current; - if (current != 0) { - uint value = _value; - while (mask_bits(current,window_mask) == 0) { - current >>= window_size; - value += window_size; - } - - uint advance = _second_bit[mask_bits(current,window_mask)]; - _current = current >> advance; - _value = value + advance; - return value + _first_bit[mask_bits(current,window_mask)]; - } else { - return advance_and_next(); - } + inline uint next() { + return iter.next(); } + }; #endif // SHARE_VM_OPTO_INDEXSET_HPP --- old/src/share/vm/opto/live.cpp 2014-11-06 00:05:09.562893847 +0300 +++ new/src/share/vm/opto/live.cpp 2014-11-06 00:05:09.510893845 +0300 @@ -187,14 +187,11 @@ IndexSet *f = _free_IndexSet; if( !f ) { f = new IndexSet; -// f->set_arena(Thread::current()->resource_area()); - f->initialize(_maxlrg, Thread::current()->resource_area()); + f->initialize_in_resource_arena(_maxlrg); } else { // Pull from free list _free_IndexSet = f->next(); - //f->_cnt = 0; // Reset to empty -// f->set_arena(Thread::current()->resource_area()); - f->initialize(_maxlrg, Thread::current()->resource_area()); + f->initialize_in_resource_arena(_maxlrg); } return f; } --- old/src/share/vm/runtime/globals.hpp 2014-11-06 00:05:09.742893850 +0300 +++ new/src/share/vm/runtime/globals.hpp 2014-11-06 00:05:09.686893849 +0300 @@ -2740,9 +2740,6 @@ notproduct(bool, TraceLivenessQuery, false, \ "Trace queries of liveness analysis information") \ \ - notproduct(bool, CollectIndexSetStatistics, false, \ - "Collect information about IndexSets") \ - \ develop(bool, UseLoopSafepoints, true, \ "Generate Safepoint nodes in every loop") \ \ --- old/src/share/vm/runtime/java.cpp 2014-11-06 00:05:09.942893855 +0300 +++ new/src/share/vm/runtime/java.cpp 2014-11-06 00:05:09.890893854 +0300 @@ -260,11 +260,6 @@ if (TimeLivenessAnalysis) { MethodLiveness::print_times(); } -#ifdef ASSERT - if (CollectIndexSetStatistics) { - IndexSet::print_statistics(); - } -#endif // ASSERT #endif // COMPILER2 if (CountCompiledCalls) { print_method_invocation_histogram(); --- old/src/share/vm/utilities/bitMap.cpp 2014-11-06 00:05:10.118893859 +0300 +++ new/src/share/vm/utilities/bitMap.cpp 2014-11-06 00:05:10.066893857 +0300 @@ -612,3 +612,87 @@ , _map(size_in_slots * bits_per_slot) { } + +// What is the first set bit in a 8 bit integer? +const uint8_t BitMapIterator::_first_bit[256] = { + 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 +}; + +// What is the second set bit in a 8 bit integer? +const uint8_t BitMapIterator::_second_bit[256] = { + 8, 8, 8, 1, 8, 2, 2, 1, 8, 3, 3, 1, 3, 2, 2, 1, + 8, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 8, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 8, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, + 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 8, 7, 7, 1, 7, 2, 2, 1, 7, 3, 3, 1, 3, 2, 2, 1, + 7, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 7, 6, 6, 1, 6, 2, 2, 1, 6, 3, 3, 1, 3, 2, 2, 1, + 6, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1, + 6, 5, 5, 1, 5, 2, 2, 1, 5, 3, 3, 1, 3, 2, 2, 1, + 5, 4, 4, 1, 4, 2, 2, 1, 4, 3, 3, 1, 3, 2, 2, 1 +}; + +BitMapIterator::BitMapIterator(BitMap* bs) { + _bs = bs; + _current = 0; + _value = 0; + _last_word = -1; + _max_word = _bs->size_in_words(); +} + +uint BitMapIterator::next() { + bm_word_t current = _current; + if (current != 0) { + idx_t value = _value; + bm_word_t masked = mask_bits(current,window_mask); + while (masked == 0) { + current >>= window_size; + value += window_size; + masked = mask_bits(current,window_mask); + } + + uint advance = _second_bit[masked]; + _current = current >> advance; + _value = value + advance; + + uint val = value + _first_bit[masked]; + assert (val != 0, "can not return zero for existing offset"); + assert (val < _bs->_size, "returned index is out of bounds"); + assert (_bs->at(val), "returned index is not found in the map"); + return val; + } else { + bm_word_t* map = _bs->_map; + for (idx_t i = _last_word + 1; i < _max_word; i++) { + bm_word_t w = map[i]; + if (w != 0) { + _current = w; + _value = i * BitsPerWord; + _last_word = i; + return next(); + }; + } + _last_word = _max_word; + return 0; + } +} --- old/src/share/vm/utilities/bitMap.hpp 2014-11-06 00:05:10.298893863 +0300 +++ new/src/share/vm/utilities/bitMap.hpp 2014-11-06 00:05:10.246893861 +0300 @@ -36,6 +36,7 @@ class BitMap VALUE_OBJ_CLASS_SPEC { friend class BitMap2D; + friend class BitMapIterator; public: typedef size_t idx_t; // Type used for bit and word indices. @@ -115,7 +116,7 @@ // Constructs a bitmap with no map, and size 0. BitMap() : _map(NULL), _size(0), _map_allocator(false) {} - + // Constructs a bitmap with the given map and size. BitMap(bm_word_t* map, idx_t size_in_bits); @@ -164,6 +165,10 @@ inline void set_bit(idx_t bit); inline void clear_bit(idx_t bit); + // Set or clear the specified bit with result + inline bool set_bit_with_result(idx_t bit); + inline bool clear_bit_with_result(idx_t bit); + // Atomically set or clear the specified bit. inline bool par_set_bit(idx_t bit); inline bool par_clear_bit(idx_t bit); @@ -272,6 +277,39 @@ #endif }; +class BitMapIterator VALUE_OBJ_CLASS_SPEC { + friend class BitMap; + + typedef BitMap::idx_t idx_t; // Type used for bit and word indices. + typedef BitMap::bm_word_t bm_word_t; // Element type of array that + // represents the bitmap. + + // We walk over the bits in a word in chunks of size window_size. + enum { window_size = 8, + window_mask = right_n_bits(window_size), + table_size = (1 << window_size) }; + + // For an integer of length window_size, what is the first set bit? + static const uint8_t _first_bit[table_size]; + + // For an integer of length window_size, what is the first set bit? + static const uint8_t _second_bit[table_size]; + + + BitMap* _bs; + bm_word_t _current; + idx_t _value; + idx_t _last_word; + idx_t _max_word; + + public: + BitMapIterator(BitMap* bs); + + // Return the next element of the set. Return 0 when done. + + uint next(); +}; + // Convenience class wrapping BitMap which provides multiple bits per slot. class BitMap2D VALUE_OBJ_CLASS_SPEC { public: --- old/src/share/vm/utilities/bitMap.inline.hpp 2014-11-06 00:05:10.474893866 +0300 +++ new/src/share/vm/utilities/bitMap.inline.hpp 2014-11-06 00:05:10.422893865 +0300 @@ -50,6 +50,22 @@ *word_addr(bit) &= ~bit_mask(bit); } +inline bool BitMap::set_bit_with_result(idx_t bit) { + verify_index(bit); + bm_word_t old_val = *word_addr(bit); + bm_word_t new_val = old_val | bit_mask(bit); + *word_addr(bit) = new_val; + return (old_val != new_val); +} + +inline bool BitMap::clear_bit_with_result(idx_t bit) { + verify_index(bit); + bm_word_t old_val = *word_addr(bit); + bm_word_t new_val = old_val & ~bit_mask(bit); + *word_addr(bit) = new_val; + return (old_val != new_val); +} + inline bool BitMap::par_set_bit(idx_t bit) { verify_index(bit); volatile bm_word_t* const addr = word_addr(bit);