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