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.osr;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.Callbacks;
017    import org.jikesrvm.adaptive.controller.Controller;
018    import org.jikesrvm.adaptive.controller.ControllerMemory;
019    import org.jikesrvm.adaptive.controller.ControllerPlan;
020    import org.jikesrvm.adaptive.recompilation.InvocationCounts;
021    import org.jikesrvm.adaptive.util.AOSLogging;
022    import org.jikesrvm.adaptive.util.CompilerAdviceAttribute;
023    import org.jikesrvm.compilers.common.CompiledMethod;
024    import org.jikesrvm.compilers.common.CompiledMethods;
025    import org.jikesrvm.compilers.common.RuntimeCompiler;
026    import org.jikesrvm.compilers.opt.driver.CompilationPlan;
027    import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
028    
029    /**
030     * Maintain statistic information about on stack replacement events
031     */
032    public class OSRProfiler implements Callbacks.ExitMonitor {
033    
034      private static int invalidations = 0;
035      private static boolean registered = false;
036    
037      @Override
038      public void notifyExit(int value) {
039        VM.sysWriteln("OSR invalidations " + invalidations);
040      }
041    
042      // we know which assumption is invalidated
043      // current we only reset the root caller method to be recompiled.
044      public static void notifyInvalidation(ExecutionState state) {
045    
046        if (!registered && VM.MeasureCompilation) {
047          registered = true;
048          Callbacks.addExitMonitor(new OSRProfiler());
049        }
050    
051        if (VM.TraceOnStackReplacement || VM.MeasureCompilation) {
052          OSRProfiler.invalidations++;
053        }
054    
055        // find the root state
056        while (state.callerState != null) {
057          state = state.callerState;
058        }
059    
060        // only invalidate the root state
061        invalidateState(state);
062      }
063    
064      // invalidate an execution state
065      private static synchronized void invalidateState(ExecutionState state) {
066        // step 1: invalidate the compiled method with this OSR assumption
067        //         how does this affect the performance?
068        CompiledMethod mostRecentlyCompiledMethod = CompiledMethods.getCompiledMethod(state.cmid);
069    
070        if (VM.VerifyAssertions) {
071          VM._assert(mostRecentlyCompiledMethod.getMethod() == state.meth);
072        }
073    
074        // check if the compiled method is the latest still the latest one
075        // this is necessary to check because the same compiled method may
076        // be invalidated in more than one thread at the same time
077        if (mostRecentlyCompiledMethod != state.meth.getCurrentCompiledMethod()) {
078          return;
079        }
080    
081        // make sure the compiled method is an opt one
082        if (!(mostRecentlyCompiledMethod instanceof OptCompiledMethod)) {
083          return;
084        }
085    
086        // reset the compiled method to null first, if other thread invokes
087        // this method before following opt recompilation, it can avoid OSR
088        state.meth.invalidateCompiledMethod(mostRecentlyCompiledMethod);
089    
090        // a list of state from callee -> caller
091        if (VM.TraceOnStackReplacement) {
092          VM.sysWriteln("OSR " + OSRProfiler.invalidations + " : " + state.bcIndex + "@" + state.meth);
093        }
094    
095        // simply reset the compiled method to null is not good
096        // for long run loops, because invalidate may cause
097        // the method falls back to the baseline again...
098        // NOW, we look for the previous compilation plan, and reuse
099        // the compilation plan.
100        boolean recmplsucc = false;
101        if (Controller.enabled) {
102          CompilationPlan cmplplan = null;
103          if (Controller.options.ENABLE_PRECOMPILE && CompilerAdviceAttribute.hasAdvice()) {
104            CompilerAdviceAttribute attr = CompilerAdviceAttribute.getCompilerAdviceInfo(state.meth);
105            if (VM.VerifyAssertions) {
106              VM._assert(attr.getCompiler() == CompiledMethod.OPT);
107            }
108            if (Controller.options.counters()) {
109              // for invocation counter, we only use one optimization level
110              cmplplan = InvocationCounts.createCompilationPlan(state.meth);
111            } else {
112              // for now there is not two options for sampling, so
113              // we don't have to use: if (Controller.options.sampling())
114              cmplplan = Controller.recompilationStrategy.createCompilationPlan(state.meth, attr.getOptLevel(), null);
115            }
116          } else {
117            ControllerPlan ctrlplan = ControllerMemory.findMatchingPlan(mostRecentlyCompiledMethod);
118            if (ctrlplan != null) {
119              cmplplan = ctrlplan.getCompPlan();
120            }
121          }
122          if (cmplplan != null) {
123            if (VM.VerifyAssertions) {VM._assert(cmplplan.getMethod() == state.meth);}
124    
125            // for invalidated method, we do not perform OSR guarded inlining anymore.
126            // the Options object may be shared by several methods,
127            // we have to reset it back
128            boolean savedOsr = cmplplan.options.OSR_GUARDED_INLINING;
129            cmplplan.options.OSR_GUARDED_INLINING = false;
130            int newcmid = RuntimeCompiler.recompileWithOpt(cmplplan);
131            cmplplan.options.OSR_GUARDED_INLINING = savedOsr;
132    
133            if (newcmid != -1) {
134              AOSLogging.logger.debug("recompiling state with opt succeeded " + state.cmid);
135              AOSLogging.logger.debug("new cmid " + newcmid);
136    
137              // transfer hotness to the new cmid
138              double oldSamples = Controller.methodSamples.getData(state.cmid);
139              Controller.methodSamples.reset(state.cmid);
140              Controller.methodSamples.augmentData(newcmid, oldSamples);
141    
142              recmplsucc = true;
143              if (VM.TraceOnStackReplacement) {
144                VM.sysWriteln("  recompile " + state.meth + " at -O" + cmplplan.options.getOptLevel());
145              }
146            }
147          }
148        }
149    
150        if (!recmplsucc) {
151          int newcmid = RuntimeCompiler.recompileWithOpt(state.meth);
152          if (newcmid == -1) {
153            if (VM.TraceOnStackReplacement) {VM.sysWriteln("  opt recompilation failed!");}
154            state.meth.invalidateCompiledMethod(mostRecentlyCompiledMethod);
155          }
156        }
157    
158        if (VM.TraceOnStackReplacement) {VM.sysWriteln("  opt recompilation done!");}
159      }
160    }