Skip to content

Commit d70545d

Browse files
LudwikJaniukVladimir Kozlov
authored andcommitted
8258603: c1 IR::verify is expensive
Reviewed-by: chagedorn, kvn
1 parent 0a094d7 commit d70545d

File tree

4 files changed

+145
-35
lines changed

4 files changed

+145
-35
lines changed

src/hotspot/share/c1/c1_IR.cpp

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1263,21 +1263,36 @@ void IR::print(bool cfg_only, bool live_only) {
12631263
tty->print_cr("invalid IR");
12641264
}
12651265
}
1266+
#endif // PRODUCT
12661267

1268+
#ifdef ASSERT
12671269
class EndNotNullValidator : public BlockClosure {
12681270
public:
1269-
EndNotNullValidator(IR* hir) {
1270-
hir->start()->iterate_postorder(this);
1271+
virtual void block_do(BlockBegin* block) {
1272+
assert(block->end() != NULL, "Expect block end to exist.");
12711273
}
1274+
};
12721275

1273-
void block_do(BlockBegin* block) {
1274-
assert(block->end() != NULL, "Expect block end to exist.");
1276+
class XentryFlagValidator : public BlockClosure {
1277+
public:
1278+
virtual void block_do(BlockBegin* block) {
1279+
for (int i = 0; i < block->end()->number_of_sux(); i++) {
1280+
assert(!block->end()->sux_at(i)->is_set(BlockBegin::exception_entry_flag), "must not be xhandler");
1281+
}
1282+
for (int i = 0; i < block->number_of_exception_handlers(); i++) {
1283+
assert(block->exception_handler_at(i)->is_set(BlockBegin::exception_entry_flag), "must be xhandler");
1284+
}
12751285
}
12761286
};
12771287

12781288
typedef GrowableArray<BlockList*> BlockListList;
12791289

1280-
class PredecessorValidator : public BlockClosure {
1290+
// Validation goals:
1291+
// - code() length == blocks length
1292+
// - code() contents == blocks content
1293+
// - Each block's computed predecessors match sux lists (length)
1294+
// - Each block's computed predecessors match sux lists (set content)
1295+
class PredecessorAndCodeValidator : public BlockClosure {
12811296
private:
12821297
BlockListList* _predecessors; // Each index i will hold predecessors of block with id i
12831298
BlockList* _blocks;
@@ -1287,7 +1302,7 @@ class PredecessorValidator : public BlockClosure {
12871302
}
12881303

12891304
public:
1290-
PredecessorValidator(IR* hir) {
1305+
PredecessorAndCodeValidator(IR* hir) {
12911306
ResourceMark rm;
12921307
_predecessors = new BlockListList(BlockBegin::number_of_blocks(), BlockBegin::number_of_blocks(), NULL);
12931308
_blocks = new BlockList(BlockBegin::number_of_blocks());
@@ -1308,20 +1323,10 @@ class PredecessorValidator : public BlockClosure {
13081323

13091324
virtual void block_do(BlockBegin* block) {
13101325
_blocks->append(block);
1311-
verify_successor_xentry_flag(block);
13121326
collect_predecessors(block);
13131327
}
13141328

13151329
private:
1316-
void verify_successor_xentry_flag(const BlockBegin* block) const {
1317-
for (int i = 0; i < block->end()->number_of_sux(); i++) {
1318-
assert(!block->end()->sux_at(i)->is_set(BlockBegin::exception_entry_flag), "must not be xhandler");
1319-
}
1320-
for (int i = 0; i < block->number_of_exception_handlers(); i++) {
1321-
assert(block->exception_handler_at(i)->is_set(BlockBegin::exception_entry_flag), "must be xhandler");
1322-
}
1323-
}
1324-
13251330
void collect_predecessors(BlockBegin* block) {
13261331
for (int i = 0; i < block->end()->number_of_sux(); i++) {
13271332
collect_predecessor(block, block->end()->sux_at(i));
@@ -1363,26 +1368,87 @@ class PredecessorValidator : public BlockClosure {
13631368
};
13641369

13651370
class VerifyBlockBeginField : public BlockClosure {
1366-
13671371
public:
1368-
1369-
virtual void block_do(BlockBegin *block) {
1370-
for ( Instruction *cur = block; cur != NULL; cur = cur->next()) {
1372+
virtual void block_do(BlockBegin* block) {
1373+
for (Instruction* cur = block; cur != NULL; cur = cur->next()) {
13711374
assert(cur->block() == block, "Block begin is not correct");
13721375
}
13731376
}
13741377
};
13751378

1376-
void IR::verify() {
1377-
#ifdef ASSERT
1378-
PredecessorValidator pv(this);
1379-
EndNotNullValidator(this);
1379+
class ValidateEdgeMutuality : public BlockClosure {
1380+
public:
1381+
virtual void block_do(BlockBegin* block) {
1382+
for (int i = 0; i < block->end()->number_of_sux(); i++) {
1383+
assert(block->end()->sux_at(i)->is_predecessor(block), "Block's successor should have it as predecessor");
1384+
}
1385+
1386+
for (int i = 0; i < block->number_of_exception_handlers(); i++) {
1387+
assert(block->exception_handler_at(i)->is_predecessor(block), "Block's exception handler should have it as predecessor");
1388+
}
1389+
1390+
for (int i = 0; i < block->number_of_preds(); i++) {
1391+
assert(block->pred_at(i) != NULL, "Predecessor must exist");
1392+
assert(block->pred_at(i)->end() != NULL, "Predecessor end must exist");
1393+
bool is_sux = block->pred_at(i)->end()->is_sux(block);
1394+
bool is_xhandler = block->pred_at(i)->is_exception_handler(block);
1395+
assert(is_sux || is_xhandler, "Block's predecessor should have it as successor or xhandler");
1396+
}
1397+
}
1398+
};
1399+
1400+
void IR::expand_with_neighborhood(BlockList& blocks) {
1401+
int original_size = blocks.length();
1402+
for (int h = 0; h < original_size; h++) {
1403+
BlockBegin* block = blocks.at(h);
1404+
1405+
for (int i = 0; i < block->end()->number_of_sux(); i++) {
1406+
if (!blocks.contains(block->end()->sux_at(i))) {
1407+
blocks.append(block->end()->sux_at(i));
1408+
}
1409+
}
1410+
1411+
for (int i = 0; i < block->number_of_preds(); i++) {
1412+
if (!blocks.contains(block->pred_at(i))) {
1413+
blocks.append(block->pred_at(i));
1414+
}
1415+
}
1416+
1417+
for (int i = 0; i < block->number_of_exception_handlers(); i++) {
1418+
if (!blocks.contains(block->exception_handler_at(i))) {
1419+
blocks.append(block->exception_handler_at(i));
1420+
}
1421+
}
1422+
}
1423+
}
1424+
1425+
void IR::verify_local(BlockList& blocks) {
1426+
EndNotNullValidator ennv;
1427+
blocks.iterate_forward(&ennv);
1428+
1429+
ValidateEdgeMutuality vem;
1430+
blocks.iterate_forward(&vem);
1431+
13801432
VerifyBlockBeginField verifier;
1381-
this->iterate_postorder(&verifier);
1382-
#endif
1433+
blocks.iterate_forward(&verifier);
13831434
}
13841435

1385-
#endif // PRODUCT
1436+
void IR::verify() {
1437+
XentryFlagValidator xe;
1438+
iterate_postorder(&xe);
1439+
1440+
PredecessorAndCodeValidator pv(this);
1441+
1442+
EndNotNullValidator ennv;
1443+
iterate_postorder(&ennv);
1444+
1445+
ValidateEdgeMutuality vem;
1446+
iterate_postorder(&vem);
1447+
1448+
VerifyBlockBeginField verifier;
1449+
iterate_postorder(&verifier);
1450+
}
1451+
#endif // ASSERT
13861452

13871453
void SubstitutionResolver::visit(Value* v) {
13881454
Value v0 = *v;

src/hotspot/share/c1/c1_IR.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -342,7 +342,10 @@ class IR: public CompilationResourceObj {
342342
// debugging
343343
static void print(BlockBegin* start, bool cfg_only, bool live_only = false) PRODUCT_RETURN;
344344
void print(bool cfg_only, bool live_only = false) PRODUCT_RETURN;
345-
void verify() PRODUCT_RETURN;
345+
346+
void expand_with_neighborhood(BlockList& blocks) NOT_DEBUG_RETURN;
347+
void verify_local(BlockList&) NOT_DEBUG_RETURN;
348+
void verify() NOT_DEBUG_RETURN;
346349
};
347350

348351

src/hotspot/share/c1/c1_Instruction.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -1822,6 +1822,7 @@ BASE(BlockEnd, StateSplit)
18221822
// successors
18231823
int number_of_sux() const { return _sux != NULL ? _sux->length() : 0; }
18241824
BlockBegin* sux_at(int i) const { return _sux->at(i); }
1825+
bool is_sux(BlockBegin* sux) const { return _sux == NULL ? false : _sux->contains(sux); }
18251826
BlockBegin* default_sux() const { return sux_at(number_of_sux() - 1); }
18261827
void substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux);
18271828
};

src/hotspot/share/c1/c1_Optimizer.cpp

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -180,6 +180,25 @@ void CE_Eliminator::block_do(BlockBegin* block) {
180180
return;
181181
}
182182

183+
#ifdef ASSERT
184+
#define DO_DELAYED_VERIFICATION
185+
/*
186+
* We need to verify the internal representation after modifying it.
187+
* Verifying only the blocks that have been tampered with is cheaper than verifying the whole graph, but we must
188+
* capture blocks_to_verify_later before making the changes, since they might not be reachable afterwards.
189+
* DO_DELAYED_VERIFICATION ensures that the code for this is either enabled in full, or not at all.
190+
*/
191+
#endif // ASSERT
192+
193+
#ifdef DO_DELAYED_VERIFICATION
194+
BlockList blocks_to_verify_later;
195+
blocks_to_verify_later.append(block);
196+
blocks_to_verify_later.append(t_block);
197+
blocks_to_verify_later.append(f_block);
198+
blocks_to_verify_later.append(sux);
199+
_hir->expand_with_neighborhood(blocks_to_verify_later);
200+
#endif // DO_DELAYED_VERIFICATION
201+
183202
// 2) substitute conditional expression
184203
// with an IfOp followed by a Goto
185204
// cut if_ away and get node before
@@ -248,7 +267,10 @@ void CE_Eliminator::block_do(BlockBegin* block) {
248267
tty->print_cr("%d. IfOp in B%d", ifop_count(), block->block_id());
249268
}
250269

251-
_hir->verify();
270+
#ifdef DO_DELAYED_VERIFICATION
271+
_hir->verify_local(blocks_to_verify_later);
272+
#endif // DO_DELAYED_VERIFICATION
273+
252274
}
253275

254276
Value CE_Eliminator::make_ifop(Value x, Instruction::Condition cond, Value y, Value tval, Value fval) {
@@ -312,6 +334,7 @@ void Optimizer::eliminate_conditional_expressions() {
312334
CE_Eliminator ce(ir());
313335
}
314336

337+
// This removes others' relation to block, but doesnt empty block's lists
315338
void disconnect_from_graph(BlockBegin* block) {
316339
for (int p = 0; p < block->number_of_preds(); p++) {
317340
BlockBegin* pred = block->pred_at(p);
@@ -387,6 +410,12 @@ class BlockMerger: public BlockClosure {
387410
assert(sux_state->caller_state() == end_state->caller_state(), "caller not equal");
388411
#endif
389412

413+
#ifdef DO_DELAYED_VERIFICATION
414+
BlockList blocks_to_verify_later;
415+
blocks_to_verify_later.append(block);
416+
_hir->expand_with_neighborhood(blocks_to_verify_later);
417+
#endif // DO_DELAYED_VERIFICATION
418+
390419
// find instruction before end & append first instruction of sux block
391420
Instruction* prev = end->prev();
392421
Instruction* next = sux->next();
@@ -396,6 +425,9 @@ class BlockMerger: public BlockClosure {
396425

397426
// disconnect this block from all other blocks
398427
disconnect_from_graph(sux);
428+
#ifdef DO_DELAYED_VERIFICATION
429+
blocks_to_verify_later.remove(sux); // Sux is not part of graph anymore
430+
#endif // DO_DELAYED_VERIFICATION
399431
block->set_end(sux->end());
400432

401433
// TODO Should this be done in set_end universally?
@@ -404,6 +436,7 @@ class BlockMerger: public BlockClosure {
404436
BlockBegin* xhandler = sux->exception_handler_at(k);
405437
block->add_exception_handler(xhandler);
406438

439+
// TODO This should be in disconnect from graph...
407440
// also substitute predecessor of exception handler
408441
assert(xhandler->is_predecessor(sux), "missing predecessor");
409442
xhandler->remove_predecessor(sux);
@@ -419,7 +452,9 @@ class BlockMerger: public BlockClosure {
419452
_merge_count, block->block_id(), sux->block_id(), sux->state()->stack_size());
420453
}
421454

422-
_hir->verify();
455+
#ifdef DO_DELAYED_VERIFICATION
456+
_hir->verify_local(blocks_to_verify_later);
457+
#endif // DO_DELAYED_VERIFICATION
423458

424459
If* if_ = block->end()->as_If();
425460
if (if_) {
@@ -469,7 +504,9 @@ class BlockMerger: public BlockClosure {
469504
tty->print_cr("%d. replaced If and IfOp at end of B%d with single If", _merge_count, block->block_id());
470505
}
471506

472-
_hir->verify();
507+
#ifdef DO_DELAYED_VERIFICATION
508+
_hir->verify_local(blocks_to_verify_later);
509+
#endif // DO_DELAYED_VERIFICATION
473510
}
474511
}
475512
}
@@ -485,6 +522,9 @@ class BlockMerger: public BlockClosure {
485522
}
486523
};
487524

525+
#ifdef ASSERT
526+
#undef DO_DELAYED_VERIFICATION
527+
#endif // ASSERT
488528

489529
void Optimizer::eliminate_blocks() {
490530
// merge blocks if possible

0 commit comments

Comments
 (0)