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. & 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 & 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 & 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}