Skip to content

Commit 008c5eb

Browse files
author
Kim Barrett
committed
8303621: BitMap::iterate should support lambdas and other function objects
Reviewed-by: aboldtch, tschatzl, stefank
1 parent 52d3008 commit 008c5eb

File tree

5 files changed

+302
-42
lines changed

5 files changed

+302
-42
lines changed

src/hotspot/share/c1/c1_LinearScan.cpp

+23-19
Original file line numberDiff line numberDiff line change
@@ -1329,10 +1329,9 @@ void LinearScan::build_intervals() {
13291329
assert(block_to == instructions->at(instructions->length() - 1)->id(), "must be");
13301330

13311331
// Update intervals for registers live at the end of this block;
1332-
ResourceBitMap live = block->live_out();
1333-
int size = (int)live.size();
1334-
for (int number = (int)live.get_next_one_offset(0, size); number < size; number = (int)live.get_next_one_offset(number + 1, size)) {
1335-
assert(live.at(number), "should not stop here otherwise");
1332+
ResourceBitMap& live = block->live_out();
1333+
auto updater = [&](BitMap::idx_t index) {
1334+
int number = static_cast<int>(index);
13361335
assert(number >= LIR_Opr::vreg_base, "fixed intervals must not be live on block bounds");
13371336
TRACE_LINEAR_SCAN(2, tty->print_cr("live in %d to %d", number, block_to + 2));
13381337

@@ -1347,7 +1346,8 @@ void LinearScan::build_intervals() {
13471346
is_interval_in_loop(number, block->loop_index())) {
13481347
interval_at(number)->add_use_pos(block_to + 1, loopEndMarker);
13491348
}
1350-
}
1349+
};
1350+
live.iterate(updater);
13511351

13521352
// iterate all instructions of the block in reverse order.
13531353
// skip the first instruction because it is always a label
@@ -1738,11 +1738,10 @@ Interval* LinearScan::interval_at_op_id(int reg_num, int op_id) {
17381738
void LinearScan::resolve_collect_mappings(BlockBegin* from_block, BlockBegin* to_block, MoveResolver &move_resolver) {
17391739
DEBUG_ONLY(move_resolver.check_empty());
17401740

1741-
const int size = live_set_size();
1742-
const ResourceBitMap live_at_edge = to_block->live_in();
1743-
17441741
// visit all registers where the live_at_edge bit is set
1745-
for (int r = (int)live_at_edge.get_next_one_offset(0, size); r < size; r = (int)live_at_edge.get_next_one_offset(r + 1, size)) {
1742+
const ResourceBitMap& live_at_edge = to_block->live_in();
1743+
auto visitor = [&](BitMap::idx_t index) {
1744+
int r = static_cast<int>(index);
17461745
assert(r < num_virtual_regs(), "live information set for not existing interval");
17471746
assert(from_block->live_out().at(r) && to_block->live_in().at(r), "interval not live at this edge");
17481747

@@ -1753,7 +1752,8 @@ void LinearScan::resolve_collect_mappings(BlockBegin* from_block, BlockBegin* to
17531752
// need to insert move instruction
17541753
move_resolver.add_mapping(from_interval, to_interval);
17551754
}
1756-
}
1755+
};
1756+
live_at_edge.iterate(visitor, 0, live_set_size());
17571757
}
17581758

17591759

@@ -1913,10 +1913,11 @@ void LinearScan::resolve_exception_entry(BlockBegin* block, MoveResolver &move_r
19131913
DEBUG_ONLY(move_resolver.check_empty());
19141914

19151915
// visit all registers where the live_in bit is set
1916-
int size = live_set_size();
1917-
for (int r = (int)block->live_in().get_next_one_offset(0, size); r < size; r = (int)block->live_in().get_next_one_offset(r + 1, size)) {
1916+
auto resolver = [&](BitMap::idx_t index) {
1917+
int r = static_cast<int>(index);
19181918
resolve_exception_entry(block, r, move_resolver);
1919-
}
1919+
};
1920+
block->live_in().iterate(resolver, 0, live_set_size());
19201921

19211922
// the live_in bits are not set for phi functions of the xhandler entry, so iterate them separately
19221923
for_each_phi_fun(block, phi,
@@ -1986,10 +1987,11 @@ void LinearScan::resolve_exception_edge(XHandler* handler, int throwing_op_id, M
19861987

19871988
// visit all registers where the live_in bit is set
19881989
BlockBegin* block = handler->entry_block();
1989-
int size = live_set_size();
1990-
for (int r = (int)block->live_in().get_next_one_offset(0, size); r < size; r = (int)block->live_in().get_next_one_offset(r + 1, size)) {
1990+
auto resolver = [&](BitMap::idx_t index) {
1991+
int r = static_cast<int>(index);
19911992
resolve_exception_edge(handler, throwing_op_id, r, NULL, move_resolver);
1992-
}
1993+
};
1994+
block->live_in().iterate(resolver, 0, live_set_size());
19931995

19941996
// the live_in bits are not set for phi functions of the xhandler entry, so iterate them separately
19951997
for_each_phi_fun(block, phi,
@@ -3466,10 +3468,11 @@ void LinearScan::verify_constants() {
34663468

34673469
for (int i = 0; i < num_blocks; i++) {
34683470
BlockBegin* block = block_at(i);
3469-
ResourceBitMap live_at_edge = block->live_in();
3471+
ResourceBitMap& live_at_edge = block->live_in();
34703472

34713473
// visit all registers where the live_at_edge bit is set
3472-
for (int r = (int)live_at_edge.get_next_one_offset(0, size); r < size; r = (int)live_at_edge.get_next_one_offset(r + 1, size)) {
3474+
auto visitor = [&](BitMap::idx_t index) {
3475+
int r = static_cast<int>(index);
34733476
TRACE_LINEAR_SCAN(4, tty->print("checking interval %d of block B%d", r, block->block_id()));
34743477

34753478
Value value = gen()->instruction_for_vreg(r);
@@ -3478,7 +3481,8 @@ void LinearScan::verify_constants() {
34783481
assert(value->operand()->is_register() && value->operand()->is_virtual(), "value must have virtual operand");
34793482
assert(value->operand()->vreg_number() == r, "register number must match");
34803483
// TKR assert(value->as_Constant() == NULL || value->is_pinned(), "only pinned constants can be alive across block boundaries");
3481-
}
3484+
};
3485+
live_at_edge.iterate(visitor, 0, size);
34823486
}
34833487
}
34843488

src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,7 @@ inline G1AddCardResult G1CardSetBitMap::add(uint card_idx, size_t threshold, siz
249249
template <class CardVisitor>
250250
inline void G1CardSetBitMap::iterate(CardVisitor& found, size_t size_in_bits, uint offset) {
251251
BitMapView bm(_bits, size_in_bits);
252-
BitMap::idx_t idx = bm.get_next_one_offset(0);
253-
while (idx != size_in_bits) {
254-
found((offset | (uint)idx));
255-
idx = bm.get_next_one_offset(idx + 1);
256-
}
252+
bm.iterate([&](BitMap::idx_t idx) { found(offset | (uint)idx); });
257253
}
258254

259255
inline size_t G1CardSetBitMap::header_size_in_bytes() {

src/hotspot/share/utilities/bitMap.hpp

+34-13
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ class BitMap {
105105
static const bm_word_t find_ones_flip = 0;
106106
static const bm_word_t find_zeros_flip = ~(bm_word_t)0;
107107

108+
template<typename ReturnType> struct IterateInvoker;
109+
108110
// Threshold for performing small range operation, even when large range
109111
// operation was requested. Measured in words.
110112
static const size_t small_range_words = 32;
@@ -252,19 +254,38 @@ class BitMap {
252254
// Verify [beg,end) is a valid range, e.g. beg <= end <= size().
253255
void verify_range(idx_t beg, idx_t end) const NOT_DEBUG_RETURN;
254256

255-
// Iteration support. Applies the closure to the index for each set bit,
256-
// starting from the least index in the range to the greatest, in order.
257-
// The iteration terminates if the closure returns false. Returns true if
258-
// the iteration completed, false if terminated early because the closure
259-
// returned false. If the closure modifies the bitmap, modifications to
260-
// bits at indices greater than the current index will affect which further
261-
// indices the closure will be applied to.
262-
// precondition: beg and end form a valid range.
263-
template <class BitMapClosureType>
264-
bool iterate(BitMapClosureType* cl, idx_t beg, idx_t end);
265-
266-
template <class BitMapClosureType>
267-
bool iterate(BitMapClosureType* cl);
257+
// Applies an operation to the index of each set bit in [beg, end), in
258+
// increasing order.
259+
//
260+
// If i is an index of the bitmap, the operation is either
261+
// - function(i)
262+
// - cl->do_bit(i)
263+
// The result of an operation must be either void or convertible to bool.
264+
//
265+
// If an operation returns false then the iteration stops at that index.
266+
// The result of the iteration is true unless the iteration was stopped by
267+
// an operation returning false.
268+
//
269+
// If an operation modifies the bitmap, modifications to bits at indices
270+
// greater than the current index will affect which further indices the
271+
// operation will be applied to.
272+
//
273+
// precondition: beg and end form a valid range for the bitmap.
274+
template<typename Function>
275+
bool iterate(Function function, idx_t beg, idx_t end) const;
276+
277+
template<typename BitMapClosureType>
278+
bool iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const;
279+
280+
template<typename Function>
281+
bool iterate(Function function) const {
282+
return iterate(function, 0, size());
283+
}
284+
285+
template<typename BitMapClosureType>
286+
bool iterate(BitMapClosureType* cl) const {
287+
return iterate(cl, 0, size());
288+
}
268289

269290
// Looking for 1's and 0's at indices equal to or greater than "beg",
270291
// stopping if none has been found before "end", and returning

src/hotspot/share/utilities/bitMap.inline.hpp

+31-5
Original file line numberDiff line numberDiff line change
@@ -243,21 +243,47 @@ BitMap::get_next_one_offset_aligned_right(idx_t beg, idx_t end) const {
243243
return get_next_bit_impl<find_ones_flip, true>(beg, end);
244244
}
245245

246-
template <typename BitMapClosureType>
247-
inline bool BitMap::iterate(BitMapClosureType* cl, idx_t beg, idx_t end) {
246+
// IterateInvoker supports conditionally stopping iteration early. The
247+
// invoker is called with the function to apply to each set index, along with
248+
// the current index. If the function returns void then the invoker always
249+
// returns true, so no early stopping. Otherwise, the result of the function
250+
// is returned by the invoker. Iteration stops early if conversion of that
251+
// result to bool is false.
252+
253+
template<typename ReturnType>
254+
struct BitMap::IterateInvoker {
255+
template<typename Function>
256+
bool operator()(Function function, idx_t index) const {
257+
return function(index); // Stop early if converting to bool is false.
258+
}
259+
};
260+
261+
template<>
262+
struct BitMap::IterateInvoker<void> {
263+
template<typename Function>
264+
bool operator()(Function function, idx_t index) const {
265+
function(index); // Result is void.
266+
return true; // Never stop early.
267+
}
268+
};
269+
270+
template <typename Function>
271+
inline bool BitMap::iterate(Function function, idx_t beg, idx_t end) const {
272+
auto invoke = IterateInvoker<decltype(function(beg))>();
248273
for (idx_t index = beg; true; ++index) {
249274
index = get_next_one_offset(index, end);
250275
if (index >= end) {
251276
return true;
252-
} else if (!cl->do_bit(index)) {
277+
} else if (!invoke(function, index)) {
253278
return false;
254279
}
255280
}
256281
}
257282

258283
template <typename BitMapClosureType>
259-
inline bool BitMap::iterate(BitMapClosureType* cl) {
260-
return iterate(cl, 0, size());
284+
inline bool BitMap::iterate(BitMapClosureType* cl, idx_t beg, idx_t end) const {
285+
auto function = [&](idx_t index) { return cl->do_bit(index); };
286+
return iterate(function, beg, end);
261287
}
262288

263289
// Returns a bit mask for a range of bits [beg, end) within a single word. Each

0 commit comments

Comments
 (0)