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.TransitiveClosure;
016 import org.mmtk.utility.heap.FreeListPageResource;
017 import org.mmtk.utility.heap.VMRequest;
018 import org.mmtk.utility.HeaderByte;
019 import org.mmtk.utility.Treadmill;
020
021 import org.mmtk.vm.VM;
022
023 import org.vmmagic.pragma.*;
024 import org.vmmagic.unboxed.*;
025
026 /**
027 * Each instance of this class corresponds to one explicitly managed
028 * large object space.
029 */
030 @Uninterruptible
031 public final class LargeObjectSpace extends BaseLargeObjectSpace {
032
033 /****************************************************************************
034 *
035 * Class variables
036 */
037
038 /**
039 *
040 */
041 public static final int LOCAL_GC_BITS_REQUIRED = 2;
042 public static final int GLOBAL_GC_BITS_REQUIRED = 0;
043 private static final byte MARK_BIT = 1; // ...01
044 private static final byte NURSERY_BIT = 2; // ...10
045 private static final byte LOS_BIT_MASK = 3; // ...11
046
047 /****************************************************************************
048 *
049 * Instance variables
050 */
051
052 /**
053 *
054 */
055 private byte markState;
056 private boolean inNurseryGC;
057 private final Treadmill treadmill;
058
059 /****************************************************************************
060 *
061 * Initialization
062 */
063
064 /**
065 * The caller specifies the region of virtual memory to be used for
066 * this space. If this region conflicts with an existing space,
067 * then the constructor will fail.
068 *
069 * @param name The name of this space (used when printing error messages etc)
070 * @param vmRequest An object describing the virtual memory requested.
071 */
072 public LargeObjectSpace(String name, VMRequest vmRequest) {
073 this(name, true, vmRequest);
074 }
075
076 /**
077 * The caller specifies the region of virtual memory to be used for
078 * this space. If this region conflicts with an existing space,
079 * then the constructor will fail.
080 *
081 * @param name The name of this space (used when printing error messages etc)
082 * @param zeroed if true, allocations return zeroed memory.
083 * @param vmRequest An object describing the virtual memory requested.
084 */
085 public LargeObjectSpace(String name, boolean zeroed, VMRequest vmRequest) {
086 super(name, zeroed, vmRequest);
087 treadmill = new Treadmill(LOG_BYTES_IN_PAGE, true);
088 markState = 0;
089 }
090
091 /****************************************************************************
092 *
093 * Collection
094 */
095
096 /**
097 * Prepare for a new collection increment. For the mark-sweep
098 * collector we must flip the state of the mark bit between
099 * collections.
100 */
101 public void prepare(boolean fullHeap) {
102 if (fullHeap) {
103 if (VM.VERIFY_ASSERTIONS) {
104 VM.assertions._assert(treadmill.fromSpaceEmpty());
105 }
106 markState = (byte) (MARK_BIT - markState);
107 }
108 treadmill.flip(fullHeap);
109 inNurseryGC = !fullHeap;
110 }
111
112 /**
113 * A new collection increment has completed. For the mark-sweep
114 * collector this means we can perform the sweep phase.
115 */
116 public void release(boolean fullHeap) {
117 // sweep the large objects
118 sweepLargePages(true); // sweep the nursery
119 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(treadmill.nurseryEmpty());
120 if (fullHeap) sweepLargePages(false); // sweep the mature space
121 }
122
123 /**
124 * Sweep through the large pages, releasing all superpages on the
125 * "from space" treadmill.
126 */
127 private void sweepLargePages(boolean sweepNursery) {
128 while (true) {
129 Address cell = sweepNursery ? treadmill.popNursery() : treadmill.pop();
130 if (cell.isZero()) break;
131 release(getSuperPage(cell));
132 }
133 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(sweepNursery ? treadmill.nurseryEmpty() : treadmill.fromSpaceEmpty());
134 }
135
136 @Override
137 @Inline
138 public void release(Address first) {
139 ((FreeListPageResource) pr).releasePages(first);
140 }
141
142 /****************************************************************************
143 *
144 * Object processing and tracing
145 */
146
147 /**
148 * Trace a reference to an object under a mark sweep collection
149 * policy. If the object header is not already marked, mark the
150 * object in either the bitmap or by moving it off the treadmill,
151 * and enqueue the object for subsequent processing. The object is
152 * marked as (an atomic) side-effect of checking whether already
153 * marked.
154 *
155 * @param trace The trace being conducted.
156 * @param object The object to be traced.
157 * @return The object (there is no object forwarding in this
158 * collector, so we always return the same object: this could be a
159 * void method but for compliance to a more general interface).
160 */
161 @Override
162 @Inline
163 public ObjectReference traceObject(TransitiveClosure trace, ObjectReference object) {
164 boolean nurseryObject = isInNursery(object);
165 if (!inNurseryGC || nurseryObject) {
166 if (testAndMark(object, markState)) {
167 internalMarkObject(object, nurseryObject);
168 trace.processNode(object);
169 }
170 }
171 return object;
172 }
173
174 /**
175 * @param object The object in question
176 * @return {@code true} if this object is known to be live (i.e. it is marked)
177 */
178 @Override
179 @Inline
180 public boolean isLive(ObjectReference object) {
181 return testMarkBit(object, markState);
182 }
183
184 /**
185 * An object has been marked (identifiged as live). Large objects
186 * are added to the to-space treadmill, while all other objects will
187 * have a mark bit set in the superpage header.
188 *
189 * @param object The object which has been marked.
190 */
191 @Inline
192 private void internalMarkObject(ObjectReference object, boolean nurseryObject) {
193
194 Address cell = VM.objectModel.objectStartRef(object);
195 Address node = Treadmill.midPayloadToNode(cell);
196 treadmill.copy(node, nurseryObject);
197 }
198
199 /****************************************************************************
200 *
201 * Header manipulation
202 */
203
204 /**
205 * Perform any required initialization of the GC portion of the header.
206 *
207 * @param object the object ref to the storage to be initialized
208 * @param alloc is this initialization occurring due to (initial) allocation
209 * ({@code true}) or due to copying ({@code false})?
210 */
211 @Inline
212 public void initializeHeader(ObjectReference object, boolean alloc) {
213 byte oldValue = VM.objectModel.readAvailableByte(object);
214 byte newValue = (byte) ((oldValue & ~LOS_BIT_MASK) | markState);
215 if (alloc) newValue |= NURSERY_BIT;
216 if (HeaderByte.NEEDS_UNLOGGED_BIT) newValue |= HeaderByte.UNLOGGED_BIT;
217 VM.objectModel.writeAvailableByte(object, newValue);
218 Address cell = VM.objectModel.objectStartRef(object);
219 treadmill.addToTreadmill(Treadmill.midPayloadToNode(cell), alloc);
220 }
221
222 /**
223 * Atomically attempt to set the mark bit of an object. Return <code>true</code>
224 * if successful, <code>false</code> if the mark bit was already set.
225 *
226 * @param object The object whose mark bit is to be written
227 * @param value The value to which the mark bit will be set
228 */
229 @Inline
230 private boolean testAndMark(ObjectReference object, byte value) {
231 Word oldValue;
232 do {
233 oldValue = VM.objectModel.prepareAvailableBits(object);
234 byte markBit = (byte) (oldValue.toInt() & (inNurseryGC ? LOS_BIT_MASK : MARK_BIT));
235 if (markBit == value) return false;
236 } while (!VM.objectModel.attemptAvailableBits(object, oldValue,
237 oldValue.and(Word.fromIntZeroExtend(LOS_BIT_MASK).not()).or(Word.fromIntZeroExtend(value))));
238 return true;
239 }
240
241 /**
242 * Return {@code true} if the mark bit for an object has the given value.
243 *
244 * @param object The object whose mark bit is to be tested
245 * @param value The value against which the mark bit will be tested
246 * @return {@code true} if the mark bit for the object has the given value.
247 */
248 @Inline
249 private boolean testMarkBit(ObjectReference object, byte value) {
250 return (byte) (VM.objectModel.readAvailableByte(object) & MARK_BIT) == value;
251 }
252
253 /**
254 * Return {@code true} if the object is in the logical nursery
255 *
256 * @param object The object whose status is to be tested
257 * @return {@code true} if the object is in the logical nursery
258 */
259 @Inline
260 private boolean isInNursery(ObjectReference object) {
261 return (byte)(VM.objectModel.readAvailableByte(object) & NURSERY_BIT) == NURSERY_BIT;
262 }
263
264 @Override
265 @Inline
266 protected int superPageHeaderSize() {
267 return Treadmill.headerSize();
268 }
269
270 @Override
271 @Inline
272 protected int cellHeaderSize() {
273 return 0;
274 }
275
276 /**
277 * This is the treadmill used by the large object space.
278 *
279 * Note that it depends on the specific local in use whether this
280 * is being used.
281 *
282 * @return The treadmill associated with this large object space.
283 */
284 public Treadmill getTreadmill() {
285 return this.treadmill;
286 }
287 }