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.refcount;
014
015import org.mmtk.plan.Phase;
016import org.mmtk.plan.StopTheWorld;
017import org.mmtk.plan.Trace;
018import org.mmtk.plan.refcount.backuptrace.BTFreeLargeObjectSweeper;
019import org.mmtk.plan.refcount.backuptrace.BTSweeper;
020import org.mmtk.policy.ExplicitFreeListSpace;
021import org.mmtk.policy.ExplicitLargeObjectSpace;
022import org.mmtk.policy.Space;
023import org.mmtk.utility.Log;
024import org.mmtk.utility.alloc.LinearScan;
025import org.mmtk.utility.deque.SharedDeque;
026import org.mmtk.utility.heap.VMRequest;
027import org.mmtk.utility.options.Options;
028import org.mmtk.utility.sanitychecker.SanityChecker;
029import org.mmtk.vm.VM;
030import org.vmmagic.pragma.*;
031import org.vmmagic.unboxed.Address;
032import org.vmmagic.unboxed.ObjectReference;
033
034/**
035 * This class implements the global state of a reference counting collector.
036 * See Shahriyar et al for details of and rationale for the optimizations used
037 * here (http://dx.doi.org/10.1145/2258996.2259008).  See Chapter 4 of
038 * Daniel Frampton's PhD thesis for details of and rationale for the cycle
039 * collection strategy used by this collector.
040 */
041@Uninterruptible
042public class RCBase extends StopTheWorld {
043  public static final short PROCESS_OLDROOTBUFFER  = Phase.createSimple("old-root");
044  public static final short PROCESS_NEWROOTBUFFER  = Phase.createSimple("new-root");
045  public static final short PROCESS_MODBUFFER      = Phase.createSimple("mods");
046  public static final short PROCESS_DECBUFFER      = Phase.createSimple("decs");
047
048  /** Is cycle collection enabled? */
049  public static final boolean CC_ENABLED           = true;
050  /** Force full cycle collection at each GC? */
051  public static boolean ccForceFull        = false;
052  /** Use backup tracing for cycle collection (currently the only option) */
053  public static final boolean CC_BACKUP_TRACE      = true;
054
055  public static boolean performCycleCollection;
056  public static final short BT_CLOSURE             = Phase.createSimple("closure-bt");
057
058  /** True if we are building for generational RC */
059  public static final boolean BUILD_FOR_GENRC = ((RCBaseConstraints) VM.activePlan.constraints()).buildForGenRC();
060
061  // CHECKSTYLE:OFF
062
063  /**
064   * Reference counting specific collection steps.
065   */
066  protected static final short refCountCollectionPhase = Phase.createComplex("release", null,
067      Phase.scheduleGlobal     (PROCESS_OLDROOTBUFFER),
068      Phase.scheduleCollector  (PROCESS_OLDROOTBUFFER),
069      Phase.scheduleGlobal     (PROCESS_NEWROOTBUFFER),
070      Phase.scheduleCollector  (PROCESS_NEWROOTBUFFER),
071      Phase.scheduleMutator    (PROCESS_MODBUFFER),
072      Phase.scheduleGlobal     (PROCESS_MODBUFFER),
073      Phase.scheduleCollector  (PROCESS_MODBUFFER),
074      Phase.scheduleMutator    (PROCESS_DECBUFFER),
075      Phase.scheduleGlobal     (PROCESS_DECBUFFER),
076      Phase.scheduleCollector  (PROCESS_DECBUFFER),
077      Phase.scheduleGlobal     (BT_CLOSURE),
078      Phase.scheduleCollector  (BT_CLOSURE));
079
080  protected static final short genRCCollectionPhase = Phase.createComplex("release", null,
081      Phase.scheduleGlobal     (PROCESS_OLDROOTBUFFER),
082      Phase.scheduleCollector  (PROCESS_OLDROOTBUFFER),
083      Phase.scheduleGlobal     (PROCESS_NEWROOTBUFFER),
084      Phase.scheduleCollector  (PROCESS_NEWROOTBUFFER),
085      Phase.scheduleMutator    (PROCESS_DECBUFFER),
086      Phase.scheduleGlobal     (PROCESS_DECBUFFER),
087      Phase.scheduleCollector  (PROCESS_DECBUFFER),
088      Phase.scheduleGlobal     (BT_CLOSURE),
089      Phase.scheduleCollector  (BT_CLOSURE));
090
091  /**
092   * Perform the initial determination of liveness from the roots.
093   */
094  protected static final short refCountRootClosurePhase = Phase.createComplex("initial-closure", null,
095      Phase.scheduleMutator    (PREPARE),
096      Phase.scheduleGlobal     (PREPARE),
097      Phase.scheduleCollector  (PREPARE),
098      Phase.scheduleComplex    (prepareStacks),
099      Phase.scheduleCollector  (STACK_ROOTS),
100      Phase.scheduleCollector  (ROOTS),
101      Phase.scheduleGlobal     (ROOTS),
102      Phase.scheduleGlobal     (CLOSURE),
103      Phase.scheduleCollector  (CLOSURE));
104
105  protected static final short genRCRootClosurePhase = Phase.createComplex("initial-closure", null,
106      Phase.scheduleMutator    (PREPARE),
107      Phase.scheduleGlobal     (PREPARE),
108      Phase.scheduleCollector  (PREPARE),
109      Phase.scheduleComplex    (prepareStacks),
110      Phase.scheduleCollector  (STACK_ROOTS),
111      Phase.scheduleCollector  (ROOTS),
112      Phase.scheduleGlobal     (ROOTS),
113      Phase.scheduleMutator    (PROCESS_MODBUFFER),
114      Phase.scheduleGlobal     (PROCESS_MODBUFFER),
115      Phase.scheduleCollector  (PROCESS_MODBUFFER),
116      Phase.scheduleGlobal     (CLOSURE),
117      Phase.scheduleCollector  (CLOSURE));
118
119  /**
120   * This is the phase that is executed to perform a collection.
121   */
122  public short refCountCollection = Phase.createComplex("collection", null,
123      Phase.scheduleComplex(initPhase),
124      Phase.scheduleComplex(refCountRootClosurePhase),
125      Phase.scheduleComplex(refCountCollectionPhase),
126      Phase.scheduleComplex(completeClosurePhase),
127      Phase.scheduleComplex(finishPhase));
128
129  public short genRCCollection = Phase.createComplex("collection", null,
130      Phase.scheduleComplex(initPhase),
131      Phase.scheduleComplex(genRCRootClosurePhase),
132      Phase.scheduleComplex(genRCCollectionPhase),
133      Phase.scheduleComplex(completeClosurePhase),
134      Phase.scheduleComplex(finishPhase));
135
136  // CHECKSTYLE:ON
137
138  /*****************************************************************************
139   *
140   * Class fields
141   */
142
143  /**
144   *
145   */
146  public static final ExplicitFreeListSpace rcSpace = new ExplicitFreeListSpace("rc", VMRequest.discontiguous());
147  public static final ExplicitLargeObjectSpace rcloSpace = new ExplicitLargeObjectSpace("rclos", VMRequest.discontiguous());
148
149  public static final int REF_COUNT = rcSpace.getDescriptor();
150  public static final int REF_COUNT_LOS = rcloSpace.getDescriptor();
151
152  public final SharedDeque modPool = new SharedDeque("mod", metaDataSpace, 1);
153  public final SharedDeque decPool = new SharedDeque("dec", metaDataSpace, 1);
154  public final SharedDeque newRootPool = new SharedDeque("newRoot", metaDataSpace, 1);
155  public final SharedDeque oldRootPool = new SharedDeque("oldRoot", metaDataSpace, 1);
156
157  /*****************************************************************************
158   *
159   * Instance fields
160   */
161
162  /**
163   *
164   */
165  public final Trace rootTrace;
166  public final Trace backupTrace;
167  private final BTSweeper rcSweeper;
168  private final BTFreeLargeObjectSweeper loFreeSweeper;
169
170  /**
171   * Constructor
172   */
173  public RCBase() {
174    Options.noReferenceTypes.setDefaultValue(true);
175    Options.noFinalizer.setDefaultValue(true);
176    rootTrace = new Trace(metaDataSpace);
177    backupTrace = new Trace(metaDataSpace);
178    rcSweeper = new BTSweeper();
179    loFreeSweeper = new BTFreeLargeObjectSweeper();
180  }
181
182  @Override
183  @Interruptible
184  public void processOptions() {
185    super.processOptions();
186    if (!Options.noReferenceTypes.getValue()) {
187      VM.assertions.fail("Reference Types are not supported by RC");
188    }
189    if (!Options.noFinalizer.getValue()) {
190      VM.assertions.fail("Finalizers are not supported by RC");
191    }
192  }
193
194  /*****************************************************************************
195   *
196   * Collection
197   */
198
199  /**
200   * @param object an object reference
201   * @return whether the object is subject to collection by reference counting
202   */
203  public static final boolean isRCObject(ObjectReference object) {
204    return !object.isNull() && (Space.isInSpace(REF_COUNT, object) || Space.isInSpace(REF_COUNT_LOS, object));
205  }
206
207  @Override
208  public boolean lastCollectionFullHeap() {
209    return performCycleCollection;
210  }
211
212  @Override
213  public void collectionPhase(short phaseId) {
214    if (phaseId == SET_COLLECTION_KIND) {
215      super.collectionPhase(phaseId);
216      if (CC_ENABLED) {
217        ccForceFull = Options.fullHeapSystemGC.getValue();
218        if (BUILD_FOR_GENRC) performCycleCollection = (collectionAttempt > 1) || emergencyCollection || ccForceFull;
219        else performCycleCollection |= (collectionAttempt > 1) || emergencyCollection || ccForceFull;
220        if (performCycleCollection && Options.verbose.getValue() > 0) Log.write(" [CC] ");
221      }
222      return;
223    }
224
225    if (phaseId == PREPARE) {
226      VM.finalizableProcessor.clear();
227      VM.weakReferences.clear();
228      VM.softReferences.clear();
229      VM.phantomReferences.clear();
230      rootTrace.prepare();
231      rcSpace.prepare();
232      if (CC_BACKUP_TRACE && performCycleCollection) {
233        backupTrace.prepare();
234      }
235      return;
236    }
237
238    if (phaseId == CLOSURE) {
239      rootTrace.prepare();
240      modPool.prepare();
241      return;
242    }
243
244    if (phaseId == BT_CLOSURE) {
245      if (CC_BACKUP_TRACE && performCycleCollection) {
246        backupTrace.prepare();
247      }
248      return;
249    }
250
251    if (phaseId == PROCESS_OLDROOTBUFFER) {
252      oldRootPool.prepare();
253      return;
254    }
255
256    if (phaseId == PROCESS_NEWROOTBUFFER) {
257      newRootPool.prepare();
258      return;
259    }
260
261
262    if (phaseId == PROCESS_MODBUFFER) {
263      modPool.prepare();
264      return;
265    }
266
267    if (phaseId == PROCESS_DECBUFFER) {
268      decPool.prepare();
269      return;
270    }
271
272    if (phaseId == RELEASE) {
273      rootTrace.release();
274      if (CC_BACKUP_TRACE && performCycleCollection) {
275        backupTrace.release();
276        rcSpace.sweepCells(rcSweeper);
277        rcloSpace.sweep(loFreeSweeper);
278      } else {
279        rcSpace.release();
280      }
281      if (!BUILD_FOR_GENRC) performCycleCollection = getPagesAvail() < Options.cycleTriggerThreshold.getPages();
282      return;
283    }
284
285    super.collectionPhase(phaseId);
286  }
287
288  /*****************************************************************************
289   *
290   * Accounting
291   */
292
293  /**
294   * {@inheritDoc}
295   */
296  @Override
297  public int getPagesUsed() {
298    return (rcSpace.reservedPages() + rcloSpace.reservedPages() + super.getPagesUsed());
299  }
300
301  /**
302   * Perform a linear scan across all objects in the heap to check for leaks.
303   */
304  @Override
305  public void sanityLinearScan(LinearScan scan) {
306    //rcSpace.linearScan(scan);
307  }
308
309  @Override
310  public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
311    if (RCBase.isRCObject(object)) {
312      int fullRC = RCHeader.getRC(object);
313      if (fullRC == 0) {
314        return SanityChecker.DEAD;
315      }
316      if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(fullRC >= sanityRootRC);
317      return fullRC - sanityRootRC;
318    }
319    return SanityChecker.ALIVE;
320  }
321
322  @Override
323  @Interruptible
324  protected void registerSpecializedMethods() {
325    super.registerSpecializedMethods();
326  }
327
328  @Override
329  public byte setBuildTimeGCByte(Address object, ObjectReference typeRef, int size) {
330    return (byte) RCHeader.UNLOGGED.toInt();
331  }
332}