/*
 *  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 org.jikesrvm.adaptive.controller.Controller;
import org.jikesrvm.adaptive.database.AOSDatabase;
import org.jikesrvm.adaptive.measurements.instrumentation.Instrumentation;
import org.jikesrvm.adaptive.measurements.instrumentation.MethodInvocationCounterData;
import org.jikesrvm.compilers.opt.OptOptions;
import org.jikesrvm.compilers.opt.driver.CompilerPhase;
import org.jikesrvm.compilers.opt.ir.BasicBlock;
import org.jikesrvm.compilers.opt.ir.IR;
import org.jikesrvm.compilers.opt.ir.Instruction;

/**
 * An CompilerPhase that inserts a method invocation counter on the first
 * basic block of the method.  It uses a
 * InstrumentedEventCounterManager to obtain the space to put the
 * counters.
 *
 * Note: one counter data, (MethodInvocationCounterData) is shared
 * across all methods, and is initialized at boot time.  This is
 * unlike other kinds of instrumentation (such as basic block
 * counters) where a separate data object is maintained for each
 * method.
 */
public class InsertMethodInvocationCounter extends CompilerPhase {

  /**
   * Return this instance of this phase. This phase contains no
   * per-compilation instance fields.
   * @param ir not used
   * @return this
   */
  public CompilerPhase newExecution(IR ir) {
    return this;
  }

  public final boolean shouldPerform(OptOptions options) {
    return Controller.options.INSERT_METHOD_COUNTERS_OPT;
  }

  public final String getName() { return "InsertMethodInvocationCounters"; }

  /**
   * Insert basic block counters
   *
   * @param ir the governing IR
   */
  public final void perform(IR ir) {
    // Don't insert counters in uninterruptible or
    // save volatile methods, or when instrumentation is disabled
    if (!ir.method.isInterruptible() ||
        !Instrumentation.instrumentationEnabled() ||
        ir.method.getDeclaringClass().hasSaveVolatileAnnotation()) {
      return;
    }

    BasicBlock firstBB = ir.cfg.entry();

    MethodInvocationCounterData data = AOSDatabase.methodInvocationCounterData;

    int cmid = ir.compiledMethod.getId();

    // Create a dummy instruction that is later converted into an
    // increment of the appropriate CounterArray element.
    Instruction c = data.createEventCounterInstruction(cmid);

    // Insert it at the beginning of the basic block
    firstBB.prependInstructionRespectingPrologue(c);
  }
}
