/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* 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/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt;
import org.jikesrvm.compilers.opt.ir.OPT_Register;
import org.jikesrvm.compilers.opt.ir.OPT_RegisterOperand;
/**
* This file provides a sorted set (of registers) ADT with the
* following public operations:
*
* clear() - empties the set
* contains(reg) - checks if reg is in the set
* add(reg) - adds reg to the set
* add(set2) - adds the contents of set2 to the set
* remove(reg) - removes reg from the set
* remove(set2) - removes the contents of set2 from the set
* enumerator() - returns an enumeration of the set
* toString() - returns a string version of the set
* isEmpty() - returns true, iff the set is empty
*/
public class OPT_LiveSet {
/**
* The beginning of the list
*/
private OPT_LiveSetElement first;
/**
* just used for debugging
*/
private static final boolean debug = false;
/**
* Empties the set
*/
public final void clear() {
first = null;
}
/**
* Determines if the item passed is in the current set
* @param item the register to search for
* @return whether the item was found
*/
public boolean contains(OPT_Register item) {
if (debug) {
System.out.println("looking for " + item + " in " + this);
}
// simply linear search
OPT_LiveSetEnumerator lsEnum = enumerator();
while (lsEnum.hasMoreElements()) {
OPT_Register elem = lsEnum.nextElement().getRegister();
if (item == elem) {
if (debug) {
System.out.println("found it, returning true");
}
return true;
}
}
if (debug) {
System.out.println("didn't find it, returning false");
}
return false;
}
/**
* create a new object from the passed parameter and add it to the list
* @param item an object that contains the register to used in the newly
* created object
*/
public void add(OPT_RegisterOperand item) {
if (debug) {
System.out.println("\t OPT_LiveSet.add (item) called with reg " + item);
System.out.println("\t before add:" + this);
}
// for each item in OPT_LiveSet add it to this.set
if (first == null) {
// add at the front
createAndAddToCurrentList(item, null);
} else {
OPT_LiveSetElement current = first;
OPT_LiveSetElement prev = null;
// traverse the current list looking for the appropriate place
int itemNumber = item.getRegister().number; // cache the item's number
while (current != null && current.getRegister().number < itemNumber) {
prev = current;
current = current.getNext();
}
// check if there is a next item
if (current != null) {
if (current.getRegister().number == itemNumber) {
// already in there. Check to see if we have an Address/Reference confusion.
// If we do, then prefer to have the Reference in the LiveSet as that will
// include item in the GC maps from this program point "up"
if (current.getRegisterType().isWordType() && item.getType().isReferenceType()) {
current.setRegisterOperand(item);
}
} else {
createAndAddToCurrentList(item, prev);
}
} else { // current == null
// we ran off the end of the list, but prev still has the last element
createAndAddToCurrentList(item, prev);
}
}
if (debug) {
System.out.println("\tafter add:" + this);
}
}
/**
* adds the contents of set2 to the set
* @param additionList
* @return whether any additions were made
*/
public boolean add(OPT_LiveSet additionList) {
// for each item in OPT_LiveSet add it to this.set
// recording if it was an addition
// first make sure there is something to add
if (additionList == null) {
return false;
}
OPT_LiveSetEnumerator lsEnum = additionList.enumerator();
if (!lsEnum.hasMoreElements()) {
return false;
}
if (debug) {
System.out.println("\t OPT_LiveSet.add called");
System.out.println("\t currentList: " + this);
System.out.println("\t additionList: " + additionList);
}
boolean change = false;
if (first == null) {
// current list is empty, just deep copy the passed list
// handle the 1st element outside the loop
OPT_RegisterOperand newElem = lsEnum.nextElement();
first = new OPT_LiveSetElement(newElem);
OPT_LiveSetElement existingPtr = first;
while (lsEnum.hasMoreElements()) {
newElem = lsEnum.nextElement();
// copy additionList and add it to first list
OPT_LiveSetElement elem = new OPT_LiveSetElement(newElem);
existingPtr.setNext(elem);
existingPtr = elem;
}
change = true;
} else {
// both (sorted) lists have at least 1 element
// walk down the lists in parallel looking for items
// in the addition list that aren't in the current list
// We don't use the enumeration here, because it is more
// familiar not too.
OPT_LiveSetElement newPtr = additionList.first;
OPT_LiveSetElement curPtr = first;
// this is always one node before "curPtr". It is used for inserts
OPT_LiveSetElement curPrevPtr = null;
while (newPtr != null && curPtr != null) {
if (newPtr.getRegister().number < curPtr.getRegister().number) {
// found one in new list that is not in current list
// When we add, the "prev" ptr will be updated
curPrevPtr = createAndAddToCurrentList(newPtr.getRegisterOperand(), curPrevPtr);
// don't forget to update curPtr
curPtr = getNextPtr(curPrevPtr);
newPtr = newPtr.getNext();
change = true;
} else if (newPtr.getRegister().number > curPtr.getRegister().number) {
// need to move up current list
curPrevPtr = curPtr;
curPtr = curPtr.getNext();
} else {
// item is already in current list, update both list ptrs
curPrevPtr = curPtr;
curPtr = curPtr.getNext();
newPtr = newPtr.getNext();
}
}
// while there is still more on the new list, add them
while (newPtr != null) {
// When we add, the "prev" ptr will be updated
curPrevPtr = createAndAddToCurrentList(newPtr.getRegisterOperand(), curPrevPtr);
// don't forget to update curPtr
curPtr = getNextPtr(curPrevPtr);
newPtr = newPtr.getNext();
change = true;
}
}
if (debug) {
System.out.println("\tafter add:" + this + "\n Change:" + change);
}
return change;
}
/**
* removes the contents of the passed set from the currrent set, i.e.,
* this = this - removeList
* @param removalList the list to remove from
*/
public void remove(OPT_LiveSet removalList) {
// for each item in the OPT_LiveSet
// remove it from this.set
// Since the "removalList" set is sorted we can perform the
// remove in 1 pass over the "this" set.
// first make sure there is something to remove
if (removalList == null) {
return;
}
OPT_LiveSetEnumerator lsEnum = removalList.enumerator();
if (!lsEnum.hasMoreElements()) {
return;
}
// if current list is empty, there is nothing to remove
if (first == null) {
return;
}
if (debug) {
System.out.println("\t OPT_LiveSet.remove called");
System.out.println("\t currentList: " + this);
System.out.println("\t removalList: " + removalList);
}
// both (sorted) lists have at least 1 element
// walk down the lists in parallel looking for items
// in the removal list that are in the current list
// We don't use the enumeration here, because it is more
// familiar not too.
OPT_LiveSetElement newPtr = removalList.first;
OPT_LiveSetElement curPtr = first;
// this is always one node before "curPtr". It is used for removal
OPT_LiveSetElement curPrevPtr = null;
while (newPtr != null && curPtr != null) {
if (newPtr.getRegister().number < curPtr.getRegister().number) {
// found one in removal list that is not in current list
// move to next on removal list
newPtr = newPtr.getNext();
} else if (newPtr.getRegister().number > curPtr.getRegister().number) {
// need to move up current list, found 1 on current list not on
// removal list
curPrevPtr = curPtr;
curPtr = curPtr.getNext();
} else {
// found one on both lists, remove it!
if (curPrevPtr != null) {
curPrevPtr.setNext(curPtr.getNext());
} else {
// removing first item on list
first = curPtr.getNext();
}
// move up both lists, curPrevPtr is already correct
curPtr = curPtr.getNext();
newPtr = newPtr.getNext();
}
}
// once we leave the loop, we may have items on 1 list, but not
// on the other. these can't be removed so there is nothing to
// be done with them
if (debug) {
System.out.println("\tafter remove:" + this);
}
}
/**
* removes the passed reg from the set
* @param item the registerOperand holding the register of interest
*/
void remove(OPT_RegisterOperand item) {
if (debug) {
System.out.println("\tOPT_LiveSet.remove (item) called with reg " + item);
}
// only something to do if the set is non-empty
if (first != null) {
int itemNumber = item.getRegister().number; // cache the item's number
// special case the first element
if (first.getRegister().number == itemNumber) {
first = first.getNext();
} else {
OPT_LiveSetElement current = first.getNext();
OPT_LiveSetElement prev = first;
// run down the current list looking for appropriate place
while (current != null && current.getRegister().number < itemNumber) {
prev = current;
current = current.getNext();
}
// did we find it?
if (current != null && current.getRegister().number == itemNumber) {
prev.setNext(current.getNext());
}
}
}
}
/**
* Is the current set empty?
* @return true iff the set is empty
*/
public boolean isEmpty() {
return first == null;
}
/**
* String-i-fy the current list
* @return the string-i-fied version
*/
public String toString() {
StringBuilder buf = new StringBuilder("");
if (first == null) {
buf.append("empty");
} else {
OPT_LiveSetElement ptr = first;
while (ptr != null) {
buf.append(ptr.getRegisterOperand()).append(" ");
ptr = ptr.getNext();
}
}
return buf.toString();
}
/**
* Returns an enumerator of the list
* @return an enumerator of the list
*/
public final OPT_LiveSetEnumerator enumerator() {
return new OPT_LiveSetEnumerator(first);
}
/**
* Copy the newElement into a new object and add it to the list
* after prevElement. If prevElement is null, update the "start"
* data member by inserting at the begining.
* @param register the element to copy and insert
* @param prevElement the element on the current list to insert after
* or null, indicating insert at the front
* @return the element that is prior to the newly inserted element
*/
private OPT_LiveSetElement createAndAddToCurrentList(OPT_RegisterOperand register, OPT_LiveSetElement prevElement) {
OPT_LiveSetElement newElement = new OPT_LiveSetElement(register);
if (prevElement == null) {
// insert at front of list
newElement.setNext(first);
first = newElement;
} else {
// insert at non-front of list
newElement.setNext(prevElement.getNext());
prevElement.setNext(newElement);
}
// new Element is now the previous element to the "curent" one
// which was the node that followed prevElement on entry to this method
return newElement;
}
/**
* Inspects the passed ptr, if it is nonnull it returns its next field
* otherwise, it returns "first"
* @param ptr the ptr to look at it
* @return the next field (if ptr is nonnull) or first (if ptr is null)
*/
private OPT_LiveSetElement getNextPtr(OPT_LiveSetElement ptr) {
if (ptr != null) {
return ptr.getNext();
} else {
return first;
}
}
}