--- a/hotspot/src/share/vm/opto/parse1.cpp Wed Sep 17 08:29:17 2008 -0700
+++ b/hotspot/src/share/vm/opto/parse1.cpp Wed Sep 17 12:59:52 2008 -0700
@@ -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 @@
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 @@
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 @@
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();
+
+ // 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);
+
+ if (block->is_parsed()) continue;
- int old_blocks_merged = -1;
- int old_blocks_parsed = -1;
+ if (!block->is_merged()) {
+ // Dead block, no state reaches this block
+ continue;
+ }
- for (int tries = 0; ; tries++) {
- visit_blocks();
- if (failing()) return; // Check for bailout
+ // Prepare to parse this block.
+ load_state_from(block);
+
+ if (stopped()) {
+ // Block is dead.
+ continue;
+ }
+
+ blocks_parsed++;
- // 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.
+ 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());
+ }
- // 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.)
+ 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);
+ }
+ }
- // 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.");
- }
+ // Parse the block.
+ do_one_block();
+
+ // Check for bailouts.
+ if (failing()) return;
+ }
+
+ // with irreducible loops multiple passes might be necessary to parse everything
+ if (!has_irreducible || !progress) {
break;
}
+ }
- // 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.
- 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 @@
_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 @@
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 @@
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 @@
#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 @@
//--------------------------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 @@
// 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 @@
// 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 @@
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 @@
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.