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.stickyms; 014 015import org.mmtk.plan.*; 016import org.mmtk.plan.marksweep.MSMutator; 017import org.mmtk.policy.MarkSweepLocal; 018 019import org.mmtk.utility.HeaderByte; 020import org.mmtk.utility.deque.ObjectReferenceDeque; 021import org.mmtk.vm.VM; 022 023import org.vmmagic.pragma.*; 024import org.vmmagic.unboxed.*; 025 026/** 027 * This class implements <i>per-mutator thread</i> behavior 028 * and state for the <i>StickyMS</i> plan, which implements a 029 * generational mark-sweep collector.<p> 030 * 031 * Specifically, this class defines <i>MS</i> mutator-time allocation 032 * and per-mutator thread collection semantics (flushing and restoring 033 * per-mutator allocator state).<p> 034 * * 035 * @see StickyMS 036 * @see StickyMSCollector 037 * @see MutatorContext 038 * @see Phase 039 */ 040@Uninterruptible 041public class StickyMSMutator extends MSMutator { 042 043 /**************************************************************************** 044 * Instance fields 045 */ 046 047 /** 048 * 049 */ 050 private final ObjectReferenceDeque modBuffer; 051 052 /**************************************************************************** 053 * 054 * Initialization 055 */ 056 057 /** 058 * Constructor 059 */ 060 public StickyMSMutator() { 061 ms = new MarkSweepLocal(StickyMS.msSpace); 062 modBuffer = new ObjectReferenceDeque("mod buf", global().modPool); 063 } 064 065 /**************************************************************************** 066 * 067 * Barriers 068 */ 069 070 /** 071 * {@inheritDoc}<p> 072 * 073 * In this case, we remember the address of the source of the 074 * pointer if the new reference points into the nursery from 075 * non-nursery space. 076 */ 077 @Override 078 @Inline 079 public final void objectReferenceWrite(ObjectReference src, Address slot, 080 ObjectReference tgt, Word metaDataA, Word metaDataB, int mode) { 081 if (HeaderByte.isUnlogged(src)) 082 logSource(src); 083 VM.barriers.objectReferenceWrite(src, tgt, metaDataA, metaDataB, mode); 084 } 085 086 /** 087 * {@inheritDoc}<p> 088 * 089 * In this case, we remember the mutated source address range and 090 * will scan that address range at GC time. 091 */ 092 @Override 093 @Inline 094 public final boolean objectReferenceBulkCopy(ObjectReference src, Offset srcOffset, 095 ObjectReference dst, Offset dstOffset, int bytes) { 096 if (HeaderByte.isUnlogged(src)) 097 logSource(src); 098 return false; 099 } 100 101 @Override 102 @Inline 103 public boolean objectReferenceTryCompareAndSwap(ObjectReference src, Address slot, 104 ObjectReference old, ObjectReference tgt, Word metaDataA, 105 Word metaDataB, int mode) { 106 if (HeaderByte.isUnlogged(src)) 107 logSource(src); 108 return VM.barriers.objectReferenceTryCompareAndSwap(src,old,tgt,metaDataA,metaDataB,mode); 109 } 110 111 112 /** 113 * Add an object to the modified objects buffer and mark the 114 * object has having been logged. Since duplicate entries do 115 * not raise any correctness issues, we do <i>not</i> worry 116 * about synchronization and allow threads to race to log the 117 * object, potentially including it twice (unlike reference 118 * counting where duplicates would lead to incorrect reference 119 * counts). 120 * 121 * @param src The object to be logged 122 */ 123 private void logSource(ObjectReference src) { 124 HeaderByte.markAsLogged(src); 125 modBuffer.push(src); 126 } 127 128 @Override 129 public final void flushRememberedSets() { 130 modBuffer.flushLocal(); 131 assertRemsetFlushed(); 132 } 133 134 /** 135 * Assert that the remsets have been flushed. This is critical to 136 * correctness. We need to maintain the invariant that remset entries 137 * do not accrue during GC. If the host JVM generates barrier entires 138 * it is its own responsibility to ensure that they are flushed before 139 * returning to MMTk. 140 */ 141 public final void assertRemsetFlushed() { 142 if (VM.VERIFY_ASSERTIONS) { 143 VM.assertions._assert(modBuffer.isFlushed()); 144 } 145 } 146 147 148 /**************************************************************************** 149 * 150 * Collection 151 */ 152 153 /** 154 * {@inheritDoc} 155 */ 156 @Override 157 @Inline 158 public final void collectionPhase(short phaseId, boolean primary) { 159 if (phaseId == StickyMS.PREPARE) { 160 flushRememberedSets(); 161 } 162 if (phaseId == StickyMS.RELEASE) { 163 assertRemsetFlushed(); 164 } 165 166 if (!global().collectWholeHeap) { 167 if (phaseId == StickyMS.PREPARE) { 168 ms.prepare(); 169 return; 170 } 171 172 if (phaseId == StickyMS.RELEASE) { 173 ms.release(); 174 return; 175 } 176 } 177 178 super.collectionPhase(phaseId, primary); 179 } 180 181 182 @Override 183 public void flush() { 184 super.flush(); 185 ms.flush(); 186 } 187 188 /**************************************************************************** 189 * 190 * Miscellaneous 191 */ 192 193 /** @return The active global plan as an <code>MSGen</code> instance. */ 194 @Inline 195 private static StickyMS global() { 196 return (StickyMS) VM.activePlan.global(); 197 } 198}