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