1 /*
   2  * Copyright (c) 2013, 2019, 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.phases;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Collections;
  29 import java.util.List;
  30 import java.util.ListIterator;
  31 
  32 import org.graalvm.compiler.nodes.StructuredGraph;
  33 
  34 /**
  35  * A compiler phase that can apply an ordered collection of phases to a graph.
  36  */
  37 public class PhaseSuite<C> extends BasePhase<C> {
  38 
  39     private List<BasePhase<? super C>> phases;
  40     private boolean immutable;
  41 
  42     public PhaseSuite() {
  43         this.phases = new ArrayList<>();
  44     }
  45 
  46     @Override
  47     public boolean checkContract() {
  48         return false;
  49     }
  50 
  51     public boolean isImmutable() {
  52         return immutable;
  53     }
  54 
  55     public synchronized void setImmutable() {
  56         if (!immutable) {
  57             phases = Collections.unmodifiableList(phases);
  58             immutable = true;
  59         }
  60     }
  61 
  62     /**
  63      * Add a new phase at the beginning of this suite.
  64      */
  65     public final void prependPhase(BasePhase<? super C> phase) {
  66         phases.add(0, phase);
  67     }
  68 
  69     /**
  70      * Add a new phase at the end of this suite.
  71      */
  72     public final void appendPhase(BasePhase<? super C> phase) {
  73         phases.add(phase);
  74     }
  75 
  76     /**
  77      * Inserts a phase before the last phase in the suite. If the suite contains no phases the new
  78      * phase will be inserted as the first phase.
  79      */
  80     public final void addBeforeLast(BasePhase<? super C> phase) {
  81         ListIterator<BasePhase<? super C>> last = findLastPhase();
  82         if (last.hasPrevious()) {
  83             last.previous();
  84         }
  85         last.add(phase);
  86     }
  87 
  88     /**
  89      * Returns a {@link ListIterator} at the position of the last phase in the suite. If the suite
  90      * has no phases then it will return an empty iterator.
  91      */
  92     public ListIterator<BasePhase<? super C>> findLastPhase() {
  93         ListIterator<BasePhase<? super C>> it = phases.listIterator();
  94         while (it.hasNext()) {
  95             it.next();
  96         }
  97         return it;
  98     }
  99 
 100     /**
 101      * Gets an unmodifiable view on the phases in this suite.
 102      */
 103     public List<BasePhase<? super C>> getPhases() {
 104         return Collections.unmodifiableList(phases);
 105     }
 106 
 107     /**
 108      * Returns a {@link ListIterator} at the position of the first phase which is an instance of
 109      * {@code phaseClass} or null if no such phase can be found.
 110      *
 111      * Calling {@link ListIterator#previous()} would return the phase that was found.
 112      *
 113      * @param phaseClass the type of phase to look for.
 114      */
 115     public final ListIterator<BasePhase<? super C>> findPhase(Class<? extends BasePhase<? super C>> phaseClass) {
 116         return findPhase(phaseClass, false);
 117     }
 118 
 119     /**
 120      * Returns a {@link ListIterator} at the position of the first phase which is an instance of
 121      * {@code phaseClass} or, if {@code recursive} is true, is a {@link PhaseSuite} containing a
 122      * phase which is an instance of {@code phaseClass}. This method returns null if no such phase
 123      * can be found.
 124      *
 125      * Calling {@link ListIterator#previous()} would return the phase or phase suite that was found.
 126      *
 127      * @param phaseClass the type of phase to look for
 128      * @param recursive whether to recursively look into phase suites.
 129      */
 130     public final ListIterator<BasePhase<? super C>> findPhase(Class<? extends BasePhase<? super C>> phaseClass, boolean recursive) {
 131         ListIterator<BasePhase<? super C>> it = phases.listIterator();
 132         if (findNextPhase(it, phaseClass, recursive)) {
 133             return it;
 134         } else {
 135             return null;
 136         }
 137     }
 138 
 139     public static <C> boolean findNextPhase(ListIterator<BasePhase<? super C>> it, Class<? extends BasePhase<? super C>> phaseClass) {
 140         return findNextPhase(it, phaseClass, false);
 141     }
 142 
 143     @SuppressWarnings("unchecked")
 144     public static <C> boolean findNextPhase(ListIterator<BasePhase<? super C>> it, Class<? extends BasePhase<? super C>> phaseClass, boolean recursive) {
 145         while (it.hasNext()) {
 146             BasePhase<? super C> phase = it.next();
 147             if (phaseClass.isInstance(phase)) {
 148                 return true;
 149             } else if (recursive && phase instanceof PhaseSuite) {
 150                 PhaseSuite<C> suite = (PhaseSuite<C>) phase;
 151                 if (suite.findPhase(phaseClass, true) != null) {
 152                     return true;
 153                 }
 154             }
 155         }
 156         return false;
 157     }
 158 
 159     /**
 160      * Removes the first instance of the given phase class, looking recursively into inner phase
 161      * suites.
 162      */
 163     @SuppressWarnings("unchecked")
 164     public boolean removePhase(Class<? extends BasePhase<? super C>> phaseClass) {
 165         ListIterator<BasePhase<? super C>> it = phases.listIterator();
 166         while (it.hasNext()) {
 167             BasePhase<? super C> phase = it.next();
 168             if (phaseClass.isInstance(phase)) {
 169                 it.remove();
 170                 return true;
 171             } else if (phase instanceof PhaseSuite) {
 172                 PhaseSuite<C> innerSuite = (PhaseSuite<C>) phase;
 173                 if (innerSuite.removePhase(phaseClass)) {
 174                     if (innerSuite.phases.isEmpty()) {
 175                         it.remove();
 176                     }
 177                     return true;
 178                 }
 179             }
 180         }
 181         return false;
 182     }
 183 
 184     /**
 185      * Removes the first instance of the given phase class, looking recursively into inner phase
 186      * suites.
 187      */
 188     @SuppressWarnings("unchecked")
 189     public boolean replacePhase(Class<? extends BasePhase<? super C>> phaseClass, BasePhase<? super C> newPhase) {
 190         ListIterator<BasePhase<? super C>> it = phases.listIterator();
 191         while (it.hasNext()) {
 192             BasePhase<? super C> phase = it.next();
 193             if (phaseClass.isInstance(phase)) {
 194                 it.set(newPhase);
 195                 return true;
 196             } else if (phase instanceof PhaseSuite) {
 197                 PhaseSuite<C> innerSuite = (PhaseSuite<C>) phase;
 198                 if (innerSuite.replacePhase(phaseClass, newPhase)) {
 199                     return true;
 200                 }
 201             }
 202         }
 203         return false;
 204     }
 205 
 206     @Override
 207     protected void run(StructuredGraph graph, C context) {
 208         for (BasePhase<? super C> phase : phases) {
 209             phase.apply(graph, context);
 210         }
 211     }
 212 
 213     public PhaseSuite<C> copy() {
 214         PhaseSuite<C> suite = new PhaseSuite<>();
 215         suite.phases.addAll(phases);
 216         return suite;
 217     }
 218 }