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