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 }