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.mm.mmtk; 014 015import org.mmtk.plan.TraceLocal; 016import org.mmtk.utility.options.Options; 017 018import org.vmmagic.pragma.*; 019import org.vmmagic.unboxed.*; 020 021import org.jikesrvm.VM; 022import org.jikesrvm.mm.mminterface.DebugUtil; 023import org.jikesrvm.mm.mminterface.Selected; 024import org.jikesrvm.runtime.Entrypoints; 025import org.jikesrvm.runtime.Magic; 026import org.jikesrvm.scheduler.RVMThread; 027 028import java.lang.ref.Reference; 029import java.lang.ref.SoftReference; 030import java.lang.ref.WeakReference; 031import java.lang.ref.PhantomReference; 032 033 034/** 035 * This class manages SoftReferences, WeakReferences, and 036 * PhantomReferences. When a java/lang/ref/Reference object is created, 037 * its address is added to a table of pending reference objects of the 038 * appropriate type. An address is used so the reference will not stay 039 * alive during GC if it isn't in use elsewhere the mutator. During 040 * GC, the various lists are processed in the proper order to 041 * determine if any Reference objects are ready to be enqueued or 042 * whether referents that have died should be kept alive until the 043 * Reference is explicitly cleared. MMTk drives this processing and 044 * uses this class, via the VM interface, to scan the lists of pending 045 * reference objects. 046 * <p> 047 * As an optimization for generational collectors, each reference type 048 * maintains two queues: a nursery queue and the main queue. 049 */ 050@Uninterruptible 051public final class ReferenceProcessor extends org.mmtk.vm.ReferenceProcessor { 052 053 /******************************************************************** 054 * Class fields 055 */ 056 057 private static final Lock lock = new Lock("ReferenceProcessor"); 058 059 private static final ReferenceProcessor softReferenceProcessor = 060 new ReferenceProcessor(Semantics.SOFT); 061 private static final ReferenceProcessor weakReferenceProcessor = 062 new ReferenceProcessor(Semantics.WEAK); 063 private static final ReferenceProcessor phantomReferenceProcessor = 064 new ReferenceProcessor(Semantics.PHANTOM); 065 066 // Debug flags 067 private static final boolean TRACE = false; 068 private static final boolean TRACE_UNREACHABLE = false; 069 private static final boolean TRACE_DETAIL = false; 070 private static final boolean STRESS = false || VM.ForceFrequentGC; 071 072 /** Initial size of the reference object table */ 073 private static final int INITIAL_SIZE = STRESS ? 1 : 256; 074 075 /** 076 * Grow the reference object table by this multiplier 077 * on overflow 078 */ 079 private static final double GROWTH_FACTOR = 2.0; 080 081 082 /************************************************************************* 083 * Instance fields 084 */ 085 086 /** 087 * The table of reference objects for the current semantics 088 */ 089 private volatile AddressArray references = AddressArray.create(INITIAL_SIZE); 090 091 /** 092 * In a MarkCompact (or similar) collector, we need to update the {@code references} 093 * field, and then update its contents. We implement this by saving the pointer in 094 * this untraced field for use during the {@code forward} pass. 095 */ 096 @Untraced 097 private volatile AddressArray unforwardedReferences = null; 098 099 /** 100 * Index into the <code>references</code> table for the start of 101 * the reference nursery. 102 */ 103 private int nurseryIndex = 0; 104 105 /** 106 * Index of the first free slot in the reference table. 107 */ 108 private volatile int maxIndex = 0; 109 110 /** 111 * Flag to prevent a race between threads growing the reference object 112 * table. 113 */ 114 private volatile boolean growingTable = false; 115 116 /** 117 * Semantics 118 */ 119 private final Semantics semantics; 120 121 /** Copy of semantics.toString() for use in uninterruptible code */ 122 private final String semanticsStr; 123 124 125 /** 126 * Create a reference processor for a given semantics 127 * 128 * @param semantics the semantics this processor should use 129 * (i.e. the types of references that it will process) 130 */ 131 private ReferenceProcessor(Semantics semantics) { 132 this.semantics = semantics; 133 this.semanticsStr = semantics.toString(); 134 } 135 136 /** 137 * Creates an instance of the appropriate reference type processor. 138 * 139 * @param semantics the semantics that the reference processor should 140 * use (i.e. the type of references that it will process) 141 * @return the reference processor 142 */ 143 @Interruptible 144 public static ReferenceProcessor get(Semantics semantics) { 145 switch(semantics) { 146 case WEAK: return weakReferenceProcessor; 147 case SOFT: return softReferenceProcessor; 148 case PHANTOM: return phantomReferenceProcessor; 149 default: 150 if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED,"Unrecognized semantics"); 151 return null; 152 } 153 } 154 155 /** 156 * Add a reference at the end of the table 157 * @param ref The reference to add 158 * @param referent the object pointed to by the reference 159 */ 160 private void addReference(Reference<?> ref, ObjectReference referent) { 161 ObjectReference reference = ObjectReference.fromObject(ref); 162 setReferent(reference, referent); 163 setReference(maxIndex++,reference); 164 } 165 166 /** 167 * Update the reference table 168 * 169 * @param i The table index 170 * @param ref The reference to insert 171 */ 172 private void setReference(int i, ObjectReference ref) { 173 if (TRACE_DETAIL) { 174 VM.sysWrite("slot ",i); 175 VM.sysWriteln(" => ",ref); 176 } 177 references.set(i,ref.toAddress()); 178 } 179 180 /** 181 * Retrieve from the reference table 182 * 183 * @param i Table index 184 * @return The reference object at index i 185 */ 186 private ObjectReference getReference(int i) { 187 return references.get(i).toObjectReference(); 188 } 189 190 /** 191 * Grow the reference table by GROWTH_FACTOR. 192 * 193 * <p>Marked as UninterruptibleNoWarn because it can GC when it allocates, but 194 * the rest of the code can't tolerate GC. 195 * 196 * <p>This method is called without the reference processor lock held, 197 * but with the flag <code>growingTable</code> set. 198 * 199 * @return the start address of the new reference table 200 */ 201 @UninterruptibleNoWarn 202 private AddressArray growReferenceTable() { 203 int newLength = STRESS ? references.length() + 1 : (int)(references.length() * GROWTH_FACTOR); 204 if (TRACE) VM.sysWriteln("Expanding reference type table ",semanticsStr," to ",newLength); 205 AddressArray newReferences = AddressArray.create(newLength); 206 for (int i = 0; i < references.length(); i++) 207 newReferences.set(i,references.get(i)); 208 return newReferences; 209 } 210 211 /** 212 * Add a reference to the list of references. This method is responsible 213 * for installing the address of the referent into the Reference object 214 * so that the referent is traced at all yield points before the Reference 215 * is correctly installed in the reference table. 216 * 217 * (SJF: This method must NOT be inlined into an inlined allocation 218 * sequence, since it contains a lock!) 219 * 220 * @param referent The referent of the reference 221 * @param ref The reference to add 222 */ 223 @NoInline 224 @Unpreemptible("Non-preemptible but yield when table needs to be grown") 225 private void addCandidate(Reference<?> ref, ObjectReference referent) { 226 if (TRACE) { 227 ObjectReference referenceAsAddress = ObjectReference.fromObject(ref); 228 VM.sysWrite("Adding Reference: ", referenceAsAddress); 229 VM.sysWriteln(" ~> ", referent); 230 } 231 232 /* 233 * Ensure that only one thread at a time can grow the 234 * table of references. The volatile flag <code>growingTable</code> is 235 * used to allow growing the table to trigger GC, but to prevent 236 * any other thread from accessing the table while it is being grown. 237 * 238 * If the table has space, threads will add the reference, incrementing maxIndex 239 * and exit. 240 * 241 * If the table is full, the first thread to notice will grow the table. 242 * Subsequent threads will release the lock and yield at (1) while the 243 * first thread 244 */ 245 lock.acquire(); 246 while (growingTable || maxIndex >= references.length()) { 247 if (growingTable) { 248 // FIXME: We should probably speculatively allocate a new table instead. 249 // note, we can copy without the lock after installing the new table (unint during copy). 250 lock.release(); 251 RVMThread.yieldWithHandshake(); // (1) Allow another thread to grow the table 252 lock.acquire(); 253 } else { 254 growingTable = true; // Prevent other threads from growing table while lock is released 255 lock.release(); // Can't hold the lock while allocating 256 AddressArray newTable = growReferenceTable(); 257 lock.acquire(); 258 references = newTable; 259 growingTable = false; // Allow other threads to grow the table rather than waiting for us 260 } 261 } 262 addReference(ref,referent); 263 lock.release(); 264 } 265 266 /*********************************************************************** 267 * GC time processing 268 */ 269 270 /** 271 * {@inheritDoc} 272 * <p> 273 * Collectors like MarkCompact determine liveness and move objects 274 * using separate traces. 275 * <p> 276 * Currently ignores the nursery hint. 277 * <p> 278 * TODO parallelise this code 279 * 280 */ 281 @Override 282 public void forward(TraceLocal trace, boolean nursery) { 283 if (VM.VerifyAssertions) VM._assert(unforwardedReferences != null); 284 if (TRACE) VM.sysWriteln("Starting ReferenceGlue.forward(",semanticsStr,")"); 285 if (TRACE_DETAIL) { 286 VM.sysWrite(semanticsStr," Reference table is ", 287 Magic.objectAsAddress(references)); 288 VM.sysWriteln("unforwardedReferences is ", 289 Magic.objectAsAddress(unforwardedReferences)); 290 } 291 for (int i = 0; i < maxIndex; i++) { 292 if (TRACE_DETAIL) VM.sysWrite("slot ",i,": "); 293 ObjectReference reference = unforwardedReferences.get(i).toObjectReference(); 294 if (TRACE_DETAIL) VM.sysWriteln("forwarding ",reference); 295 setReferent(reference, trace.getForwardedReferent(getReferent(reference))); 296 ObjectReference newReference = trace.getForwardedReference(reference); 297 unforwardedReferences.set(i, newReference.toAddress()); 298 } 299 if (TRACE) VM.sysWriteln("Ending ReferenceGlue.forward(",semanticsStr,")"); 300 unforwardedReferences = null; 301 } 302 303 @Override 304 public void clear() { 305 maxIndex = 0; 306 } 307 308 /** 309 * {@inheritDoc} Calls ReferenceProcessor's 310 * processReference method for each reference and builds a new 311 * list of those references still active. 312 * <p> 313 * Depending on the value of <code>nursery</code>, we will either 314 * scan all references, or just those created since the last scan. 315 * <p> 316 * TODO parallelise this code 317 * 318 * @param nursery Scan only the newly created references 319 */ 320 @Override 321 public void scan(TraceLocal trace, boolean nursery, boolean retain) { 322 unforwardedReferences = references; 323 324 if (TRACE) VM.sysWriteln("Starting ReferenceGlue.scan(",semanticsStr,")"); 325 int toIndex = nursery ? nurseryIndex : 0; 326 327 if (TRACE_DETAIL) VM.sysWriteln(semanticsStr," Reference table is ",Magic.objectAsAddress(references)); 328 if (retain) { 329 for (int fromIndex = toIndex; fromIndex < maxIndex; fromIndex++) { 330 ObjectReference reference = getReference(fromIndex); 331 retainReferent(trace, reference); 332 } 333 } else { 334 for (int fromIndex = toIndex; fromIndex < maxIndex; fromIndex++) { 335 ObjectReference reference = getReference(fromIndex); 336 337 /* Determine liveness (and forward if necessary) the reference */ 338 ObjectReference newReference = processReference(trace,reference); 339 if (!newReference.isNull()) { 340 setReference(toIndex++,newReference); 341 if (TRACE_DETAIL) { 342 int index = toIndex - 1; 343 VM.sysWrite("SCANNED ",index); 344 VM.sysWrite(" ",references.get(index)); 345 VM.sysWrite(" -> "); 346 VM.sysWriteln(getReferent(references.get(index).toObjectReference())); 347 } 348 } 349 } 350 if (Options.verbose.getValue() >= 3) { 351 VM.sysWrite(semanticsStr); 352 VM.sysWriteln(" references: ",maxIndex," -> ",toIndex); 353 } 354 nurseryIndex = maxIndex = toIndex; 355 } 356 357 /* flush out any remset entries generated during the above activities */ 358 Selected.Mutator.get().flushRememberedSets(); 359 if (TRACE) VM.sysWriteln("Ending ReferenceGlue.scan(",semanticsStr,")"); 360 } 361 362 /** 363 * This method deals only with soft references. It retains the referent 364 * if the reference is definitely reachable. 365 * @param reference the address of the reference. This may or may not 366 * be the address of a heap object, depending on the VM. 367 * @param trace the thread local trace element. 368 */ 369 protected void retainReferent(TraceLocal trace, ObjectReference reference) { 370 if (VM.VerifyAssertions) VM._assert(!reference.isNull()); 371 if (VM.VerifyAssertions) VM._assert(semantics == Semantics.SOFT); 372 373 if (TRACE_DETAIL) { 374 VM.sysWrite("Processing reference: ",reference); 375 } 376 377 if (!trace.isLive(reference)) { 378 /* 379 * Reference is currently unreachable but may get reachable by the 380 * following trace. We postpone the decision. 381 */ 382 return; 383 } 384 385 /* 386 * Reference is definitely reachable. Retain the referent. 387 */ 388 ObjectReference referent = getReferent(reference); 389 if (!referent.isNull()) 390 trace.retainReferent(referent); 391 if (TRACE_DETAIL) { 392 VM.sysWriteln(" ~> ", referent.toAddress(), " (retained)"); 393 } 394 } 395 396 /** 397 * Put this Reference object on its ReferenceQueue (if it has one) 398 * when its referent is no longer sufficiently reachable. The 399 * definition of "reachable" is defined by the semantics of the 400 * particular subclass of Reference. 401 * <p> 402 * The implementation of this routine is determined by the the 403 * implementation of java.lang.ref.ReferenceQueue in the class library. 404 * It is in this class rather than the public Reference class to 405 * ensure that Jikes has a safe way of enqueueing the object, 406 * one that cannot be overridden by the application program. 407 * 408 * @see java.lang.ref.ReferenceQueue 409 * @param addr the address of the Reference object 410 * @return <code>true</code> if the reference was enqueued 411 */ 412 public boolean enqueueReference(ObjectReference addr) { 413 Reference<?> reference = (Reference<?>)addr.toObject(); 414 return reference.enqueueInternal(); 415 } 416 417 /** 418 * Add a reference to the list of soft references. 419 * @param ref the SoftReference to add 420 * @param referent the object that the reference points to 421 */ 422 @Interruptible 423 public static void addSoftCandidate(SoftReference<?> ref, ObjectReference referent) { 424 softReferenceProcessor.addCandidate(ref, referent); 425 } 426 427 /** 428 * Add a reference to the list of weak references. 429 * @param ref the WeakReference to add 430 * @param referent the object that the reference points to 431 */ 432 @Interruptible 433 public static void addWeakCandidate(WeakReference<?> ref, ObjectReference referent) { 434 weakReferenceProcessor.addCandidate(ref, referent); 435 } 436 437 /** 438 * Add a reference to the list of phantom references. 439 * @param ref the PhantomReference to add 440 * @param referent the object that the reference points to 441 */ 442 @Interruptible 443 public static void addPhantomCandidate(PhantomReference<?> ref, ObjectReference referent) { 444 phantomReferenceProcessor.addCandidate(ref, referent); 445 } 446 447 /**************************************************************************** 448 * 449 * Semantics of reference types 450 * 451 */ 452 453 /** 454 * Processes a reference with the current semantics. 455 * <p> 456 * This method deals with a soft reference as if it were a weak reference, i.e. 457 * it does not retain the referent. To retain the referent, use 458 * {@link #retainReferent(TraceLocal, ObjectReference)} followed by a transitive 459 * closure phase. 460 * 461 * @param reference the address of the reference. This may or may not 462 * be the address of a heap object, depending on the VM. 463 * @param trace the thread local trace element. 464 * @return an updated reference (e.g. with a new address) if the reference 465 * is still live, {@code ObjectReference.nullReference()} otherwise 466 */ 467 public ObjectReference processReference(TraceLocal trace, ObjectReference reference) { 468 if (VM.VerifyAssertions) VM._assert(!reference.isNull()); 469 470 if (TRACE_DETAIL) { 471 VM.sysWrite("Processing reference: ",reference); 472 } 473 /* 474 * If the reference is dead, we're done with it. Let it (and 475 * possibly its referent) be garbage-collected. 476 */ 477 if (!trace.isLive(reference)) { 478 clearReferent(reference); // Too much paranoia ... 479 if (TRACE_UNREACHABLE) { 480 VM.sysWriteln(" UNREACHABLE reference: ",reference); 481 } 482 if (TRACE_DETAIL) { 483 VM.sysWriteln(" (unreachable)"); 484 } 485 return ObjectReference.nullReference(); 486 } 487 488 /* The reference object is live */ 489 ObjectReference newReference = trace.getForwardedReference(reference); 490 ObjectReference oldReferent = getReferent(reference); 491 492 if (TRACE_DETAIL) { 493 VM.sysWrite(" ~> ",oldReferent); 494 } 495 496 /* 497 * If the application has cleared the referent the Java spec says 498 * this does not cause the Reference object to be enqueued. We 499 * simply allow the Reference object to fall out of our 500 * waiting list. 501 */ 502 if (oldReferent.isNull()) { 503 if (TRACE_DETAIL) VM.sysWriteln(" (null referent)"); 504 return ObjectReference.nullReference(); 505 } 506 507 if (TRACE_DETAIL) VM.sysWrite(" => ",newReference); 508 509 if (trace.isLive(oldReferent)) { 510 if (VM.VerifyAssertions) { 511 if (!DebugUtil.validRef(oldReferent)) { 512 VM.sysWriteln("Error in old referent."); 513 DebugUtil.dumpRef(oldReferent); 514 VM.sysFail("Invalid reference"); 515 } 516 } 517 /* 518 * Referent is still reachable in a way that is as strong as 519 * or stronger than the current reference level. 520 */ 521 ObjectReference newReferent = trace.getForwardedReferent(oldReferent); 522 523 if (TRACE_DETAIL) VM.sysWriteln(" ~> ",newReferent); 524 525 if (VM.VerifyAssertions) { 526 if (!DebugUtil.validRef(newReferent)) { 527 VM.sysWriteln("Error forwarding reference object."); 528 DebugUtil.dumpRef(oldReferent); 529 VM.sysFail("Invalid reference"); 530 } 531 VM._assert(trace.isLive(newReferent)); 532 } 533 534 /* 535 * The reference object stays on the waiting list, and the 536 * referent is untouched. The only thing we must do is 537 * ensure that the former addresses are updated with the 538 * new forwarding addresses in case the collector is a 539 * copying collector. 540 */ 541 542 /* Update the referent */ 543 setReferent(newReference, newReferent); 544 return newReference; 545 } else { 546 /* Referent is unreachable. Clear the referent and enqueue the reference object. */ 547 548 if (TRACE_DETAIL) VM.sysWriteln(" UNREACHABLE"); 549 else if (TRACE_UNREACHABLE) VM.sysWriteln(" UNREACHABLE referent: ",oldReferent); 550 551 clearReferent(newReference); 552 enqueueReference(newReference); 553 return ObjectReference.nullReference(); 554 } 555 } 556 557 /** 558 * Weak and soft references always clear the referent 559 * before enqueueing. We don't actually call 560 * {@code Reference.clear()} as the user could have overridden the 561 * implementation and we don't want any side-effects to 562 * occur. 563 * 564 * @param newReference the reference whose referent is to 565 * be cleared 566 */ 567 protected void clearReferent(ObjectReference newReference) { 568 setReferent(newReference, ObjectReference.nullReference()); 569 } 570 571 /*********************************************************************** 572 * 573 * Reference object field accessors 574 */ 575 576 /** 577 * Get the referent from a reference. For Java the reference 578 * is a Reference object. 579 * @param object the object reference. 580 * @return the referent object reference. 581 */ 582 protected ObjectReference getReferent(ObjectReference object) { 583 if (VM.VerifyAssertions) VM._assert(!object.isNull()); 584 return object.toAddress().loadObjectReference(Entrypoints.referenceReferentField.getOffset()); 585 } 586 587 /** 588 * Set the referent in a reference. For Java the reference is 589 * a Reference object. 590 * @param ref the ObjectReference for the reference (confusing eh?). 591 * @param referent the referent object reference. 592 */ 593 protected void setReferent(ObjectReference ref, ObjectReference referent) { 594 ref.toAddress().store(referent, Entrypoints.referenceReferentField.getOffset()); 595 } 596 597 /*********************************************************************** 598 * 599 * Statistics and debugging 600 */ 601 602 @Override 603 public int countWaitingReferences() { 604 return maxIndex; 605 } 606}