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.instrumentation;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.adaptive.controller.Controller;
017    import org.jikesrvm.adaptive.database.AOSDatabase;
018    import org.jikesrvm.adaptive.measurements.instrumentation.Instrumentation;
019    import org.jikesrvm.adaptive.measurements.instrumentation.YieldpointCounterData;
020    import org.jikesrvm.compilers.opt.OptOptions;
021    import org.jikesrvm.compilers.opt.driver.CompilerPhase;
022    import org.jikesrvm.compilers.opt.ir.BasicBlock;
023    import org.jikesrvm.compilers.opt.ir.BasicBlockEnumeration;
024    import org.jikesrvm.compilers.opt.ir.IR;
025    import org.jikesrvm.compilers.opt.ir.Instruction;
026    import org.jikesrvm.compilers.opt.ir.Operator;
027    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_BACKEDGE;
028    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_EPILOGUE;
029    import static org.jikesrvm.compilers.opt.ir.Operators.YIELDPOINT_PROLOGUE;
030    
031    /**
032     * An opt compiler phase that inserts yieldpoint counters.  Searches
033     * for all yieldpoint instructions and inserts an increment after
034     * them, using the CounterArrayManager counter manager to implement
035     * the counters.
036     */
037    public class InsertYieldpointCounters extends CompilerPhase {
038    
039      static final boolean DEBUG = false;
040    
041      /**
042       * Return this instance of this phase. This phase contains no
043       * per-compilation instance fields.
044       * @param ir not used
045       * @return this
046       */
047      public CompilerPhase newExecution(IR ir) {
048        return this;
049      }
050    
051      public final boolean shouldPerform(OptOptions options) {
052        return Controller.options.INSERT_YIELDPOINT_COUNTERS;
053      }
054    
055      public final String getName() { return "InsertYieldpointCounters"; }
056    
057      /**
058       * counters after all yieldpoint instructions
059       *
060       * @param ir the governing IR
061       */
062      public final void perform(IR ir) {
063    
064        // Don't insert counters in uninterruptible methods,
065        // the boot image, or when instrumentation is disabled
066        if (!ir.method.isInterruptible() ||
067            ir.method.getDeclaringClass().isInBootImage() ||
068            !Instrumentation.instrumentationEnabled()) {
069          return;
070        }
071    
072        YieldpointCounterData data = AOSDatabase.yieldpointCounterData;
073    
074        if (InsertYieldpointCounters.DEBUG) {
075          VM.sysWrite("InsertYieldpointCounters.perform() " + ir.method + "\n");
076        }
077        // For each yieldpoint, insert a counter.
078        for (BasicBlockEnumeration bbe = ir.getBasicBlocks(); bbe.hasMoreElements();) {
079          BasicBlock bb = bbe.next();
080    
081          if (InsertYieldpointCounters.DEBUG) {
082            VM.sysWrite("Considering basic block " + bb.toString() + "\n");
083            bb.printExtended();
084          }
085    
086          Instruction i = bb.firstInstruction();
087          while (i != null && i != bb.lastInstruction()) {
088    
089            if (i.operator() == YIELDPOINT_PROLOGUE ||
090                i.operator() == YIELDPOINT_EPILOGUE ||
091                i.operator() == YIELDPOINT_BACKEDGE) {
092              String prefix = yieldpointPrefix(i.operator());
093              double incrementValue = 1.0;
094    
095              if (i.operator() == YIELDPOINT_EPILOGUE) {
096                prefix = "METHOD ENTRY ";
097              } else if (i.operator() == YIELDPOINT_PROLOGUE) {
098                prefix = "METHOD EXIT ";
099              } else {
100                prefix = "BACKEDGE ";
101                incrementValue = 1.0;
102              }
103    
104              // Create an instruction to increment the counter for this
105              // method.  By appending the prefix and method name, it
106              // maintains a separate counter for each method, and
107              // separates between method entry and backedges.
108              Instruction counterInst = data.
109                  getCounterInstructionForEvent(prefix + ir.method.toString(), incrementValue);
110    
111              // Insert the new instruction into the code order
112              i.insertAfter(counterInst);
113            }
114    
115            i = i.nextInstructionInCodeOrder();
116          }
117        }
118      }
119    
120      /**
121       * Return a string based version of the passed yieldpoint operator
122       * @param op the yieldpoint operator
123       * @return a string based on the type of yieldpoint operator
124       */
125      private static String yieldpointPrefix(Operator op) {
126        if (op == YIELDPOINT_PROLOGUE) return "Prologue";
127        if (op == YIELDPOINT_EPILOGUE) return "Epilogue";
128        if (op == YIELDPOINT_BACKEDGE) return "Backedge";
129        return "ERROR";
130      }
131    }
132