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    }