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 */
013package org.jikesrvm.compilers.opt.driver;
014
015import java.lang.reflect.Constructor;
016
017import org.jikesrvm.VM;
018import org.jikesrvm.compilers.opt.OptOptions;
019import org.jikesrvm.compilers.opt.OptimizingCompilerException;
020import 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 */
048public 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 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   * @param klass the compiler phase to construct
163   * @return a no-argument constructor for the compiler phase
164   */
165  protected static Constructor<CompilerPhase> getCompilerPhaseConstructor(Class<? extends CompilerPhase> klass) {
166    return getCompilerPhaseConstructor(klass, null);
167  }
168
169  /**
170   * Given the name of a compiler phase return the default (no
171   * argument) constructor for it.
172   *
173   * @param phaseType the class for the compiler phase
174   * @param initTypes the argument types for the constructor
175   * @return a constructor for the compiler phase
176   */
177  protected static Constructor<CompilerPhase> getCompilerPhaseConstructor(Class<? extends CompilerPhase> phaseType,
178                                                                              Class<?>[] initTypes) {
179    try {
180      @SuppressWarnings("unchecked") // We are explicitly breaking type safety
181          Constructor<CompilerPhase> constructor =
182          (Constructor<CompilerPhase>) phaseType.getConstructor(initTypes);
183      return constructor;
184    } catch (NoSuchMethodException e) {
185      throw new Error("Constructor not found in " + phaseType.getName() + " compiler phase", e);
186    }
187  }
188
189  public final void setContainer(OptimizationPlanAtomicElement atomEl) {
190    container = atomEl;
191  }
192
193  /**
194   * Runs a phase by calling perform on the supplied IR surrounded by
195   * printing/messaging/debugging glue.
196   * @param ir the IR object on which to do the work of the phase.
197   */
198  public final void performPhase(IR ir) {
199    if (printingEnabled(ir.options, true)) {
200      if (!ir.options.hasMETHOD_TO_PRINT() || ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
201        // only print above certain opt level.
202        //if (ir.options.getOptLevel() >= ir.options.IR_PRINT_LEVEL) {
203        dumpIR(ir, "Before " + getName());
204        //}
205      }
206    }
207    if (ir.options.PRINT_PHASES) VM.sysWrite(getName() + " (" + ir.method.toString() + ")");
208
209    perform(ir);                // DOIT!!
210
211    if (ir.options.PRINT_PHASES) VM.sysWrite(" done\n");
212    if (ir.options.PRINT_ALL_IR || printingEnabled(ir.options, false)) {
213      if (!ir.options.hasMETHOD_TO_PRINT() || ir.options.fuzzyMatchMETHOD_TO_PRINT(ir.method.toString())) {
214        // only print when above certain opt level
215        if (ir.options.getOptLevel() >= ir.options.PRINT_IR_LEVEL) {
216          dumpIR(ir, "After " + getName());
217        }
218      }
219    }
220
221    if (IR.PARANOID) verify(ir);
222  }
223
224  /**
225   * Prints the IR, optionally including the CFG
226   *
227   * @param ir the IR to print
228   * @param tag a String to use in the start/end message of the IR dump
229   */
230  public static void dumpIR(IR ir, String tag) {
231    if (ir.options.PRINT_VISUALIZATION) {
232      try {
233        CFGVisualization visualization = new CFGVisualization(ir, tag);
234        visualization.visualizeCFG();
235        return;
236      } catch (Exception e) {
237        System.out.println("Error generating IR visualization: ");
238        e.printStackTrace(System.out);
239        System.out.println("Generating text dump instead ...");
240      }
241    }
242
243    dumpIR(ir, tag, false);
244  }
245
246  /**
247   * Prints the IR, optionally including the CFG
248   *
249   * @param ir the IR to print
250   * @param forceCFG should the CFG be printed, independent of the value of ir.options.PRINT_CFG?
251   * @param tag a String to use in the start/end message of the IR dump
252   */
253  public static void dumpIR(IR ir, String tag, boolean forceCFG) {
254    System.out.println("********* START OF IR DUMP  " + tag + "   FOR " + ir.method);
255    ir.printInstructions();
256    if (forceCFG || ir.options.PRINT_CFG) {
257      ir.cfg.printDepthFirst();
258    }
259    System.out.println("*********   END OF IR DUMP  " + tag + "   FOR " + ir.method);
260  }
261
262  /**
263   * Verify the IR.
264   * Written as a non-final virtual method to allow late stages in the
265   * compilation pipeline (eg ConvertMIR2MC) to skip verification.
266   *
267   * @param ir the IR to verify
268   */
269  public void verify(IR ir) {
270    ir.verify(getName(), true);
271  }
272}