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    }