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 org.jikesrvm.Callbacks; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.classloader.NormalMethod; 018 import org.jikesrvm.compilers.common.CompiledMethod; 019 import org.jikesrvm.compilers.opt.MagicNotImplementedException; 020 import org.jikesrvm.compilers.opt.OptOptions; 021 import org.jikesrvm.compilers.opt.OptimizingCompilerException; 022 import org.jikesrvm.compilers.opt.ir.IR; 023 import org.jikesrvm.compilers.opt.specialization.InvokeeThreadLocalContext; 024 import org.jikesrvm.compilers.opt.specialization.SpecializationDatabase; 025 026 /** 027 * <p> The main driver of the Compiler. 028 * <p> External drivers are responsible for providing the policies; the 029 * role of this class is simply to take a CompilationPlan 030 * and execute it. 031 * 032 * <p> Currently, this class is invoked from four clients: 033 * <ul> 034 * <li> (1) Command line: ExecuteOptCode 035 * <li> (2) BootImageWriting: BootImageCompiler.compile (optimizing version) 036 * <li> (3) RuntimeCompiler: RuntimeCompiler.compile (optimizing version) 037 * <li> (4) AOS: Compilation threads execute controller plans by invoking 038 * the opt compiler. 039 * </ul> 040 * 041 * <p> Clients are responsible for ensuring that: 042 * <ul> 043 * <li> (1) the VM has been initialized 044 * <li> (2) Compiler.init has been called before the first opt compilation 045 * </ul> 046 * 047 * <p> This class is not meant to be instantiated. 048 */ 049 public final class OptimizingCompiler implements Callbacks.StartupMonitor { 050 051 //////////////////////////////////////////// 052 // Initialization 053 //////////////////////////////////////////// 054 /** 055 * Prepare compiler for use. 056 * @param options options to use for compilations during initialization 057 */ 058 public static void init(OptOptions options) { 059 try { 060 if (!(VM.writingBootImage || VM.runningTool || VM.runningVM)) { 061 // Caller failed to ensure that the VM was initialized. 062 throw new OptimizingCompilerException("VM not initialized", true); 063 } 064 // Make a local copy so that some options can be forced off just for the 065 // duration of this initialization step. 066 options = options.dup(); 067 options.ESCAPE_SIMPLE_IPA = false; 068 069 initializeStatics(); 070 071 // want to be notified when VM boot is done and ready to start application 072 Callbacks.addStartupMonitor(new OptimizingCompiler()); 073 isInitialized = true; 074 } catch (OptimizingCompilerException e) { 075 // failures during initialization can't be ignored 076 e.isFatal = true; 077 throw e; 078 } catch (Throwable e) { 079 VM.sysWriteln(e.toString()); 080 throw new OptimizingCompilerException("Compiler", 081 "untrapped failure during init, " + 082 " Converting to OptimizingCompilerException"); 083 } 084 } 085 086 /* 087 * callback when application is about to start. 088 */ 089 @Override 090 public void notifyStartup() { 091 if (VM.TraceOnStackReplacement) { 092 VM.sysWriteln("Compiler got notified of app ready to begin"); 093 } 094 setAppStarted(); 095 } 096 097 /** 098 * indicate when the application has started 099 */ 100 private static boolean appStarted = false; 101 102 public static synchronized boolean getAppStarted() { return appStarted; } 103 104 public static synchronized void setAppStarted() { appStarted = true; } 105 106 /** 107 * Set up option used while compiling the boot image 108 * @param options the options to set 109 */ 110 public static void setBootOptions(OptOptions options) { 111 // Only do guarded inlining if we can use code patches. 112 // Early speculation with method test/class test can result in 113 // bad code that we can't recover from later. 114 options.INLINE_GUARDED = options.guardWithCodePatch(); 115 116 // Compute summaries of bootimage methods if we haven't encountered them yet. 117 // Does not handle unimplemented magics very well; disable until 118 // we can get a chance to either implement them on IA32 or fix the 119 // analysis to not be so brittle. 120 // options.SIMPLE_ESCAPE_IPA = true; 121 } 122 123 /** 124 * Call the static init functions for the Compiler subsystems 125 */ 126 private static void initializeStatics() { 127 InvokeeThreadLocalContext.init(); 128 } 129 130 /** 131 * Prevent instantiation by clients 132 */ 133 private OptimizingCompiler() { 134 } 135 136 /** 137 * Has the optimizing compiler been initialized? 138 */ 139 private static boolean isInitialized = false; 140 141 /** 142 * Has the optimizing compiler been initialized? 143 */ 144 public static boolean isInitialized() { 145 return isInitialized; 146 } 147 148 /** 149 * Reset the optimizing compiler 150 */ 151 static void reset() { 152 isInitialized = false; 153 } 154 155 //////////////////////////////////////////// 156 // Public interface for compiling a method 157 //////////////////////////////////////////// 158 /** 159 * Invoke the opt compiler to execute a compilation plan. 160 * 161 * @param cp the compilation plan to be executed 162 * @return the CompiledMethod object that is the result of compilation 163 */ 164 public static CompiledMethod compile(CompilationPlan cp) { 165 NormalMethod method = cp.method; 166 OptOptions options = cp.options; 167 checkSupported(method, options); 168 try { 169 printMethodMessage(method, options); 170 IR ir = cp.execute(); 171 // if doing analysis only, don't try to return an object 172 if (cp.analyzeOnly || cp.irGeneration) { 173 return null; 174 } 175 // now that we're done compiling, give the specialization 176 // system a chance to eagerly compile any specialized version 177 // that are pending. TODO: use lazy compilation with specialization. 178 SpecializationDatabase.doDeferredSpecializations(); 179 ir.compiledMethod.compileComplete(ir.MIRInfo.machinecode); 180 return ir.compiledMethod; 181 } catch (OptimizingCompilerException e) { 182 throw e; 183 } catch (Throwable e) { 184 fail(e, method); 185 return null; 186 } 187 } 188 189 /** 190 * Debugging aid. 191 * @param what a string message to print 192 */ 193 public static void report(String what) { 194 VM.sysWrite(what + '\n'); 195 } 196 197 /** 198 * Debugging aid. 199 * @param what a string message to print 200 * @param time a timestamp to print 201 */ 202 public static void report(String what, long time) { 203 VM.sysWrite(what); 204 if (what.length() < 8) { 205 VM.sysWrite('\t'); 206 } 207 if (what.length() < 16) { 208 VM.sysWrite('\t'); 209 } 210 VM.sysWrite('\t' + time + " ms"); 211 } 212 213 /** 214 * Debugging aid to be called before printing the IR 215 * @param what a string message to print 216 * @param method the method being compiled 217 */ 218 public static void header(String what, NormalMethod method) { 219 System.out.println("********* START OF: " + what + " FOR " + method); 220 } 221 222 /** 223 * Debugging aid to be called after printing the IR 224 * @param what a string message to print 225 * @param method the method being compiled 226 */ 227 public static void bottom(String what, NormalMethod method) { 228 System.out.println("********* END OF: " + what + " FOR " + method); 229 } 230 231 /** 232 * Print the IR along with a message 233 * @param ir 234 * @param message 235 */ 236 public static void printInstructions(IR ir, String message) { 237 header(message, ir.method); 238 ir.printInstructions(); 239 bottom(message, ir.method); 240 } 241 242 /** 243 * Print a message of a method name 244 * @param method 245 * @param options 246 */ 247 private static void printMethodMessage(NormalMethod method, OptOptions options) { 248 if (options.PRINT_METHOD || options.PRINT_INLINE_REPORT) { 249 VM.sysWrite("-methodOpt " + 250 method.getDeclaringClass() + 251 ' ' + 252 method.getName() + 253 ' ' + 254 method.getDescriptor() + 255 " \n"); 256 } 257 } 258 259 /** 260 * Abort a compilation with an error. 261 * @param e The exception thrown by a compiler phase 262 * @param method The method being compiled 263 */ 264 private static void fail(Throwable e, NormalMethod method) { 265 OptimizingCompilerException optExn = 266 new OptimizingCompilerException("Compiler", "failure during compilation of", method.toString()); 267 if (e instanceof OutOfMemoryError) { 268 VM.sysWriteln("Compiler ran out of memory during compilation of ", method.toString()); 269 optExn.isFatal = false; 270 } else { 271 VM.sysWriteln("Compiler failure during compilation of ", method.toString()); 272 e.printStackTrace(); 273 } 274 throw optExn; 275 } 276 277 /** 278 * Check whether opt compilation of a particular method is supported. 279 * If not, throw a non-fatal run-time exception. 280 */ 281 private static void checkSupported(NormalMethod method, OptOptions options) { 282 if (method.getDeclaringClass().hasDynamicBridgeAnnotation()) { 283 String msg = "Dynamic Bridge register save protocol not implemented"; 284 throw MagicNotImplementedException.EXPECTED(msg); 285 } 286 if (method.getDeclaringClass().hasBridgeFromNativeAnnotation()) { 287 String msg = "Native Bridge prologue not implemented"; 288 throw MagicNotImplementedException.EXPECTED(msg); 289 } 290 if (method.hasNoOptCompileAnnotation()) { 291 String msg = "Method throws NoOptCompilePragma"; 292 throw MagicNotImplementedException.EXPECTED(msg); 293 } 294 if (options.hasDRIVER_EXCLUDE()) { 295 String name = method.getDeclaringClass().toString() + "." + method.getName(); 296 if (options.fuzzyMatchDRIVER_EXCLUDE(name)) { 297 if (!method.getDeclaringClass().hasSaveVolatileAnnotation()) { 298 throw new OptimizingCompilerException("method excluded", false); 299 } 300 } 301 } 302 } 303 }