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 */
013package org.jikesrvm.compilers.common;
014
015import static org.jikesrvm.VM.NOT_REACHED;
016import static org.jikesrvm.runtime.ExitStatus.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG;
017
018import org.jikesrvm.VM;
019import org.jikesrvm.adaptive.controller.Controller;
020import org.jikesrvm.adaptive.controller.ControllerMemory;
021import org.jikesrvm.adaptive.controller.ControllerPlan;
022import org.jikesrvm.adaptive.recompilation.InvocationCounts;
023import org.jikesrvm.adaptive.recompilation.BulkCompile;
024import org.jikesrvm.adaptive.recompilation.instrumentation.AOSInstrumentationPlan;
025import org.jikesrvm.adaptive.util.AOSGenerator;
026import org.jikesrvm.adaptive.util.AOSLogging;
027import org.jikesrvm.adaptive.util.CompilerAdviceAttribute;
028import org.jikesrvm.architecture.ArchConstants;
029import org.jikesrvm.classloader.NativeMethod;
030import org.jikesrvm.classloader.NormalMethod;
031import org.jikesrvm.classloader.RVMType;
032import org.jikesrvm.classloader.TypeReference;
033import org.jikesrvm.compilers.baseline.BaselineCompiler;
034import org.jikesrvm.compilers.opt.MagicNotImplementedException;
035import org.jikesrvm.compilers.opt.OptimizingCompilerException;
036import org.jikesrvm.compilers.opt.OptOptions;
037import org.jikesrvm.compilers.opt.driver.CompilationPlan;
038import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement;
039import org.jikesrvm.compilers.opt.driver.OptimizationPlanner;
040import org.jikesrvm.compilers.opt.driver.OptimizingCompiler;
041import org.jikesrvm.runtime.Callbacks;
042import org.jikesrvm.runtime.Time;
043import org.jikesrvm.scheduler.RVMThread;
044
045/**
046 * Harness to select which compiler to dynamically
047 * compile a method in first invocation.
048 * <p>
049 * A place to put code common to all runtime compilers.
050 * This includes instrumentation code to get equivalent data for
051 * each of the runtime compilers.
052 * <p>
053 * We collect the following data for each compiler
054 * <ol>
055 * <li>
056 *   total number of methods complied by the compiler
057 * <li>
058 *   total compilation time in milliseconds.
059 * <li>
060 *   total number of bytes of bytecodes compiled by the compiler
061 *   (under the assumption that there is no padding in the bytecode
062 *   array and thus RVMMethod.getBytecodes().length is the number bytes
063 *   of bytecode for a method)
064 * <li>
065 *   total number of machine code instructions generated by the compiler
066 *   (under the assumption that there is no (excessive) padding in the
067 *   machine code array and thus CompiledMethod.numberOfInsturctions()
068 *   is a close enough approximation of the number of machinecodes generated)
069 * </ol>
070 *   Note that even if 3. &amp; 4. are inflated due to padding, the numbers will
071 *   still be an accurate measure of the space costs of the compile-only
072 *   approach.
073 */
074public class RuntimeCompiler implements Callbacks.ExitMonitor {
075
076  // Use these to encode the compiler for record()
077  public static final byte JNI_COMPILER = 0;
078  public static final byte BASELINE_COMPILER = 1;
079  public static final byte OPT_COMPILER = 2;
080
081  // Data accumulators
082  private static final String[] name = {"JNI\t", "Base\t", "Opt\t"};   // Output names
083  private static int[] totalMethods = {0, 0, 0};
084  private static double[] totalCompTime = {0, 0, 0};
085  private static int[] totalBCLength = {0, 0, 0};
086  private static int[] totalMCLength = {0, 0, 0};
087
088  // running sum of the natural logs of the rates,
089  //  used for geometric mean, the product of rates is too big for doubles
090  //  so we use the principle of logs to help us
091  // We compute  e ** ((log a + log b + ... + log n) / n )
092  private static double[] totalLogOfRates = {0, 0, 0};
093
094  // We can't record values until Math.log is loaded, so we miss the first few
095  private static int[] totalLogValueMethods = {0, 0, 0};
096
097  private static String[] earlyOptArgs = new String[0];
098
099  /** is the opt compiler usable? This will be the case after booting. */
100  protected static boolean compilerEnabled;
101
102  // FIXME Make opt compiler reentrant and update documentation accordingly.
103
104  /**
105   * is opt compiler currently in use? This flag is used to detect/avoid
106   * recursive opt compilation (ie when opt compilation causes a method to be
107   * compiled). We also make all public entrypoints static synchronized methods
108   * because the opt compiler is not reentrant. There are two cases here:
109   * <ol>
110   *   <li>recursive opt compilation by the same thread (always bad)
111   *   <li>parallel opt compilation (currently bad because opt compiler
112   *     is not reentrant, future ok)
113   * </ol>
114   * <p>
115   * NOTE: The associated code can be quite subtle, so please be absolutely sure
116   * you know what you're doing before modifying it!!!
117   */
118  protected static boolean compilationInProgress;
119
120  // Cache objects needed to cons up compilation plans
121  // TODO: cutting link to opt compiler by declaring type as object.
122  public static final Object /* Options */ options = VM.BuildForAdaptiveSystem ? new OptOptions() : null;
123  public static Object /* OptimizationPlanElement[] */ optimizationPlan;
124
125  /**
126   * To be called when the VM is about to exit.
127   * @param value the exit value
128   */
129  @Override
130  public void notifyExit(int value) {
131    report(false);
132  }
133
134  /**
135   * This method records the time and sizes (bytecode and machine code) for
136   * a compilation.
137   * @param compiler the compiler used
138   * @param method the resulting RVMMethod
139   * @param compiledMethod the resulting compiled method
140   */
141  public static void record(byte compiler, NormalMethod method, CompiledMethod compiledMethod) {
142
143    recordCompilation(compiler,
144                      method.getBytecodeLength(),
145                      compiledMethod.numberOfInstructions(),
146                      compiledMethod.getCompilationTime());
147
148    if (VM.BuildForAdaptiveSystem) {
149      if (AOSLogging.logger.booted()) {
150        AOSLogging.logger.recordUpdatedCompilationRates(compiler,
151                                                    method,
152                                                    method.getBytecodeLength(),
153                                                    totalBCLength[compiler],
154                                                    compiledMethod.numberOfInstructions(),
155                                                    totalMCLength[compiler],
156                                                    compiledMethod.getCompilationTime(),
157                                                    totalCompTime[compiler],
158                                                    totalLogOfRates[compiler],
159                                                    totalLogValueMethods[compiler],
160                                                    totalMethods[compiler]);
161      }
162    }
163  }
164
165  /**
166   * This method records the time and sizes (bytecode and machine code) for
167   * a compilation
168   * @param compiler the compiler used
169   * @param method the resulting RVMMethod
170   * @param compiledMethod the resulting compiled method
171   */
172  public static void record(byte compiler, NativeMethod method, CompiledMethod compiledMethod) {
173
174    recordCompilation(compiler, 0, // don't have any bytecode info, its native
175                      compiledMethod.numberOfInstructions(), compiledMethod.getCompilationTime());
176  }
177
178  /**
179   * This method does the actual recording
180   * @param compiler the compiler used
181   * @param BCLength the number of bytecodes in method source
182   * @param MCLength the length of the generated machine code
183   * @param compTime the compilation time in ms
184   */
185  private static void recordCompilation(byte compiler, int BCLength, int MCLength, double compTime) {
186
187    totalMethods[compiler]++;
188    totalMCLength[compiler] += MCLength;
189    totalCompTime[compiler] += compTime;
190
191    // Comp rate not useful for JNI compiler because there is no bytecode!
192    if (compiler != JNI_COMPILER) {
193      totalBCLength[compiler] += BCLength;
194      double rate = BCLength / compTime;
195
196      // need to be fully booted before calling log
197      if (VM.fullyBooted) {
198        // we want the geometric mean, but the product of rates is too big
199        //  for doubles, so we use the principle of logs to help us
200        // We compute  e ** ((log a + log b + ... + log n) / n )
201        totalLogOfRates[compiler] += Math.log(rate);
202        totalLogValueMethods[compiler]++;
203      }
204    }
205  }
206
207  /**
208   * This method produces a summary report of compilation activities
209   * @param explain Explains the metrics used in the report
210   */
211  public static void report(boolean explain) {
212    VM.sysWrite("\n\t\tCompilation Subsystem Report\n");
213    VM.sysWrite("Comp\t#Meths\tTime\tbcb/ms\tmcb/bcb\tMCKB\tBCKB\n");
214    for (int i = 0; i <= name.length - 1; i++) {
215      if (totalMethods[i] > 0) {
216        VM.sysWrite(name[i]);
217        // Number of methods
218        VM.sysWrite(totalMethods[i]);
219        VM.sysWrite("\t");
220        // Compilation time
221        VM.sysWrite(totalCompTime[i]);
222        VM.sysWrite("\t");
223
224        if (i == JNI_COMPILER) {
225          VM.sysWrite("NA");
226        } else {
227          // Bytecode bytes per millisecond,
228          //  use unweighted geomean
229          VM.sysWrite(Math.exp(totalLogOfRates[i] / totalLogValueMethods[i]), 2);
230        }
231        VM.sysWrite("\t");
232        // Ratio of machine code bytes to bytecode bytes
233        if (i != JNI_COMPILER) {
234          VM.sysWrite((double) (totalMCLength[i] << ArchConstants.getLogInstructionWidth()) /
235                      totalBCLength[i], 2);
236        } else {
237          VM.sysWrite("NA");
238        }
239        VM.sysWrite("\t");
240        // Generated machine code Kbytes
241        VM.sysWrite((double) (totalMCLength[i] << ArchConstants.getLogInstructionWidth()) /
242                    1024, 1);
243        VM.sysWrite("\t");
244        // Compiled bytecode Kbytes
245        if (i != JNI_COMPILER) {
246          VM.sysWrite((double) totalBCLength[i] / 1024, 1);
247        } else {
248          VM.sysWrite("NA");
249        }
250        VM.sysWrite("\n");
251      }
252    }
253    if (explain) {
254      // Generate an explanation of the metrics reported
255      VM.sysWrite("\t\t\tExplanation of Metrics\n");
256      VM.sysWrite("#Meths:\t\tTotal number of methods compiled by the compiler\n");
257      VM.sysWrite("Time:\t\tTotal compilation time in milliseconds\n");
258      VM.sysWrite("bcb/ms:\t\tNumber of bytecode bytes complied per millisecond\n");
259      VM.sysWrite("mcb/bcb:\tRatio of machine code bytes to bytecode bytes\n");
260      VM.sysWrite("MCKB:\t\tTotal number of machine code bytes generated in kilobytes\n");
261      VM.sysWrite("BCKB:\t\tTotal number of bytecode bytes compiled in kilobytes\n");
262    }
263
264    BaselineCompiler.generateBaselineCompilerSubsystemReport(explain);
265
266    if (VM.BuildForAdaptiveSystem) {
267      // Get the opt's report
268      RVMType theType = TypeReference.OptimizationPlanner.peekType();
269      if (theType != null && theType.asClass().isInitialized()) {
270        OptimizationPlanner.generateOptimizingCompilerSubsystemReport(explain);
271      } else {
272        VM.sysWrite("\n\tNot generating Optimizing Compiler SubSystem Report because \n");
273        VM.sysWrite("\tthe opt compiler was never invoked.\n\n");
274      }
275    }
276  }
277
278  /**
279   * @return the current estimate of basline-compiler rate, in bcb/msec
280   */
281  public static double getBaselineRate() {
282    return Math.exp(totalLogOfRates[BASELINE_COMPILER] / totalLogValueMethods[BASELINE_COMPILER]);
283  }
284
285  /**
286   * This method will compile the passed method using the baseline compiler.
287   * @param method the method to compile
288   * @return the compiled method
289   */
290  public static CompiledMethod baselineCompile(NormalMethod method) {
291    Callbacks.notifyMethodCompile(method, CompiledMethod.BASELINE);
292    long start = 0;
293    CompiledMethod cm = null;
294    try {
295      if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) {
296        start = Time.nanoTime();
297      }
298
299      cm = BaselineCompiler.compile(method);
300    } finally {
301      if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) {
302        long end = Time.nanoTime();
303        if (cm != null) {
304          double compileTime = Time.nanosToMillis(end - start);
305          cm.setCompilationTime(compileTime);
306          record(BASELINE_COMPILER, method, cm);
307        }
308      }
309    }
310
311
312    return cm;
313  }
314
315  /**
316   * Processes a command line argument destined for the opt compiler.
317   *
318   * @param prefix the prefix, e.g. "-X:opt:"
319   * @param arg everything after the last ':'
320   */
321  public static void processOptCommandLineArg(String prefix, String arg) {
322    if (VM.BuildForAdaptiveSystem) {
323      if (compilerEnabled) {
324        if (((OptOptions) options).processAsOption(prefix, arg)) {
325          // update the optimization plan to reflect the new command line argument
326          optimizationPlan = OptimizationPlanner.createOptimizationPlan((OptOptions) options);
327        } else {
328          VM.sysWrite("Unrecognized opt compiler argument \"" + arg + "\"");
329          VM.sysExit(EXIT_STATUS_BOGUS_COMMAND_LINE_ARG);
330        }
331      } else {
332        String[] tmp = new String[earlyOptArgs.length + 2];
333        for (int i = 0; i < earlyOptArgs.length; i++) {
334          tmp[i] = earlyOptArgs[i];
335        }
336        earlyOptArgs = tmp;
337        earlyOptArgs[earlyOptArgs.length - 2] = prefix;
338        earlyOptArgs[earlyOptArgs.length - 1] = arg;
339      }
340    } else {
341      if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
342    }
343  }
344
345  /**
346   * Attempt to compile the passed method with the Compiler.
347   * Don't handle OptimizingCompilerExceptions
348   *   (leave it up to caller to decide what to do)<p>
349   * Precondition: compilationInProgress "lock" has been acquired
350   * @param method the method to compile
351   * @param plan the plan to use for compiling the method
352   * @return a compiled method
353   */
354  private static CompiledMethod optCompile(NormalMethod method, CompilationPlan plan)
355      throws OptimizingCompilerException {
356    if (VM.BuildForOptCompiler) {
357      if (VM.VerifyAssertions) {
358        VM._assert(compilationInProgress, "Failed to acquire compilationInProgress \"lock\"");
359      }
360
361      Callbacks.notifyMethodCompile(method, CompiledMethod.OPT);
362      long start = 0;
363      CompiledMethod cm = null;
364      try {
365        if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) {
366          start = Time.nanoTime();
367        }
368        cm = OptimizingCompiler.compile(plan);
369      } finally {
370        if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) {
371          long end = Time.nanoTime();
372          if (cm != null) {
373            double compileTime = Time.nanosToMillis(end - start);
374            cm.setCompilationTime(compileTime);
375            record(OPT_COMPILER, method, cm);
376          }
377        }
378      }
379
380      return cm;
381    } else {
382      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
383      return null;
384    }
385  }
386
387  // These methods are safe to invoke from RuntimeCompiler.compile
388
389  /**
390   * This method tries to compile the passed method with the Compiler,
391   * using the default compilation plan.  If
392   * this fails we will use the quicker compiler (baseline for now)
393   * The following is carefully crafted to avoid (infinte) recursive opt
394   * compilation for all combinations of bootimages &amp; lazy/eager compilation.
395   * Be absolutely sure you know what you're doing before changing it !!!
396   * @param method the method to compile
397   * @return a compiled method (opt when possible, baseline when the opt compiler
398   *  busy)
399   */
400  public static synchronized CompiledMethod optCompileWithFallBack(NormalMethod method) {
401    if (VM.BuildForOptCompiler) {
402      if (compilationInProgress) {
403        return fallback(method);
404      } else {
405        try {
406          compilationInProgress = true;
407          CompilationPlan plan =
408              new CompilationPlan(method,
409                                      (OptimizationPlanElement[]) optimizationPlan,
410                                      null,
411                                      (OptOptions) options);
412          return optCompileWithFallBackInternal(method, plan);
413        } finally {
414          compilationInProgress = false;
415        }
416      }
417    } else {
418      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
419      return null;
420    }
421  }
422
423  /**
424   * This method tries to compile the passed method with the Compiler
425   * with the passed compilation plan.  If
426   * this fails we will use the quicker compiler (baseline for now)
427   * The following is carefully crafted to avoid (infinite) recursive opt
428   * compilation for all combinations of bootimages &amp; lazy/eager compilation.
429   * Be absolutely sure you know what you're doing before changing it !!!
430   * @param method the method to compile
431   * @param plan the compilation plan to use for the compile
432   * @return a compiled method (opt when possible, baseline when the opt compiler
433   *  busy)
434   */
435  public static synchronized CompiledMethod optCompileWithFallBack(NormalMethod method,
436                                                                      CompilationPlan plan) {
437    if (VM.BuildForOptCompiler) {
438      if (compilationInProgress) {
439        return fallback(method);
440      } else {
441        try {
442          compilationInProgress = true;
443          return optCompileWithFallBackInternal(method, plan);
444        } finally {
445          compilationInProgress = false;
446        }
447      }
448    } else {
449      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
450      return null;
451    }
452  }
453
454  /**
455   * This real method that performs the opt compilation.
456   * @param method the method to compile
457   * @param plan the compilation plan to use
458   * @return a compiled method (opt when possible, baseline when the opt compiler
459   *  busy)
460   */
461  private static CompiledMethod optCompileWithFallBackInternal(NormalMethod method, CompilationPlan plan) {
462    if (VM.BuildForOptCompiler) {
463      if (method.hasNoOptCompileAnnotation()) return fallback(method);
464      try {
465        return optCompile(method, plan);
466      } catch (OptimizingCompilerException e) {
467        String msg =
468            "RuntimeCompiler: can't optimize \"" +
469            method +
470            "\" (error was: " +
471            e +
472            "): reverting to baseline compiler\n";
473        if (e.isFatal && VM.ErrorsFatal) {
474          e.printStackTrace();
475          VM.sysFail(msg);
476        } else {
477          boolean printMsg = true;
478          if (e instanceof MagicNotImplementedException) {
479            printMsg = !((MagicNotImplementedException) e).isExpected;
480          }
481          if (printMsg) VM.sysWrite(msg);
482        }
483        return fallback(method);
484      }
485    } else {
486      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
487      return null;
488    }
489  }
490
491  /* recompile the specialized method with Compiler. */
492  public static CompiledMethod recompileWithOptOnStackSpecialization(CompilationPlan plan) {
493    if (VM.BuildForOptCompiler) {
494      if (VM.VerifyAssertions) {
495        VM._assert(plan.method.isForOsrSpecialization());
496      }
497      if (compilationInProgress) {
498        return null;
499      }
500
501      try {
502        compilationInProgress = true;
503
504        // the compiler will check if isForOsrSpecialization of the method
505        CompiledMethod cm = optCompile(plan.method, plan);
506
507        // we do not replace the compiledMethod of original method,
508        // because it is temporary method
509        return cm;
510      } catch (OptimizingCompilerException e) {
511        e.printStackTrace();
512        String msg =
513            "Optimizing compiler " +
514            "(via recompileWithOptOnStackSpecialization): " +
515            "can't optimize \"" +
516            plan
517                .method +
518                        "\" (error was: " +
519                        e +
520                        ")\n";
521
522        if (e.isFatal && VM.ErrorsFatal) {
523          VM.sysFail(msg);
524        } else {
525          VM.sysWrite(msg);
526        }
527        return null;
528      } finally {
529        compilationInProgress = false;
530      }
531    } else {
532      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
533      return null;
534    }
535  }
536
537  /**
538   * This method tries to compile the passed method with the Compiler.
539   * It will install the new compiled method in the VM, if successful.
540   * <p>
541   * NOTE: the recompile method should never be invoked via
542   *      RuntimeCompiler.compile;
543   *   it does not have sufficient guards against recursive recompilation.
544   * @param plan the compilation plan to use
545   * @return the CMID of the new method if successful, -1 if the
546   *    recompilation failed.
547   *
548   **/
549  public static synchronized int recompileWithOpt(CompilationPlan plan) {
550    if (VM.BuildForOptCompiler) {
551      if (compilationInProgress) {
552        return -1;
553      } else {
554        try {
555          compilationInProgress = true;
556          CompiledMethod cm = optCompile(plan.method, plan);
557          try {
558            plan.method.replaceCompiledMethod(cm);
559          } catch (Throwable e) {
560            String msg = "Failure in RVMMethod.replaceCompiledMethod (via recompileWithOpt): while replacing \"" + plan
561                .method + "\" (error was: " + e + ")\n";
562            if (VM.ErrorsFatal) {
563              e.printStackTrace();
564              VM.sysFail(msg);
565            } else {
566              VM.sysWrite(msg);
567            }
568            return -1;
569          }
570          return cm.getId();
571        } catch (OptimizingCompilerException e) {
572          String msg = "Optimizing compiler (via recompileWithOpt): can't optimize \"" + plan
573              .method + "\" (error was: " + e + ")\n";
574          if (e.isFatal && VM.ErrorsFatal) {
575            e.printStackTrace();
576            VM.sysFail(msg);
577          } else {
578            // VM.sysWrite(msg);
579          }
580          return -1;
581        } finally {
582          compilationInProgress = false;
583        }
584      }
585    } else {
586      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
587      return -1;
588    }
589  }
590
591  /**
592   * A wrapper method for those callers who don't want to make
593   * optimization plans
594   * @param method the method to recompile
595   * @return a compiled method id or -1 when the compilation failed
596   */
597  public static int recompileWithOpt(NormalMethod method) {
598    if (VM.BuildForOptCompiler) {
599      CompilationPlan plan =
600          new CompilationPlan(method,
601                                  (OptimizationPlanElement[]) optimizationPlan,
602                                  null,
603                                  (OptOptions) options);
604      return recompileWithOpt(plan);
605    } else {
606      if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
607      return -1;
608    }
609  }
610
611  /**
612   * This method uses the default compiler (baseline) to compile a method
613   * It is typically called when a more aggressive compilation fails.
614   * This method is safe to invoke from RuntimeCompiler.compile.
615   *
616   * @param method method to compile
617   * @return a baseline compiled method
618   */
619  protected static CompiledMethod fallback(NormalMethod method) {
620    // call the inherited method "baselineCompile"
621    return baselineCompile(method);
622  }
623
624  public static void boot() {
625    if (VM.MeasureCompilation) {
626      Callbacks.addExitMonitor(new RuntimeCompiler());
627    }
628    if (VM.BuildForAdaptiveSystem) {
629      optimizationPlan = OptimizationPlanner.createOptimizationPlan((OptOptions) options);
630      if (VM.MeasureCompilationPhases) {
631        OptimizationPlanner.initializeMeasureCompilation();
632      }
633
634      OptimizingCompiler.init((OptOptions) options);
635
636      BulkCompile.init();
637      // when we reach here the OPT compiler is enabled.
638      compilerEnabled = true;
639
640      for (int i = 0; i < earlyOptArgs.length; i += 2) {
641        processOptCommandLineArg(earlyOptArgs[i], earlyOptArgs[i + 1]);
642      }
643    }
644  }
645
646  public static void processCommandLineArg(String prefix, String arg) {
647    if (VM.BuildForAdaptiveSystem) {
648      if (Controller.options != null && Controller.options.optIRC()) {
649        processOptCommandLineArg(prefix, arg);
650      } else {
651        BaselineCompiler.processCommandLineArg(prefix, arg);
652      }
653    } else {
654      BaselineCompiler.processCommandLineArg(prefix, arg);
655    }
656  }
657
658  /**
659   * Compile a Java method when it is first invoked.
660   * @param method the method to compile
661   * @return its compiled method.
662   */
663  public static CompiledMethod compile(NormalMethod method) {
664    if (VM.BuildForAdaptiveSystem) {
665      CompiledMethod cm;
666      if (!Controller.enabled) {
667        // System still early in boot process; compile with baseline compiler
668        cm = baselineCompile(method);
669        ControllerMemory.incrementNumBase();
670      } else {
671        if (Controller.options.optIRC()) {
672          if (// will only run once: don't bother optimizing
673              method.isClassInitializer() ||
674              // exception in progress. can't use opt compiler:
675              // it uses exceptions and runtime doesn't support
676              // multiple pending (undelivered) exceptions [--DL]
677              RVMThread.getCurrentThread().getExceptionRegisters().getInUse()) {
678            // compile with baseline compiler
679            cm = baselineCompile(method);
680            ControllerMemory.incrementNumBase();
681          } else { // compile with opt compiler
682            AOSInstrumentationPlan instrumentationPlan =
683                new AOSInstrumentationPlan(Controller.options, method);
684            CompilationPlan compPlan =
685                new CompilationPlan(method,
686                                        (OptimizationPlanElement[]) optimizationPlan,
687                                        instrumentationPlan,
688                                        (OptOptions) options);
689            cm = optCompileWithFallBack(method, compPlan);
690          }
691        } else {
692          if ((Controller.options.BACKGROUND_RECOMPILATION && !Controller.options.ENABLE_PRECOMPILE)) {
693            // must be an initial compilation: compile with baseline compiler
694            // or if recompilation with OSR.
695            cm = baselineCompile(method);
696            ControllerMemory.incrementNumBase();
697          } else {
698            if (CompilerAdviceAttribute.hasAdvice()) {
699              CompilerAdviceAttribute attr = CompilerAdviceAttribute.getCompilerAdviceInfo(method);
700              if (attr.getCompiler() != CompiledMethod.OPT) {
701                cm = fallback(method);
702                AOSLogging.logger.recordCompileTime(cm, 0.0);
703                return cm;
704              }
705              int newCMID = -2;
706              CompilationPlan compPlan;
707              if (Controller.options.counters()) {
708                // for invocation counter, we only use one optimization level
709                compPlan = InvocationCounts.createCompilationPlan(method);
710              } else {
711                // for now there is not two options for sampling, so
712                // we don't have to use: if (Controller.options.sampling())
713                compPlan = Controller.recompilationStrategy.createCompilationPlan(method, attr.getOptLevel(), null);
714              }
715              AOSLogging.logger.recompilationStarted(compPlan);
716              newCMID = recompileWithOpt(compPlan);
717              cm = newCMID == -1 ? null : CompiledMethods.getCompiledMethod(newCMID);
718              if (newCMID == -1) {
719                AOSLogging.logger.recompilationAborted(compPlan);
720              } else if (newCMID > 0) {
721                AOSLogging.logger.recompilationCompleted(compPlan);
722              }
723              if (cm == null) { // if recompilation is aborted
724                cm = baselineCompile(method);
725                ControllerMemory.incrementNumBase();
726              }
727            } else {
728              // check to see if there is a compilation plan for this method.
729              ControllerPlan plan = ControllerMemory.findLatestPlan(method);
730              if (plan == null || plan.getStatus() != ControllerPlan.IN_PROGRESS) {
731                // initial compilation or some other funny state: compile with baseline compiler
732                cm = baselineCompile(method);
733                ControllerMemory.incrementNumBase();
734              } else {
735                cm = plan.doRecompile();
736                if (cm == null) {
737                  // opt compilation aborted for some reason.
738                  cm = baselineCompile(method);
739                }
740              }
741            }
742          }
743        }
744      }
745      if ((Controller.options.ENABLE_ADVICE_GENERATION) &&
746          (cm.getCompilerType() == CompiledMethod.BASELINE) &&
747          Controller
748              .enabled) {
749        AOSGenerator.baseCompilationCompleted(cm);
750      }
751      AOSLogging.logger.recordCompileTime(cm, 0.0);
752      return cm;
753    } else {
754      return baselineCompile(method);
755    }
756  }
757
758  /**
759   * Compile the stub for a native method when it is first invoked.
760   * @param method the method to compile
761   * @return its compiled method.
762   */
763  public static CompiledMethod compile(NativeMethod method) {
764    Callbacks.notifyMethodCompile(method, CompiledMethod.JNI);
765    long start = 0;
766    CompiledMethod cm = null;
767    try {
768      if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) {
769        start = Time.nanoTime();
770      }
771
772      if (VM.BuildForIA32) {
773        cm = org.jikesrvm.jni.ia32.JNICompiler.compile(method);
774      } else {
775        if (VM.VerifyAssertions) VM._assert(VM.BuildForPowerPC);
776        cm = org.jikesrvm.jni.ppc.JNICompiler.compile(method);
777      }
778      if (VM.verboseJNI) {
779        VM.sysWriteln("[Dynamic-linking native method " +
780                      method.getDeclaringClass() +
781                      "." +
782                      method.getName() +
783                      " " +
784                      method.getDescriptor());
785      }
786    } finally {
787      if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) {
788        long end = Time.nanoTime();
789        if (cm != null) {
790          double compileTime = Time.nanosToMillis(end - start);
791          cm.setCompilationTime(compileTime);
792          record(JNI_COMPILER, method, cm);
793        }
794      }
795    }
796
797    return cm;
798  }
799
800  /**
801   * returns the string version of compiler number, using the naming scheme
802   * in this file
803   * @param compiler the compiler of interest
804   * @return the string version of compiler number
805   */
806  public static String getCompilerName(byte compiler) {
807    return name[compiler];
808  }
809
810  /**
811   * @return total compilation time in milliseconds
812   */
813  public static long getTotalCompilationTime() {
814    double baseTime = getTotalCompilationTime(BASELINE_COMPILER);
815    double optTime = getTotalCompilationTime(OPT_COMPILER);
816    double jniTime = getTotalCompilationTime(JNI_COMPILER);
817    return Math.round(baseTime + optTime + jniTime);
818  }
819
820  /**
821   * Returns the total compilation time of compiler number, using the naming scheme
822   * from this class
823   * @param compilerType the compiler of interest
824   * @return the total compilation time for the given compiler in milliseconds
825   */
826  public static double getTotalCompilationTime(byte compilerType) {
827    return totalCompTime[compilerType];
828  }
829
830}