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.ArrayList;
016import java.util.Enumeration;
017
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.StringEventCounterData;
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 static org.jikesrvm.compilers.opt.ir.Operators.LABEL;
028import static org.jikesrvm.compilers.opt.ir.Operators.RETURN;
029import org.jikesrvm.compilers.opt.ir.Prologue;
030
031/**
032 * The following OPT phase inserts counters on all instructions in the
033 * IR.  It maintains one counter for each operand type, so it output
034 * how many loads were executed, how many int_add's etc.  This is
035 * useful for debugging and assessing the accuracy of optimizations.
036 * <p>
037 * Note: The counters are added at the end of HIR, so the counts will
038 * NOT reflect any changes to the code that occur after HIR.
039 */
040public class InsertInstructionCounters extends CompilerPhase {
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_INSTRUCTION_COUNTERS;
056  }
057
058  @Override
059  public final String getName() {
060    return "InsertInstructionCounters";
061  }
062
063  /**
064   * Insert a counter on every instruction, and group counts by
065   * opcode type.
066   *
067   * @param ir the governing IR
068   */
069  @Override
070  public final void perform(IR ir) {
071
072    // Don't insert counters in uninterruptible methods,
073    // the boot image, or when instrumentation is disabled
074    if (!ir.method.isInterruptible() ||
075        ir.method.getDeclaringClass().isInBootImage() ||
076        !Instrumentation.instrumentationEnabled()) {
077      return;
078    }
079
080    // Get the data object that handles the counters
081    StringEventCounterData data = AOSDatabase.instructionCounterData;
082
083    // Create a vector of basic blocks up front because the blocks
084    // are modified as we iterate below.
085    ArrayList<BasicBlock> bbList = new ArrayList<BasicBlock>();
086    for (Enumeration<BasicBlock> bbe = ir.getBasicBlocks(); bbe.hasMoreElements();) {
087      BasicBlock bb = bbe.nextElement();
088      bbList.add(bb);
089    }
090
091    // Iterate through the basic blocks
092    for (BasicBlock bb : bbList) {
093      // Add instructions to vector so enumeration doesn't mess
094      // things up.  There is probably a better way to do this, but
095      // it doesn't matter because this is a debugging phase.
096      ArrayList<Instruction> iList = new ArrayList<Instruction>();
097      Instruction inst = bb.firstInstruction();
098      while (inst != null && inst != bb.lastInstruction()) {
099        iList.add(inst);
100        inst = inst.nextInstructionInCodeOrder();
101      }
102
103      // Iterate through all the instructions in this block.
104      for (Instruction i : iList) {
105
106        // Skip dangerous instructions
107        if (i.operator() == LABEL || Prologue.conforms(i)) {
108          continue;
109        }
110
111        if (i.isBranch() || i.operator() == RETURN) {
112
113          // It's a branch, so you need to be careful how you insert the
114          // counter.
115          Instruction prev = i.prevInstructionInCodeOrder();
116
117          // If the instruction above this branch is also a branch,
118          // then we can't instrument as-is because a basic block
119          // must end with branches only.  Solve by splitting block.
120          if (prev.isBranch()) {
121            // BasicBlock newBlock =
122            bb.splitNodeWithLinksAt(prev, ir);
123            bb.recomputeNormalOut(ir);
124          }
125
126          // Use the name of the operator as the name of the event
127          Instruction counterInst = data.
128              getCounterInstructionForEvent(i.operator().toString());
129
130          // Insert the new instruction into the code order
131          i.insertBefore(counterInst);
132        } else {
133          // It's a non-branching instruction.  Insert counter before
134          // the instruction.
135
136          // Use the name of the operator as the name of the event
137          Instruction counterInst = data.
138              getCounterInstructionForEvent(i.operator().toString());
139
140          i.insertBefore(counterInst);
141        }
142      }
143    }
144  }
145}