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.StopTheWorldMutator;
016    import org.mmtk.plan.refcount.backuptrace.BTSweepImmortalScanner;
017    import org.mmtk.policy.ExplicitFreeListLocal;
018    import org.mmtk.policy.ExplicitFreeListSpace;
019    import org.mmtk.policy.LargeObjectLocal;
020    import org.mmtk.policy.Space;
021    import org.mmtk.utility.alloc.Allocator;
022    import org.mmtk.utility.deque.ObjectReferenceDeque;
023    import org.mmtk.vm.VM;
024    
025    import org.vmmagic.pragma.*;
026    import org.vmmagic.unboxed.*;
027    
028    /**
029     * This class implements the mutator 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 class RCBaseMutator extends StopTheWorldMutator {
037    
038      /************************************************************************
039       * Instance fields
040       */
041    
042      /**
043       *
044       */
045      private final ExplicitFreeListLocal rc;
046      private final LargeObjectLocal rclos;
047      private final ObjectReferenceDeque modBuffer;
048      private final RCDecBuffer decBuffer;
049      private final BTSweepImmortalScanner btSweepImmortal;
050    
051      /************************************************************************
052       *
053       * Initialization
054       */
055    
056      /**
057       * Constructor. One instance is created per physical processor.
058       */
059      public RCBaseMutator() {
060        rc = new ExplicitFreeListLocal(RCBase.rcSpace);
061        rclos = new LargeObjectLocal(RCBase.rcloSpace);
062        modBuffer = new ObjectReferenceDeque("mod", global().modPool);
063        decBuffer = new RCDecBuffer(global().decPool);
064        btSweepImmortal = new BTSweepImmortalScanner();
065      }
066    
067      /****************************************************************************
068       *
069       * Mutator-time allocation
070       */
071    
072      /**
073       * {@inheritDoc}
074       */
075      @Override
076      @Inline
077      public Address alloc(int bytes, int align, int offset, int allocator, int site) {
078        switch (allocator) {
079          case RCBase.ALLOC_DEFAULT:
080          case RCBase.ALLOC_NON_MOVING:
081          case RCBase.ALLOC_CODE:
082            return rc.alloc(bytes, align, offset);
083          case RCBase.ALLOC_LOS:
084          case RCBase.ALLOC_PRIMITIVE_LOS:
085          case RCBase.ALLOC_LARGE_CODE:
086            return rclos.alloc(bytes, align, offset);
087          case RCBase.ALLOC_IMMORTAL:
088            return super.alloc(bytes, align, offset, allocator, site);
089          default:
090            VM.assertions.fail("Allocator not understood by RC");
091            return Address.zero();
092        }
093      }
094    
095      @Override
096      @Inline
097      public void postAlloc(ObjectReference ref, ObjectReference typeRef, int bytes, int allocator) {
098        switch (allocator) {
099        case RCBase.ALLOC_DEFAULT:
100        case RCBase.ALLOC_NON_MOVING:
101          if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref);
102        case RCBase.ALLOC_CODE:
103          if (RCBase.BUILD_FOR_GENRC) {
104            decBuffer.push(ref);
105            RCHeader.initializeHeader(ref, true);
106            ExplicitFreeListSpace.unsyncSetLiveBit(ref);
107          }
108          break;
109        case RCBase.ALLOC_LOS:
110          if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref);
111        case RCBase.ALLOC_PRIMITIVE_LOS:
112        case RCBase.ALLOC_LARGE_CODE:
113          decBuffer.push(ref);
114          if (RCBase.BUILD_FOR_GENRC) RCHeader.initializeHeader(ref, true);
115          RCBase.rcloSpace.initializeHeader(ref, true);
116          return;
117        case RCBase.ALLOC_IMMORTAL:
118          if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref);
119          decBuffer.push(ref);
120          if (RCBase.BUILD_FOR_GENRC) RCHeader.initializeHeader(ref, true);
121          return;
122        default:
123          VM.assertions.fail("Allocator not understood by RC");
124          return;
125        }
126      }
127    
128      @Override
129      public Allocator getAllocatorFromSpace(Space space) {
130        if (space == RCBase.rcSpace) return rc;
131        if (space == RCBase.rcloSpace) return rclos;
132        return super.getAllocatorFromSpace(space);
133      }
134    
135      /****************************************************************************
136       *
137       * Collection
138       */
139    
140    
141      /**
142       * {@inheritDoc}
143       */
144      @Override
145      public void collectionPhase(short phaseId, boolean primary) {
146        if (phaseId == RCBase.PREPARE) {
147          rc.prepare();
148          return;
149        }
150    
151        if (phaseId == RCBase.PROCESS_MODBUFFER) {
152          modBuffer.flushLocal();
153          return;
154        }
155    
156        if (phaseId == RCBase.PROCESS_DECBUFFER) {
157          decBuffer.flushLocal();
158          return;
159        }
160    
161        if (phaseId == RCBase.RELEASE) {
162          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
163            immortal.linearScan(btSweepImmortal);
164          }
165          rc.release();
166          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(modBuffer.isEmpty());
167          if (!RCBase.BUILD_FOR_GENRC) {
168            if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(decBuffer.isEmpty());
169          }
170          return;
171        }
172    
173        super.collectionPhase(phaseId, primary);
174      }
175    
176      @Override
177      public final void flushRememberedSets() {
178        decBuffer.flushLocal();
179        modBuffer.flushLocal();
180        assertRemsetsFlushed();
181      }
182    
183      @Override
184      public final void assertRemsetsFlushed() {
185        if (VM.VERIFY_ASSERTIONS) {
186          VM.assertions._assert(decBuffer.isFlushed());
187          VM.assertions._assert(modBuffer.isFlushed());
188        }
189      }
190    
191      @Override
192      public void flush() {
193        super.flush();
194        rc.flush();
195      }
196    
197      /****************************************************************************
198       *
199       * Write barriers.
200       */
201    
202      /**
203       * {@inheritDoc}
204       */
205      @Override
206      @Inline
207      public void objectReferenceWrite(ObjectReference src, Address slot,
208                               ObjectReference tgt, Word metaDataA,
209                               Word metaDataB, int mode) {
210        if (RCHeader.logRequired(src)) {
211          coalescingWriteBarrierSlow(src);
212        }
213        VM.barriers.objectReferenceWrite(src,tgt,metaDataA, metaDataB, mode);
214      }
215    
216      @Override
217      @Inline
218      public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot,
219                                                   ObjectReference old, ObjectReference tgt, Word metaDataA,
220                                                   Word metaDataB, int mode) {
221        if (RCHeader.logRequired(src)) {
222          coalescingWriteBarrierSlow(src);
223        }
224        return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode);
225      }
226    
227      /**
228       * {@inheritDoc}
229       *
230       * @param src The source of the values to be copied
231       * @param srcOffset The offset of the first source address, in
232       * bytes, relative to <code>src</code> (in principle, this could be
233       * negative).
234       * @param dst The mutated object, i.e. the destination of the copy.
235       * @param dstOffset The offset of the first destination address, in
236       * bytes relative to <code>tgt</code> (in principle, this could be
237       * negative).
238       * @param bytes The size of the region being copied, in bytes.
239       * @return True if the update was performed by the barrier, false if
240       * left to the caller (always false in this case).
241       */
242      @Override
243      @Inline
244      public boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
245                                  ObjectReference dst, Offset dstOffset, int bytes) {
246        if (RCHeader.logRequired(dst)) {
247          coalescingWriteBarrierSlow(dst);
248        }
249        return false;
250      }
251    
252      /**
253       * Slow path of the coalescing write barrier.
254       *
255       * <p> Attempt to log the source object. If successful in racing for
256       * the log bit, push an entry into the modified buffer and add a
257       * decrement buffer entry for each referent object (in the RC space)
258       * before setting the header bit to indicate that it has finished
259       * logging (allowing others in the race to continue).
260       *
261       * @param srcObj The object being mutated
262       */
263      @NoInline
264      private void coalescingWriteBarrierSlow(ObjectReference srcObj) {
265        if (RCHeader.attemptToLog(srcObj)) {
266          modBuffer.push(srcObj);
267          decBuffer.processChildren(srcObj);
268          RCHeader.makeLogged(srcObj);
269        }
270      }
271    
272      /****************************************************************************
273       *
274       * Miscellaneous
275       */
276    
277      /** @return The active global plan as an <code>RC</code> instance. */
278      @Inline
279      private static RCBase global() {
280        return (RCBase) VM.activePlan.global();
281      }
282    }