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