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.compilers.opt.mir2mc;
014
015import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE_opcode;
016
017import java.util.HashMap;
018import java.util.Map;
019
020import org.jikesrvm.compilers.opt.OptimizingCompilerException;
021import org.jikesrvm.compilers.opt.ir.Instruction;
022import org.jikesrvm.VM;
023
024/**
025 * Saves machine code offsets during the compilation of the method.
026 * <p>
027 * Information that is needed at runtime is saved in other classes,
028 * e.g. {@link org.jikesrvm.compilers.opt.runtimesupport.OptMachineCodeMap}.
029 */
030public final class MachineCodeOffsets {
031
032  private final Map<Instruction, Integer> mcOffsets;
033
034  MachineCodeOffsets() {
035    this.mcOffsets = new HashMap<Instruction, Integer>();
036  }
037
038  /**
039   * This method is only for use by opt assemblers to generate code.
040   * It sets the machine code offset of the instruction as described in
041   * {@link #getMachineCodeOffset(Instruction)}.
042   *
043   * @param inst the instruction whose offset will be set
044   * @param mcOffset the offset (in bytes) for the instruction
045   */
046  public void setMachineCodeOffset(Instruction inst, int mcOffset) {
047    mcOffsets.put(inst, Integer.valueOf(mcOffset));
048  }
049
050  /**
051   * Gets the offset into the machine code array (in bytes) that
052   * corresponds to the first byte after this instruction.<p>
053   * This method only returns a valid value after it has been set as a
054   * side-effect of a call to generateCode in AssemblerOpt during final assembly.<p>
055   * To get the offset in INSTRUCTIONs you must shift by LG_INSTRUCTION_SIZE.<p>
056   *
057   * @param inst the instruction whose offset is queried
058   * @return the offset (in bytes) of the machinecode instruction
059   *  generated for the IR instruction in the final machinecode
060   * @throws OptimizingCompilerException when no machine code offset is present for
061   *  the instruction
062   */
063  public int getMachineCodeOffset(Instruction inst) {
064    Integer offset = mcOffsets.get(inst);
065    if (offset == null) {
066      throw new OptimizingCompilerException("No valid machine code offset was ever set for instruction " + inst);
067    }
068    return offset.intValue();
069  }
070
071  /**
072   * Checks whether a machine code offset is missing for the instruction.
073   *
074   * @param inst the instruction to check
075   * @return {@code true} if the instruction never had a machine code offset
076   *  set
077   */
078  public boolean lacksMachineCodeOffset(Instruction inst) {
079    return mcOffsets.get(inst) == null;
080  }
081
082  /**
083   * Fabricates an offset for prologue instructions in methods that are not
084   * interruptible to deal with an oddity.
085   * <p>
086   * Note: General clients must not call this method.
087   *
088   * @param instr a prologue instruction in a method that's not interruptible
089   */
090  public void fabricateMachineCodeOffsetForPrologueInstruction(Instruction instr) {
091    if (VM.VerifyAssertions) {
092      boolean prologueInstr = instr.getOpcode() == IR_PROLOGUE_opcode;
093      boolean hasNoValidOffset = lacksMachineCodeOffset(instr);
094      if (!prologueInstr || !hasNoValidOffset) {
095        VM.sysWriteln("Instruction " + instr);
096      }
097      VM._assert(prologueInstr, "Instruction was not a valid argument for this method!");
098      VM._assert(hasNoValidOffset, "Instruction already had a valid machine code offset!");
099    }
100    // Use zero as a value because this value was used for instructions that had no
101    // machine code offset set before the machine code offset information was
102    // moved to this class.
103    mcOffsets.put(instr, Integer.valueOf(0));
104  }
105
106}