1 /*
   2  * Copyright (c) 2009, 2016, 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 package org.graalvm.compiler.nodes.cfg;
  24 
  25 import java.util.ArrayList;
  26 import java.util.Iterator;
  27 
  28 import org.graalvm.compiler.core.common.LocationIdentity;
  29 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
  30 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
  31 import org.graalvm.compiler.core.common.cfg.Loop;
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.nodeinfo.Verbosity;
  34 import org.graalvm.compiler.nodes.AbstractBeginNode;
  35 import org.graalvm.compiler.nodes.FixedNode;
  36 import org.graalvm.compiler.nodes.FixedWithNextNode;
  37 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
  38 import org.graalvm.compiler.nodes.LoopBeginNode;
  39 import org.graalvm.compiler.nodes.LoopEndNode;
  40 import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
  41 
  42 public final class Block extends AbstractBlockBase<Block> {
  43 
  44     public static final Block[] EMPTY_ARRAY = new Block[0];
  45 
  46     protected final AbstractBeginNode beginNode;
  47 
  48     protected FixedNode endNode;
  49 
  50     protected double probability;
  51     protected Loop<Block> loop;
  52 
  53     protected Block postdominator;
  54     protected Block distancedDominatorCache;
  55     private LocationSet killLocations;
  56     private LocationSet killLocationsBetweenThisAndDominator;
  57 
  58     public Block(AbstractBeginNode node) {
  59         this.beginNode = node;
  60     }
  61 
  62     public AbstractBeginNode getBeginNode() {
  63         return beginNode;
  64     }
  65 
  66     public FixedNode getEndNode() {
  67         return endNode;
  68     }
  69 
  70     @Override
  71     public Loop<Block> getLoop() {
  72         return loop;
  73     }
  74 
  75     public void setLoop(Loop<Block> loop) {
  76         this.loop = loop;
  77     }
  78 
  79     @Override
  80     public int getLoopDepth() {
  81         return loop == null ? 0 : loop.getDepth();
  82     }
  83 
  84     @Override
  85     public boolean isLoopHeader() {
  86         return getBeginNode() instanceof LoopBeginNode;
  87     }
  88 
  89     @Override
  90     public boolean isLoopEnd() {
  91         return getEndNode() instanceof LoopEndNode;
  92     }
  93 
  94     @Override
  95     public boolean isExceptionEntry() {
  96         Node predecessor = getBeginNode().predecessor();
  97         return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
  98     }
  99 
 100     public Block getFirstPredecessor() {
 101         return getPredecessors()[0];
 102     }
 103 
 104     public Block getFirstSuccessor() {
 105         return getSuccessors()[0];
 106     }
 107 
 108     public Block getEarliestPostDominated() {
 109         Block b = this;
 110         while (true) {
 111             Block dom = b.getDominator();
 112             if (dom != null && dom.getPostdominator() == b) {
 113                 b = dom;
 114             } else {
 115                 break;
 116             }
 117         }
 118         return b;
 119     }
 120 
 121     @Override
 122     public Block getPostdominator() {
 123         return postdominator;
 124     }
 125 
 126     private class NodeIterator implements Iterator<FixedNode> {
 127 
 128         private FixedNode cur;
 129 
 130         NodeIterator() {
 131             cur = getBeginNode();
 132         }
 133 
 134         @Override
 135         public boolean hasNext() {
 136             return cur != null;
 137         }
 138 
 139         @Override
 140         public FixedNode next() {
 141             FixedNode result = cur;
 142             if (result instanceof FixedWithNextNode) {
 143                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) result;
 144                 FixedNode next = fixedWithNextNode.next();
 145                 if (next instanceof AbstractBeginNode) {
 146                     next = null;
 147                 }
 148                 cur = next;
 149             } else {
 150                 cur = null;
 151             }
 152             assert !(cur instanceof AbstractBeginNode);
 153             return result;
 154         }
 155 
 156         @Override
 157         public void remove() {
 158             throw new UnsupportedOperationException();
 159         }
 160     }
 161 
 162     public Iterable<FixedNode> getNodes() {
 163         return new Iterable<FixedNode>() {
 164 
 165             @Override
 166             public Iterator<FixedNode> iterator() {
 167                 return new NodeIterator();
 168             }
 169 
 170             @Override
 171             public String toString() {
 172                 StringBuilder str = new StringBuilder().append('[');
 173                 for (FixedNode node : this) {
 174                     str.append(node).append(", ");
 175                 }
 176                 if (str.length() > 1) {
 177                     str.setLength(str.length() - 2);
 178                 }
 179                 return str.append(']').toString();
 180             }
 181         };
 182     }
 183 
 184     @Override
 185     public String toString() {
 186         return toString(Verbosity.Id);
 187     }
 188 
 189     public String toString(Verbosity verbosity) {
 190         StringBuilder sb = new StringBuilder();
 191         sb.append('B').append(id);
 192         if (verbosity != Verbosity.Id) {
 193             if (isLoopHeader()) {
 194                 sb.append(" lh");
 195             }
 196 
 197             if (getSuccessorCount() > 0) {
 198                 sb.append(" ->[");
 199                 for (int i = 0; i < getSuccessorCount(); ++i) {
 200                     if (i != 0) {
 201                         sb.append(',');
 202                     }
 203                     sb.append('B').append(getSuccessors()[i].getId());
 204                 }
 205                 sb.append(']');
 206             }
 207 
 208             if (getPredecessorCount() > 0) {
 209                 sb.append(" <-[");
 210                 for (int i = 0; i < getPredecessorCount(); ++i) {
 211                     if (i != 0) {
 212                         sb.append(',');
 213                     }
 214                     sb.append('B').append(getPredecessors()[i].getId());
 215                 }
 216                 sb.append(']');
 217             }
 218         }
 219         return sb.toString();
 220     }
 221 
 222     @Override
 223     public double probability() {
 224         return probability;
 225     }
 226 
 227     public void setProbability(double probability) {
 228         assert probability >= 0 && Double.isFinite(probability);
 229         this.probability = probability;
 230     }
 231 
 232     @Override
 233     public Block getDominator(int distance) {
 234         Block result = this;
 235         for (int i = 0; i < distance; ++i) {
 236             result = result.getDominator();
 237         }
 238         return result;
 239     }
 240 
 241     public boolean canKill(LocationIdentity location) {
 242         if (location.isImmutable()) {
 243             return false;
 244         }
 245         return getKillLocations().contains(location);
 246     }
 247 
 248     public LocationSet getKillLocations() {
 249         if (killLocations == null) {
 250             killLocations = calcKillLocations();
 251         }
 252         return killLocations;
 253     }
 254 
 255     private LocationSet calcKillLocations() {
 256         LocationSet result = new LocationSet();
 257         for (FixedNode node : this.getNodes()) {
 258             if (node instanceof MemoryCheckpoint.Single) {
 259                 LocationIdentity identity = ((MemoryCheckpoint.Single) node).getLocationIdentity();
 260                 result.add(identity);
 261             } else if (node instanceof MemoryCheckpoint.Multi) {
 262                 for (LocationIdentity identity : ((MemoryCheckpoint.Multi) node).getLocationIdentities()) {
 263                     result.add(identity);
 264                 }
 265             }
 266             if (result.isAny()) {
 267                 break;
 268             }
 269         }
 270         return result;
 271     }
 272 
 273     public boolean canKillBetweenThisAndDominator(LocationIdentity location) {
 274         if (location.isImmutable()) {
 275             return false;
 276         }
 277         return this.getKillLocationsBetweenThisAndDominator().contains(location);
 278     }
 279 
 280     private LocationSet getKillLocationsBetweenThisAndDominator() {
 281         if (this.killLocationsBetweenThisAndDominator == null) {
 282             LocationSet dominatorResult = new LocationSet();
 283             Block stopBlock = getDominator();
 284             if (this.isLoopHeader()) {
 285                 assert stopBlock.getLoopDepth() < this.getLoopDepth();
 286                 dominatorResult.addAll(((HIRLoop) this.getLoop()).getKillLocations());
 287             } else {
 288                 for (Block b : this.getPredecessors()) {
 289                     assert !this.isLoopHeader();
 290                     if (b != stopBlock) {
 291                         dominatorResult.addAll(b.getKillLocations());
 292                         if (dominatorResult.isAny()) {
 293                             break;
 294                         }
 295                         b.calcKillLocationsBetweenThisAndTarget(dominatorResult, stopBlock);
 296                         if (dominatorResult.isAny()) {
 297                             break;
 298                         }
 299                     }
 300                 }
 301             }
 302             this.killLocationsBetweenThisAndDominator = dominatorResult;
 303         }
 304         return this.killLocationsBetweenThisAndDominator;
 305     }
 306 
 307     private void calcKillLocationsBetweenThisAndTarget(LocationSet result, Block stopBlock) {
 308         assert AbstractControlFlowGraph.dominates(stopBlock, this);
 309         if (stopBlock == this || result.isAny()) {
 310             // We reached the stop block => nothing to do.
 311             return;
 312         } else {
 313             if (stopBlock == this.getDominator()) {
 314                 result.addAll(this.getKillLocationsBetweenThisAndDominator());
 315             } else {
 316                 // Divide and conquer: Aggregate kill locations from this to the dominator and then
 317                 // from the dominator onwards.
 318                 calcKillLocationsBetweenThisAndTarget(result, this.getDominator());
 319                 result.addAll(this.getDominator().getKillLocations());
 320                 if (result.isAny()) {
 321                     return;
 322                 }
 323                 this.getDominator().calcKillLocationsBetweenThisAndTarget(result, stopBlock);
 324             }
 325         }
 326     }
 327 
 328     @Override
 329     public void delete() {
 330 
 331         // adjust successor and predecessor lists
 332         Block next = getSuccessors()[0];
 333         for (Block pred : getPredecessors()) {
 334             Block[] predSuccs = pred.successors;
 335             Block[] newPredSuccs = new Block[predSuccs.length];
 336             for (int i = 0; i < predSuccs.length; ++i) {
 337                 if (predSuccs[i] == this) {
 338                     newPredSuccs[i] = next;
 339                 } else {
 340                     newPredSuccs[i] = predSuccs[i];
 341                 }
 342             }
 343             pred.setSuccessors(newPredSuccs);
 344         }
 345 
 346         ArrayList<Block> newPreds = new ArrayList<>();
 347         for (int i = 0; i < next.getPredecessorCount(); i++) {
 348             Block curPred = next.getPredecessors()[i];
 349             if (curPred == this) {
 350                 for (Block b : getPredecessors()) {
 351                     newPreds.add(b);
 352                 }
 353             } else {
 354                 newPreds.add(curPred);
 355             }
 356         }
 357 
 358         next.setPredecessors(newPreds.toArray(new Block[0]));
 359     }
 360 
 361     protected void setPostDominator(Block postdominator) {
 362         this.postdominator = postdominator;
 363     }
 364 }