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