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     */
013    package org.mmtk.plan.refcount;
014    
015    import org.mmtk.plan.Phase;
016    import org.mmtk.plan.StopTheWorld;
017    import org.mmtk.plan.Trace;
018    import org.mmtk.plan.refcount.backuptrace.BTFreeLargeObjectSweeper;
019    import org.mmtk.plan.refcount.backuptrace.BTScanLargeObjectSweeper;
020    import org.mmtk.plan.refcount.backuptrace.BTSweeper;
021    import org.mmtk.policy.ExplicitFreeListSpace;
022    import org.mmtk.policy.ExplicitLargeObjectSpace;
023    import org.mmtk.policy.Space;
024    import org.mmtk.utility.Log;
025    import org.mmtk.utility.alloc.LinearScan;
026    import org.mmtk.utility.deque.SharedDeque;
027    import org.mmtk.utility.heap.VMRequest;
028    import org.mmtk.utility.options.Options;
029    import org.mmtk.utility.sanitychecker.SanityChecker;
030    import org.mmtk.vm.VM;
031    
032    import org.vmmagic.pragma.*;
033    import org.vmmagic.unboxed.ObjectReference;
034    
035    /**
036     * This class implements the global state of a a simple reference counting collector.
037     */
038    @Uninterruptible
039    public class RCBase extends StopTheWorld {
040      public static final short PROCESS_OLDROOTBUFFER  = Phase.createSimple("old-root");
041      public static final short PROCESS_NEWROOTBUFFER  = Phase.createSimple("new-root");
042      public static final short PROCESS_MODBUFFER      = Phase.createSimple("mods");
043      public static final short PROCESS_DECBUFFER      = Phase.createSimple("decs");
044    
045      /** Is cycle collection enabled? */
046      public static final boolean CC_ENABLED           = true;
047      /** Force full cycle collection at each GC? */
048      public static final boolean CC_FORCE_FULL        = false;
049      /** Use backup tracing for cycle collection (currently the only option) */
050      public static final boolean CC_BACKUP_TRACE      = true;
051    
052      public static boolean performCycleCollection;
053      public static final short BT_CLOSURE             = Phase.createSimple("closure-bt");
054    
055      // CHECKSTYLE:OFF
056    
057      /**
058       * Reference counting specific collection steps.
059       */
060      protected static final short refCountCollectionPhase = Phase.createComplex("release", null,
061          Phase.scheduleGlobal     (PROCESS_OLDROOTBUFFER),
062          Phase.scheduleCollector  (PROCESS_OLDROOTBUFFER),
063          Phase.scheduleGlobal     (PROCESS_NEWROOTBUFFER),
064          Phase.scheduleCollector  (PROCESS_NEWROOTBUFFER),
065          Phase.scheduleMutator    (PROCESS_DECBUFFER),
066          Phase.scheduleGlobal     (PROCESS_DECBUFFER),
067          Phase.scheduleCollector  (PROCESS_DECBUFFER),
068          Phase.scheduleGlobal     (BT_CLOSURE),
069          Phase.scheduleCollector  (BT_CLOSURE));
070    
071      /**
072       * Perform the initial determination of liveness from the roots.
073       */
074      protected static final short rootClosurePhase = Phase.createComplex("initial-closure", null,
075          Phase.scheduleMutator    (PREPARE),
076          Phase.scheduleGlobal     (PREPARE),
077          Phase.scheduleCollector  (PREPARE),
078          Phase.scheduleComplex    (prepareStacks),
079          Phase.scheduleCollector  (PRECOPY),
080          Phase.scheduleCollector  (STACK_ROOTS),
081          Phase.scheduleCollector  (ROOTS),
082          Phase.scheduleGlobal     (ROOTS),
083          Phase.scheduleMutator    (PROCESS_MODBUFFER),
084          Phase.scheduleGlobal     (PROCESS_MODBUFFER),
085          Phase.scheduleCollector  (PROCESS_MODBUFFER),
086          Phase.scheduleGlobal     (CLOSURE),
087          Phase.scheduleCollector  (CLOSURE));
088    
089      /**
090       * This is the phase that is executed to perform a collection.
091       */
092      public short collection = Phase.createComplex("collection", null,
093          Phase.scheduleComplex(initPhase),
094          Phase.scheduleComplex(rootClosurePhase),
095          Phase.scheduleComplex(refCountCollectionPhase),
096          Phase.scheduleComplex(completeClosurePhase),
097          Phase.scheduleComplex(finishPhase));
098    
099      // CHECKSTYLE:ON
100    
101      /*****************************************************************************
102       *
103       * Class fields
104       */
105      public static final ExplicitFreeListSpace rcSpace = new ExplicitFreeListSpace("rc", DEFAULT_POLL_FREQUENCY, VMRequest.create());
106      public static final ExplicitLargeObjectSpace rcloSpace = new ExplicitLargeObjectSpace("rclos", DEFAULT_POLL_FREQUENCY, VMRequest.create());
107    
108      public static final int REF_COUNT = rcSpace.getDescriptor();
109      public static final int REF_COUNT_LOS = rcloSpace.getDescriptor();
110    
111      public final SharedDeque modPool = new SharedDeque("mod", metaDataSpace, 1);
112      public final SharedDeque decPool = new SharedDeque("dec", metaDataSpace, 1);
113      public final SharedDeque newRootPool = new SharedDeque("newRoot", metaDataSpace, 1);
114      public final SharedDeque oldRootPool = new SharedDeque("oldRoot", metaDataSpace, 1);
115    
116      /*****************************************************************************
117       *
118       * Instance fields
119       */
120      public final Trace rootTrace;
121      public final Trace backupTrace;
122      private final BTSweeper rcSweeper;
123      private final BTScanLargeObjectSweeper loScanSweeper;
124      private final BTFreeLargeObjectSweeper loFreeSweeper;
125    
126      /**
127       * Constructor
128       */
129      public RCBase() {
130        Options.noReferenceTypes.setDefaultValue(true);
131        Options.noFinalizer.setDefaultValue(true);
132    
133        rootTrace = new Trace(metaDataSpace);
134        backupTrace = new Trace(metaDataSpace);
135        rcSweeper = new BTSweeper();
136        loScanSweeper = new BTScanLargeObjectSweeper();
137        loFreeSweeper = new BTFreeLargeObjectSweeper();
138      }
139    
140      /**
141       * The boot method is called early in the boot process before any
142       * allocation.
143       */
144      @Interruptible
145      public void postBoot() {
146        super.postBoot();
147    
148        if (!Options.noReferenceTypes.getValue()) {
149          VM.assertions.fail("Reference Types are not supported by RC");
150        }
151        if (!Options.noFinalizer.getValue()) {
152          VM.assertions.fail("Finalizers are not supported by RC");
153        }
154      }
155    
156      /*****************************************************************************
157       *
158       * Collection
159       */
160    
161      public static final boolean isRCObject(ObjectReference object) {
162        return !object.isNull() && !Space.isInSpace(VM_SPACE, object);
163      }
164    
165      /**
166       * @return Whether last GC is a full GC.
167       */
168      public boolean lastCollectionFullHeap() {
169        return performCycleCollection;
170      }
171    
172      /**
173       * Perform a (global) collection phase.
174       *
175       * @param phaseId Collection phase
176       */
177      public void collectionPhase(short phaseId) {
178        if (phaseId == SET_COLLECTION_KIND) {
179          super.collectionPhase(phaseId);
180          if (CC_ENABLED) {
181            performCycleCollection = (collectionAttempt > 1) || emergencyCollection || CC_FORCE_FULL;
182            if (performCycleCollection && Options.verbose.getValue() > 0) Log.write(" [CC] ");
183          }
184          return;
185        }
186    
187        if (phaseId == PREPARE) {
188          VM.finalizableProcessor.clear();
189          VM.weakReferences.clear();
190          VM.softReferences.clear();
191          VM.phantomReferences.clear();
192          rootTrace.prepare();
193          rcSpace.prepare();
194          if (CC_BACKUP_TRACE && performCycleCollection) {
195            backupTrace.prepare();
196          }
197          return;
198        }
199    
200        if (phaseId == CLOSURE) {
201          rootTrace.prepare();
202          return;
203        }
204    
205        if (phaseId == BT_CLOSURE) {
206          if (CC_BACKUP_TRACE && performCycleCollection) {
207            backupTrace.prepare();
208          }
209          return;
210        }
211    
212        if (phaseId == PROCESS_OLDROOTBUFFER) {
213          oldRootPool.prepare();
214          return;
215        }
216    
217        if (phaseId == PROCESS_NEWROOTBUFFER) {
218          newRootPool.prepare();
219          return;
220        }
221    
222    
223        if (phaseId == PROCESS_MODBUFFER) {
224          modPool.prepare();
225          return;
226        }
227    
228        if (phaseId == PROCESS_DECBUFFER) {
229          decPool.prepare();
230          return;
231        }
232    
233        if (phaseId == RELEASE) {
234          rootTrace.release();
235          if (CC_BACKUP_TRACE && performCycleCollection) {
236            backupTrace.release();
237            rcSpace.sweepCells(rcSweeper);
238            rcloSpace.sweep(loScanSweeper);
239            rcloSpace.sweep(loFreeSweeper);
240          } else {
241            rcSpace.release();
242          }
243          return;
244        }
245    
246        super.collectionPhase(phaseId);
247      }
248    
249      /*****************************************************************************
250       *
251       * Accounting
252       */
253    
254      /**
255       * Return the number of pages used given the pending
256       * allocation.
257       *
258       * @return The number of pages reserved given the pending
259       * allocation, excluding space reserved for copying.
260       */
261      public int getPagesUsed() {
262        return (rcSpace.reservedPages() + rcloSpace.reservedPages() + super.getPagesUsed());
263      }
264    
265      /**
266       * Perform a linear scan across all objects in the heap to check for leaks.
267       */
268      public void sanityLinearScan(LinearScan scan) {
269        //rcSpace.linearScan(scan);
270      }
271    
272      /**
273       * Return the expected reference count. For non-reference counting
274       * collectors this becomes a true/false relationship.
275       *
276       * @param object The object to check.
277       * @param sanityRootRC The number of root references to the object.
278       * @return The expected (root excluded) reference count.
279       */
280      public int sanityExpectedRC(ObjectReference object, int sanityRootRC) {
281        if (RCBase.isRCObject(object)) {
282          int fullRC = RCHeader.getRC(object);
283          if (fullRC == 0) {
284            return SanityChecker.DEAD;
285          }
286          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(fullRC >= sanityRootRC);
287          return fullRC - sanityRootRC;
288        }
289        return SanityChecker.ALIVE;
290      }
291    
292      /**
293       * Register specialized methods.
294       */
295      @Interruptible
296      protected void registerSpecializedMethods() {
297        super.registerSpecializedMethods();
298      }
299    }