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 simple reference counting collector.
030     */
031    @Uninterruptible
032    public class RCBaseMutator extends StopTheWorldMutator {
033    
034      /************************************************************************
035       * Instance fields
036       */
037      private final ExplicitFreeListLocal rc;
038      private final LargeObjectLocal rclos;
039      private final ObjectReferenceDeque modBuffer;
040      private final RCDecBuffer decBuffer;
041      private final BTSweepImmortalScanner btSweepImmortal;
042    
043      /************************************************************************
044       *
045       * Initialization
046       */
047    
048      /**
049       * Constructor. One instance is created per physical processor.
050       */
051      public RCBaseMutator() {
052        rc = new ExplicitFreeListLocal(RCBase.rcSpace);
053        rclos = new LargeObjectLocal(RCBase.rcloSpace);
054        modBuffer = new ObjectReferenceDeque("mod", global().modPool);
055        decBuffer = new RCDecBuffer(global().decPool);
056        btSweepImmortal = new BTSweepImmortalScanner();
057      }
058    
059      /****************************************************************************
060       *
061       * Mutator-time allocation
062       */
063    
064      /**
065       * Allocate memory for an object.
066       *
067       * @param bytes The number of bytes required for the object.
068       * @param align Required alignment for the object.
069       * @param offset Offset associated with the alignment.
070       * @param allocator The allocator associated with this request.
071       * @param site Allocation site
072       * @return The address of the newly allocated memory.
073       */
074      @Inline
075      public Address alloc(int bytes, int align, int offset, int allocator, int site) {
076        switch (allocator) {
077          case RCBase.ALLOC_DEFAULT:
078          case RCBase.ALLOC_NON_MOVING:
079          case RCBase.ALLOC_CODE:
080            return rc.alloc(bytes, align, offset);
081          case RCBase.ALLOC_LOS:
082          case RCBase.ALLOC_PRIMITIVE_LOS:
083          case RCBase.ALLOC_LARGE_CODE:
084            return rclos.alloc(bytes, align, offset);
085          case RCBase.ALLOC_IMMORTAL:
086            return super.alloc(bytes, align, offset, allocator, site);
087          default:
088            VM.assertions.fail("Allocator not understood by RC");
089            return Address.zero();
090        }
091      }
092    
093      /**
094       * Perform post-allocation actions.  For many allocators none are
095       * required.
096       *
097       * @param ref The newly allocated object
098       * @param typeRef the type reference for the instance being created
099       * @param bytes The size of the space to be allocated (in bytes)
100       * @param allocator The allocator number to be used for this allocation
101       */
102      @Inline
103      public void postAlloc(ObjectReference ref, ObjectReference typeRef, int bytes, int allocator) {
104        switch (allocator) {
105        case RCBase.ALLOC_DEFAULT:
106        case RCBase.ALLOC_NON_MOVING:
107          modBuffer.push(ref);
108        case RCBase.ALLOC_CODE:
109          decBuffer.push(ref);
110          RCHeader.initializeHeader(ref, true);
111          ExplicitFreeListSpace.unsyncSetLiveBit(ref);
112          break;
113        case RCBase.ALLOC_LOS:
114          modBuffer.push(ref);
115        case RCBase.ALLOC_PRIMITIVE_LOS:
116        case RCBase.ALLOC_LARGE_CODE:
117          decBuffer.push(ref);
118          RCHeader.initializeHeader(ref, true);
119          RCBase.rcloSpace.initializeHeader(ref, true);
120          return;
121        case RCBase.ALLOC_IMMORTAL:
122          modBuffer.push(ref);
123          decBuffer.push(ref);
124          RCHeader.initializeHeader(ref, true);
125          return;
126        default:
127          VM.assertions.fail("Allocator not understood by RC");
128          return;
129        }
130      }
131    
132      /**
133       * Return the allocator instance associated with a space
134       * <code>space</code>, for this plan instance.
135       *
136       * @param space The space for which the allocator instance is desired.
137       * @return The allocator instance associated with this plan instance
138       * which is allocating into <code>space</code>, or <code>null</code>
139       * if no appropriate allocator can be established.
140       */
141      public Allocator getAllocatorFromSpace(Space space) {
142        if (space == RCBase.rcSpace) return rc;
143        if (space == RCBase.rcloSpace) return rclos;
144    
145        return super.getAllocatorFromSpace(space);
146      }
147    
148      /****************************************************************************
149       *
150       * Collection
151       */
152    
153      /**
154       * Perform a per-mutator collection phase.
155       *
156       * @param phaseId The collection phase to perform
157       * @param primary perform any single-threaded local activities.
158       */
159      public void collectionPhase(short phaseId, boolean primary) {
160        if (phaseId == RCBase.PREPARE) {
161          rc.prepare();
162          return;
163        }
164    
165        if (phaseId == RCBase.PROCESS_MODBUFFER) {
166          modBuffer.flushLocal();
167          return;
168        }
169    
170        if (phaseId == RCBase.PROCESS_DECBUFFER) {
171          decBuffer.flushLocal();
172          return;
173        }
174    
175        if (phaseId == RCBase.RELEASE) {
176          if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) {
177            immortal.linearScan(btSweepImmortal);
178          }
179          rc.release();
180          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(modBuffer.isEmpty());
181          if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(decBuffer.isEmpty());
182          return;
183        }
184    
185        super.collectionPhase(phaseId, primary);
186      }
187    
188      /**
189       * Flush per-mutator remembered sets into the global remset pool.
190       */
191      public final void flushRememberedSets() {
192        decBuffer.flushLocal();
193        modBuffer.flushLocal();
194        assertRemsetsFlushed();
195      }
196    
197      /**
198       * Assert that the remsets have been flushed.  This is critical to
199       * correctness.  We need to maintain the invariant that remset entries
200       * do not accrue during GC.  If the host JVM generates barrier entires
201       * it is its own responsibility to ensure that they are flushed before
202       * returning to MMTk.
203       */
204      public final void assertRemsetsFlushed() {
205        if (VM.VERIFY_ASSERTIONS) {
206          VM.assertions._assert(decBuffer.isFlushed());
207          VM.assertions._assert(modBuffer.isFlushed());
208        }
209      }
210    
211      /**
212       * Flush mutator context, in response to a requestMutatorFlush.
213       * Also called by the default implementation of deinitMutator.
214       */
215      @Override
216      public void flush() {
217        super.flush();
218        rc.flush();
219      }
220    
221      /****************************************************************************
222       *
223       * Write barriers.
224       */
225    
226      /**
227       * A new reference is about to be created. Take appropriate write
228       * barrier actions.<p>
229       *
230       * <b>By default do nothing, override if appropriate.</b>
231       *
232       * @param src The object into which the new reference will be stored
233       * @param slot The address into which the new reference will be
234       * stored.
235       * @param tgt The target of the new reference
236       * @param metaDataA A value that assists the host VM in creating a store
237       * @param metaDataB A value that assists the host VM in creating a store
238       * @param mode The context in which the store occurred
239       */
240      @Inline
241      public void objectReferenceWrite(ObjectReference src, Address slot,
242                               ObjectReference tgt, Word metaDataA,
243                               Word metaDataB, int mode) {
244        if (RCHeader.logRequired(src)) {
245          coalescingWriteBarrierSlow(src);
246        }
247        VM.barriers.objectReferenceWrite(src,tgt,metaDataA, metaDataB, mode);
248      }
249    
250      /**
251       * Attempt to atomically exchange the value in the given slot
252       * with the passed replacement value. If a new reference is
253       * created, we must then take appropriate write barrier actions.<p>
254       *
255       * <b>By default do nothing, override if appropriate.</b>
256       *
257       * @param src The object into which the new reference will be stored
258       * @param slot The address into which the new reference will be
259       * stored.
260       * @param old The old reference to be swapped out
261       * @param tgt The target of the new reference
262       * @param metaDataA A value that assists the host VM in creating a store
263       * @param metaDataB A value that assists the host VM in creating a store
264       * @param mode The context in which the store occured
265       * @return True if the swap was successful.
266       */
267      @Inline
268      public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot,
269                                                   ObjectReference old, ObjectReference tgt, Word metaDataA,
270                                                   Word metaDataB, int mode) {
271        if (RCHeader.logRequired(src)) {
272          coalescingWriteBarrierSlow(src);
273        }
274        return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode);
275      }
276    
277      /**
278       * A number of references are about to be copied from object
279       * <code>src</code> to object <code>dst</code> (as in an array
280       * copy).  Thus, <code>dst</code> is the mutated object.  Take
281       * appropriate write barrier actions.<p>
282       *
283       * @param src The source of the values to be copied
284       * @param srcOffset The offset of the first source address, in
285       * bytes, relative to <code>src</code> (in principle, this could be
286       * negative).
287       * @param dst The mutated object, i.e. the destination of the copy.
288       * @param dstOffset The offset of the first destination address, in
289       * bytes relative to <code>tgt</code> (in principle, this could be
290       * negative).
291       * @param bytes The size of the region being copied, in bytes.
292       * @return True if the update was performed by the barrier, false if
293       * left to the caller (always false in this case).
294       */
295      @Inline
296      public boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset,
297                                  ObjectReference dst, Offset dstOffset, int bytes) {
298        if (RCHeader.logRequired(dst)) {
299          coalescingWriteBarrierSlow(dst);
300        }
301        return false;
302      }
303    
304      /**
305       * Slow path of the coalescing write barrier.
306       *
307       * <p> Attempt to log the source object. If successful in racing for
308       * the log bit, push an entry into the modified buffer and add a
309       * decrement buffer entry for each referent object (in the RC space)
310       * before setting the header bit to indicate that it has finished
311       * logging (allowing others in the race to continue).
312       *
313       * @param srcObj The object being mutated
314       */
315      @NoInline
316      private void coalescingWriteBarrierSlow(ObjectReference srcObj) {
317        if (RCHeader.attemptToLog(srcObj)) {
318          modBuffer.push(srcObj);
319          decBuffer.processChildren(srcObj);
320          RCHeader.makeLogged(srcObj);
321        }
322      }
323    
324      /****************************************************************************
325       *
326       * Miscellaneous
327       */
328    
329      /** @return The active global plan as an <code>RC</code> instance. */
330      @Inline
331      private static RCBase global() {
332        return (RCBase) VM.activePlan.global();
333      }
334    }