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