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