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 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 }