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}