src/share/vm/opto/callnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Cdiff src/share/vm/opto/callnode.cpp

src/share/vm/opto/callnode.cpp

Print this page
rev 6442 : 8026796: Make replace_in_map() on parent maps generic
Summary: propagate node replacements along control flow edges to callers
Reviewed-by:

*** 1088,1097 **** --- 1088,1098 ---- } #ifndef PRODUCT void SafePointNode::dump_spec(outputStream *st) const { st->print(" SafePoint "); + _replaced_nodes.dump(st); } #endif const RegMask &SafePointNode::in_RegMask(uint idx) const { if( idx < TypeFunc::Parms ) return RegMask::Empty;
*** 1170,1179 **** --- 1171,1369 ---- return 0; return (TypeFunc::Parms == idx); } + void ReplacedNodes::allocate_if_necessary() { + if (_replaced_nodes == NULL) { + _replaced_nodes = new GrowableArray<ReplacedNode>(); + } + } + + bool ReplacedNodes::is_empty() const { + return _replaced_nodes == NULL || _replaced_nodes->length() == 0; + } + + bool ReplacedNodes::has_node(ReplacedNode r) const { + return _replaced_nodes->find(r) != -1; + } + + bool ReplacedNodes::has_target_node(Node* n) const { + for (int i = 0; i < _replaced_nodes->length(); i++) { + if (_replaced_nodes->at(i).after() == n) { + return true; + } + } + return false; + } + + // Record replaced node if not seen before + void ReplacedNodes::record(Node* o, Node* n) { + allocate_if_necessary(); + ReplacedNode r(o, n); + if (!has_node(r)) { + _replaced_nodes->push(r); + } + } + + // Copy replaced nodes from one map to another. idx is used to + // identify nodes that are too new to be of interest in the target + // node list. + void ReplacedNodes::transfer_from(ReplacedNodes other, uint idx) { + if (other.is_empty()) { + return; + } + allocate_if_necessary(); + for (int i = 0; i < other._replaced_nodes->length(); i++) { + ReplacedNode replaced = other._replaced_nodes->at(i); + // Only transfer the nodes that can actually be useful + if (!has_node(replaced) && (replaced.before()->_idx < idx || has_target_node(replaced.before()))) { + _replaced_nodes->push(replaced); + } + } + } + + void ReplacedNodes::clone() { + if (_replaced_nodes != NULL) { + GrowableArray<ReplacedNode>* replaced_nodes_clone = new GrowableArray<ReplacedNode>(); + replaced_nodes_clone->appendAll(_replaced_nodes); + _replaced_nodes = replaced_nodes_clone; + } + } + + void ReplacedNodes::reset() { + _replaced_nodes = NULL; + } + + // Perfom node replacement (used when returning to caller) + void ReplacedNodes::apply(Node* n) { + if (is_empty()) { + return; + } + for (int i = 0; i < _replaced_nodes->length(); i++) { + ReplacedNode replaced = _replaced_nodes->at(i); + n->replace_edge(replaced.before(), replaced.after()); + } + } + + static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) { + if (use->is_Phi()) { + Node* r = use->in(0); + assert(r->is_Region(), "Phi should have Region"); + for (uint i = 1; i < use->req(); i++) { + if (use->in(i) == n) { + work.push(r->in(i)); + } + } + } else { + work.push(use); + } + } + + // Perfom node replacement following late inlining + void ReplacedNodes::apply(Compile* C, Node* ctl) { + // ctl is the control on exit of the method that was late inlined + if (is_empty()) { + return; + } + for (int i = 0; i < _replaced_nodes->length(); i++) { + ReplacedNode replaced = _replaced_nodes->at(i); + Node* before = replaced.before(); + Node* after = replaced.after(); + assert (ctl != NULL && !ctl->is_top(), "replaced node should have actual control"); + + ResourceMark rm; + Unique_Node_List work; + // Go over all the uses of the node that is considered for replacement... + for (DUIterator j = before->outs(); before->has_out(j); j++) { + Node* use = before->out(j); + + if (use == after || use->outcnt() == 0) { + continue; + } + work.clear(); + enqueue_use(before, use, work); + bool replace = true; + // Check that this use is dominated by ctl. Go ahead with the + // replacement if it is. + while (work.size() != 0 && replace) { + Node* n = work.pop(); + if (use->outcnt() == 0) { + continue; + } + if (n->is_CFG() || (n->in(0) != NULL && !n->in(0)->is_top())) { + int depth = 0; + Node *m = n; + if (!n->is_CFG()) { + n = n->in(0); + } + assert(n->is_CFG(), "should be CFG now"); + while(n != ctl) { + n = IfNode::up_one_dom(n); + depth++; + // limit search depth + if (depth >= 100 || n == NULL) { + replace = false; + break; + } + } + } else { + for (DUIterator k = n->outs(); n->has_out(k); k++) { + enqueue_use(n, n->out(k), work); + } + } + } + if (replace) { + bool is_in_table = C->initial_gvn()->hash_delete(use); + int replaced = use->replace_edge(before, after); + if (is_in_table) { + C->initial_gvn()->hash_find_insert(use); + } + C->record_for_igvn(use); + + assert(replaced > 0, "inconsistent"); + --j; + } + } + } + } + + void ReplacedNodes::dump(outputStream *st) const { + if (!is_empty()) { + tty->print("replaced nodes: "); + for (int i = 0; i < _replaced_nodes->length(); i++) { + tty->print("%d->%d", _replaced_nodes->at(i).before()->_idx, _replaced_nodes->at(i).after()->_idx); + if (i < _replaced_nodes->length()-1) { + tty->print(","); + } + } + } + } + + // Merge 2 list of replaced node at a point where control flow paths merge + void ReplacedNodes::merge_with(ReplacedNodes other) { + if (is_empty()) { + return; + } + if (other.is_empty()) { + reset(); + return; + } + int shift = 0; + int len = _replaced_nodes->length(); + for (int i = 0; i < len; i++) { + if (!other.has_node(_replaced_nodes->at(i))) { + shift++; + } else if (shift > 0) { + _replaced_nodes->at_put(i-shift, _replaced_nodes->at(i)); + } + } + if (shift > 0) { + _replaced_nodes->trunc_to(len - shift); + } + } + //============== SafePointScalarObjectNode ============== SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, #ifdef ASSERT AllocateNode* alloc,
src/share/vm/opto/callnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File