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}