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.plan.generational; 014 015import org.mmtk.plan.*; 016import org.mmtk.policy.CopyLocal; 017import org.mmtk.policy.Space; 018import org.mmtk.utility.HeaderByte; 019import org.mmtk.utility.deque.*; 020import org.mmtk.utility.alloc.Allocator; 021import org.mmtk.utility.statistics.Stats; 022import org.mmtk.vm.VM; 023import static org.mmtk.plan.generational.Gen.USE_OBJECT_BARRIER_FOR_AASTORE; 024import static org.mmtk.plan.generational.Gen.USE_OBJECT_BARRIER_FOR_PUTFIELD; 025import static org.mmtk.utility.Constants.*; 026 027import org.vmmagic.pragma.*; 028import org.vmmagic.unboxed.*; 029 030/** 031 * This abstract class implements <i>per-mutator thread</i> behavior 032 * and state for <i>generational copying collectors</i>.<p> 033 * 034 * Specifically, this class defines mutator-time allocation into the nursery; 035 * write barrier semantics, and per-mutator thread collection semantics 036 * (flushing and restoring per-mutator allocator and remset state). 037 * 038 * @see Gen 039 * @see GenCollector 040 * @see StopTheWorldMutator 041 * @see MutatorContext 042 */ 043@Uninterruptible public class GenMutator extends StopTheWorldMutator { 044 045 /***************************************************************************** 046 * 047 * Instance fields 048 */ 049 050 /** 051 * 052 */ 053 protected final CopyLocal nursery = new CopyLocal(Gen.nurserySpace); 054 055 private final ObjectReferenceDeque modbuf; /* remember modified scalars */ 056 protected final WriteBuffer remset; /* remember modified array fields */ 057 protected final AddressPairDeque arrayRemset; /* remember modified array ranges */ 058 059 /**************************************************************************** 060 * 061 * Initialization 062 */ 063 064 /** 065 * Constructor<p> 066 * 067 * Note that each mutator is a producer of remsets, while each 068 * collector is a consumer. The <code>GenCollector</code> class 069 * is responsible for construction of the consumer. 070 * @see GenCollector 071 */ 072 public GenMutator() { 073 modbuf = new ObjectReferenceDeque("modbuf", global().modbufPool); 074 remset = new WriteBuffer(global().remsetPool); 075 arrayRemset = new AddressPairDeque(global().arrayRemsetPool); 076 } 077 078 /**************************************************************************** 079 * 080 * Mutator-time allocation 081 */ 082 083 /** 084 * {@inheritDoc} 085 */ 086 @Override 087 @Inline 088 public Address alloc(int bytes, int align, int offset, int allocator, int site) { 089 if (allocator == Gen.ALLOC_NURSERY) { 090 if (Stats.GATHER_MARK_CONS_STATS) Gen.nurseryCons.inc(bytes); 091 return nursery.alloc(bytes, align, offset); 092 } 093 return super.alloc(bytes, align, offset, allocator, site); 094 } 095 096 @Override 097 @Inline 098 public void postAlloc(ObjectReference ref, ObjectReference typeRef, 099 int bytes, int allocator) { 100 if (allocator != Gen.ALLOC_NURSERY) { 101 super.postAlloc(ref, typeRef, bytes, allocator); 102 } 103 } 104 105 @Override 106 public Allocator getAllocatorFromSpace(Space space) { 107 if (space == Gen.nurserySpace) return nursery; 108 return super.getAllocatorFromSpace(space); 109 } 110 111 /**************************************************************************** 112 * 113 * Barriers 114 */ 115 116 /** 117 * Perform the write barrier fast path, which may involve remembering 118 * a reference if necessary. 119 * 120 * @param src The object into which the new reference will be stored 121 * @param slot The address into which the new reference will be 122 * stored. 123 * @param tgt The target of the new reference 124 * @param mode The mode of the store (eg putfield, putstatic etc) 125 */ 126 @Inline 127 private void fastPath(ObjectReference src, Address slot, ObjectReference tgt, int mode) { 128 if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbFast.inc(); 129 if ((mode == ARRAY_ELEMENT && USE_OBJECT_BARRIER_FOR_AASTORE) || 130 (mode == INSTANCE_FIELD && USE_OBJECT_BARRIER_FOR_PUTFIELD)) { 131 if (HeaderByte.isUnlogged(src)) { 132 if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbSlow.inc(); 133 HeaderByte.markAsLogged(src); 134 modbuf.insert(src); 135 } 136 } else { 137 if (!Gen.inNursery(slot) && Gen.inNursery(tgt)) { 138 if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbSlow.inc(); 139 remset.insert(slot); 140 } 141 } 142 } 143 144 /** 145 * {@inheritDoc}<p> 146 * 147 * In this case, we remember the address of the source of the 148 * pointer if the new reference points into the nursery from 149 * non-nursery space. 150 */ 151 @Override 152 @Inline 153 public final void objectReferenceWrite(ObjectReference src, Address slot, 154 ObjectReference tgt, Word metaDataA, 155 Word metaDataB, int mode) { 156 fastPath(src, slot, tgt, mode); 157 VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode); 158 } 159 160 161 /** 162 * Perform the root write barrier fast path, which may involve remembering 163 * a reference if necessary. 164 * 165 * @param slot The address into which the new reference will be 166 * stored. 167 * @param tgt The target of the new reference 168 */ 169 @Inline 170 private void fastPath(Address slot, ObjectReference tgt) { 171 if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbFast.inc(); 172 if (Gen.inNursery(tgt)) { 173 if (Gen.GATHER_WRITE_BARRIER_STATS) Gen.wbSlow.inc(); 174 remset.insert(slot); 175 } 176 } 177 178 /** 179 * {@inheritDoc}<p> 180 * 181 * In this case, we remember the address of the source of the 182 * pointer if the new reference points into the nursery from 183 * non-nursery space. 184 */ 185 @Override 186 @Inline 187 public final void objectReferenceNonHeapWrite(Address slot, ObjectReference tgt, 188 Word metaDataA, Word metaDataB) { 189 fastPath(slot, tgt); 190 VM.barriers.objectReferenceNonHeapWrite(slot, tgt, metaDataA, metaDataB); 191 } 192 193 /** 194 * {@inheritDoc}<p> 195 * 196 * In this case, we remember the address of the source of the 197 * pointer if the new reference points into the nursery from 198 * non-nursery space. 199 */ 200 @Override 201 @Inline 202 public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot, ObjectReference old, ObjectReference tgt, 203 Word metaDataA, Word metaDataB, int mode) { 204 boolean result = VM.barriers.objectReferenceTryCompareAndSwap(src, old, tgt, metaDataA, metaDataB, mode); 205 if (result) 206 fastPath(src, slot, tgt, mode); 207 return result; 208 } 209 210 /** 211 * {@inheritDoc}<p> 212 * 213 * In this case, we remember the mutated source address range and 214 * will scan that address range at GC time. 215 */ 216 @Inline 217 @Override 218 public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset, ObjectReference dst, Offset dstOffset, int bytes) { 219 if (!Gen.inNursery(dst)) { 220 Address start = dst.toAddress().plus(dstOffset); 221 arrayRemset.insert(start, start.plus(bytes)); 222 } 223 return false; 224 } 225 226 @Override 227 public final void flushRememberedSets() { 228 modbuf.flushLocal(); 229 remset.flushLocal(); 230 arrayRemset.flushLocal(); 231 assertRemsetsFlushed(); 232 } 233 234 @Override 235 public final void assertRemsetsFlushed() { 236 if (VM.VERIFY_ASSERTIONS) { 237 VM.assertions._assert(modbuf.isFlushed()); 238 VM.assertions._assert(remset.isFlushed()); 239 VM.assertions._assert(arrayRemset.isFlushed()); 240 } 241 } 242 243 /**************************************************************************** 244 * 245 * Collection 246 */ 247 248 /** 249 * {@inheritDoc} 250 */ 251 @Override 252 @NoInline 253 public void collectionPhase(short phaseId, boolean primary) { 254 255 if (phaseId == Gen.PREPARE) { 256 nursery.reset(); 257 if (global().traceFullHeap()) { 258 super.collectionPhase(phaseId, primary); 259 modbuf.flushLocal(); 260 remset.flushLocal(); 261 arrayRemset.flushLocal(); 262 } else { 263 flushRememberedSets(); 264 } 265 return; 266 } 267 268 if (phaseId == Gen.RELEASE) { 269 if (global().traceFullHeap()) { 270 super.collectionPhase(phaseId, primary); 271 } 272 assertRemsetsFlushed(); 273 return; 274 } 275 276 super.collectionPhase(phaseId, primary); 277 } 278 279 /**************************************************************************** 280 * 281 * Miscellaneous 282 */ 283 284 /** @return The active global plan as a <code>Gen</code> instance. */ 285 @Inline 286 private static Gen global() { 287 return (Gen) VM.activePlan.global(); 288 } 289}