1 /*
   2  * Copyright (c) 2011, 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 package org.graalvm.compiler.nodes;
  26 
  27 import java.util.Iterator;
  28 import java.util.NoSuchElementException;
  29 
  30 import org.graalvm.compiler.core.common.type.Stamp;
  31 import org.graalvm.compiler.core.common.type.StampFactory;
  32 import org.graalvm.compiler.graph.IterableNodeType;
  33 import org.graalvm.compiler.graph.Node;
  34 import org.graalvm.compiler.graph.NodeClass;
  35 import org.graalvm.compiler.graph.iterators.NodeIterable;
  36 import org.graalvm.compiler.nodeinfo.InputType;
  37 import org.graalvm.compiler.nodeinfo.NodeInfo;
  38 import org.graalvm.compiler.nodes.extended.AnchoringNode;
  39 import org.graalvm.compiler.nodes.extended.GuardingNode;
  40 import org.graalvm.compiler.nodes.spi.LIRLowerable;
  41 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  42 
  43 @NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
  44 public abstract class AbstractBeginNode extends FixedWithNextNode implements LIRLowerable, GuardingNode, AnchoringNode, IterableNodeType {
  45 
  46     public static final NodeClass<AbstractBeginNode> TYPE = NodeClass.create(AbstractBeginNode.class);
  47 
  48     private boolean withSpeculationFence;
  49 
  50     protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c) {
  51         this(c, StampFactory.forVoid());
  52     }
  53 
  54     protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c, Stamp stamp) {
  55         super(c, stamp);
  56     }
  57 
  58     public static AbstractBeginNode prevBegin(FixedNode from) {
  59         Node next = from;
  60         while (next != null) {
  61             if (next instanceof AbstractBeginNode) {
  62                 AbstractBeginNode begin = (AbstractBeginNode) next;
  63                 return begin;
  64             }
  65             next = next.predecessor();
  66         }
  67         return null;
  68     }
  69 
  70     private void evacuateGuards(FixedNode evacuateFrom) {
  71         if (!hasNoUsages()) {
  72             AbstractBeginNode prevBegin = prevBegin(evacuateFrom);
  73             assert prevBegin != null;
  74             for (Node anchored : anchored().snapshot()) {
  75                 anchored.replaceFirstInput(this, prevBegin);
  76             }
  77         }
  78     }
  79 
  80     public void prepareDelete() {
  81         prepareDelete((FixedNode) predecessor());
  82     }
  83 
  84     public void prepareDelete(FixedNode evacuateFrom) {
  85         evacuateGuards(evacuateFrom);
  86     }
  87 
  88     @Override
  89     public boolean verify() {
  90         assertTrue(predecessor() != null || this == graph().start() || this instanceof AbstractMergeNode, "begin nodes must be connected");
  91         return super.verify();
  92     }
  93 
  94     @Override
  95     public void generate(NodeLIRBuilderTool gen) {
  96         if (withSpeculationFence) {
  97             gen.getLIRGeneratorTool().emitSpeculationFence();
  98         }
  99     }
 100 
 101     public NodeIterable<GuardNode> guards() {
 102         return usages().filter(GuardNode.class);
 103     }
 104 
 105     public NodeIterable<Node> anchored() {
 106         return usages();
 107     }
 108 
 109     public NodeIterable<FixedNode> getBlockNodes() {
 110         return new NodeIterable<FixedNode>() {
 111 
 112             @Override
 113             public Iterator<FixedNode> iterator() {
 114                 return new BlockNodeIterator(AbstractBeginNode.this);
 115             }
 116         };
 117     }
 118 
 119     /**
 120      * Set this begin node to be a speculation fence. This will prevent speculative execution of
 121      * this block.
 122      */
 123     public void setWithSpeculationFence() {
 124         this.withSpeculationFence = true;
 125     }
 126 
 127     private static class BlockNodeIterator implements Iterator<FixedNode> {
 128 
 129         private FixedNode current;
 130 
 131         BlockNodeIterator(FixedNode next) {
 132             this.current = next;
 133         }
 134 
 135         @Override
 136         public boolean hasNext() {
 137             return current != null;
 138         }
 139 
 140         @Override
 141         public FixedNode next() {
 142             FixedNode ret = current;
 143             if (ret == null) {
 144                 throw new NoSuchElementException();
 145             }
 146             if (current instanceof FixedWithNextNode) {
 147                 current = ((FixedWithNextNode) current).next();
 148                 if (current instanceof AbstractBeginNode) {
 149                     current = null;
 150                 }
 151             } else {
 152                 current = null;
 153             }
 154             return ret;
 155         }
 156 
 157         @Override
 158         public void remove() {
 159             throw new UnsupportedOperationException();
 160         }
 161     }
 162 }