Skip to content
This repository has been archived by the owner on Sep 19, 2023. It is now read-only.
/ jdk19 Public archive

Commit

Permalink
8289069: Very slow C1 arraycopy jcstress tests after JDK-8279886
Browse files Browse the repository at this point in the history
Reviewed-by: thartmann, kvn
  • Loading branch information
Igor Veresov committed Jun 28, 2022
1 parent c42b796 commit 9b7805e
Showing 1 changed file with 32 additions and 22 deletions.
54 changes: 32 additions & 22 deletions src/hotspot/share/c1/c1_GraphBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ class BlockListBuilder {
GrowableArray<ResourceBitMap> _loop_map; // caches the information if a block is contained in a loop
int _next_loop_index; // next free loop number
int _next_block_number; // for reverse postorder numbering of blocks
int _block_id_start;

int bit_number(int block_id) const { return block_id - _block_id_start; }
// accessors
Compilation* compilation() const { return _compilation; }
IRScope* scope() const { return _scope; }
Expand Down Expand Up @@ -122,6 +124,7 @@ BlockListBuilder::BlockListBuilder(Compilation* compilation, IRScope* scope, int
, _loop_map() // size not known yet
, _next_loop_index(0)
, _next_block_number(0)
, _block_id_start(0)
{
set_entries(osr_bci);
set_leaders();
Expand Down Expand Up @@ -384,11 +387,12 @@ void BlockListBuilder::set_leaders() {
void BlockListBuilder::mark_loops() {
ResourceMark rm;

_active.initialize(BlockBegin::number_of_blocks());
_visited.initialize(BlockBegin::number_of_blocks());
_loop_map = GrowableArray<ResourceBitMap>(BlockBegin::number_of_blocks(), BlockBegin::number_of_blocks(), ResourceBitMap());
for (int i = 0; i < BlockBegin::number_of_blocks(); i++) {
_loop_map.at(i).initialize(BlockBegin::number_of_blocks());
const int number_of_blocks = _blocks.length();
_active.initialize(number_of_blocks);
_visited.initialize(number_of_blocks);
_loop_map = GrowableArray<ResourceBitMap>(number_of_blocks, number_of_blocks, ResourceBitMap());
for (int i = 0; i < number_of_blocks; i++) {
_loop_map.at(i).initialize(number_of_blocks);
}
_next_loop_index = 0;
_next_block_number = _blocks.length();
Expand All @@ -401,12 +405,14 @@ void BlockListBuilder::mark_loops() {
// - The bit is then propagated for all the blocks in the loop after we exit them (post-order). There could be multiple bits
// of course in case of nested loops.
// - When we exit the loop header we remove that single bit and assign the real loop state for it.
// - Now, the tricky part here is how we detect irriducible loops. In the algorithm above the loop state bits
// - Now, the tricky part here is how we detect irreducible loops. In the algorithm above the loop state bits
// are propagated to the predecessors. If we encounter an irreducible loop (a loop with multiple heads) we would see
// a node with some loop bit set that would then propagate back and be never cleared because we would
// never go back through the original loop header. Therefore if there are any irreducible loops the bits in the states
// for these loops are going to propagate back to the root.
BitMap& loop_state = mark_loops(_bci2block->at(0), false);
BlockBegin* start = _bci2block->at(0);
_block_id_start = start->block_id();
BitMap& loop_state = mark_loops(start, false);
if (!loop_state.is_empty()) {
compilation()->set_has_irreducible_loops(true);
}
Expand All @@ -419,6 +425,8 @@ void BlockListBuilder::mark_loops() {
}

void BlockListBuilder::make_loop_header(BlockBegin* block) {
int block_id = block->block_id();
int block_bit = bit_number(block_id);
if (block->is_set(BlockBegin::exception_entry_flag)) {
// exception edges may look like loops but don't mark them as such
// since it screws up block ordering.
Expand All @@ -427,43 +435,45 @@ void BlockListBuilder::make_loop_header(BlockBegin* block) {
if (!block->is_set(BlockBegin::parser_loop_header_flag)) {
block->set(BlockBegin::parser_loop_header_flag);

assert(_loop_map.at(block->block_id()).is_empty(), "must not be set yet");
assert(0 <= _next_loop_index && _next_loop_index < BlockBegin::number_of_blocks(), "_next_loop_index is too large");
_loop_map.at(block->block_id()).set_bit(_next_loop_index++);
assert(_loop_map.at(block_bit).is_empty(), "must not be set yet");
assert(0 <= _next_loop_index && _next_loop_index < _loop_map.length(), "_next_loop_index is too large");
_loop_map.at(block_bit).set_bit(_next_loop_index++);
} else {
// block already marked as loop header
assert(_loop_map.at(block->block_id()).count_one_bits() == 1, "exactly one bit must be set");
assert(_loop_map.at(block_bit).count_one_bits() == 1, "exactly one bit must be set");
}
}

BitMap& BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) {
int block_id = block->block_id();
if (_visited.at(block_id)) {
if (_active.at(block_id)) {
int block_bit = bit_number(block_id);
if (_visited.at(block_bit)) {
if (_active.at(block_bit)) {
// reached block via backward branch
make_loop_header(block);
}
// return cached loop information for this block
return _loop_map.at(block_id);
return _loop_map.at(block_bit);
}

if (block->is_set(BlockBegin::subroutine_entry_flag)) {
in_subroutine = true;
}

// set active and visited bits before successors are processed
_visited.set_bit(block_id);
_active.set_bit(block_id);
_visited.set_bit(block_bit);
_active.set_bit(block_bit);

ResourceMark rm;
ResourceBitMap loop_state(BlockBegin::number_of_blocks());
ResourceBitMap loop_state(_loop_map.length());
for (int i = number_of_successors(block) - 1; i >= 0; i--) {
BlockBegin* sux = successor_at(block, i);
// recursively process all successors
loop_state.set_union(mark_loops(successor_at(block, i), in_subroutine));
loop_state.set_union(mark_loops(sux, in_subroutine));
}

// clear active-bit after all successors are processed
_active.clear_bit(block_id);
_active.clear_bit(block_bit);

// reverse-post-order numbering of all blocks
block->set_depth_first_number(_next_block_number);
Expand All @@ -476,15 +486,15 @@ BitMap& BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) {
}

if (block->is_set(BlockBegin::parser_loop_header_flag)) {
BitMap& header_loop_state = _loop_map.at(block_id);
BitMap& header_loop_state = _loop_map.at(block_bit);
assert(header_loop_state.count_one_bits() == 1, "exactly one bit must be set");
// remove the bit with the loop number for the state (header is outside of the loop)
loop_state.set_difference(header_loop_state);
}

// cache and return loop information for this block
_loop_map.at(block_id).set_from(loop_state);
return _loop_map.at(block_id);
_loop_map.at(block_bit).set_from(loop_state);
return _loop_map.at(block_bit);
}

inline int BlockListBuilder::number_of_successors(BlockBegin* block)
Expand Down

1 comment on commit 9b7805e

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.