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