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