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}