1 /*
   2  * Copyright (c) 2011, 2015, 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 static org.graalvm.compiler.nodeinfo.InputType.Association;
  28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
  29 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  30 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
  31 
  32 import java.util.Collections;
  33 
  34 import org.graalvm.compiler.graph.Node;
  35 import org.graalvm.compiler.graph.NodeClass;
  36 import org.graalvm.compiler.nodeinfo.NodeCycles;
  37 import org.graalvm.compiler.nodeinfo.NodeInfo;
  38 import org.graalvm.compiler.nodeinfo.NodeSize;
  39 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
  40 
  41 /**
  42  * LoopEnd nodes represent a loop back-edge. When a LoopEnd is reached, execution continues at the
  43  * {@linkplain #loopBegin() loop header}.
  44  */
  45 @NodeInfo(cycles = CYCLES_1, cyclesRationale = "Backedge jmp", size = SIZE_1, sizeRationale = "Backedge jmp")
  46 public final class LoopEndNode extends AbstractEndNode {
  47 
  48     public static final NodeClass<LoopEndNode> TYPE = NodeClass.create(LoopEndNode.class);
  49 
  50     /*
  51      * The declared type of the field cannot be LoopBeginNode, because loop explosion during partial
  52      * evaluation can temporarily assign a non-loop begin. This node will then be deleted shortly
  53      * after - but we still must not have type system violations for that short amount of time.
  54      */
  55     @Input(Association) AbstractBeginNode loopBegin;
  56     protected int endIndex;
  57 
  58     /**
  59      * Most loop ends need a safepoint (flag set to true) so that garbage collection can interrupt a
  60      * long-running (possibly endless) loop. Safepoints may be disabled for two reasons: 1) Some
  61      * code must be safepoint free, i.e., uninterruptible by garbage collection. 2) An optimization
  62      * phase determined that the loop already has another safepoint or cannot be endless, so there
  63      * is no need for a loop-end safepoint.
  64      *
  65      * Note that 1) is a hard correctness issue: emitting a safepoint in uninterruptible code is a
  66      * bug, i.e., it is not allowed to set the flag back to true once it is false. To ensure that
  67      * loop ends that are created late, e.g., during control flow simplifications, have no
  68      * safepoints in such cases, the safepoints are actually disabled for the
  69      * {@link LoopBeginNode#canEndsSafepoint loop begin}. New loop ends inherit the flag value from
  70      * the loop begin.
  71      */
  72     boolean canSafepoint;
  73 
  74     public LoopEndNode(LoopBeginNode begin) {
  75         super(TYPE);
  76         int idx = begin.nextEndIndex();
  77         assert idx >= 0;
  78         this.endIndex = idx;
  79         this.loopBegin = begin;
  80         this.canSafepoint = begin.canEndsSafepoint;
  81     }
  82 
  83     @Override
  84     public AbstractMergeNode merge() {
  85         return loopBegin();
  86     }
  87 
  88     public LoopBeginNode loopBegin() {
  89         return (LoopBeginNode) loopBegin;
  90     }
  91 
  92     public void setLoopBegin(LoopBeginNode x) {
  93         updateUsages(this.loopBegin, x);
  94         this.loopBegin = x;
  95     }
  96 
  97     /**
  98      * Disables safepoints for only this loop end (in contrast to disabling it for
  99      * {@link LoopBeginNode#disableSafepoint() the whole loop}.
 100      */
 101     public void disableSafepoint() {
 102         this.canSafepoint = false;
 103     }
 104 
 105     public boolean canSafepoint() {
 106         assert !canSafepoint || loopBegin().canEndsSafepoint : "When safepoints are disabled for loop begin, safepoints must be disabled for all loop ends";
 107         return canSafepoint;
 108     }
 109 
 110     @Override
 111     public void generate(NodeLIRBuilderTool gen) {
 112         gen.visitLoopEnd(this);
 113         super.generate(gen);
 114     }
 115 
 116     @Override
 117     public boolean verify() {
 118         assertTrue(loopBegin != null, "must have a loop begin");
 119         assertTrue(hasNoUsages(), "LoopEnds can not be used");
 120         return super.verify();
 121     }
 122 
 123     /**
 124      * Returns the index of this loop end amongst its {@link LoopBeginNode}'s loop ends.<br>
 125      *
 126      * Since a LoopBeginNode also has {@linkplain LoopBeginNode#forwardEnds() forward ends}, this is
 127      * <b>not</b> the index into {@link PhiNode} values at the loop begin. Use
 128      * {@link LoopBeginNode#phiPredecessorIndex(AbstractEndNode)} for this purpose.
 129      *
 130      */
 131     int endIndex() {
 132         return endIndex;
 133     }
 134 
 135     void setEndIndex(int idx) {
 136         this.endIndex = idx;
 137     }
 138 
 139     @Override
 140     public Iterable<? extends Node> cfgSuccessors() {
 141         return Collections.emptyList();
 142     }
 143 
 144     @Override
 145     public NodeCycles estimatedNodeCycles() {
 146         if (canSafepoint()) {
 147             // jmp+read
 148             return CYCLES_2;
 149         }
 150         return super.estimatedNodeCycles();
 151     }
 152 
 153     @Override
 154     public NodeSize estimatedNodeSize() {
 155         if (canSafepoint()) {
 156             return NodeSize.SIZE_2;
 157         }
 158         return super.estimatedNodeSize();
 159     }
 160 }