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}