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.refcount; 014 015import org.mmtk.plan.StopTheWorldMutator; 016import org.mmtk.plan.refcount.backuptrace.BTSweepImmortalScanner; 017import org.mmtk.policy.ExplicitFreeListLocal; 018import org.mmtk.policy.ExplicitFreeListSpace; 019import org.mmtk.policy.LargeObjectLocal; 020import org.mmtk.policy.Space; 021import org.mmtk.utility.alloc.Allocator; 022import org.mmtk.utility.deque.ObjectReferenceDeque; 023import org.mmtk.vm.VM; 024 025import org.vmmagic.pragma.*; 026import org.vmmagic.unboxed.*; 027 028/** 029 * This class implements the mutator context for a reference counting collector. 030 * See Shahriyar et al for details of and rationale for the optimizations used 031 * here (http://dx.doi.org/10.1145/2258996.2259008). See Chapter 4 of 032 * Daniel Frampton's PhD thesis for details of and rationale for the cycle 033 * collection strategy used by this collector. 034 */ 035@Uninterruptible 036public class RCBaseMutator extends StopTheWorldMutator { 037 038 /************************************************************************ 039 * Instance fields 040 */ 041 042 /** 043 * 044 */ 045 private final ExplicitFreeListLocal rc; 046 private final LargeObjectLocal rclos; 047 private final ObjectReferenceDeque modBuffer; 048 private final RCDecBuffer decBuffer; 049 private final BTSweepImmortalScanner btSweepImmortal; 050 051 /************************************************************************ 052 * 053 * Initialization 054 */ 055 056 /** 057 * Constructor. One instance is created per physical processor. 058 */ 059 public RCBaseMutator() { 060 rc = new ExplicitFreeListLocal(RCBase.rcSpace); 061 rclos = new LargeObjectLocal(RCBase.rcloSpace); 062 modBuffer = new ObjectReferenceDeque("mod", global().modPool); 063 decBuffer = new RCDecBuffer(global().decPool); 064 btSweepImmortal = new BTSweepImmortalScanner(); 065 } 066 067 /**************************************************************************** 068 * 069 * Mutator-time allocation 070 */ 071 072 /** 073 * {@inheritDoc} 074 */ 075 @Override 076 @Inline 077 public Address alloc(int bytes, int align, int offset, int allocator, int site) { 078 switch (allocator) { 079 case RCBase.ALLOC_DEFAULT: 080 case RCBase.ALLOC_NON_MOVING: 081 case RCBase.ALLOC_CODE: 082 return rc.alloc(bytes, align, offset); 083 case RCBase.ALLOC_LOS: 084 case RCBase.ALLOC_PRIMITIVE_LOS: 085 case RCBase.ALLOC_LARGE_CODE: 086 return rclos.alloc(bytes, align, offset); 087 case RCBase.ALLOC_IMMORTAL: 088 return super.alloc(bytes, align, offset, allocator, site); 089 default: 090 VM.assertions.fail("Allocator not understood by RC"); 091 return Address.zero(); 092 } 093 } 094 095 @Override 096 @Inline 097 public void postAlloc(ObjectReference ref, ObjectReference typeRef, int bytes, int allocator) { 098 switch (allocator) { 099 case RCBase.ALLOC_DEFAULT: 100 case RCBase.ALLOC_NON_MOVING: 101 if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref); 102 case RCBase.ALLOC_CODE: 103 if (RCBase.BUILD_FOR_GENRC) { 104 decBuffer.push(ref); 105 RCHeader.initializeHeader(ref, true); 106 ExplicitFreeListSpace.unsyncSetLiveBit(ref); 107 } 108 break; 109 case RCBase.ALLOC_LOS: 110 if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref); 111 case RCBase.ALLOC_PRIMITIVE_LOS: 112 case RCBase.ALLOC_LARGE_CODE: 113 decBuffer.push(ref); 114 if (RCBase.BUILD_FOR_GENRC) RCHeader.initializeHeader(ref, true); 115 RCBase.rcloSpace.initializeHeader(ref, true); 116 return; 117 case RCBase.ALLOC_IMMORTAL: 118 if (RCBase.BUILD_FOR_GENRC) modBuffer.push(ref); 119 decBuffer.push(ref); 120 if (RCBase.BUILD_FOR_GENRC) RCHeader.initializeHeader(ref, true); 121 return; 122 default: 123 VM.assertions.fail("Allocator not understood by RC"); 124 return; 125 } 126 } 127 128 @Override 129 public Allocator getAllocatorFromSpace(Space space) { 130 if (space == RCBase.rcSpace) return rc; 131 if (space == RCBase.rcloSpace) return rclos; 132 return super.getAllocatorFromSpace(space); 133 } 134 135 /**************************************************************************** 136 * 137 * Collection 138 */ 139 140 141 /** 142 * {@inheritDoc} 143 */ 144 @Override 145 public void collectionPhase(short phaseId, boolean primary) { 146 if (phaseId == RCBase.PREPARE) { 147 rc.prepare(); 148 return; 149 } 150 151 if (phaseId == RCBase.PROCESS_MODBUFFER) { 152 modBuffer.flushLocal(); 153 return; 154 } 155 156 if (phaseId == RCBase.PROCESS_DECBUFFER) { 157 decBuffer.flushLocal(); 158 return; 159 } 160 161 if (phaseId == RCBase.RELEASE) { 162 if (RCBase.CC_BACKUP_TRACE && RCBase.performCycleCollection) { 163 immortal.linearScan(btSweepImmortal); 164 } 165 rc.release(); 166 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(modBuffer.isEmpty()); 167 if (!RCBase.BUILD_FOR_GENRC) { 168 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(decBuffer.isEmpty()); 169 } 170 return; 171 } 172 173 super.collectionPhase(phaseId, primary); 174 } 175 176 @Override 177 public final void flushRememberedSets() { 178 decBuffer.flushLocal(); 179 modBuffer.flushLocal(); 180 assertRemsetsFlushed(); 181 } 182 183 @Override 184 public final void assertRemsetsFlushed() { 185 if (VM.VERIFY_ASSERTIONS) { 186 VM.assertions._assert(decBuffer.isFlushed()); 187 VM.assertions._assert(modBuffer.isFlushed()); 188 } 189 } 190 191 @Override 192 public void flush() { 193 super.flush(); 194 rc.flush(); 195 } 196 197 /**************************************************************************** 198 * 199 * Write barriers. 200 */ 201 202 /** 203 * {@inheritDoc} 204 */ 205 @Override 206 @Inline 207 public void objectReferenceWrite(ObjectReference src, Address slot, 208 ObjectReference tgt, Word metaDataA, 209 Word metaDataB, int mode) { 210 if (RCHeader.logRequired(src)) { 211 coalescingWriteBarrierSlow(src); 212 } 213 VM.barriers.objectReferenceWrite(src,tgt,metaDataA, metaDataB, mode); 214 } 215 216 @Override 217 @Inline 218 public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot, 219 ObjectReference old, ObjectReference tgt, Word metaDataA, 220 Word metaDataB, int mode) { 221 if (RCHeader.logRequired(src)) { 222 coalescingWriteBarrierSlow(src); 223 } 224 return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode); 225 } 226 227 /** 228 * {@inheritDoc} 229 * 230 * @param src The source of the values to be copied 231 * @param srcOffset The offset of the first source address, in 232 * bytes, relative to <code>src</code> (in principle, this could be 233 * negative). 234 * @param dst The mutated object, i.e. the destination of the copy. 235 * @param dstOffset The offset of the first destination address, in 236 * bytes relative to <code>tgt</code> (in principle, this could be 237 * negative). 238 * @param bytes The size of the region being copied, in bytes. 239 * @return True if the update was performed by the barrier, false if 240 * left to the caller (always false in this case). 241 */ 242 @Override 243 @Inline 244 public boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset, 245 ObjectReference dst, Offset dstOffset, int bytes) { 246 if (RCHeader.logRequired(dst)) { 247 coalescingWriteBarrierSlow(dst); 248 } 249 return false; 250 } 251 252 /** 253 * Slow path of the coalescing write barrier. 254 * 255 * <p> Attempt to log the source object. If successful in racing for 256 * the log bit, push an entry into the modified buffer and add a 257 * decrement buffer entry for each referent object (in the RC space) 258 * before setting the header bit to indicate that it has finished 259 * logging (allowing others in the race to continue). 260 * 261 * @param srcObj The object being mutated 262 */ 263 @NoInline 264 private void coalescingWriteBarrierSlow(ObjectReference srcObj) { 265 if (RCHeader.attemptToLog(srcObj)) { 266 modBuffer.push(srcObj); 267 decBuffer.processChildren(srcObj); 268 RCHeader.makeLogged(srcObj); 269 } 270 } 271 272 /**************************************************************************** 273 * 274 * Miscellaneous 275 */ 276 277 /** @return The active global plan as an <code>RC</code> instance. */ 278 @Inline 279 private static RCBase global() { 280 return (RCBase) VM.activePlan.global(); 281 } 282}