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.ir;
014
015import java.util.Iterator;
016import java.util.List;
017import java.util.ListIterator;
018import org.jikesrvm.compilers.opt.OptimizingCompilerException;
019import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
020import org.jikesrvm.compilers.opt.liveness.LiveSet;
021import org.jikesrvm.compilers.opt.liveness.LiveSetEnumerator;
022import org.jikesrvm.util.LinkedListRVM;
023
024/**
025 *  This class holds GC maps for various program points.
026 *  This data structure is IR-based.  In a later phase, this information
027 *  will be used to create the final GC map (see OptMachineCodeMap.java)
028 */
029public final class GCIRMap implements Iterable<GCIRMapElement> {
030  /**
031   *  This is the list of maps.
032   *  Each element on the list is an GCIRMapElement, which is a pair
033   *   <ol>
034   *     <li>an IR instruction (the GC point)
035   *     <li>a list of RegSpillListElement, which initially hold symbolic
036   *         registers that are references (these are expanded to either
037   *         physical regs or spills by the register allocator)
038   *   </ol>
039   */
040  private final LinkedListRVM<GCIRMapElement> list = new LinkedListRVM<GCIRMapElement>();
041
042  /**
043   *  Used for class-wide debugging
044   */
045  private static final boolean DEBUG = false;
046
047  /**
048   * returns the number of GC points in this map, i.e., the number of
049   * instructions we have maps for.
050   * @return the number of GC points in this map
051   */
052  public int getNumInstructionMaps() {
053    return list.size();
054  }
055
056  /**
057   *  Calculates the number of spill entries in this GCIRMap
058   *  This is the total number of spills for all instructions
059   *  in this map.
060   *  @return the number of spill entries in this map
061   */
062  public int countNumSpillElements() {
063    // Since spill locations are not determined until after
064    // register allocation occurs, i.e., after the initial
065    // IR-based maps are created, we actually count the
066    // number of spills.
067    int count = 0;
068    for (GCIRMapElement elem : this) {
069      count += elem.countNumSpillElements();
070    }
071    return count;
072  }
073
074  /**
075   * TODO What is this method doing in this class ?? RJG
076   *
077   * This method creates a regSpillList from the passed live set.
078   * @param set the set of registers, encoded as a LiveSet object
079   * @return a list corresponding to the set passed
080   */
081  public List<RegSpillListElement> createDU(LiveSet set) {
082    if (DEBUG) {
083      System.out.println("creating a RegList for " + set);
084    }
085
086    // construct register list
087    List<RegSpillListElement> regList = new LinkedListRVM<RegSpillListElement>();
088    LiveSetEnumerator lsEnum = set.enumerator();
089    while (lsEnum.hasMoreElements()) {
090      RegisterOperand regOp = lsEnum.nextElement();
091
092      // add this register to the regList, if it is a reference
093      //  and not a physcial register
094      if (regOp.getType().isReferenceType() && !regOp.getRegister().isPhysical()) {
095        RegSpillListElement elem = new RegSpillListElement(regOp.getRegister());
096        regList.add(elem);
097      }
098    }
099    return regList;
100  }
101
102  /**
103   * This method inserts a new entry into the GCIRMap
104   * @param inst    the IR instruction we care about
105   * @param regList the set of symbolic registers as a list
106   */
107  public void insert(Instruction inst, List<RegSpillListElement> regList) {
108
109    // make a GCIRMapElement and put it on the big list
110    GCIRMapElement item = new GCIRMapElement(inst, regList);
111
112    if (DEBUG) {
113      System.out.println("Inserting new item: " + item);
114    }
115
116    list.add(item);
117  }
118
119  /**
120   * This method removes an entry in the GCIRMap that is specified
121   * by inst. Only one element of the list will be removed per call.
122   * If the instruction is not found in the GC Map and exeception is thrown.
123   * @param inst    the IR instruction we want to remove
124   */
125  public void delete(Instruction inst) {
126
127    Iterator<GCIRMapElement> iter = list.iterator();
128    while (iter.hasNext()) {
129      GCIRMapElement ptr = iter.next();
130      if (ptr.getInstruction() == inst) {
131        iter.remove();
132        return;
133      }
134    }
135    throw new OptimizingCompilerException("GCIRMap.delete(" +
136                                              inst +
137                                              ") did not delete instruction from GC Map ");
138  }
139
140  /**
141   * This method moves an entry in the GCIRMap that is specified
142   * by inst to the end of the list. Only one element of the list will be moved per call.
143   * If the instruction is not found in the GC Map and exception is thrown.
144   * @param inst    the IR instruction we want to remove
145   */
146  public void moveToEnd(Instruction inst) {
147    Iterator<GCIRMapElement> iter = list.iterator();
148    while (iter.hasNext()) {
149      GCIRMapElement newPtr = iter.next();
150      if (newPtr.getInstruction() == inst) {
151        iter.remove();
152        list.add(newPtr);
153        return;
154      }
155    }
156    throw new OptimizingCompilerException("GCIRMap.moveToEnd(" +
157                                              inst +
158                                              ") did not delete instruction from GC Map ");
159  }
160
161  /**
162   * This method inserts an entry for a "twin" instruction immediately after the
163   * original entry.
164   * If the instruction is not found in the GC Map an exception is thrown.
165   * @param inst    the original IR instruction
166   * @param twin    the new twin IR instruction
167   */
168  public void insertTwin(Instruction inst, Instruction twin) {
169    ListIterator<GCIRMapElement> iter = list.listIterator();
170    while (iter.hasNext()) {
171      GCIRMapElement newPtr = iter.next();
172      if (newPtr.getInstruction() == inst) {
173        iter.add(newPtr.createTwin(twin));
174        return;
175      }
176    }
177    throw new OptimizingCompilerException("GCIRMap.createTwin: " + inst + " not found");
178  }
179
180  @Override
181  public Iterator<GCIRMapElement> iterator() {
182    return list.iterator();
183  }
184
185  /**
186   * dumps the map
187   */
188  public void dump() {
189    System.out.println(toString());
190  }
191
192  /**
193   * @return string version of this object
194   */
195  @Override
196  public String toString() {
197    StringBuilder buf = new StringBuilder();
198    if (list.isEmpty()) {
199      buf.append("empty");
200    } else {
201      for (GCIRMapElement ptr : list) {
202        buf.append(ptr);
203      }
204    }
205    return buf.toString();
206  }
207}