/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.mir2mc;
import static org.jikesrvm.compilers.opt.ir.Operators.IR_PROLOGUE_opcode;
import java.util.HashMap;
import java.util.Map;
import org.jikesrvm.compilers.opt.OptimizingCompilerException;
import org.jikesrvm.compilers.opt.ir.Instruction;
import org.jikesrvm.VM;
/**
* Saves machine code offsets during the compilation of the method.
* <p>
* Information that is needed at runtime is saved in other classes,
* e.g. {@link org.jikesrvm.compilers.opt.runtimesupport.OptMachineCodeMap}.
*/
public final class MachineCodeOffsets {
private final Map<Instruction, Integer> mcOffsets;
MachineCodeOffsets() {
this.mcOffsets = new HashMap<Instruction, Integer>();
}
/**
* This method is only for use by opt assemblers to generate code.
* It sets the machine code offset of the instruction as described in
* {@link #getMachineCodeOffset(Instruction)}.
*
* @param inst the instruction whose offset will be set
* @param mcOffset the offset (in bytes) for the instruction
*/
public void setMachineCodeOffset(Instruction inst, int mcOffset) {
mcOffsets.put(inst, Integer.valueOf(mcOffset));
}
/**
* Gets the offset into the machine code array (in bytes) that
* corresponds to the first byte after this instruction.<p>
* This method only returns a valid value after it has been set as a
* side-effect of a call to generateCode in AssemblerOpt during final assembly.<p>
* To get the offset in INSTRUCTIONs you must shift by LG_INSTRUCTION_SIZE.<p>
*
* @param inst the instruction whose offset is queried
* @return the offset (in bytes) of the machinecode instruction
* generated for the IR instruction in the final machinecode
* @throws OptimizingCompilerException when no machine code offset is present for
* the instruction
*/
public int getMachineCodeOffset(Instruction inst) {
Integer offset = mcOffsets.get(inst);
if (offset == null) {
throw new OptimizingCompilerException("No valid machine code offset was ever set for instruction " + inst);
}
return offset.intValue();
}
/**
* Checks whether a machine code offset is missing for the instruction.
*
* @param inst the instruction to check
* @return {@code true} if the instruction never had a machine code offset
* set
*/
public boolean lacksMachineCodeOffset(Instruction inst) {
return mcOffsets.get(inst) == null;
}
/**
* Fabricates an offset for prologue instructions in methods that are not
* interruptible to deal with an oddity.
* <p>
* Note: General clients must not call this method.
*
* @param instr a prologue instruction in a method that's not interruptible
*/
public void fabricateMachineCodeOffsetForPrologueInstruction(Instruction instr) {
if (VM.VerifyAssertions) {
boolean prologueInstr = instr.getOpcode() == IR_PROLOGUE_opcode;
boolean hasNoValidOffset = lacksMachineCodeOffset(instr);
if (!prologueInstr || !hasNoValidOffset) {
VM.sysWriteln("Instruction " + instr);
}
VM._assert(prologueInstr, "Instruction was not a valid argument for this method!");
VM._assert(hasNoValidOffset, "Instruction already had a valid machine code offset!");
}
// Use zero as a value because this value was used for instructions that had no
// machine code offset set before the machine code offset information was
// moved to this class.
mcOffsets.put(instr, Integer.valueOf(0));
}
}