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.liveness;
014
015import org.jikesrvm.compilers.opt.ir.Register;
016import org.jikesrvm.compilers.opt.ir.operand.RegisterOperand;
017
018/**
019 * This file provides a sorted set of registers.
020 */
021public class LiveSet {
022
023  /**
024   *  The beginning of the list
025   */
026  private LiveSetElement first;
027
028  /**
029   * just used for debugging
030   */
031  private static final boolean DEBUG = false;
032
033  /**
034   * Empties the set.
035   */
036  public final void clear() {
037    first = null;
038  }
039
040  /**
041   * Determines if the item passed is in the current set
042   * @param item the register to search for
043   * @return whether the item was found
044   */
045  public boolean contains(Register item) {
046    if (DEBUG) {
047      System.out.println("looking for " + item + " in " + this);
048    }
049    // simply linear search
050    LiveSetEnumerator lsEnum = enumerator();
051    while (lsEnum.hasMoreElements()) {
052      Register elem = lsEnum.nextElement().getRegister();
053      if (item == elem) {
054        if (DEBUG) {
055          System.out.println("found it, returning true");
056        }
057        return true;
058      }
059    }
060    if (DEBUG) {
061      System.out.println("didn't find it, returning false");
062    }
063    return false;
064  }
065
066  /**
067   * create a new object from the passed parameter and add it to the list
068   * @param item an object that contains the register to used in the newly
069   *             created object
070   */
071  public void add(RegisterOperand item) {
072    if (DEBUG) {
073      System.out.println("\t LiveSet.add (item) called with reg " + item);
074      System.out.println("\t before add:" + this);
075    }
076    // for each item in LiveSet add it to this.set
077    if (first == null) {
078      // add at the front
079      createAndAddToCurrentList(item, null);
080    } else {
081      LiveSetElement current = first;
082      LiveSetElement prev = null;
083      // traverse the current list looking for the appropriate place
084      int itemNumber = item.getRegister().number;      // cache the item's number
085      while (current != null && current.getRegister().number < itemNumber) {
086        prev = current;
087        current = current.getNext();
088      }
089      // check if there is a next item
090      if (current != null) {
091        if (current.getRegister().number == itemNumber) {
092          // already in there.  Check to see if we have an Address/Reference confusion.
093          // If we do, then prefer to have the Reference in the LiveSet as that will
094          // include item in the GC maps from this program point "up"
095          if (current.getRegisterType().isWordLikeType() && item.getType().isReferenceType()) {
096            current.setRegisterOperand(item);
097          }
098        } else {
099          createAndAddToCurrentList(item, prev);
100        }
101      } else {                    // current == null
102        // we ran off the end of the list, but prev still has the last element
103        createAndAddToCurrentList(item, prev);
104      }
105    }
106    if (DEBUG) {
107      System.out.println("\tafter add:" + this);
108    }
109  }
110
111  /**
112   * Adds the contents of the given set to this set.
113   * @param additionList the set to add to this set
114   * @return whether any additions were made
115   */
116  public boolean add(LiveSet additionList) {
117    // for each item in LiveSet add it to this.set
118    // recording if it was an addition
119    // first make sure there is something to add
120    if (additionList == null) {
121      return false;
122    }
123    LiveSetEnumerator lsEnum = additionList.enumerator();
124    if (!lsEnum.hasMoreElements()) {
125      return false;
126    }
127    if (DEBUG) {
128      System.out.println("\t LiveSet.add called");
129      System.out.println("\t   currentList: " + this);
130      System.out.println("\t   additionList: " + additionList);
131    }
132
133    boolean change = false;
134    if (first == null) {
135      // current list is empty, just deep copy the passed list
136      // handle the 1st element outside the loop
137      RegisterOperand newElem = lsEnum.nextElement();
138      first = new LiveSetElement(newElem);
139      LiveSetElement existingPtr = first;
140      while (lsEnum.hasMoreElements()) {
141        newElem = lsEnum.nextElement();
142        // copy additionList and add it to first list
143        LiveSetElement elem = new LiveSetElement(newElem);
144        existingPtr.setNext(elem);
145        existingPtr = elem;
146      }
147      change = true;
148    } else {
149      // both (sorted) lists have at least 1 element
150      // walk down the lists in parallel looking for items
151      // in the addition list that aren't in the current list
152      // We don't use the enumeration here, because it is more
153      // familiar not too.
154      LiveSetElement newPtr = additionList.first;
155      LiveSetElement curPtr = first;
156      // this is always one node before "curPtr". It is used for inserts
157      LiveSetElement curPrevPtr = null;
158      while (newPtr != null && curPtr != null) {
159        if (newPtr.getRegister().number < curPtr.getRegister().number) {
160          // found one in new list that is not in current list
161          // When we add, the "prev" ptr will be updated
162          curPrevPtr = createAndAddToCurrentList(newPtr.getRegisterOperand(), curPrevPtr);
163          // don't forget to update curPtr
164          curPtr = getNextPtr(curPrevPtr);
165          newPtr = newPtr.getNext();
166          change = true;
167        } else if (newPtr.getRegister().number > curPtr.getRegister().number) {
168          // need to move up current list
169          curPrevPtr = curPtr;
170          curPtr = curPtr.getNext();
171        } else {
172          // item is already in current list, update both list ptrs
173          curPrevPtr = curPtr;
174          curPtr = curPtr.getNext();
175          newPtr = newPtr.getNext();
176        }
177      }
178      // while there is still more on the new list, add them
179      while (newPtr != null) {
180        // When we add, the "prev" ptr will be updated
181        curPrevPtr = createAndAddToCurrentList(newPtr.getRegisterOperand(), curPrevPtr);
182        // don't forget to update curPtr
183        curPtr = getNextPtr(curPrevPtr);
184        newPtr = newPtr.getNext();
185        change = true;
186      }
187    }
188    if (DEBUG) {
189      System.out.println("\tafter add:" + this + "\n Change:" + change);
190    }
191    return change;
192  }
193
194  /**
195   * Removes the contents of the passed set from the this set, i.e.,
196   *    {@code this = this - removeList}
197   * @param removalList the list to remove from this set
198   */
199  public void remove(LiveSet removalList) {
200    // for each item in the LiveSet
201    // remove it from this.set
202    // Since the "removalList" set is sorted we can perform the
203    // remove in 1 pass over the "this" set.
204    // first make sure there is something to remove
205    if (removalList == null) {
206      return;
207    }
208    LiveSetEnumerator lsEnum = removalList.enumerator();
209    if (!lsEnum.hasMoreElements()) {
210      return;
211    }
212    // if current list is empty, there is nothing to remove
213    if (first == null) {
214      return;
215    }
216    if (DEBUG) {
217      System.out.println("\t LiveSet.remove called");
218      System.out.println("\t   currentList: " + this);
219      System.out.println("\t   removalList: " + removalList);
220    }
221    // both (sorted) lists have at least 1 element
222    // walk down the lists in parallel looking for items
223    // in the removal list that are in the current list
224    // We don't use the enumeration here, because it is more
225    // familiar not too.
226    LiveSetElement newPtr = removalList.first;
227    LiveSetElement curPtr = first;
228    // this is always one node before "curPtr". It is used for removal
229    LiveSetElement curPrevPtr = null;
230    while (newPtr != null && curPtr != null) {
231      if (newPtr.getRegister().number < curPtr.getRegister().number) {
232        // found one in removal list that is not in current list
233        // move to next on removal list
234        newPtr = newPtr.getNext();
235      } else if (newPtr.getRegister().number > curPtr.getRegister().number) {
236        // need to move up current list, found 1 on current list not on
237        // removal list
238        curPrevPtr = curPtr;
239        curPtr = curPtr.getNext();
240      } else {
241        // found one on both lists, remove it!
242        if (curPrevPtr != null) {
243          curPrevPtr.setNext(curPtr.getNext());
244        } else {
245          // removing first item on list
246          first = curPtr.getNext();
247        }
248        // move up both lists, curPrevPtr is already correct
249        curPtr = curPtr.getNext();
250        newPtr = newPtr.getNext();
251      }
252    }
253    // once we leave the loop, we may have items on 1 list, but not
254    // on the other.  these can't be removed so there is nothing to
255    // be done with them
256    if (DEBUG) {
257      System.out.println("\tafter remove:" + this);
258    }
259  }
260
261  /**
262   * Removes the passed register from this set.
263   * @param item the registerOperand holding the register of interest
264   */
265  void remove(RegisterOperand item) {
266    if (DEBUG) {
267      System.out.println("\tLiveSet.remove (item) called with reg " + item);
268    }
269    // only something to do if the set is non-empty
270    if (first != null) {
271      int itemNumber = item.getRegister().number;    // cache the item's number
272      // special case the first element
273      if (first.getRegister().number == itemNumber) {
274        first = first.getNext();
275      } else {
276        LiveSetElement current = first.getNext();
277        LiveSetElement prev = first;
278        // run down the current list looking for appropriate place
279        while (current != null && current.getRegister().number < itemNumber) {
280          prev = current;
281          current = current.getNext();
282        }
283        // did we find it?
284        if (current != null && current.getRegister().number == itemNumber) {
285          prev.setNext(current.getNext());
286        }
287      }
288    }
289  }
290
291  /**
292   * Is the current set empty?
293   * @return {@code true} iff the set is empty
294   */
295  public boolean isEmpty() {
296    return first == null;
297  }
298
299  /**
300   * String-i-fy the current list
301   * @return the string-i-fied version
302   */
303  @Override
304  public String toString() {
305    StringBuilder buf = new StringBuilder();
306    if (first == null) {
307      buf.append("empty");
308    } else {
309      LiveSetElement ptr = first;
310      while (ptr != null) {
311        buf.append(ptr.getRegisterOperand()).append("  ");
312        ptr = ptr.getNext();
313      }
314    }
315    return buf.toString();
316  }
317
318  /**
319   * Returns an enumerator of the list
320   * @return an enumerator of the list
321   */
322  public final LiveSetEnumerator enumerator() {
323    return new LiveSetEnumerator(first);
324  }
325
326  /**
327   * Copy the newElement into a new object and add it to the list
328   * after prevElement.  If prevElement is null, update the "start"
329   * data member by inserting at the begining.
330   * @param  register the element to copy and insert
331   * @param  prevElement the element on the current list to insert after
332   *                     or null, indicating insert at the front
333   * @return the element that is prior to the newly inserted element
334   */
335  private LiveSetElement createAndAddToCurrentList(RegisterOperand register, LiveSetElement prevElement) {
336    LiveSetElement newElement = new LiveSetElement(register);
337    if (prevElement == null) {
338      // insert at front of list
339      newElement.setNext(first);
340      first = newElement;
341    } else {
342      // insert at non-front of list
343      newElement.setNext(prevElement.getNext());
344      prevElement.setNext(newElement);
345    }
346    // new Element is now the previous element to the "curent" one
347    // which was the node that followed prevElement on entry to this method
348
349    return newElement;
350  }
351
352  /**
353   *  Inspects the passed ptr, if it is nonnull it returns its next field
354   *  otherwise, it returns "first"
355   *  @param ptr  the ptr to look at it
356   *  @return the next field (if ptr is nonnull) or first (if ptr is null)
357   */
358  private LiveSetElement getNextPtr(LiveSetElement ptr) {
359    if (ptr != null) {
360      return ptr.getNext();
361    } else {
362      return first;
363    }
364  }
365
366}
367
368
369