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 * 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 public void notifyStartup() {
090 if (VM.TraceOnStackReplacement) {
091 VM.sysWriteln("Compiler got notified of app ready to begin");
092 }
093 setAppStarted();
094 }
095
096 /**
097 * indicate when the application has started
098 */
099 private static boolean appStarted = false;
100
101 public static synchronized boolean getAppStarted() { return appStarted; }
102
103 public static synchronized void setAppStarted() { appStarted = true; }
104
105 /**
106 * Set up option used while compiling the boot image
107 * @param options the options to set
108 */
109 public static void setBootOptions(OptOptions options) {
110 // Only do guarded inlining if we can use code patches.
111 // Early speculation with method test/class test can result in
112 // bad code that we can't recover from later.
113 options.INLINE_GUARDED = options.guardWithCodePatch();
114
115 // Compute summaries of bootimage methods if we haven't encountered them yet.
116 // Does not handle unimplemented magics very well; disable until
117 // we can get a chance to either implement them on IA32 or fix the
118 // analysis to not be so brittle.
119 // options.SIMPLE_ESCAPE_IPA = true;
120 }
121
122 /**
123 * Call the static init functions for the Compiler subsystems
124 */
125 private static void initializeStatics() {
126 InvokeeThreadLocalContext.init();
127 }
128
129 /**
130 * Prevent instantiation by clients
131 */
132 private OptimizingCompiler() {
133 }
134
135 /**
136 * Has the optimizing compiler been initialized?
137 */
138 private static boolean isInitialized = false;
139
140 /**
141 * Has the optimizing compiler been initialized?
142 */
143 public static boolean isInitialized() {
144 return isInitialized;
145 }
146
147 /**
148 * Reset the optimizing compiler
149 */
150 static void reset() {
151 isInitialized = false;
152 }
153
154 ////////////////////////////////////////////
155 // Public interface for compiling a method
156 ////////////////////////////////////////////
157 /**
158 * Invoke the opt compiler to execute a compilation plan.
159 *
160 * @param cp the compilation plan to be executed
161 * @return the CompiledMethod object that is the result of compilation
162 */
163 public static CompiledMethod compile(CompilationPlan cp) {
164 NormalMethod method = cp.method;
165 OptOptions options = cp.options;
166 checkSupported(method, options);
167 try {
168 printMethodMessage(method, options);
169 IR ir = cp.execute();
170 // if doing analysis only, don't try to return an object
171 if (cp.analyzeOnly || cp.irGeneration) {
172 return null;
173 }
174 // now that we're done compiling, give the specialization
175 // system a chance to eagerly compile any specialized version
176 // that are pending. TODO: use lazy compilation with specialization.
177 SpecializationDatabase.doDeferredSpecializations();
178 ir.compiledMethod.compileComplete(ir.MIRInfo.machinecode);
179 return ir.compiledMethod;
180 } catch (OptimizingCompilerException e) {
181 throw e;
182 } catch (Throwable e) {
183 fail(e, method);
184 return null;
185 }
186 }
187
188 /**
189 * Debugging aid.
190 * @param what a string message to print
191 */
192 public static void report(String what) {
193 VM.sysWrite(what + '\n');
194 }
195
196 /**
197 * Debugging aid.
198 * @param what a string message to print
199 * @param time a timestamp to print
200 */
201 public static void report(String what, long time) {
202 VM.sysWrite(what);
203 if (what.length() < 8) {
204 VM.sysWrite('\t');
205 }
206 if (what.length() < 16) {
207 VM.sysWrite('\t');
208 }
209 VM.sysWrite('\t' + time + " ms");
210 }
211
212 /**
213 * Debugging aid to be called before printing the IR
214 * @param what a string message to print
215 * @param method the method being compiled
216 */
217 public static void header(String what, NormalMethod method) {
218 System.out.println("********* START OF: " + what + " FOR " + method);
219 }
220
221 /**
222 * Debugging aid to be called after printing the IR
223 * @param what a string message to print
224 * @param method the method being compiled
225 */
226 public static void bottom(String what, NormalMethod method) {
227 System.out.println("********* END OF: " + what + " FOR " + method);
228 }
229
230 /**
231 * Print the IR along with a message
232 * @param ir
233 * @param message
234 */
235 public static void printInstructions(IR ir, String message) {
236 header(message, ir.method);
237 ir.printInstructions();
238 bottom(message, ir.method);
239 }
240
241 /**
242 * Print a message of a method name
243 * @param method
244 * @param options
245 */
246 private static void printMethodMessage(NormalMethod method, OptOptions options) {
247 if (options.PRINT_METHOD || options.PRINT_INLINE_REPORT) {
248 VM.sysWrite("-methodOpt " +
249 method.getDeclaringClass() +
250 ' ' +
251 method.getName() +
252 ' ' +
253 method.getDescriptor() +
254 " \n");
255 }
256 }
257
258 /**
259 * Abort a compilation with an error.
260 * @param e The exception thrown by a compiler phase
261 * @param method The method being compiled
262 */
263 private static void fail(Throwable e, NormalMethod method) {
264 OptimizingCompilerException optExn =
265 new OptimizingCompilerException("Compiler", "failure during compilation of", method.toString());
266 if (e instanceof OutOfMemoryError) {
267 VM.sysWriteln("Compiler ran out of memory during compilation of ", method.toString());
268 optExn.isFatal = false;
269 } else {
270 VM.sysWriteln("Compiler failure during compilation of ", method.toString());
271 e.printStackTrace();
272 }
273 throw optExn;
274 }
275
276 /**
277 * Check whether opt compilation of a particular method is supported.
278 * If not, throw a non-fatal run-time exception.
279 */
280 private static void checkSupported(NormalMethod method, OptOptions options) {
281 if (method.getDeclaringClass().hasDynamicBridgeAnnotation()) {
282 String msg = "Dynamic Bridge register save protocol not implemented";
283 throw MagicNotImplementedException.EXPECTED(msg);
284 }
285 if (method.getDeclaringClass().hasBridgeFromNativeAnnotation()) {
286 String msg = "Native Bridge prologue not implemented";
287 throw MagicNotImplementedException.EXPECTED(msg);
288 }
289 if (method.hasNoOptCompileAnnotation()) {
290 String msg = "Method throws NoOptCompilePragma";
291 throw MagicNotImplementedException.EXPECTED(msg);
292 }
293 if (options.hasDRIVER_EXCLUDE()) {
294 String name = method.getDeclaringClass().toString() + "." + method.getName();
295 if (options.fuzzyMatchDRIVER_EXCLUDE(name)) {
296 if (!method.getDeclaringClass().hasSaveVolatileAnnotation()) {
297 throw new OptimizingCompilerException("method excluded", false);
298 }
299 }
300 }
301 }
302 }