/*
* 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];
}
}