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