001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.compilers.opt.driver;
014
015 import java.lang.reflect.Constructor;
016
017 import org.jikesrvm.VM;
018 import org.jikesrvm.compilers.opt.OptOptions;
019 import org.jikesrvm.compilers.opt.OptimizingCompilerException;
020 import org.jikesrvm.compilers.opt.ir.IR;
021
022 /**
023 * Compiler phases all extend this abstract class.
024 * All compiler phases must provide implementations of
025 * two abstract methods:
026 * <ul>
027 * <li> getName: return a String that is the name of the phase
028 * <li> perform: actually do the work of the phase
029 * </ul>
030 *
031 * <p> By default, a new instance of the phase is created each time
032 * shouldPerform is called. This instance is discarded as soon
033 * as shouldPerform completes. Therefore, it is allowable
034 * (and is suggested when necessary) for subclasses
035 * to use their instance fields to hold per-compilation state.
036 * To be more concrete, the pattern of use is:
037 * <pre>
038 * newExecution(ir).performPhase(ir).
039 * </pre>
040 * @see OptimizationPlanAtomicElement#perform
041 *
042 * <p> NOTE: compiler phases that do not need to use instance
043 * fields to hold per-compilation state may override
044 * <code> newExecution() </code> to return this. Doing so may lead to
045 * memory leaks and concurrent access problems, so this should be done
046 * with great care!
047 */
048 public abstract class CompilerPhase {
049
050 /**
051 * The plan element that contains this phase.
052 * Only useful if the phase wants to gather additional statistics
053 * for a measure compilation report.
054 */
055 protected OptimizationPlanAtomicElement container;
056
057 /**
058 * Arguments to constructor that copies this phase
059 */
060 private final Object[] initargs;
061
062 /**
063 * Constructor
064 */
065 public CompilerPhase() {
066 initargs = null;
067 }
068
069 /**
070 * Constructor
071 *
072 * @param initargs arguments used when constructing copies of this phase
073 */
074 public CompilerPhase(Object[] initargs) {
075 this.initargs = initargs;
076 }
077
078 /**
079 * @return a String which is the name of the phase.
080 */
081 public abstract String getName();
082
083 /**
084 * This is the method that actually does the work of the phase.
085 *
086 * @param ir the IR on which to apply the phase
087 */
088 public abstract void perform(IR ir);
089
090 /**
091 * This method determines if the phase should be run, based on the
092 * Options object it is passed.
093 * By default, phases are always performed.
094 * Subclasses should override this method if they only want
095 * to be performed conditionally.
096 *
097 * @param options the compiler options for the compilation
098 * @return true if the phase should be performed
099 */
100 public boolean shouldPerform(OptOptions options) {
101 return true;
102 }
103
104 /**
105 * Returns true if the phase wants the IR dumped before and/or after it runs.
106 * By default, printing is not enabled.
107 * Subclasses should override this method if they want to provide IR dumping.
108 *
109 * @param options the compiler options for the compilation
110 * @param before true when invoked before perform, false otherwise.
111 * @return true if the IR should be printed, false otherwise.
112 */
113 public boolean printingEnabled(OptOptions options, boolean before) {
114 return false;
115 }
116
117 /**
118 * Called when printing a measure compilation report to enable a phase
119 * to report additional phase-specific statistics.
120 */
121 public void reportAdditionalStats() {}
122
123 /**
124 * This method is called immediately before performPhase. Phases
125 * that do not need to create a new instance for each execution may
126 * override this method to return this, but this must be done
127 * carefully! Classes that don't override this method need to
128 * override getClassConstructor.
129 *
130 * @param ir the IR that is about to be passed to performPhase
131 * @return an opt compiler phase on which performPhase may be invoked.
132 */
133 public CompilerPhase newExecution(IR ir) {
134 Constructor<CompilerPhase> cons = getClassConstructor();
135 if (cons != null) {
136 try {
137 return (CompilerPhase) cons.newInstance(initargs);
138 } catch (Exception e) {
139 throw new Error("Failed to create phase " + this.getClass() + " with constructor " + cons, e);
140 }
141 } else {
142 throw new Error("Error, no constructor found in phase " +
143 this.getClass() +
144 " make sure a public constructor is declared");
145 }
146 }
147
148 /**
149 * Get a constructor object for this compiler phase
150 *
151 * @return exception/null as this phase can't be created
152 */
153 public Constructor<CompilerPhase> getClassConstructor() {
154 OptimizingCompilerException.UNREACHABLE();
155 return null;
156 }
157
158 /**
159 * Given the name of a compiler phase return the default (no
160 * argument) constructor for it.
161 */
162 protected static Constructor<CompilerPhase> getCompilerPhaseConstructor(Class<? extends CompilerPhase> klass) {
163 return getCompilerPhaseConstructor(klass, null);
164 }
165
166 /**
167 * Given the name of a compiler phase return the default (no
168 * argument) constructor for it.
169 */
170 protected static Constructor<CompilerPhase> getCompilerPhaseConstructor(Class<? extends CompilerPhase> phaseType,
171 Class<?>[] initTypes) {
172 try {
173 @SuppressWarnings("unchecked") // We are explicitly breaking type safety
174 Constructor<CompilerPhase> constructor =
175 (Constructor<CompilerPhase>) phaseType.getConstructor(initTypes);
176 return constructor;
177 } catch (NoSuchMethodException e) {
178 throw new Error("Constructor not found in " + phaseType.getName() + " compiler phase", e);
179 }
180 }
181
182 /**
183 * Set the containing optimization plan element for this phase
184 */
185 public final void setContainer(OptimizationPlanAtomicElement atomEl) {
186 container = atomEl;
187 }
188
189 /**
190 * Runs a phase by calling perform on the supplied IR surrounded by
191 * printing/messaging/debugging glue.
192 * @param ir the IR object on which to do the work of the phase.
193 */
194 public final void performPhase(IR ir) {
195 if (printingEnabled(ir.options, true)) {
196 if (!ir.options.hasMETHOD_TO_PRINT() || ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
197 // only print above certain opt level.
198 //if (ir.options.getOptLevel() >= ir.options.IR_PRINT_LEVEL) {
199 dumpIR(ir, "Before " + getName());
200 //}
201 }
202 }
203 if (ir.options.PRINT_PHASES) VM.sysWrite(getName() + " (" + ir.method.toString()+ ")");
204
205 perform(ir); // DOIT!!
206
207 if (ir.options.PRINT_PHASES) VM.sysWrite(" done\n");
208 if (ir.options.PRINT_ALL_IR || printingEnabled(ir.options, false)) {
209 if (!ir.options.hasMETHOD_TO_PRINT() || ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
210 // only print when above certain opt level
211 if (ir.options.getOptLevel() >= ir.options.PRINT_IR_LEVEL) {
212 dumpIR(ir, "After " + getName());
213 }
214 }
215 }
216
217 if (IR.PARANOID) verify(ir);
218 }
219
220 /**
221 * Prints the IR, optionally including the CFG
222 *
223 * @param ir the IR to print
224 * @param tag a String to use in the start/end message of the IR dump
225 */
226 public static void dumpIR(IR ir, String tag) {
227 dumpIR(ir, tag, false);
228 }
229
230 /**
231 * Prints the IR, optionally including the CFG
232 *
233 * @param ir the IR to print
234 * @param forceCFG should the CFG be printed, independent of the value of ir.options.PRINT_CFG?
235 * @param tag a String to use in the start/end message of the IR dump
236 */
237 public static void dumpIR(IR ir, String tag, boolean forceCFG) {
238 System.out.println("********* START OF IR DUMP " + tag + " FOR " + ir.method);
239 ir.printInstructions();
240 if (forceCFG || ir.options.PRINT_CFG) {
241 ir.cfg.printDepthFirst();
242 }
243 System.out.println("********* END OF IR DUMP " + tag + " FOR " + ir.method);
244 }
245
246 /**
247 * Verify the IR.
248 * Written as a non-final virtual method to allow late stages in the
249 * compilation pipeline (eg ConvertMIR2MC) to skip verification.
250 *
251 * @param ir the IR to verify
252 */
253 public void verify(IR ir) {
254 ir.verify(getName(), true);
255 }
256 }