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.policy;
014    
015    import org.mmtk.plan.Plan;
016    import org.mmtk.plan.TransitiveClosure;
017    import org.mmtk.utility.heap.MonotonePageResource;
018    import org.mmtk.utility.heap.VMRequest;
019    import org.mmtk.utility.Constants;
020    import org.mmtk.utility.HeaderByte;
021    
022    import org.mmtk.vm.VM;
023    
024    import org.vmmagic.unboxed.*;
025    import org.vmmagic.pragma.*;
026    
027    /**
028     * This class implements tracing for a simple immortal collection
029     * policy.  Under this policy all that is required is for the
030     * "collector" to propagate marks in a liveness trace.  It does not
031     * actually collect.  This class does not hold any state, all methods
032     * are static.
033     */
034    @Uninterruptible public final class ImmortalSpace extends Space
035      implements Constants {
036    
037      /****************************************************************************
038       *
039       * Class variables
040       */
041    
042      /**
043       *
044       */
045      static final byte GC_MARK_BIT_MASK = 1;
046      private static final int META_DATA_PAGES_PER_REGION = CARD_META_PAGES_PER_REGION;
047    
048      /****************************************************************************
049       *
050       * Instance variables
051       */
052    
053      /**
054       *
055       */
056      private byte markState = 0; // when GC off, the initialization value
057    
058      /****************************************************************************
059       *
060       * Initialization
061       */
062    
063      /**
064       * The caller specifies the region of virtual memory to be used for
065       * this space.  If this region conflicts with an existing space,
066       * then the constructor will fail.
067       *
068       * @param name The name of this space (used when printing error messages etc)
069       * @param vmRequest An object describing the virtual memory requested.
070       */
071      public ImmortalSpace(String name, VMRequest vmRequest) {
072        this(name, true, vmRequest);
073      }
074    
075      /**
076       * The caller specifies the region of virtual memory to be used for
077       * this space.  If this region conflicts with an existing space,
078       * then the constructor will fail.
079       *
080       * @param name The name of this space (used when printing error messages etc)
081       * @param zeroed if true, allocations return zeroed memory.
082       * @param vmRequest An object describing the virtual memory requested.
083       */
084      public ImmortalSpace(String name, boolean zeroed, VMRequest vmRequest) {
085        super(name, false, true, zeroed, vmRequest);
086        if (vmRequest.isDiscontiguous()) {
087          pr = new MonotonePageResource(this, META_DATA_PAGES_PER_REGION);
088        } else {
089          pr = new MonotonePageResource(this, start, extent, META_DATA_PAGES_PER_REGION);
090        }
091      }
092    
093      /** @return the current mark state */
094      @Inline
095      public Word getMarkState() { return Word.fromIntZeroExtend(markState); }
096    
097      /****************************************************************************
098       *
099       * Object header manipulations
100       */
101    
102      /**
103       * Initialize the object header post-allocation.  We need to set the mark state
104       * correctly and set the logged bit if necessary.
105       *
106       * @param object The newly allocated object instance whose header we are initializing
107       */
108      public void initializeHeader(ObjectReference object) {
109        byte oldValue = VM.objectModel.readAvailableByte(object);
110        byte newValue = (byte) ((oldValue & GC_MARK_BIT_MASK) | markState);
111        if (HeaderByte.NEEDS_UNLOGGED_BIT) newValue |= HeaderByte.UNLOGGED_BIT;
112        VM.objectModel.writeAvailableByte(object, newValue);
113      }
114    
115      /**
116       * Used to mark boot image objects during a parallel scan of objects during GC
117       * Returns {@code true} if marking was done.
118       */
119      @Inline
120      private static boolean testAndMark(ObjectReference object, byte value) {
121        Word oldValue;
122        do {
123          oldValue = VM.objectModel.prepareAvailableBits(object);
124          byte markBit = (byte) (oldValue.toInt() & GC_MARK_BIT_MASK);
125          if (markBit == value) return false;
126        } while (!VM.objectModel.attemptAvailableBits(object, oldValue,
127            oldValue.xor(Word.fromIntZeroExtend(GC_MARK_BIT_MASK))));
128        return true;
129      }
130    
131      /**
132       * Trace a reference to an object under an immortal collection
133       * policy.  If the object is not already marked, enqueue the object
134       * for subsequent processing. The object is marked as (an atomic)
135       * side-effect of checking whether already marked.
136       *
137       * @param trace The trace being conducted.
138       * @param object The object to be traced.
139       */
140      @Override
141      @Inline
142      public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) {
143        if (testAndMark(object, markState))
144          trace.processNode(object);
145        return object;
146      }
147    
148      /**
149       * Prepare for a new collection increment.  For the immortal
150       * collector we must flip the state of the mark bit between
151       * collections.
152       */
153      public void prepare() {
154        markState = (byte) (GC_MARK_BIT_MASK - markState);
155      }
156    
157      public void release() {}
158    
159      /**
160       * Release an allocated page or pages.  In this case we do nothing
161       * because we only release pages enmasse.
162       *
163       * @param start The address of the start of the page or pages
164       */
165      @Override
166      @Inline
167      public void release(Address start) {
168        if (VM.VERIFY_ASSERTIONS)
169          VM.assertions._assert(false); // this policy only releases pages enmasse
170      }
171    
172      @Override
173      @Inline
174      public boolean isLive(ObjectReference object) {
175        return true;
176      }
177    
178      /**
179       * Returns if the object in question is currently thought to be reachable.
180       * This is done by comparing the mark bit to the current mark state. For the
181       * immortal collector reachable and live are different, making this method
182       * necessary.
183       *
184       * @param object The address of an object in immortal space to test
185       * @return <code>true</code> if <code>ref</code> may be a reachable object (e.g., having
186       *         the current mark state).  While all immortal objects are live,
187       *         some may be unreachable.
188       */
189      @Override
190      public boolean isReachable(ObjectReference object) {
191        if (Plan.SCAN_BOOT_IMAGE && this == Plan.vmSpace)
192          return true;  // ignore boot image "reachabilty" if we're not tracing it
193        else
194          return (VM.objectModel.readAvailableByte(object) & GC_MARK_BIT_MASK) == markState;
195      }
196    }