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