1 /*
   2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "opto/cfgnode.hpp"
  26 #include "opto/phaseX.hpp"
  27 #include "opto/replacednodes.hpp"
  28 
  29 void ReplacedNodes::allocate_if_necessary() {
  30   if (_replaced_nodes == NULL) {
  31     _replaced_nodes = new GrowableArray<ReplacedNode>();
  32   }
  33 }
  34 
  35 bool ReplacedNodes::is_empty() const {
  36   return _replaced_nodes == NULL || _replaced_nodes->length() == 0;
  37 }
  38 
  39 bool ReplacedNodes::has_node(const ReplacedNode& r) const {
  40   return _replaced_nodes->find(r) != -1;
  41 }
  42 
  43 bool ReplacedNodes::has_target_node(Node* n) const {
  44   for (int i = 0; i < _replaced_nodes->length(); i++) {
  45     if (_replaced_nodes->at(i).improved() == n) {
  46       return true;
  47     }
  48   }
  49   return false;
  50 }
  51 
  52 // Record replaced node if not seen before
  53 void ReplacedNodes::record(Node* initial, Node* improved) {
  54   allocate_if_necessary();
  55   ReplacedNode r(initial, improved);
  56   if (!has_node(r)) {
  57     _replaced_nodes->push(r);
  58   }
  59 }
  60 
  61 // Copy replaced nodes from one map to another. idx is used to
  62 // identify nodes that are too new to be of interest in the target
  63 // node list.
  64 void ReplacedNodes::transfer_from(const ReplacedNodes& other, uint idx) {
  65   if (other.is_empty()) {
  66     return;
  67   }
  68   allocate_if_necessary();
  69   for (int i = 0; i < other._replaced_nodes->length(); i++) {
  70     ReplacedNode replaced = other._replaced_nodes->at(i);
  71     // Only transfer the nodes that can actually be useful
  72     if (!has_node(replaced) && (replaced.initial()->_idx < idx || has_target_node(replaced.initial()))) {
  73       _replaced_nodes->push(replaced);
  74     }
  75   }
  76 }
  77 
  78 void ReplacedNodes::clone() {
  79   if (_replaced_nodes != NULL) {
  80     GrowableArray<ReplacedNode>* replaced_nodes_clone = new GrowableArray<ReplacedNode>();
  81     replaced_nodes_clone->appendAll(_replaced_nodes);
  82     _replaced_nodes = replaced_nodes_clone;
  83   }
  84 }
  85 
  86 void ReplacedNodes::reset() {
  87   if (_replaced_nodes != NULL) {
  88     _replaced_nodes->clear();
  89   }
  90 }
  91 
  92 // Perfom node replacement (used when returning to caller)
  93 void ReplacedNodes::apply(Node* n) {
  94   if (is_empty()) {
  95     return;
  96   }
  97   for (int i = 0; i < _replaced_nodes->length(); i++) {
  98     ReplacedNode replaced = _replaced_nodes->at(i);
  99     n->replace_edge(replaced.initial(), replaced.improved());
 100   }
 101 }
 102 
 103 static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) {
 104   if (use->is_Phi()) {
 105     Node* r = use->in(0);
 106     assert(r->is_Region(), "Phi should have Region");
 107     for (uint i = 1; i < use->req(); i++) {
 108       if (use->in(i) == n) {
 109         work.push(r->in(i));
 110       }
 111     }
 112   } else {
 113     work.push(use);
 114   }
 115 }
 116 
 117 // Perfom node replacement following late inlining
 118 void ReplacedNodes::apply(Compile* C, Node* ctl) {
 119   // ctl is the control on exit of the method that was late inlined
 120   if (is_empty()) {
 121     return;
 122   }
 123   for (int i = 0; i < _replaced_nodes->length(); i++) {
 124     ReplacedNode replaced = _replaced_nodes->at(i);
 125     Node* initial = replaced.initial();
 126     Node* improved = replaced.improved();
 127     assert (ctl != NULL && !ctl->is_top(), "replaced node should have actual control");
 128     
 129     ResourceMark rm;
 130     Unique_Node_List work;
 131     // Go over all the uses of the node that is considered for replacement...
 132     for (DUIterator j = initial->outs(); initial->has_out(j); j++) {
 133       Node* use = initial->out(j);
 134 
 135       if (use == improved || use->outcnt() == 0) {
 136         continue;
 137       }
 138       work.clear();
 139       enqueue_use(initial, use, work);
 140       bool replace = true;
 141       // Check that this use is dominated by ctl. Go ahead with the
 142       // replacement if it is.
 143       while (work.size() != 0 && replace) {
 144         Node* n = work.pop();
 145         if (use->outcnt() == 0) {
 146           continue;
 147         }
 148         if (n->is_CFG() || (n->in(0) != NULL && !n->in(0)->is_top())) {
 149           int depth = 0;
 150           Node *m = n;
 151           if (!n->is_CFG()) {
 152             n = n->in(0);
 153           }
 154           assert(n->is_CFG(), "should be CFG now");
 155           while(n != ctl) {
 156             n = IfNode::up_one_dom(n);
 157             depth++;
 158             // limit search depth
 159             if (depth >= 100 || n == NULL) {
 160               replace = false;
 161               break;
 162             }
 163           }
 164         } else {
 165           for (DUIterator k = n->outs(); n->has_out(k); k++) {
 166             enqueue_use(n, n->out(k), work);
 167           }
 168         }
 169       }
 170       if (replace) {
 171         bool is_in_table = C->initial_gvn()->hash_delete(use);
 172         int replaced = use->replace_edge(initial, improved);
 173         if (is_in_table) {
 174           C->initial_gvn()->hash_find_insert(use);
 175         }
 176         C->record_for_igvn(use);
 177 
 178         assert(replaced > 0, "inconsistent");
 179         --j;
 180       }
 181     }
 182   }
 183 }
 184 
 185 void ReplacedNodes::dump(outputStream *st) const {
 186   if (!is_empty()) {
 187     tty->print("replaced nodes: ");
 188     for (int i = 0; i < _replaced_nodes->length(); i++) {
 189       tty->print("%d->%d", _replaced_nodes->at(i).initial()->_idx, _replaced_nodes->at(i).improved()->_idx);
 190       if (i < _replaced_nodes->length()-1) {
 191         tty->print(",");
 192       }
 193     }
 194   }
 195 }
 196 
 197 // Merge 2 list of replaced node at a point where control flow paths merge
 198 void ReplacedNodes::merge_with(const ReplacedNodes& other) {
 199   if (is_empty()) {
 200     return;
 201   }
 202   if (other.is_empty()) {
 203     reset();
 204     return;
 205   }
 206   int shift = 0;
 207   int len = _replaced_nodes->length();
 208   for (int i = 0; i < len; i++) {
 209     if (!other.has_node(_replaced_nodes->at(i))) {
 210       shift++;
 211     } else if (shift > 0) {
 212       _replaced_nodes->at_put(i-shift, _replaced_nodes->at(i));
 213     }
 214   }
 215   if (shift > 0) {
 216     _replaced_nodes->trunc_to(len - shift);
 217   }
 218 }
 219