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; 014 015 import org.mmtk.policy.Space; 016 import org.mmtk.utility.Constants; 017 import org.mmtk.utility.Log; 018 import org.mmtk.utility.deque.*; 019 import org.mmtk.utility.options.Options; 020 021 import org.mmtk.vm.VM; 022 023 import org.vmmagic.pragma.*; 024 import org.vmmagic.unboxed.*; 025 026 /** 027 * This abstract class and its global counterpart implement the core 028 * functionality for a transitive closure over the heap graph. This class 029 * specifically implements the unsynchronized thread-local component 030 * (ie the 'fast path') of the trace mechanism.<p> 031 * 032 * @see org.mmtk.plan.Plan 033 * @see org.mmtk.plan.Trace 034 */ 035 @Uninterruptible 036 public abstract class TraceLocal extends TransitiveClosure implements Constants { 037 /**************************************************************************** 038 * 039 * Instance variables 040 */ 041 042 /** gray objects */ 043 protected final ObjectReferenceDeque values; 044 /** delayed root slots */ 045 protected final AddressDeque rootLocations; 046 047 /**************************************************************************** 048 * 049 * Initialization 050 */ 051 052 /** 053 * Constructor 054 * 055 * @param trace The global trace class to use. 056 */ 057 public TraceLocal(Trace trace) { 058 this(-1, trace); 059 } 060 061 /** 062 * Constructor 063 * 064 * @param specializedScan The specialized scan id. 065 * @param trace The global trace class to use. 066 */ 067 public TraceLocal(int specializedScan, Trace trace) { 068 super(specializedScan); 069 values = new ObjectReferenceDeque("value", trace.valuePool); 070 rootLocations = new AddressDeque("roots", trace.rootLocationPool); 071 } 072 073 /**************************************************************************** 074 * 075 * Internally visible Object processing and tracing 076 */ 077 078 /** 079 * Should reference values be overwritten as the heap is traced? 080 */ 081 protected boolean overwriteReferenceDuringTrace() { 082 return true; 083 } 084 085 /** 086 * Trace a reference during GC. This involves determining which 087 * collection policy applies and calling the appropriate 088 * <code>trace</code> method. 089 * 090 * @param source The source of the reference. 091 * @param slot The location containing the object reference to be 092 * traced. The object reference is <i>NOT</i> an interior pointer. 093 */ 094 @Override 095 @Inline 096 public final void processEdge(ObjectReference source, Address slot) { 097 ObjectReference object = VM.activePlan.global().loadObjectReference(slot); 098 ObjectReference newObject = traceObject(object, false); 099 if (overwriteReferenceDuringTrace()) { 100 VM.activePlan.global().storeObjectReference(slot, newObject); 101 } 102 } 103 104 /** 105 * Report a root edge to be processed during GC. As the given reference 106 * may theoretically point to an object required during root scanning, 107 * the caller has requested processing be delayed. 108 * 109 * NOTE: delayed roots are assumed to be raw. 110 * 111 * @param slot The location containing the object reference to be 112 * traced. The object reference is <i>NOT</i> an interior pointer. 113 */ 114 @Inline 115 public final void reportDelayedRootEdge(Address slot) { 116 rootLocations.push(slot); 117 } 118 119 /** 120 * Trace a reference during GC. This involves determining which 121 * collection policy applies and calling the appropriate 122 * <code>trace</code> method. 123 * 124 * @param slot The location containing the object reference to be 125 * traced. The object reference is <i>NOT</i> an interior pointer. 126 * @param untraced <code>true</code> if <code>objLoc</code> is an untraced root. 127 */ 128 @Inline 129 public final void processRootEdge(Address slot, boolean untraced) { 130 ObjectReference object; 131 if (untraced) object = slot.loadObjectReference(); 132 else object = VM.activePlan.global().loadObjectReference(slot); 133 ObjectReference newObject = traceObject(object, true); 134 if (overwriteReferenceDuringTrace()) { 135 if (untraced) slot.store(newObject); 136 else VM.activePlan.global().storeObjectReference(slot, newObject); 137 } 138 } 139 140 /** 141 * Trace a reference during GC. This involves determining which 142 * collection policy applies and calling the appropriate 143 * <code>trace</code> method. 144 * 145 * @param target The object the interior edge points within. 146 * @param slot The location of the interior edge. 147 * @param root <code>true</code> if this is a root edge. 148 */ 149 public final void processInteriorEdge(ObjectReference target, Address slot, boolean root) { 150 Address interiorRef = slot.loadAddress(); 151 Offset offset = interiorRef.diff(target.toAddress()); 152 ObjectReference newTarget = traceObject(target, root); 153 if (VM.VERIFY_ASSERTIONS) { 154 if (offset.sLT(Offset.zero()) || offset.sGT(Offset.fromIntSignExtend(1<<24))) { 155 // There is probably no object this large 156 Log.writeln("ERROR: Suspiciously large delta to interior pointer"); 157 Log.write(" object base = "); Log.writeln(target); 158 Log.write(" interior reference = "); Log.writeln(interiorRef); 159 Log.write(" delta = "); Log.writeln(offset); 160 VM.assertions._assert(false); 161 } 162 } 163 if (overwriteReferenceDuringTrace()) { 164 slot.store(newTarget.toAddress().plus(offset)); 165 } 166 } 167 168 /** 169 * Collectors that move objects <b>must</b> override this method. 170 * It performs the deferred scanning of objects which are forwarded 171 * during bootstrap of each copying collection. Because of the 172 * complexities of the collection bootstrap (such objects are 173 * generally themselves gc-critical), the forwarding and scanning of 174 * the objects must be dislocated. It is an error for a non-moving 175 * collector to call this method. 176 * 177 * @param object The forwarded object to be scanned 178 */ 179 @Inline 180 protected void scanObject(ObjectReference object) { 181 if (specializedScan >= 0) { 182 VM.scanning.specializedScanObject(specializedScan, this, object); 183 } else { 184 VM.scanning.scanObject(this, object); 185 } 186 } 187 188 189 /**************************************************************************** 190 * 191 * Externally visible Object processing and tracing 192 */ 193 194 /** 195 * Add a gray object 196 * 197 * @param object The object to be enqueued 198 */ 199 @Override 200 @Inline 201 public final void processNode(ObjectReference object) { 202 values.push(object); 203 } 204 205 /** 206 * Flush the local buffers of all deques. 207 */ 208 public final void flush() { 209 values.flushLocal(); 210 rootLocations.flushLocal(); 211 } 212 213 /** 214 * Is the specified object live? 215 * 216 * @param object The object. 217 * @return {@code true} if the object is live. 218 */ 219 @Inline 220 public boolean isLive(ObjectReference object) { 221 Space space = Space.getSpaceForObject(object); 222 if (space == Plan.loSpace) 223 return Plan.loSpace.isLive(object); 224 else if (space == Plan.nonMovingSpace) 225 return Plan.nonMovingSpace.isLive(object); 226 else if (Plan.USE_CODE_SPACE && space == Plan.smallCodeSpace) 227 return Plan.smallCodeSpace.isLive(object); 228 else if (Plan.USE_CODE_SPACE && space == Plan.largeCodeSpace) 229 return Plan.largeCodeSpace.isLive(object); 230 else if (space == null) { 231 if (VM.VERIFY_ASSERTIONS) { 232 Log.write("space failure: "); Log.writeln(object); 233 } 234 } 235 return true; 236 } 237 238 /** 239 * Is the specified object reachable? Used for GC Trace 240 * 241 * @param object The object. 242 * @return {@code true} if the object is live. 243 */ 244 @Inline 245 public boolean isReachable(ObjectReference object) { 246 return Space.getSpaceForObject(object).isReachable(object); 247 } 248 249 /** 250 * Is the specified referent of a reference type object live? 251 * 252 * @param object The object. 253 * @return {@code true} if the reference object is live. 254 */ 255 @Inline 256 public boolean isReferentLive(ObjectReference object) { 257 return isLive(object); 258 } 259 260 /** 261 * This method is the core method during the trace of the object graph. 262 * The role of this method is to: 263 * 264 * <ol> 265 * <li>Ensure the traced object is not collected.</li> 266 * <li>If this is the first visit to the object enqueue it to be scanned.</li> 267 * <li>Return the forwarded reference to the object.</li> 268 * </ol> 269 * 270 * @param object The object to be traced. 271 * @return The new reference to the same object instance. 272 */ 273 @Inline 274 public ObjectReference traceObject(ObjectReference object) { 275 if (Space.isInSpace(Plan.VM_SPACE, object)) 276 return (Plan.SCAN_BOOT_IMAGE) ? object : Plan.vmSpace.traceObject(this, object); 277 if (Space.isInSpace(Plan.IMMORTAL, object)) 278 return Plan.immortalSpace.traceObject(this, object); 279 if (Space.isInSpace(Plan.LOS, object)) 280 return Plan.loSpace.traceObject(this, object); 281 if (Space.isInSpace(Plan.NON_MOVING, object)) 282 return Plan.nonMovingSpace.traceObject(this, object); 283 if (Plan.USE_CODE_SPACE && Space.isInSpace(Plan.SMALL_CODE, object)) 284 return Plan.smallCodeSpace.traceObject(this, object); 285 if (Plan.USE_CODE_SPACE && Space.isInSpace(Plan.LARGE_CODE, object)) 286 return Plan.largeCodeSpace.traceObject(this, object); 287 if (VM.VERIFY_ASSERTIONS) { 288 Log.write("Failing object => "); Log.writeln(object); 289 Space.printVMMap(); 290 VM.assertions._assert(false, "No special case for space in traceObject"); 291 } 292 return ObjectReference.nullReference(); 293 } 294 295 /** 296 * This method traces an object with knowledge of the fact that object 297 * is a root or not. In simple collectors the fact it is a root is not 298 * important so this is the default implementation given here. 299 * 300 * @param object The object to be traced. 301 * @param root Is this object a root? 302 * @return The new reference to the same object instance. 303 */ 304 @Inline 305 public ObjectReference traceObject(ObjectReference object, boolean root) { 306 return traceObject(object); 307 } 308 309 /** 310 * Ensure that the referenced object will not move from this point through 311 * to the end of the collection. This can involve forwarding the object 312 * if necessary. 313 * 314 * <i>Non-copying collectors do nothing, copying collectors must 315 * override this method in each of their trace classes.</i> 316 * 317 * @param object The object that must not move during the collection. 318 * @return {@code true} If the object will not move during collection 319 */ 320 public boolean willNotMoveInCurrentCollection(ObjectReference object) { 321 if (!VM.activePlan.constraints().movesObjects()) 322 return true; 323 if (Space.isInSpace(Plan.LOS, object)) 324 return true; 325 if (Space.isInSpace(Plan.IMMORTAL, object)) 326 return true; 327 if (Space.isInSpace(Plan.VM_SPACE, object)) 328 return true; 329 if (Space.isInSpace(Plan.NON_MOVING, object)) 330 return true; 331 if (Plan.USE_CODE_SPACE && Space.isInSpace(Plan.SMALL_CODE, object)) 332 return true; 333 if (Plan.USE_CODE_SPACE && Space.isInSpace(Plan.LARGE_CODE, object)) 334 return true; 335 if (VM.VERIFY_ASSERTIONS) 336 VM.assertions._assert(false, "willNotMove not defined properly in subclass"); 337 return false; 338 } 339 340 /** 341 * If a Finalizable object has moved, return the new location. 342 * 343 * @param object The object which may have been forwarded. 344 * @return The new location of <code>object</code>. 345 */ 346 public ObjectReference getForwardedFinalizable(ObjectReference object) { 347 return getForwardedReference(object); 348 } 349 350 /** 351 * If the reference object (from a Reference Type) has object has moved, 352 * return the new location. 353 * 354 * @param object The object which may have been forwarded. 355 * @return The new location of <code>object</code>. 356 */ 357 @Inline 358 public ObjectReference getForwardedReferent(ObjectReference object) { 359 return getForwardedReference(object); 360 } 361 362 /** 363 * If the Reference Type object has moved, return the new location. 364 * 365 * @param object The object which may have been forwarded. 366 * @return The new location of <code>object</code>. 367 */ 368 @Inline 369 public ObjectReference getForwardedReferenceType(ObjectReference object) { 370 return getForwardedReference(object); 371 } 372 373 /** 374 * If the referenced object has moved, return the new location. 375 * 376 * Some copying collectors will need to override this method. 377 * 378 * @param object The object which may have been forwarded. 379 * @return The new location of <code>object</code>. 380 */ 381 @Inline 382 public ObjectReference getForwardedReference(ObjectReference object) { 383 return traceObject(object); 384 } 385 386 /** 387 * Make alive a referent object that is known not to be live 388 * (isLive is false). This is used by the ReferenceProcessor. 389 * 390 * <i>For many collectors these semantics reflect those of 391 * <code>traceObject</code>, which is implemented here. Other 392 * collectors must override this method.</i> 393 * 394 * @param object The object which is to be made alive. 395 * @return The possibly forwarded address of the object. 396 */ 397 @Inline 398 public ObjectReference retainReferent(ObjectReference object) { 399 return traceObject(object); 400 } 401 402 /** 403 * An object is unreachable and is about to be added to the 404 * finalizable queue. The collector must ensure the object is not 405 * collected (despite being otherwise unreachable), and should 406 * return its forwarded address if keeping the object alive involves 407 * forwarding. This is only ever called once for an object.<p> 408 * 409 * <i>For many collectors these semantics reflect those of 410 * <code>traceObject</code>, which is implemented here. Other 411 * collectors must override this method.</i> 412 * 413 * @param object The object which may have been forwarded. 414 * @return The forwarded value for <code>object</code>. <i>In this 415 * case return <code>object</code>, copying collectors must override 416 * this method. 417 */ 418 public ObjectReference retainForFinalize(ObjectReference object) { 419 return traceObject(object); 420 } 421 422 /** 423 * Return true if an object is ready to move to the finalizable 424 * queue, i.e. it has no regular references to it. This method may 425 * (and in some cases is) be overridden by subclasses. If this method 426 * returns true then it can be assumed that retainForFinalize will be 427 * called during the current collection. 428 * 429 * <i>For many collectors these semantics reflect those of 430 * <code>isLive</code>, which is implemented here. Other 431 * collectors must override this method.</i> 432 * 433 * @param object The object being queried. 434 * @return <code>true</code> if the object has no regular references 435 * to it. 436 */ 437 public boolean readyToFinalize(ObjectReference object) { 438 return !isLive(object); 439 } 440 441 /**************************************************************************** 442 * 443 * Collection 444 * 445 * Important notes: 446 * . Global actions are executed by only one thread 447 * . Thread-local actions are executed by all threads 448 * . The following order is guaranteed by BasePlan, with each 449 * separated by a synchronization barrier. 450 * 1. globalPrepare() 451 * 2. threadLocalPrepare() 452 * 3. threadLocalRelease() 453 * 4. globalRelease() 454 */ 455 456 /** 457 * TODO write JavaDoc comment 458 */ 459 public void prepare() { 460 // Nothing to do 461 } 462 463 public void release() { 464 values.reset(); 465 rootLocations.reset(); 466 } 467 468 /** 469 * Process any roots for which processing was delayed. 470 */ 471 @Inline 472 public void processRoots() { 473 logMessage(5, "processing delayed root objects"); 474 while (!rootLocations.isEmpty()) { 475 processRootEdge(rootLocations.pop(), true); 476 } 477 } 478 479 /** 480 * Finishing processing all GC work. This method iterates until all work queues 481 * are empty. 482 */ 483 @Inline 484 public void completeTrace() { 485 logMessage(4, "Processing GC in parallel"); 486 if (!rootLocations.isEmpty()) { 487 processRoots(); 488 } 489 logMessage(5, "processing gray objects"); 490 assertMutatorRemsetsFlushed(); 491 do { 492 while (!values.isEmpty()) { 493 ObjectReference v = values.pop(); 494 scanObject(v); 495 } 496 processRememberedSets(); 497 } while (!values.isEmpty()); 498 assertMutatorRemsetsFlushed(); 499 } 500 501 /** 502 * Process GC work until either complete or workLimit 503 * units of work are completed. 504 * 505 * @param workLimit The maximum units of work to perform. 506 * @return <code>true</code> if all work was completed within workLimit. 507 */ 508 @Inline 509 public boolean incrementalTrace(int workLimit) { 510 logMessage(4, "Continuing GC in parallel (incremental)"); 511 logMessage(5, "processing gray objects"); 512 int units = 0; 513 do { 514 while (!values.isEmpty() && units < workLimit) { 515 ObjectReference v = values.pop(); 516 scanObject(v); 517 units++; 518 } 519 } while (!values.isEmpty() && units < workLimit); 520 return values.isEmpty(); 521 } 522 523 /** 524 * Flush any remembered sets pertaining to the current collection. 525 * Non-generational collectors do nothing. 526 */ 527 protected void processRememberedSets() {} 528 529 /** 530 * Assert that the remsets have been flushed. This is critical to 531 * correctness. We need to maintain the invariant that remset entries 532 * do not accrue during GC. If the host JVM generates barrier entries 533 * it is its own responsibility to ensure that they are flushed before 534 * returning to MMTk. 535 */ 536 private void assertMutatorRemsetsFlushed() { 537 /* FIXME: PNT 538 if (VM.VERIFY_ASSERTIONS) { 539 for (int m = 0; m < VM.activePlan.mutatorCount(); m++) { 540 VM.activePlan.mutator(m).assertRemsetsFlushed(); 541 } 542 } 543 */ 544 } 545 546 /** 547 * This method logs a message with prepended thread id, if the 548 * verbosity level is greater or equal to the passed level. 549 * 550 * @param minVerbose The required verbosity level 551 * @param message The message to display 552 */ 553 @Inline 554 protected final void logMessage(int minVerbose, String message) { 555 if (Options.verbose.getValue() >= minVerbose) { 556 Log.prependThreadId(); 557 Log.write(" "); 558 Log.writeln(message); 559 } 560 } 561 }