/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.common; import org.jikesrvm.ArchitectureSpecific; import org.jikesrvm.ArchitectureSpecific.VM_JNICompiler; import org.jikesrvm.VM; import org.jikesrvm.VM_Callbacks; import org.jikesrvm.VM_Constants; import org.jikesrvm.adaptive.controller.VM_Controller; import org.jikesrvm.adaptive.controller.VM_ControllerMemory; import org.jikesrvm.adaptive.controller.VM_ControllerPlan; import org.jikesrvm.adaptive.recompilation.VM_InvocationCounts; import org.jikesrvm.adaptive.recompilation.VM_PreCompile; import org.jikesrvm.adaptive.recompilation.instrumentation.VM_AOSInstrumentationPlan; import org.jikesrvm.adaptive.util.VM_AOSGenerator; import org.jikesrvm.adaptive.util.VM_AOSLogging; import org.jikesrvm.adaptive.util.VM_CompilerAdviceAttribute; import org.jikesrvm.classloader.VM_NativeMethod; import org.jikesrvm.classloader.VM_NormalMethod; import org.jikesrvm.classloader.VM_Type; import org.jikesrvm.classloader.VM_TypeReference; import org.jikesrvm.compilers.baseline.VM_BaselineCompiler; import org.jikesrvm.compilers.opt.OPT_CompilationPlan; import org.jikesrvm.compilers.opt.OPT_Compiler; import org.jikesrvm.compilers.opt.OPT_MagicNotImplementedException; import org.jikesrvm.compilers.opt.OPT_OptimizationPlanElement; import org.jikesrvm.compilers.opt.OPT_OptimizationPlanner; import org.jikesrvm.compilers.opt.OPT_OptimizingCompilerException; import org.jikesrvm.compilers.opt.OPT_Options; import org.jikesrvm.runtime.VM_Time; import org.jikesrvm.scheduler.VM_Scheduler; /** * Harness to select which compiler to dynamically * compile a method in first invocation. * * A place to put code common to all runtime compilers. * This includes instrumentation code to get equivalent data for * each of the runtime compilers. * <p> * We collect the following data for each compiler * <ol> * <li> * total number of methods complied by the compiler * <li> * total compilation time in milliseconds. * <li> * total number of bytes of bytecodes compiled by the compiler * (under the assumption that there is no padding in the bytecode * array and thus VM_Method.getBytecodes().length is the number bytes * of bytecode for a method) * <li> * total number of machine code insructions generated by the compiler * (under the assumption that there is no (excessive) padding in the * machine code array and thus VM_CompiledMethod.numberOfInsturctions() * is a close enough approximation of the number of machinecodes generated) * </ol> * Note that even if 3. & 4. are inflated due to padding, the numbers will * still be an accurate measure of the space costs of the compile-only * approach. */ public class VM_RuntimeCompiler implements VM_Constants, VM_Callbacks.ExitMonitor { // Use these to encode the compiler for record() public static final byte JNI_COMPILER = 0; public static final byte BASELINE_COMPILER = 1; public static final byte OPT_COMPILER = 2; // Data accumulators private static final String[] name = {"JNI\t", "Base\t", "Opt\t"}; // Output names private static int[] totalMethods = {0, 0, 0}; private static double[] totalCompTime = {0, 0, 0}; private static int[] totalBCLength = {0, 0, 0}; private static int[] totalMCLength = {0, 0, 0}; // running sum of the natural logs of the rates, // used for geometric mean, the product of rates is too big for doubles // so we use the principle of logs to help us // We compute e ** ((log a + log b + ... + log n) / n ) private static double[] totalLogOfRates = {0, 0, 0}; // We can't record values until Math.log is loaded, so we miss the first few private static int[] totalLogValueMethods = {0, 0, 0}; private static String[] earlyOptArgs = new String[0]; // is the opt compiler usable? protected static boolean compilerEnabled; // is opt compiler currently in use? // This flag is used to detect/avoid recursive opt compilation. // (ie when opt compilation causes a method to be compiled). // We also make all public entrypoints static synchronized methods // because the opt compiler is not reentrant. // When we actually fix defect 2912, we'll have to implement a different // scheme that can distinguish between recursive opt compilation by the same // thread (always bad) and parallel opt compilation (currently bad, future ok). // NOTE: This code can be quite subtle, so please be absolutely sure // you know what you're doing before modifying it!!! protected static boolean compilationInProgress; // One time check to optionally preload and compile a specified class protected static boolean preloadChecked = false; // Cache objects needed to cons up compilation plans // TODO: cutting link to opt compiler by declaring type as object. public static final Object /* OPT_Options */ options = VM.BuildForAdaptiveSystem ? new OPT_Options() : null; public static Object /* OPT_OptimizationPlanElement[] */ optimizationPlan; /** * To be called when the VM is about to exit. * @param value the exit value */ public void notifyExit(int value) { report(false); } /** * This method records the time and sizes (bytecode and machine code) for * a compilation. * @param compiler the compiler used * @param method the resulting VM_Method * @param compiledMethod the resulting compiled method */ public static void record(byte compiler, VM_NormalMethod method, VM_CompiledMethod compiledMethod) { recordCompilation(compiler, method.getBytecodeLength(), compiledMethod.numberOfInstructions(), compiledMethod.getCompilationTime()); if (VM.BuildForAdaptiveSystem) { if (VM_AOSLogging.booted()) { VM_AOSLogging.recordUpdatedCompilationRates(compiler, method, method.getBytecodeLength(), totalBCLength[compiler], compiledMethod.numberOfInstructions(), totalMCLength[compiler], compiledMethod.getCompilationTime(), totalCompTime[compiler], totalLogOfRates[compiler], totalLogValueMethods[compiler], totalMethods[compiler]); } } } /** * This method records the time and sizes (bytecode and machine code) for * a compilation * @param compiler the compiler used * @param method the resulting VM_Method * @param compiledMethod the resulting compiled method */ public static void record(byte compiler, VM_NativeMethod method, VM_CompiledMethod compiledMethod) { recordCompilation(compiler, 0, // don't have any bytecode info, its native compiledMethod.numberOfInstructions(), compiledMethod.getCompilationTime()); } /** * This method does the actual recording * @param compiler the compiler used * @param BCLength the number of bytecodes in method source * @param MCLength the length of the generated machine code * @param compTime the compilation time in ms */ private static void recordCompilation(byte compiler, int BCLength, int MCLength, double compTime) { totalMethods[compiler]++; totalMCLength[compiler] += MCLength; totalCompTime[compiler] += compTime; // Comp rate not useful for JNI compiler because there is no bytecode! if (compiler != JNI_COMPILER) { totalBCLength[compiler] += BCLength; double rate = BCLength / compTime; // need to be fully booted before calling log if (VM.fullyBooted) { // we want the geometric mean, but the product of rates is too big // for doubles, so we use the principle of logs to help us // We compute e ** ((log a + log b + ... + log n) / n ) totalLogOfRates[compiler] += Math.log(rate); totalLogValueMethods[compiler]++; } } } /** * This method produces a summary report of compilation activities * @param explain Explains the metrics used in the report */ public static void report(boolean explain) { VM.sysWrite("\n\t\tCompilation Subsystem Report\n"); VM.sysWrite("Comp\t#Meths\tTime\tbcb/ms\tmcb/bcb\tMCKB\tBCKB\n"); for (int i = 0; i <= name.length - 1; i++) { if (totalMethods[i] > 0) { VM.sysWrite(name[i]); // Number of methods VM.sysWrite(totalMethods[i]); VM.sysWrite("\t"); // Compilation time VM.sysWrite(totalCompTime[i]); VM.sysWrite("\t"); if (i == JNI_COMPILER) { VM.sysWrite("NA"); } else { // Bytecode bytes per millisecond, // use unweighted geomean VM.sysWrite(Math.exp(totalLogOfRates[i] / totalLogValueMethods[i]), 2); } VM.sysWrite("\t"); // Ratio of machine code bytes to bytecode bytes if (i != JNI_COMPILER) { VM.sysWrite((double) (totalMCLength[i] << ArchitectureSpecific.VM_RegisterConstants.LG_INSTRUCTION_WIDTH) / (double) totalBCLength[i], 2); } else { VM.sysWrite("NA"); } VM.sysWrite("\t"); // Generated machine code Kbytes VM.sysWrite((double) (totalMCLength[i] << ArchitectureSpecific.VM_RegisterConstants.LG_INSTRUCTION_WIDTH) / 1024, 1); VM.sysWrite("\t"); // Compiled bytecode Kbytes if (i != JNI_COMPILER) { VM.sysWrite((double) totalBCLength[i] / 1024, 1); } else { VM.sysWrite("NA"); } VM.sysWrite("\n"); } } if (explain) { // Generate an explanation of the metrics reported VM.sysWrite("\t\t\tExplanation of Metrics\n"); VM.sysWrite("#Meths:\t\tTotal number of methods compiled by the compiler\n"); VM.sysWrite("Time:\t\tTotal compilation time in milliseconds\n"); VM.sysWrite("bcb/ms:\t\tNumber of bytecode bytes complied per millisecond\n"); VM.sysWrite("mcb/bcb:\tRatio of machine code bytes to bytecode bytes\n"); VM.sysWrite("MCKB:\t\tTotal number of machine code bytes generated in kilobytes\n"); VM.sysWrite("BCKB:\t\tTotal number of bytecode bytes compiled in kilobytes\n"); } VM_BaselineCompiler.generateBaselineCompilerSubsystemReport(explain); if (VM.BuildForAdaptiveSystem) { // Get the opt's report VM_Type theType = VM_TypeReference.OPT_OptimizationPlanner.peekType(); if (theType != null && theType.asClass().isInitialized(false)) { OPT_OptimizationPlanner.generateOptimizingCompilerSubsystemReport(explain); } else { VM.sysWrite("\n\tNot generating Optimizing Compiler SubSystem Report because \n"); VM.sysWrite("\tthe opt compiler was never invoked.\n\n"); } } } /** * Return the current estimate of basline-compiler rate, in bcb/msec */ public static double getBaselineRate() { return Math.exp(totalLogOfRates[BASELINE_COMPILER] / totalLogValueMethods[BASELINE_COMPILER]); } /** * This method will compile the passed method using the baseline compiler. * @param method the method to compile */ public static VM_CompiledMethod baselineCompile(VM_NormalMethod method, boolean forSubArch) { VM_Callbacks.notifyMethodCompile(method, VM_CompiledMethod.BASELINE); long start = 0; VM_CompiledMethod cm = null; try { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { start = VM_Scheduler.getCurrentThread().startTimedInterval(); } cm = VM_BaselineCompiler.compile(method, forSubArch); } finally { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { long end = VM_Scheduler.getCurrentThread().endTimedInterval(); if (cm != null) { double compileTime = VM_Time.nanosToMillis(end - start); cm.setCompilationTime(compileTime); record(BASELINE_COMPILER, method, cm); } } } return cm; } /** * Process command line argument destined for the opt compiler */ public static void processOptCommandLineArg(String prefix, String arg) { if (VM.BuildForAdaptiveSystem) { if (compilerEnabled) { if (((OPT_Options) options).processAsOption(prefix, arg)) { // update the optimization plan to reflect the new command line argument optimizationPlan = OPT_OptimizationPlanner.createOptimizationPlan((OPT_Options) options); } else { VM.sysWrite("Unrecognized opt compiler argument \"" + arg + "\""); VM.sysExit(VM.EXIT_STATUS_BOGUS_COMMAND_LINE_ARG); } } else { String[] tmp = new String[earlyOptArgs.length + 2]; for (int i = 0; i < earlyOptArgs.length; i++) { tmp[i] = earlyOptArgs[i]; } earlyOptArgs = tmp; earlyOptArgs[earlyOptArgs.length - 2] = prefix; earlyOptArgs[earlyOptArgs.length - 1] = arg; } } else { if (VM.VerifyAssertions) VM._assert(NOT_REACHED); } } /** * attempt to compile the passed method with the OPT_Compiler. * Don't handle OPT_OptimizingCompilerExceptions * (leave it up to caller to decide what to do) * Precondition: compilationInProgress "lock" has been acquired * @param method the method to compile * @param plan the plan to use for compiling the method */ private static VM_CompiledMethod optCompile(VM_NormalMethod method, OPT_CompilationPlan plan) throws OPT_OptimizingCompilerException { if (VM.BuildForOptCompiler) { if (VM.VerifyAssertions) { VM._assert(compilationInProgress, "Failed to acquire compilationInProgress \"lock\""); } VM_Callbacks.notifyMethodCompile(method, VM_CompiledMethod.JNI); long start = 0; VM_CompiledMethod cm = null; try { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { start = VM_Scheduler.getCurrentThread().startTimedInterval(); } cm = OPT_Compiler.compile(plan); } finally { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { long end = VM_Scheduler.getCurrentThread().endTimedInterval(); if (cm != null) { double compileTime = VM_Time.nanosToMillis(end - start); cm.setCompilationTime(compileTime); record(OPT_COMPILER, method, cm); } } } return cm; } else { if (VM.VerifyAssertions) VM._assert(false); return null; } } // These methods are safe to invoke from VM_RuntimeCompiler.compile /** * This method tries to compile the passed method with the OPT_Compiler, * using the default compilation plan. If * this fails we will use the quicker compiler (baseline for now) * The following is carefully crafted to avoid (infinte) recursive opt * compilation for all combinations of bootimages & lazy/eager compilation. * Be absolutely sure you know what you're doing before changing it !!! * @param method the method to compile */ public static synchronized VM_CompiledMethod optCompileWithFallBack(VM_NormalMethod method) { // TODO - Make work with Subarch if (VM.BuildForOptCompiler) { if (compilationInProgress) { return fallback(method, false); } else { try { compilationInProgress = true; OPT_CompilationPlan plan = new OPT_CompilationPlan(method, (OPT_OptimizationPlanElement[]) optimizationPlan, null, (OPT_Options) options); return optCompileWithFallBackInternal(method, plan); } finally { compilationInProgress = false; } } } else { if (VM.VerifyAssertions) VM._assert(false); return null; } } /** * This method tries to compile the passed method with the OPT_Compiler * with the passed compilation plan. If * this fails we will use the quicker compiler (baseline for now) * The following is carefully crafted to avoid (infinte) recursive opt * compilation for all combinations of bootimages & lazy/eager compilation. * Be absolutely sure you know what you're doing before changing it !!! * @param method the method to compile * @param plan the compilation plan to use for the compile */ public static synchronized VM_CompiledMethod optCompileWithFallBack(VM_NormalMethod method, OPT_CompilationPlan plan) { // TODO - Make work for subarch if (VM.BuildForOptCompiler) { if (compilationInProgress) { return fallback(method, false); } else { try { compilationInProgress = true; return optCompileWithFallBackInternal(method, plan); } finally { compilationInProgress = false; } } } else { if (VM.VerifyAssertions) VM._assert(false); return null; } } /** * This real method that performs the opt compilation. * @param method the method to compile * @param plan the compilation plan to use */ private static VM_CompiledMethod optCompileWithFallBackInternal(VM_NormalMethod method, OPT_CompilationPlan plan) { // TODO - Make work for subarch if (VM.BuildForOptCompiler) { if (method.hasNoOptCompileAnnotation()) return fallback(method, false); try { return optCompile(method, plan); } catch (OPT_OptimizingCompilerException e) { String msg = "VM_RuntimeCompiler: can't optimize \"" + method + "\" (error was: " + e + "): reverting to baseline compiler\n"; if (e.isFatal && VM.ErrorsFatal) { e.printStackTrace(); VM.sysFail(msg); } else { boolean printMsg = true; if (e instanceof OPT_MagicNotImplementedException) { printMsg = !((OPT_MagicNotImplementedException) e).isExpected; } if (printMsg) VM.sysWrite(msg); } return fallback(method, false); } } else { if (VM.VerifyAssertions) VM._assert(false); return null; } } /* recompile the specialized method with OPT_Compiler. */ public static VM_CompiledMethod recompileWithOptOnStackSpecialization(OPT_CompilationPlan plan) { if (VM.BuildForOptCompiler) { if (VM.VerifyAssertions) { VM._assert(plan.method.isForOsrSpecialization());} if (compilationInProgress) { return null; } try { compilationInProgress = true; // the compiler will check if isForOsrSpecialization of the method VM_CompiledMethod cm = optCompile(plan.method, plan); // we donot replace the compiledMethod of original method, // because it is temporary method return cm; } catch (OPT_OptimizingCompilerException e) { e.printStackTrace(); String msg = "Optimizing compiler " + "(via recompileWithOptOnStackSpecialization): " + "can't optimize \"" + plan .method + "\" (error was: " + e + ")\n"; if (e.isFatal && VM.ErrorsFatal) { VM.sysFail(msg); } else { VM.sysWrite(msg); } return null; } finally { compilationInProgress = false; } } else { if (VM.VerifyAssertions) VM._assert(false); return null; } } /** * This method tries to compile the passed method with the OPT_Compiler. * It will install the new compiled method in the VM, if sucessful. * NOTE: the recompile method should never be invoked via * VM_RuntimeCompiler.compile; * it does not have sufficient guards against recursive recompilation. * @param plan the compilation plan to use * @return the CMID of the new method if successful, -1 if the * recompilation failed. * **/ public static synchronized int recompileWithOpt(OPT_CompilationPlan plan) { // TODO - Check if the if (VM.BuildForOptCompiler) { if (compilationInProgress) { return -1; } else { try { compilationInProgress = true; VM_CompiledMethod cm = optCompile(plan.method, plan); try { plan.method.replaceCompiledMethod(cm, false); } catch (Throwable e) { String msg = "Failure in VM_Method.replaceCompiledMethod (via recompileWithOpt): while replacing \"" + plan .method + "\" (error was: " + e + ")\n"; if (VM.ErrorsFatal) { e.printStackTrace(); VM.sysFail(msg); } else { VM.sysWrite(msg); } return -1; } return cm.getId(); } catch (OPT_OptimizingCompilerException e) { String msg = "Optimizing compiler (via recompileWithOpt): can't optimize \"" + plan .method + "\" (error was: " + e + ")\n"; if (e.isFatal && VM.ErrorsFatal) { e.printStackTrace(); VM.sysFail(msg); } else { // VM.sysWrite(msg); } return -1; } finally { compilationInProgress = false; } } } else { if (VM.VerifyAssertions) VM._assert(false); return -1; } } /** * A wrapper method for those callers who don't want to make * optimization plans * @param method the method to recompile */ public static int recompileWithOpt(VM_NormalMethod method) { if (VM.BuildForOptCompiler) { OPT_CompilationPlan plan = new OPT_CompilationPlan(method, (OPT_OptimizationPlanElement[]) optimizationPlan, null, (OPT_Options) options); return recompileWithOpt(plan); } else { if (VM.VerifyAssertions) VM._assert(false); return -1; } } /** * This method uses the default compiler (baseline) to compile a method * It is typically called when a more aggressive compilation fails. * This method is safe to invoke from VM_RuntimeCompiler.compile */ protected static VM_CompiledMethod fallback(VM_NormalMethod method, boolean forSubArch) { // call the inherited method "baselineCompile" return baselineCompile(method, forSubArch); } public static void boot() { if (VM.MeasureCompilation) { VM_Callbacks.addExitMonitor(new VM_RuntimeCompiler()); } if (VM.BuildForAdaptiveSystem) { optimizationPlan = OPT_OptimizationPlanner.createOptimizationPlan((OPT_Options) options); if (VM.MeasureCompilationPhases) { OPT_OptimizationPlanner.initializeMeasureCompilation(); } OPT_Compiler.init((OPT_Options) options); VM_PreCompile.init(); // when we reach here the OPT compiler is enabled. compilerEnabled = true; for (int i = 0; i < earlyOptArgs.length; i += 2) { processOptCommandLineArg(earlyOptArgs[i], earlyOptArgs[i + 1]); } } } public static void processCommandLineArg(String prefix, String arg) { if (VM.BuildForAdaptiveSystem) { if (VM_Controller.options != null && VM_Controller.options.optIRC()) { processOptCommandLineArg(prefix, arg); } else { VM_BaselineCompiler.processCommandLineArg(prefix, arg); } } else { VM_BaselineCompiler.processCommandLineArg(prefix, arg); } } /** * Compile a Java method when it is first invoked. * @param method the method to compile * @return its compiled method. */ public static VM_CompiledMethod compile(VM_NormalMethod method, boolean forSubArch) { if (VM.BuildForAdaptiveSystem) { // TODO - make adaptive system take subarch into account if (VM.VerifyAssertions) VM._assert(!forSubArch); VM_CompiledMethod cm; if (!VM_Controller.enabled) { // System still early in boot process; compile with baseline compiler cm = baselineCompile(method, false); VM_ControllerMemory.incrementNumBase(); } else { if (!preloadChecked) { preloadChecked = true; // prevent subsequent calls // N.B. This will use irc options if (VM_BaselineCompiler.options.PRELOAD_CLASS != null) { compilationInProgress = true; // use baseline during preload // Other than when boot options are requested (processed during preloadSpecialClass // It is hard to communicate options for these special compilations. Use the // default options and at least pick up the verbose if requested for base/irc OPT_Options tmpoptions = ((OPT_Options) options).dup(); tmpoptions.PRELOAD_CLASS = VM_BaselineCompiler.options.PRELOAD_CLASS; tmpoptions.PRELOAD_AS_BOOT = VM_BaselineCompiler.options.PRELOAD_AS_BOOT; if (VM_BaselineCompiler.options.PRINT_METHOD) { tmpoptions.PRINT_METHOD = true; } else { tmpoptions = (OPT_Options) options; } OPT_Compiler.preloadSpecialClass(tmpoptions); compilationInProgress = false; } } if (VM_Controller.options.optIRC()) { if (// will only run once: don't bother optimizing method.isClassInitializer() || // exception in progress. can't use opt compiler: // it uses exceptions and runtime doesn't support // multiple pending (undelivered) exceptions [--DL] VM_Scheduler.getCurrentThread().getHardwareExceptionRegisters().inuse) { // compile with baseline compiler cm = baselineCompile(method, false); VM_ControllerMemory.incrementNumBase(); } else { // compile with opt compiler VM_AOSInstrumentationPlan instrumentationPlan = new VM_AOSInstrumentationPlan(VM_Controller.options, method); OPT_CompilationPlan compPlan = new OPT_CompilationPlan(method, (OPT_OptimizationPlanElement[]) optimizationPlan, instrumentationPlan, (OPT_Options) options); cm = optCompileWithFallBack(method, compPlan); } } else { if ((VM_Controller.options .BACKGROUND_RECOMPILATION && (!VM_Controller.options.ENABLE_REPLAY_COMPILE) && (!VM_Controller.options.ENABLE_PRECOMPILE))) { // must be an inital compilation: compile with baseline compiler // or if recompilation with OSR. cm = baselineCompile(method, false); VM_ControllerMemory.incrementNumBase(); } else { if (VM_CompilerAdviceAttribute.hasAdvice()) { VM_CompilerAdviceAttribute attr = VM_CompilerAdviceAttribute.getCompilerAdviceInfo(method); if (attr.getCompiler() != VM_CompiledMethod.OPT) { cm = fallback(method, false); VM_AOSLogging.recordCompileTime(cm, 0.0); return cm; } int newCMID = -2; OPT_CompilationPlan compPlan; if (VM_Controller.options.counters()) { // for invocation counter, we only use one optimization level compPlan = VM_InvocationCounts.createCompilationPlan(method); } else { // for now there is not two options for sampling, so // we don't have to use: if (VM_Controller.options.sampling()) compPlan = VM_Controller.recompilationStrategy.createCompilationPlan(method, attr.getOptLevel(), null); } VM_AOSLogging.recompilationStarted(compPlan); newCMID = recompileWithOpt(compPlan); cm = newCMID == -1 ? null : VM_CompiledMethods.getCompiledMethod(newCMID); if (newCMID == -1) { VM_AOSLogging.recompilationAborted(compPlan); } else if (newCMID > 0) { VM_AOSLogging.recompilationCompleted(compPlan); } if (cm == null) { // if recompilation is aborted cm = baselineCompile(method, false); VM_ControllerMemory.incrementNumBase(); } } else { // check to see if there is a compilation plan for this method. VM_ControllerPlan plan = VM_ControllerMemory.findLatestPlan(method); if (plan == null || plan.getStatus() != VM_ControllerPlan.IN_PROGRESS) { // initial compilation or some other funny state: compile with baseline compiler cm = baselineCompile(method, false); VM_ControllerMemory.incrementNumBase(); } else { cm = plan.doRecompile(); if (cm == null) { // opt compilation aborted for some reason. cm = baselineCompile(method, false); } } } } } } if ((VM_Controller.options.ENABLE_ADVICE_GENERATION) && (cm.getCompilerType() == VM_CompiledMethod.BASELINE) && VM_Controller .enabled) { VM_AOSGenerator.baseCompilationCompleted(cm); } VM_AOSLogging.recordCompileTime(cm, 0.0); return cm; } else { return baselineCompile(method, forSubArch); } } /** * Compile the stub for a native method when it is first invoked. * @param method the method to compile * @return its compiled method. */ public static VM_CompiledMethod compile(VM_NativeMethod method) { VM_Callbacks.notifyMethodCompile(method, VM_CompiledMethod.JNI); long start = 0; VM_CompiledMethod cm = null; try { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { start = VM_Scheduler.getCurrentThread().startTimedInterval(); } cm = VM_JNICompiler.compile(method); if (VM.verboseJNI) { VM.sysWriteln("[Dynamic-linking native method " + method.getDeclaringClass() + "." + method.getName() + " " + method.getDescriptor()); } } finally { if (VM.MeasureCompilation || VM.BuildForAdaptiveSystem) { long end = VM_Scheduler.getCurrentThread().endTimedInterval(); if (cm != null) { double compileTime = VM_Time.nanosToMillis(end - start); cm.setCompilationTime(compileTime); record(JNI_COMPILER, method, cm); } } } return cm; } /** * returns the string version of compiler number, using the naming scheme * in this file * @param compiler the compiler of interest * @return the string version of compiler number */ public static String getCompilerName(byte compiler) { return name[compiler]; } }