1 /*
2  * Copyright (c) 2013, 2018, 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 
PhaseSuite()42     public PhaseSuite() {
43         this.phases = new ArrayList<>();
44     }
45 
46     @Override
checkContract()47     public boolean checkContract() {
48         return false;
49     }
50 
isImmutable()51     public boolean isImmutable() {
52         return immutable;
53     }
54 
setImmutable()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      */
prependPhase(BasePhase<? super C> phase)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      */
appendPhase(BasePhase<? super C> phase)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      */
addBeforeLast(BasePhase<? super C> phase)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      */
findLastPhase()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      */
getPhases()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      */
findPhase(Class<? extends BasePhase<? super C>> phaseClass)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      */
findPhase(Class<? extends BasePhase<? super C>> phaseClass, boolean recursive)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 
findNextPhase(ListIterator<BasePhase<? super C>> it, Class<? extends BasePhase<? super C>> phaseClass)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")
findNextPhase(ListIterator<BasePhase<? super C>> it, Class<? extends BasePhase<? super C>> phaseClass, boolean recursive)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")
removePhase(Class<? extends BasePhase<? super C>> phaseClass)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")
replacePhase(Class<? extends BasePhase<? super C>> phaseClass, BasePhase<? super C> newPhase)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.removePhase(phaseClass)) {
199                     if (innerSuite.phases.isEmpty()) {
200                         it.set(newPhase);
201                     }
202                     return true;
203                 }
204             }
205         }
206         return false;
207     }
208 
209     @Override
run(StructuredGraph graph, C context)210     protected void run(StructuredGraph graph, C context) {
211         for (BasePhase<? super C> phase : phases) {
212             phase.apply(graph, context);
213         }
214     }
215 
copy()216     public PhaseSuite<C> copy() {
217         PhaseSuite<C> suite = new PhaseSuite<>();
218         suite.phases.addAll(phases);
219         return suite;
220     }
221 }
222