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 */ 013 package org.mmtk.plan.refcount; 014 015 import org.mmtk.utility.Constants; 016 import org.mmtk.vm.VM; 017 import org.vmmagic.pragma.Inline; 018 import org.vmmagic.pragma.Uninterruptible; 019 import org.vmmagic.unboxed.ObjectReference; 020 import org.vmmagic.unboxed.Word; 021 022 @Uninterruptible 023 public class RCHeader implements Constants { 024 025 /* Requirements */ 026 public static final int LOCAL_GC_BITS_REQUIRED = 0; 027 public static final int GLOBAL_GC_BITS_REQUIRED = 8; 028 public static final int GC_HEADER_WORDS_REQUIRED = 0; 029 030 /**************************************************************************** 031 * Object Logging (applies to *all* objects) 032 */ 033 034 /* Mask bits to signify the start/finish of logging an object */ 035 036 /** 037 * 038 */ 039 public static final int LOG_BIT = 0; 040 public static final Word LOGGED = Word.zero(); //...00000 041 public static final Word UNLOGGED = Word.one(); //...00001 042 public static final Word BEING_LOGGED = Word.one().lsh(2).minus(Word.one()); //...00011 043 public static final Word LOGGING_MASK = LOGGED.or(UNLOGGED).or(BEING_LOGGED); //...00011 044 045 /** 046 * Return <code>true</code> if <code>object</code> is yet to be logged (for 047 * coalescing RC). 048 * 049 * @param object The object in question 050 * @return <code>true</code> if <code>object</code> needs to be logged. 051 */ 052 @Inline 053 @Uninterruptible 054 public static boolean logRequired(ObjectReference object) { 055 Word value = VM.objectModel.readAvailableBitsWord(object); 056 return value.and(LOGGING_MASK).EQ(UNLOGGED); 057 } 058 059 /** 060 * Attempt to log <code>object</code> for coalescing RC. This is 061 * used to handle a race to log the object, and returns 062 * <code>true</code> if we are to log the object and 063 * <code>false</code> if we lost the race to log the object. 064 * 065 * <p>If this method returns <code>true</code>, it leaves the object 066 * in the <code>BEING_LOGGED</code> state. It is the responsibility 067 * of the caller to change the object to <code>LOGGED</code> once 068 * the logging is complete. 069 * 070 * @see #makeLogged(ObjectReference) 071 * @param object The object in question 072 * @return <code>true</code> if the race to log 073 * <code>object</code>was won. 074 */ 075 @Inline 076 @Uninterruptible 077 public static boolean attemptToLog(ObjectReference object) { 078 Word oldValue; 079 do { 080 oldValue = VM.objectModel.prepareAvailableBits(object); 081 if (oldValue.and(LOGGING_MASK).EQ(LOGGED)) { 082 return false; 083 } 084 } while ((oldValue.and(LOGGING_MASK).EQ(BEING_LOGGED)) || 085 !VM.objectModel.attemptAvailableBits(object, oldValue, oldValue.or(BEING_LOGGED))); 086 if (VM.VERIFY_ASSERTIONS) { 087 Word value = VM.objectModel.readAvailableBitsWord(object); 088 VM.assertions._assert(value.and(LOGGING_MASK).EQ(BEING_LOGGED)); 089 } 090 return true; 091 } 092 093 094 /** 095 * Signify completion of logging <code>object</code>. 096 * 097 * <code>object</code> is left in the <code>LOGGED</code> state. 098 * 099 * @see #attemptToLog(ObjectReference) 100 * @param object The object whose state is to be changed. 101 */ 102 @Inline 103 @Uninterruptible 104 public static void makeLogged(ObjectReference object) { 105 Word value = VM.objectModel.readAvailableBitsWord(object); 106 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(LOGGING_MASK).NE(LOGGED)); 107 VM.objectModel.writeAvailableBitsWord(object, value.and(LOGGING_MASK.not())); 108 } 109 110 /** 111 * Change <code>object</code>'s state to <code>UNLOGGED</code>. 112 * 113 * @param object The object whose state is to be changed. 114 */ 115 @Inline 116 @Uninterruptible 117 public static void makeUnlogged(ObjectReference object) { 118 Word oldValue, newValue; 119 do { 120 oldValue = VM.objectModel.prepareAvailableBits(object); 121 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(oldValue.and(LOGGING_MASK).EQ(LOGGED)); 122 newValue = oldValue.or(UNLOGGED); 123 } while(!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 124 } 125 126 /************************************************************************ 127 * RC header word 128 */ 129 130 /** The mark bit used for backup tracing. */ 131 public static final int MARK_BIT = LOG_BIT + 2; 132 public static final Word MARK_BIT_MASK = Word.one().lsh(MARK_BIT); 133 134 /** The bit used for newly allocated objects. */ 135 public static final int NEW_BIT = MARK_BIT + 1; 136 public static final Word NEW_BIT_MASK = Word.one().lsh(NEW_BIT); 137 138 /** Current not using any bits for cycle detection, etc */ 139 public static final int BITS_USED = NEW_BIT + 1; 140 141 /* Reference counting increments */ 142 143 public static final int INCREMENT_SHIFT = BITS_USED; 144 public static final Word INCREMENT = Word.one().lsh(INCREMENT_SHIFT); 145 public static final Word DOUBLE_INCREMENT = INCREMENT.lsh(1); 146 public static final Word LIVE_THRESHOLD = INCREMENT; 147 148 /* Return values from decRC */ 149 150 public static final int DEC_KILL = 0; 151 public static final int DEC_ALIVE = 1; 152 153 /* Return values from incRC */ 154 155 public static final int INC_OLD = 0; 156 public static final int INC_NEW = 1; 157 158 /* Limited bit thresholds and masks */ 159 160 public static final Word refSticky = Word.one().lsh(BITS_IN_BYTE - BITS_USED).minus(Word.one()).lsh(INCREMENT_SHIFT); 161 public static final int refStickyValue = refSticky.rshl(INCREMENT_SHIFT).toInt(); 162 public static final Word WRITE_MASK = refSticky.not(); 163 public static final Word READ_MASK = refSticky; 164 165 /** 166 * Has this object been marked by the most recent backup trace. 167 */ 168 @Inline 169 public static boolean isMarked(ObjectReference object) { 170 return isHeaderMarked(VM.objectModel.readAvailableBitsWord(object)); 171 } 172 173 /** 174 * Has this object been marked by the most recent backup trace. 175 */ 176 @Inline 177 public static void clearMarked(ObjectReference object) { 178 Word oldValue, newValue; 179 do { 180 oldValue = VM.objectModel.prepareAvailableBits(object); 181 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isHeaderMarked(oldValue)); 182 newValue = oldValue.and(MARK_BIT_MASK.not()); 183 } while (!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 184 } 185 186 /** 187 * Has this object been marked by the most recent backup trace. 188 */ 189 @Inline 190 private static boolean isHeaderMarked(Word header) { 191 return header.and(MARK_BIT_MASK).EQ(MARK_BIT_MASK); 192 } 193 194 /** 195 * Attempt to atomically mark this object. Return <code>true</code> if the mark was performed. 196 */ 197 @Inline 198 public static boolean testAndMark(ObjectReference object) { 199 Word oldValue, newValue; 200 do { 201 oldValue = VM.objectModel.prepareAvailableBits(object); 202 if (isHeaderMarked(oldValue)) { 203 return false; 204 } 205 newValue = oldValue.or(MARK_BIT_MASK); 206 } while (!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 207 return true; 208 } 209 210 /** 211 * Has this object been marked as new. 212 */ 213 @Inline 214 public static boolean isNew(ObjectReference object) { 215 return isHeaderNew(VM.objectModel.readAvailableBitsWord(object)); 216 } 217 218 /** 219 * Has this object been marked as new. 220 */ 221 @Inline 222 private static boolean isHeaderNew(Word header) { 223 return header.and(NEW_BIT_MASK).NE(NEW_BIT_MASK); 224 } 225 226 /** 227 * Perform any required initialization of the GC portion of the header. 228 * 229 * @param object the object 230 * @param initialInc start with a reference count of 1 (0 if <code>false</code>) 231 */ 232 @Inline 233 public static void initializeHeader(ObjectReference object, boolean initialInc) { 234 Word existingValue = VM.objectModel.readAvailableBitsWord(object); 235 Word initialValue = existingValue.and(WRITE_MASK).or((initialInc)? INCREMENT : Word.zero()); 236 VM.objectModel.writeAvailableBitsWord(object, initialValue); 237 } 238 239 /** 240 * Return <code>true</code> if given object is live 241 * 242 * @param object The object whose liveness is to be tested 243 * @return <code>true</code> if the object is alive 244 */ 245 @Inline 246 @Uninterruptible 247 public static boolean isLiveRC(ObjectReference object) { 248 Word value = VM.objectModel.readAvailableBitsWord(object); 249 if (isStuck(value)) return true; 250 return value.and(READ_MASK).GE(LIVE_THRESHOLD); 251 } 252 253 /** 254 * Return the reference count for the object. 255 * 256 * @param object The object whose liveness is to be tested 257 * @return <code>true</code> if the object is alive 258 */ 259 @Inline 260 @Uninterruptible 261 public static int getRC(ObjectReference object) { 262 Word value = VM.objectModel.readAvailableBitsWord(object); 263 if (isStuck(value)) return refStickyValue; 264 return value.and(READ_MASK).rshl(INCREMENT_SHIFT).toInt(); 265 } 266 267 /** 268 * Increment the reference count of an object. Return either 269 * <code>INC_OLD</code> if the object is not new, 270 * <code>INC_NEW</code> if the object is new. 271 * 272 * @param object The object whose RC is to be incremented. 273 * @return <code>INC_OLD</code> if the object is not new, 274 * <code>INC_NEW</code> if the object is new. 275 */ 276 @Inline 277 public static int incRC(ObjectReference object) { 278 Word oldValue, newValue; 279 int rtn; 280 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(RCBase.isRCObject(object)); 281 do { 282 oldValue = VM.objectModel.prepareAvailableBits(object); 283 if (isStuck(oldValue)) return INC_OLD; 284 if (RCBase.BUILD_FOR_GENRC) { 285 newValue = oldValue.plus(INCREMENT); 286 rtn = INC_OLD; 287 } else { 288 if (isHeaderNew(oldValue)) { 289 newValue = oldValue.plus(DOUBLE_INCREMENT); 290 newValue = newValue.or(NEW_BIT_MASK); 291 rtn = INC_NEW; 292 } else { 293 newValue = oldValue.plus(INCREMENT); 294 rtn = INC_OLD; 295 } 296 } 297 } while (!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 298 return rtn; 299 } 300 301 /** 302 * Decrement the reference count of an object. Return either 303 * <code>DEC_KILL</code> if the count went to zero, 304 * <code>DEC_ALIVE</code> if the count did not go to zero. 305 * 306 * @param object The object whose RC is to be decremented. 307 * @return <code>DEC_KILL</code> if the count went to zero, 308 * <code>DEC_ALIVE</code> if the count did not go to zero. 309 */ 310 @Inline 311 @Uninterruptible 312 public static int decRC(ObjectReference object) { 313 Word oldValue, newValue; 314 int rtn; 315 if (VM.VERIFY_ASSERTIONS) { 316 VM.assertions._assert(RCBase.isRCObject(object)); 317 VM.assertions._assert(isLiveRC(object)); 318 } 319 do { 320 oldValue = VM.objectModel.prepareAvailableBits(object); 321 if (isStuck(oldValue)) return DEC_ALIVE; 322 newValue = oldValue.minus(INCREMENT); 323 if (newValue.and(READ_MASK).LT(LIVE_THRESHOLD)) { 324 rtn = DEC_KILL; 325 } else { 326 rtn = DEC_ALIVE; 327 } 328 } while (!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 329 return rtn; 330 } 331 332 /** 333 * Initialize the reference count of an object. Return either 334 * <code>INC_OLD</code> if the object is not new, 335 * <code>INC_NEW</code> if the object is new. 336 * 337 * @param object The object whose RC is to be initialized. 338 * @return <code>INC_OLD</code> if the object is not new, 339 * <code>INC_NEW</code> if the object is new. 340 */ 341 @Inline 342 public static int initRC(ObjectReference object) { 343 Word oldValue, newValue; 344 int rtn; 345 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(RCBase.isRCObject(object)); 346 do { 347 oldValue = VM.objectModel.prepareAvailableBits(object); 348 newValue = oldValue.and(WRITE_MASK).or(INCREMENT); 349 if (RCBase.BUILD_FOR_GENRC) { 350 rtn = INC_OLD; 351 } else { 352 if (isHeaderNew(oldValue)) { 353 newValue = newValue.or(NEW_BIT_MASK); 354 rtn = INC_NEW; 355 } else { 356 rtn = INC_OLD; 357 } 358 } 359 } while (!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 360 return rtn; 361 } 362 363 /** 364 * Retain the reference count of an object. Return either 365 * <code>INC_OLD</code> if the object is not new, 366 * <code>INC_NEW</code> if the object is new. 367 * 368 * @param object The object whose RC is to be retained. 369 * @return <code>INC_OLD</code> if the object is not new, 370 * <code>INC_NEW</code> if the object is new. 371 */ 372 @Inline 373 public static int remainRC(ObjectReference object) { 374 Word oldValue, newValue; 375 int rtn; 376 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(RCBase.isRCObject(object)); 377 do { 378 oldValue = VM.objectModel.prepareAvailableBits(object); 379 newValue = oldValue; 380 if (RCBase.BUILD_FOR_GENRC) { 381 return INC_OLD; 382 } else { 383 if (isHeaderNew(oldValue)) { 384 newValue = newValue.or(NEW_BIT_MASK); 385 rtn = INC_NEW; 386 } else { 387 return INC_OLD; 388 } 389 } 390 } while (!VM.objectModel.attemptAvailableBits(object, oldValue, newValue)); 391 return rtn; 392 } 393 394 /** 395 * Has this object been stuck 396 */ 397 @Inline 398 private static boolean isStuck(Word value) { 399 return value.and(refSticky).EQ(refSticky); 400 } 401 }