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.StopTheWorldCollector;
017    import org.mmtk.plan.TraceLocal;
018    import org.mmtk.plan.TransitiveClosure;
019    import org.mmtk.plan.refcount.backuptrace.BTTraceLocal;
020    import org.mmtk.policy.Space;
021    import org.mmtk.policy.ExplicitFreeListSpace;
022    import org.mmtk.utility.deque.ObjectReferenceDeque;
023    import org.mmtk.vm.VM;
024    import org.vmmagic.pragma.Inline;
025    import org.vmmagic.pragma.Uninterruptible;
026    import org.vmmagic.unboxed.ObjectReference;
027    
028    /**
029     * This class implements the collector context for a reference counting collector.
030     * See Shahriyar et al for details of and rationale for the optimizations used
031     * here (http://dx.doi.org/10.1145/2258996.2259008).  See Chapter 4 of
032     * Daniel Frampton's PhD thesis for details of and rationale for the cycle
033     * collection strategy used by this collector.
034     */
035    @Uninterruptible
036    public abstract class RCBaseCollector extends StopTheWorldCollector {
037    
038      /************************************************************************
039       * Initialization
040       */
041    
042      /**
043       *
044       */
045      protected final ObjectReferenceDeque newRootBuffer;
046      private final BTTraceLocal backupTrace;
047      private final ObjectReferenceDeque modBuffer;
048      private final ObjectReferenceDeque oldRootBuffer;
049      private final RCDecBuffer decBuffer;
050      private final RCZero zero;
051    
052      /**
053       * Constructor.
054       */
055      public RCBaseCollector() {
056        newRootBuffer = new ObjectReferenceDeque("new-root", global().newRootPool);
057        oldRootBuffer = new ObjectReferenceDeque("old-root", global().oldRootPool);
058        modBuffer = new ObjectReferenceDeque("mod buf", global().modPool);
059        decBuffer = new RCDecBuffer(global().decPool);
060        backupTrace = new BTTraceLocal(global().backupTrace);
061        zero = new RCZero();
062      }
063    
064      /**
065       * Get the modified processor to use.
066       */
067      protected abstract TransitiveClosure getModifiedProcessor();
068    
069      /**
070       * Get the root trace to use.
071       */
072      protected abstract TraceLocal getRootTrace();
073    
074      /****************************************************************************
075       *
076       * Collection
077       */
078    
079      /**
080       * {@inheritDoc}
081       */
082      @Override
083      public void collect() {
084        if (RCBase.BUILD_FOR_GENRC) Phase.beginNewPhaseStack(Phase.scheduleComplex(global().genRCCollection));
085        else Phase.beginNewPhaseStack(Phase.scheduleComplex(global().refCountCollection));
086      }
087    
088      @Override
089      public void collectionPhase(short phaseId, boolean primary) {
090        if (phaseId == RCBase.PREPARE) {
091          getRootTrace().prepare();
092          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) backupTrace.prepare();
093          return;
094        }
095    
096        if (phaseId == RCBase.CLOSURE) {
097          getRootTrace().completeTrace();
098          newRootBuffer.flushLocal();
099          return;
100        }
101    
102        if (phaseId == RCBase.BT_CLOSURE) {
103          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
104            backupTrace.completeTrace();
105          }
106          return;
107        }
108    
109        if (phaseId == RCBase.PROCESS_OLDROOTBUFFER) {
110          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) return;
111          ObjectReference current;
112          while(!(current = oldRootBuffer.pop()).isNull()) {
113            decBuffer.push(current);
114          }
115          return;
116        }
117    
118        if (phaseId == RCBase.PROCESS_NEWROOTBUFFER) {
119          ObjectReference current;
120          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
121            while(!(current = newRootBuffer.pop()).isNull()) {
122              if (RCHeader.testAndMark(current)) {
123                if (RCBase.BUILD_FOR_GENRC) {
124                  RCHeader.initRC(current);
125                } else {
126                  if (RCHeader.initRC(current) == RCHeader.INC_NEW) {
127                    modBuffer.push(current);
128                  }
129                }
130                backupTrace.processNode(current);
131              } else {
132                if (RCBase.BUILD_FOR_GENRC) {
133                  RCHeader.incRC(current);
134                } else {
135                  if (RCHeader.incRC(current) == RCHeader.INC_NEW) {
136                    modBuffer.push(current);
137                  }
138                }
139              }
140            }
141            if (!RCBase.BUILD_FOR_GENRC) modBuffer.flushLocal();
142            return;
143          }
144          while(!(current = newRootBuffer.pop()).isNull()) {
145            if (RCBase.BUILD_FOR_GENRC) {
146              RCHeader.incRC(current);
147            } else {
148              if (RCHeader.incRC(current) == RCHeader.INC_NEW) {
149                modBuffer.push(current);
150              }
151            }
152            oldRootBuffer.push(current);
153          }
154          oldRootBuffer.flushLocal();
155          if (!RCBase.BUILD_FOR_GENRC) modBuffer.flushLocal();
156          return;
157        }
158    
159        if (phaseId == RCBase.PROCESS_MODBUFFER) {
160          ObjectReference current;
161          while(!(current = modBuffer.pop()).isNull()) {
162            RCHeader.makeUnlogged(current);
163            if (!RCBase.BUILD_FOR_GENRC) {
164              if (Space.isInSpace(RCBase.REF_COUNT, current)) {
165                ExplicitFreeListSpace.testAndSetLiveBit(current);
166              }
167            }
168            VM.scanning.scanObject(getModifiedProcessor(), current);
169          }
170          return;
171        }
172    
173        if (phaseId == RCBase.PROCESS_DECBUFFER) {
174          ObjectReference current;
175          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
176            if (!RCBase.BUILD_FOR_GENRC) {
177              while(!(current = decBuffer.pop()).isNull()) {
178                if (RCHeader.isNew(current)) {
179                  if (Space.isInSpace(RCBase.REF_COUNT, current)) {
180                    RCBase.rcSpace.free(current);
181                  } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
182                    RCBase.rcloSpace.free(current);
183                  } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
184                    VM.scanning.scanObject(zero, current);
185                  }
186                }
187              }
188            }
189            return;
190          }
191          while(!(current = decBuffer.pop()).isNull()) {
192            if (RCBase.BUILD_FOR_GENRC) {
193              if (RCHeader.decRC(current) == RCHeader.DEC_KILL) {
194                decBuffer.processChildren(current);
195                if (Space.isInSpace(RCBase.REF_COUNT, current)) {
196                  RCBase.rcSpace.free(current);
197                } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
198                  RCBase.rcloSpace.free(current);
199                } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
200                  VM.scanning.scanObject(zero, current);
201                }
202              }
203            } else {
204              if (RCHeader.isNew(current)) {
205                if (Space.isInSpace(RCBase.REF_COUNT, current)) {
206                  RCBase.rcSpace.free(current);
207                } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
208                  RCBase.rcloSpace.free(current);
209                } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
210                  VM.scanning.scanObject(zero, current);
211                }
212              } else {
213                if (RCHeader.decRC(current) == RCHeader.DEC_KILL) {
214                  decBuffer.processChildren(current);
215                  if (Space.isInSpace(RCBase.REF_COUNT, current)) {
216                    RCBase.rcSpace.free(current);
217                  } else if (Space.isInSpace(RCBase.REF_COUNT_LOS, current)) {
218                    RCBase.rcloSpace.free(current);
219                  } else if (Space.isInSpace(RCBase.IMMORTAL, current)) {
220                    VM.scanning.scanObject(zero, current);
221                  }
222                }
223              }
224            }
225          }
226          return;
227        }
228    
229        if (phaseId == RCBase.RELEASE) {
230          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
231            backupTrace.release();
232            global().oldRootPool.clearDeque(1);
233            if (RCBase.BUILD_FOR_GENRC) global().decPool.clearDeque(1);
234          }
235          getRootTrace().release();
236          if (VM.VERIFY_ASSERTIONS) {
237            VM.assertions._assert(newRootBuffer.isEmpty());
238            VM.assertions._assert(modBuffer.isEmpty());
239            VM.assertions._assert(decBuffer.isEmpty());
240          }
241          return;
242        }
243    
244        super.collectionPhase(phaseId, primary);
245      }
246    
247      /****************************************************************************
248       *
249       * Miscellaneous
250       */
251    
252      /** @return The active global plan as an <code>RC</code> instance. */
253      @Inline
254      protected static RCBase global() {
255        return (RCBase) VM.activePlan.global();
256      }
257    
258      @Override
259      public final TraceLocal getCurrentTrace() {
260        return getRootTrace();
261      }
262    
263      /** @return The current modBuffer instance. */
264      @Inline
265      public final ObjectReferenceDeque getModBuffer() {
266        return modBuffer;
267      }
268    }