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.adaptive.recompilation;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.adaptive.controller.Controller;
017    import org.jikesrvm.adaptive.controller.ControllerPlan;
018    import org.jikesrvm.adaptive.controller.RecompilationStrategy;
019    import org.jikesrvm.adaptive.recompilation.instrumentation.AOSInstrumentationPlan;
020    import org.jikesrvm.classloader.NormalMethod;
021    import org.jikesrvm.compilers.baseline.BaselineCompiler;
022    import org.jikesrvm.compilers.common.CompiledMethod;
023    import org.jikesrvm.compilers.common.CompiledMethods;
024    import org.jikesrvm.compilers.opt.OptOptions;
025    import org.jikesrvm.compilers.opt.driver.CompilationPlan;
026    import org.jikesrvm.compilers.opt.driver.OptimizationPlanElement;
027    import org.jikesrvm.compilers.opt.driver.OptimizationPlanner;
028    import org.jikesrvm.runtime.Magic;
029    
030    /**
031     * Runtime system support for using invocation counters in baseline
032     * compiled code to select methods for optimizing recompilation
033     * by the adaptive system.  Bypasses the normal controller logic:
034     * If an invocation counter trips, then the method is enqueued for
035     * recompilation at a default optimization level.
036     */
037    public final class InvocationCounts {
038    
039      private static int[] counts;
040      private static boolean[] processed;
041    
042      public static synchronized void allocateCounter(int id) {
043        if (counts == null) {
044          counts = new int[id + 500];
045          processed = new boolean[counts.length];
046        }
047        if (id >= counts.length) {
048          int newSize = counts.length * 2;
049          if (newSize <= id) newSize = id + 500;
050          int[] tmp = new int[newSize];
051          System.arraycopy(counts, 0, tmp, 0, counts.length);
052          boolean[] tmp2 = new boolean[newSize];
053          System.arraycopy(processed, 0, tmp2, 0, processed.length);
054          Magic.sync();
055          counts = tmp;
056          processed = tmp2;
057        }
058        counts[id] = Controller.options.INVOCATION_COUNT_THRESHOLD;
059      }
060    
061      /**
062       * Called from baseline compiled code when a method's invocation counter
063       * becomes negative and thus must be handled
064       */
065      static synchronized void counterTripped(int id) {
066        counts[id] = 0x7fffffff; // set counter to max int to avoid lots of redundant calls.
067        if (processed[id]) return;
068        processed[id] = true;
069        CompiledMethod cm = CompiledMethods.getCompiledMethod(id);
070        if (cm == null) return;
071        if (VM.VerifyAssertions) VM._assert(cm.getCompilerType() == CompiledMethod.BASELINE);
072        NormalMethod m = (NormalMethod) cm.getMethod();
073        CompilationPlan compPlan = new CompilationPlan(m, _optPlan, null, _options);
074        ControllerPlan cp =
075            new ControllerPlan(compPlan, Controller.controllerClock, id, 2.0, 2.0, 2.0); // 2.0 is a bogus number....
076        cp.execute();
077      }
078    
079      /**
080       * Create the compilation plan according to the default set
081       * of {@literal <optimization plan, options>} pairs
082       */
083      public static CompilationPlan createCompilationPlan(NormalMethod method) {
084        return new CompilationPlan(method, _optPlan, null, _options);
085      }
086    
087      public static CompilationPlan createCompilationPlan(NormalMethod method, AOSInstrumentationPlan instPlan) {
088        return new CompilationPlan(method, _optPlan, instPlan, _options);
089      }
090    
091      /**
092       *  Initialize the recompilation strategy.<p>
093       *
094       *  Note: This uses the command line options to set up the
095       *  optimization plans, so this must be run after the command line
096       *  options are available.
097       */
098      public static void init() {
099        createOptimizationPlan();
100        BaselineCompiler.options.INVOCATION_COUNTERS = true;
101      }
102    
103      private static OptimizationPlanElement[] _optPlan;
104      private static OptOptions _options;
105    
106      /**
107       * Create the default set of <optimization plan, options> pairs
108       * Process optimizing compiler command line options.
109       */
110      static void createOptimizationPlan() {
111        _options = new OptOptions();
112    
113        int optLevel = Controller.options.INVOCATION_COUNT_OPT_LEVEL;
114        String[] optCompilerOptions = Controller.getOptCompilerOptions();
115        _options.setOptLevel(optLevel);
116        RecompilationStrategy.processCommandLineOptions(_options, optLevel, optLevel, optCompilerOptions);
117        _optPlan = OptimizationPlanner.createOptimizationPlan(_options);
118      }
119    
120    }