/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.adaptive.recompilation.instrumentation;
import java.util.ArrayList;
import org.jikesrvm.adaptive.controller.VM_Controller;
import org.jikesrvm.adaptive.database.VM_AOSDatabase;
import org.jikesrvm.adaptive.measurements.instrumentation.VM_Instrumentation;
import org.jikesrvm.adaptive.measurements.instrumentation.VM_StringEventCounterData;
import org.jikesrvm.compilers.opt.OPT_CompilerPhase;
import org.jikesrvm.compilers.opt.OPT_Options;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlock;
import org.jikesrvm.compilers.opt.ir.OPT_BasicBlockEnumeration;
import org.jikesrvm.compilers.opt.ir.OPT_IR;
import org.jikesrvm.compilers.opt.ir.OPT_Instruction;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.LABEL;
import static org.jikesrvm.compilers.opt.ir.OPT_Operators.RETURN;
import org.jikesrvm.compilers.opt.ir.Prologue;
/**
* The following OPT phase inserts counters on all instructions in the
* IR. It maintians one counter for each operand type, so it output
* how many loads were executed, how many int_add's etc. This is
* useful for debugging and assessing the accuracy of optimizations.
*
* Note: The counters are added at the end of HIR, so the counts will
* NOT reflect any changes to the code that occur after HIR.
*/
public class OPT_InsertInstructionCounters extends OPT_CompilerPhase {
/**
* Return this instance of this phase. This phase contains no
* per-compilation instance fields.
* @param ir not used
* @return this
*/
public OPT_CompilerPhase newExecution(OPT_IR ir) {
return this;
}
public final boolean shouldPerform(OPT_Options options) {
return VM_Controller.options.INSERT_INSTRUCTION_COUNTERS;
}
public final String getName() { return "InsertInstructionCounters"; }
/**
* Insert a counter on every instruction, and group counts by
* opcode type.
*
* @param ir the governing IR
*/
public final void perform(OPT_IR ir) {
// Don't insert counters in uninterruptible methods,
// the boot image, or when instrumentation is disabled
if (!ir.method.isInterruptible() ||
ir.method.getDeclaringClass().isInBootImage() ||
!VM_Instrumentation.instrumentationEnabled()) {
return;
}
// Get the data object that handles the counters
VM_StringEventCounterData data = VM_AOSDatabase.instructionCounterData;
// Create a vector of basic blocks up front because the blocks
// are modified as we iterate below.
ArrayList<OPT_BasicBlock> bbList = new ArrayList<OPT_BasicBlock>();
for (OPT_BasicBlockEnumeration bbe = ir.getBasicBlocks(); bbe.hasMoreElements();) {
OPT_BasicBlock bb = bbe.next();
bbList.add(bb);
}
// Iterate through the basic blocks
for (OPT_BasicBlock bb : bbList) {
// Add instructions to vector so enumeration doesn't mess
// things up. There is probably a better way to do this, but
// it doesn't matter because this is a debugging phase.
ArrayList<OPT_Instruction> iList = new ArrayList<OPT_Instruction>();
OPT_Instruction inst = bb.firstInstruction();
while (inst != null && inst != bb.lastInstruction()) {
iList.add(inst);
inst = inst.nextInstructionInCodeOrder();
}
// Iterate through all the instructions in this block.
for (OPT_Instruction i : iList) {
// Skip dangerous instructions
if (i.operator() == LABEL || Prologue.conforms(i)) {
continue;
}
if (i.isBranch() || i.operator() == RETURN) {
// It's a branch, so you need to be careful how you insert the
// counter.
OPT_Instruction prev = i.prevInstructionInCodeOrder();
// If the instruction above this branch is also a branch,
// then we can't instrument as-is because a basic block
// must end with branches only. Solve by splitting block.
if (prev.isBranch()) {
// OPT_BasicBlock newBlock =
bb.splitNodeWithLinksAt(prev, ir);
bb.recomputeNormalOut(ir);
}
// Use the name of the operator as the name of the event
OPT_Instruction counterInst = data.
getCounterInstructionForEvent(i.operator().toString());
// Insert the new instruction into the code order
i.insertBefore(counterInst);
} else {
// It's a non-branching instruction. Insert counter before
// the instruction.
// Use the name of the operator as the name of the event
OPT_Instruction counterInst = data.
getCounterInstructionForEvent(i.operator().toString());
i.insertBefore(counterInst);
}
}
}
}
}