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