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.stickyms;
014
015 import org.mmtk.plan.*;
016 import org.mmtk.plan.marksweep.MSMutator;
017 import org.mmtk.policy.MarkSweepLocal;
018
019 import org.mmtk.utility.HeaderByte;
020 import org.mmtk.utility.deque.ObjectReferenceDeque;
021 import org.mmtk.vm.VM;
022
023 import org.vmmagic.pragma.*;
024 import 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
041 public class StickyMSMutator extends MSMutator {
042
043 /****************************************************************************
044 * Instance fields
045 */
046
047 /**
048 *
049 */
050 private 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 }