6384206: Phis which are later unneeded are impairing our ability to inline based on static types

Reviewed-by: rasbold, jrose
This commit is contained in:
Tom Rodriguez 2008-09-17 12:59:52 -07:00
parent eee15b163e
commit 4b1e242299
18 changed files with 1082 additions and 401 deletions

View file

@ -29,17 +29,17 @@
// the most. Some of the non-static variables are needed in bytecodeInfo.cpp
// and eventually should be encapsulated in a proper class (gri 8/18/98).
int nodes_created = 0; int nodes_created_old = 0;
int methods_parsed = 0; int methods_parsed_old = 0;
int methods_seen = 0; int methods_seen_old = 0;
int nodes_created = 0;
int methods_parsed = 0;
int methods_seen = 0;
int blocks_parsed = 0;
int blocks_seen = 0;
int explicit_null_checks_inserted = 0, explicit_null_checks_inserted_old = 0;
int explicit_null_checks_elided = 0, explicit_null_checks_elided_old = 0;
int explicit_null_checks_inserted = 0;
int explicit_null_checks_elided = 0;
int all_null_checks_found = 0, implicit_null_checks = 0;
int implicit_null_throws = 0;
int parse_idx = 0;
size_t parse_arena = 0;
int reclaim_idx = 0;
int reclaim_in = 0;
int reclaim_node = 0;
@ -61,6 +61,7 @@ void Parse::print_statistics() {
tty->cr();
if (methods_seen != methods_parsed)
tty->print_cr("Reasons for parse failures (NOT cumulative):");
tty->print_cr("Blocks parsed: %d Blocks seen: %d", blocks_parsed, blocks_seen);
if( explicit_null_checks_inserted )
tty->print_cr("%d original NULL checks - %d elided (%2d%%); optimizer leaves %d,", explicit_null_checks_inserted, explicit_null_checks_elided, (100*explicit_null_checks_elided)/explicit_null_checks_inserted, all_null_checks_found);
@ -373,6 +374,12 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
C->record_method_not_compilable_all_tiers(_flow->failure_reason());
}
#ifndef PRODUCT
if (_flow->has_irreducible_entry()) {
C->set_parsed_irreducible_loop(true);
}
#endif
if (_expected_uses <= 0) {
_prof_factor = 1;
} else {
@ -556,118 +563,93 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
set_map(entry_map);
do_exits();
// Collect a few more statistics.
parse_idx += C->unique();
parse_arena += C->node_arena()->used();
if (log) log->done("parse nodes='%d' memory='%d'",
C->unique(), C->node_arena()->used());
}
//---------------------------do_all_blocks-------------------------------------
void Parse::do_all_blocks() {
_blocks_merged = 0;
_blocks_parsed = 0;
bool has_irreducible = flow()->has_irreducible_entry();
int old_blocks_merged = -1;
int old_blocks_parsed = -1;
// Walk over all blocks in Reverse Post-Order.
while (true) {
bool progress = false;
for (int rpo = 0; rpo < block_count(); rpo++) {
Block* block = rpo_at(rpo);
for (int tries = 0; ; tries++) {
visit_blocks();
if (failing()) return; // Check for bailout
if (block->is_parsed()) continue;
// No need for a work list. The outer loop is hardly ever repeated.
// The following loop traverses the blocks in a reasonable pre-order,
// as produced by the ciTypeFlow pass.
// This loop can be taken more than once if there are two entries to
// a loop (irreduceable CFG), and the edge which ciTypeFlow chose
// as the first predecessor to the loop goes dead in the parser,
// due to parse-time optimization. (Could happen with obfuscated code.)
// Look for progress, or the lack of it:
if (_blocks_parsed == block_count()) {
// That's all, folks.
if (TraceOptoParse) {
tty->print_cr("All blocks parsed.");
if (!block->is_merged()) {
// Dead block, no state reaches this block
continue;
}
break;
// Prepare to parse this block.
load_state_from(block);
if (stopped()) {
// Block is dead.
continue;
}
blocks_parsed++;
progress = true;
if (block->is_loop_head() || block->is_handler() || has_irreducible && !block->is_ready()) {
// Not all preds have been parsed. We must build phis everywhere.
// (Note that dead locals do not get phis built, ever.)
ensure_phis_everywhere();
// Leave behind an undisturbed copy of the map, for future merges.
set_map(clone_map());
}
if (control()->is_Region() && !block->is_loop_head() && !has_irreducible && !block->is_handler()) {
// In the absence of irreducible loops, the Region and Phis
// associated with a merge that doesn't involve a backedge can
// be simplfied now since the RPO parsing order guarantees
// that any path which was supposed to reach here has already
// been parsed or must be dead.
Node* c = control();
Node* result = _gvn.transform_no_reclaim(control());
if (c != result && TraceOptoParse) {
tty->print_cr("Block #%d replace %d with %d", block->rpo(), c->_idx, result->_idx);
}
if (result != top()) {
record_for_igvn(result);
}
}
// Parse the block.
do_one_block();
// Check for bailouts.
if (failing()) return;
}
// How much work was done this time around?
int new_blocks_merged = _blocks_merged - old_blocks_merged;
int new_blocks_parsed = _blocks_parsed - old_blocks_parsed;
if (new_blocks_merged == 0) {
if (TraceOptoParse) {
tty->print_cr("All live blocks parsed; %d dead blocks.", block_count() - _blocks_parsed);
}
// No new blocks have become parseable. Some blocks are just dead.
// with irreducible loops multiple passes might be necessary to parse everything
if (!has_irreducible || !progress) {
break;
}
assert(new_blocks_parsed > 0, "must make progress");
assert(tries < block_count(), "the pre-order cannot be this bad!");
old_blocks_merged = _blocks_merged;
old_blocks_parsed = _blocks_parsed;
}
blocks_seen += block_count();
#ifndef PRODUCT
// Make sure there are no half-processed blocks remaining.
// Every remaining unprocessed block is dead and may be ignored now.
for (int po = 0; po < block_count(); po++) {
Block* block = pre_order_at(po);
for (int rpo = 0; rpo < block_count(); rpo++) {
Block* block = rpo_at(rpo);
if (!block->is_parsed()) {
if (TraceOptoParse) {
tty->print("Skipped dead block %d at bci:%d", po, block->start());
assert(!block->is_merged(), "no half-processed blocks");
tty->print_cr("Skipped dead block %d at bci:%d", rpo, block->start());
}
assert(!block->is_merged(), "no half-processed blocks");
}
}
#endif
}
//---------------------------visit_blocks--------------------------------------
void Parse::visit_blocks() {
// Walk over all blocks, parsing every one that has been reached (merged).
for (int po = 0; po < block_count(); po++) {
Block* block = pre_order_at(po);
if (block->is_parsed()) {
// Do not parse twice.
continue;
}
if (!block->is_merged()) {
// No state on this block. It had not yet been reached.
// Delay reaching it until later.
continue;
}
// Prepare to parse this block.
load_state_from(block);
if (stopped()) {
// Block is dead.
continue;
}
if (!block->is_ready() || block->is_handler()) {
// Not all preds have been parsed. We must build phis everywhere.
// (Note that dead locals do not get phis built, ever.)
ensure_phis_everywhere();
// Leave behind an undisturbed copy of the map, for future merges.
set_map(clone_map());
}
// Ready or not, parse the block.
do_one_block();
// Check for bailouts.
if (failing()) return;
}
}
//-------------------------------build_exits----------------------------------
// Build normal and exceptional exit merge points.
void Parse::build_exits() {
@ -1134,24 +1116,24 @@ void Parse::init_blocks() {
_blocks = NEW_RESOURCE_ARRAY(Block, _block_count);
Copy::zero_to_bytes(_blocks, sizeof(Block)*_block_count);
int po;
int rpo;
// Initialize the structs.
for (po = 0; po < block_count(); po++) {
Block* block = pre_order_at(po);
block->init_node(this, po);
for (rpo = 0; rpo < block_count(); rpo++) {
Block* block = rpo_at(rpo);
block->init_node(this, rpo);
}
// Collect predecessor and successor information.
for (po = 0; po < block_count(); po++) {
Block* block = pre_order_at(po);
for (rpo = 0; rpo < block_count(); rpo++) {
Block* block = rpo_at(rpo);
block->init_graph(this);
}
}
//-------------------------------init_node-------------------------------------
void Parse::Block::init_node(Parse* outer, int po) {
_flow = outer->flow()->pre_order_at(po);
void Parse::Block::init_node(Parse* outer, int rpo) {
_flow = outer->flow()->rpo_at(rpo);
_pred_count = 0;
_preds_parsed = 0;
_count = 0;
@ -1177,7 +1159,7 @@ void Parse::Block::init_graph(Parse* outer) {
int p = 0;
for (int i = 0; i < ns+ne; i++) {
ciTypeFlow::Block* tf2 = (i < ns) ? tfs->at(i) : tfe->at(i-ns);
Block* block2 = outer->pre_order_at(tf2->pre_order());
Block* block2 = outer->rpo_at(tf2->rpo());
_successors[i] = block2;
// Accumulate pred info for the other block, too.
@ -1368,10 +1350,11 @@ void Parse::do_one_block() {
int nt = b->all_successors();
tty->print("Parsing block #%d at bci [%d,%d), successors: ",
block()->pre_order(), block()->start(), block()->limit());
block()->rpo(), block()->start(), block()->limit());
for (int i = 0; i < nt; i++) {
tty->print((( i < ns) ? " %d" : " %d(e)"), b->successor_at(i)->pre_order());
tty->print((( i < ns) ? " %d" : " %d(e)"), b->successor_at(i)->rpo());
}
if (b->is_loop_head()) tty->print(" lphd");
tty->print_cr("");
}
@ -1501,7 +1484,7 @@ void Parse::handle_missing_successor(int target_bci) {
#ifndef PRODUCT
Block* b = block();
int trap_bci = b->flow()->has_trap()? b->flow()->trap_bci(): -1;
tty->print_cr("### Missing successor at bci:%d for block #%d (trap_bci:%d)", target_bci, b->pre_order(), trap_bci);
tty->print_cr("### Missing successor at bci:%d for block #%d (trap_bci:%d)", target_bci, b->rpo(), trap_bci);
#endif
ShouldNotReachHere();
}
@ -1509,7 +1492,7 @@ void Parse::handle_missing_successor(int target_bci) {
//--------------------------merge_common---------------------------------------
void Parse::merge_common(Parse::Block* target, int pnum) {
if (TraceOptoParse) {
tty->print("Merging state at block #%d bci:%d", target->pre_order(), target->start());
tty->print("Merging state at block #%d bci:%d", target->rpo(), target->start());
}
// Zap extra stack slots to top
@ -1534,6 +1517,7 @@ void Parse::merge_common(Parse::Block* target, int pnum) {
// which must not be allowed into this block's map.)
if (pnum > PhiNode::Input // Known multiple inputs.
|| target->is_handler() // These have unpredictable inputs.
|| target->is_loop_head() // Known multiple inputs
|| control()->is_Region()) { // We must hide this guy.
// Add a Region to start the new basic block. Phis will be added
// later lazily.
@ -1575,15 +1559,21 @@ void Parse::merge_common(Parse::Block* target, int pnum) {
// Compute where to merge into
// Merge incoming control path
r->set_req(pnum, newin->control());
r->init_req(pnum, newin->control());
if (pnum == 1) { // Last merge for this Region?
_gvn.transform_no_reclaim(r);
if (!block()->flow()->is_irreducible_entry()) {
Node* result = _gvn.transform_no_reclaim(r);
if (r != result && TraceOptoParse) {
tty->print_cr("Block #%d replace %d with %d", block()->rpo(), r->_idx, result->_idx);
}
}
record_for_igvn(r);
}
// Update all the non-control inputs to map:
assert(TypeFunc::Parms == newin->jvms()->locoff(), "parser map should contain only youngest jvms");
bool check_elide_phi = target->is_SEL_backedge(save_block);
for (uint j = 1; j < newin->req(); j++) {
Node* m = map()->in(j); // Current state of target.
Node* n = newin->in(j); // Incoming change to target state.
@ -1603,7 +1593,11 @@ void Parse::merge_common(Parse::Block* target, int pnum) {
merge_memory_edges(n->as_MergeMem(), pnum, nophi);
continue;
default: // All normal stuff
if (phi == NULL) phi = ensure_phi(j, nophi);
if (phi == NULL) {
if (!check_elide_phi || !target->can_elide_SEL_phi(j)) {
phi = ensure_phi(j, nophi);
}
}
break;
}
}
@ -1736,9 +1730,13 @@ void Parse::ensure_phis_everywhere() {
uint nof_monitors = map()->jvms()->nof_monitors();
assert(TypeFunc::Parms == map()->jvms()->locoff(), "parser map should contain only youngest jvms");
bool check_elide_phi = block()->is_SEL_head();
for (uint i = TypeFunc::Parms; i < monoff; i++) {
ensure_phi(i);
if (!check_elide_phi || !block()->can_elide_SEL_phi(i)) {
ensure_phi(i);
}
}
// Even monitors need Phis, though they are well-structured.
// This is true for OSR methods, and also for the rare cases where
// a monitor object is the subject of a replace_in_map operation.