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