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.semispace.gcspy;
014
015import org.mmtk.plan.Phase;
016import org.mmtk.plan.semispace.SSMutator;
017import org.mmtk.policy.CopySpace;
018import org.mmtk.policy.Space;
019import org.mmtk.policy.ImmortalLocal;
020import org.mmtk.utility.Log;
021import org.mmtk.utility.alloc.BumpPointer;
022import org.mmtk.utility.alloc.Allocator;
023import org.mmtk.utility.gcspy.GCspy;
024import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
025
026import org.vmmagic.pragma.*;
027import org.vmmagic.unboxed.*;
028
029/**
030 * This class implements <i>per-mutator thread</i> behavior and state for the
031 * <i>SSGCspy</i> plan.
032 *
033 * See {@link SSGCspy} for an overview of the GC-spy mechanisms.
034 *
035 * @see SSMutator
036 * @see SSGCspy
037 * @see SSGCspyCollector
038 * @see org.mmtk.plan.StopTheWorldMutator
039 * @see org.mmtk.plan.MutatorContext
040 */
041@Uninterruptible public class SSGCspyMutator extends SSMutator {
042
043  /*****************************************************************************
044   * Instance fields
045   */
046
047  /**
048   *
049   */
050  private static final boolean DEBUG = false;
051
052  private static final boolean LOS_TOSPACE = true;    // gather from tospace
053  private static final boolean LOS_FROMSPACE = false; // gather from fromspace
054
055  /** Per-mutator allocator into GCspy's space */
056  private final BumpPointer gcspy = new ImmortalLocal(SSGCspy.gcspySpace);
057
058
059
060  /*****************************************************************************
061   *
062   * Mutator-time allocation
063   */
064
065  /**
066   * {@inheritDoc}
067   */
068  @Override
069  @Inline
070  public Address alloc(int bytes, int align, int offset, int allocator, int site) {
071    if (allocator == SSGCspy.ALLOC_GCSPY)
072      return gcspy.alloc(bytes, align, offset);
073    else
074      return super.alloc(bytes, align, offset, allocator, site);
075  }
076
077  @Override
078  @Inline
079  public void postAlloc(ObjectReference object, ObjectReference typeRef,
080                        int bytes, int allocator) {
081    if (allocator == SSGCspy.ALLOC_GCSPY)
082      SSGCspy.gcspySpace.initializeHeader(object);
083    else
084      super.postAlloc(object, typeRef, bytes, allocator);
085  }
086
087  @Override
088  public Allocator getAllocatorFromSpace(Space space) {
089    if (space == SSGCspy.gcspySpace) return gcspy;
090    return super.getAllocatorFromSpace(space);
091  }
092
093  /*****************************************************************************
094   *
095   * Collection
096   */
097
098  /**
099   * Perform a per-mutator collection phase.
100   * Before a collection, we need to discover
101   * <ul>
102   * <li>the tospace objects copied by the collector in the last GC cycle
103   * <li>the ojects allocated since by the mutator.
104   * <li>all immortal objects allocated by the mutator
105   * <li>all large objects allocated by the mutator
106   * </ul>
107   * After the semispace has been copied, we need to discover
108   * <ul>
109   * <li>the tospace objects copied by the collector
110   * <li>all immortal objects allocated by the mutator
111   * <li>all large objects allocated by the mutator
112   * </ul>
113   */
114  @Override
115  @Inline
116  public final void collectionPhase(short phaseId, boolean primary) {
117    if (DEBUG) {
118      Log.write("--Phase Mutator.");
119      Log.writeln(Phase.getName(phaseId));
120    }
121
122    // TODO do we need to worry any longer about primary??
123    if (phaseId == SSGCspy.PREPARE) {
124      //if (primary)
125        gcspyGatherData(SSGCspy.BEFORE_COLLECTION);
126      super.collectionPhase(phaseId, primary);
127      return;
128    }
129
130    if (phaseId == SSGCspy.RELEASE) {
131      //if (primary)
132        gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
133      super.collectionPhase(phaseId, primary);
134      //if (primary)
135        gcspyGatherData(SSGCspy.AFTER_COLLECTION);
136      return;
137    }
138
139    super.collectionPhase(phaseId, primary);
140  }
141
142  /**
143   * Gather data for GCspy for the semispaces, the immortal space and the large
144   * object space.
145   * <p>
146   * This method sweeps the semispace under consideration to gather data.
147   * Alternatively and more efficiently, 'used space' can obviously be
148   * discovered in constant time simply by comparing the start and the end
149   * addresses of the semispace. However, per-object information can only be
150   * gathered by sweeping through the space and we do this here for tutorial
151   * purposes.
152   *
153   * @param event
154   *          The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
155   *          AFTER_COLLECTION
156   */
157  private void gcspyGatherData(int event) {
158    if (DEBUG) {
159      Log.writeln("SSGCspyMutator.gcspyGatherData, event=", event);
160      Log.writeln("SSGCspyMutator.gcspyGatherData, port=", GCspy.getGCspyPort());
161    }
162
163    // If port = 0 there can be no GCspy client connected
164    if (GCspy.getGCspyPort() == 0)
165      return;
166
167    // If the server is connected to a client that is interested in this
168    // event, then we gather data. But first we start a timer to
169    // compensate for the time spent gathering data here.
170    if (GCspy.server.isConnected(event)) {
171
172      if (DEBUG) {
173        if (SSGCspy.hi)
174          Log.write("\nMutator Examining Lowspace (event ", event);
175        else
176          Log.write("\nMutator Examining Highspace (event ", event);
177        Log.write(")");
178        SSGCspy.reportSpaces(); Log.writeln();
179      }
180
181      if (event == SSGCspy.BEFORE_COLLECTION) {
182        // Before the flip
183        // Mutator has not rebound toSpace yet
184        GCspy.server.startCompensationTimer();
185
186        // -- Handle the semispaces
187        // Here I need to scan newly allocated objects
188        if (DEBUG) {
189          //debugSpaces(SSGCspy.fromSpace());
190          debugSpaces(SSGCspy.toSpace());
191          Log.write("SSGCspyMutator.gcspyGatherData reset, gather and transmit driver ");
192          //Log.writeln(SSGCspy.fromSpace().getName());
193          Log.writeln(SSGCspy.toSpace().getName());
194        }
195        //ss.gcspyGatherData(fromSpaceDriver(), SSGCspy.fromSpace());
196        ss.gcspyGatherData(toSpaceDriver(), SSGCspy.toSpace());
197
198        // -- Handle the immortal space --
199        gatherImmortal(event);
200
201        // -- Handle the LOSes
202
203        // reset, collect and scan los data for the nursery and tospace
204        SSGCspy.losNurseryDriver.resetData();
205        los.gcspyGatherData(event, SSGCspy.losNurseryDriver);
206        SSGCspy.losDriver.resetData();
207        los.gcspyGatherData(event, SSGCspy.losDriver, LOS_TOSPACE);
208
209        // transmit the data
210        GCspy.server.stopCompensationTimer();
211        //fromSpaceDriver().transmit(event);
212        toSpaceDriver().transmit(event);
213        SSGCspy.immortalDriver.transmit(event);
214        SSGCspy.losNurseryDriver.transmit(event);
215        SSGCspy.losDriver.transmit(event);
216        SSGCspy.plosNurseryDriver.transmit(event);
217        SSGCspy.plosDriver.transmit(event);
218
219        // As this follows Collector.gcspyGatherData, I'll safepoint here
220        // This is a safepoint for the server, i.e. it is a point at which
221        // the server can pause.
222        GCspy.server.serverSafepoint(event);
223      } else if (event == SSGCspy.SEMISPACE_COPIED) {
224        // We have flipped
225        // toSpace still has not been rebound
226
227        // -- Handle the semispaces
228        if (DEBUG) {
229          //debugSpaces(SSGCspy.toSpace());
230          debugSpaces(SSGCspy.fromSpace());
231          Log.writeln("SSGCspyMutator.gcspyGatherData: do nothing");
232        }
233
234        // -- Handle the immortal space --
235        GCspy.server.startCompensationTimer();
236        gatherImmortal(event);
237
238        // reset, scan and send the los for the nursery and tospace
239        // and fromspace as well if full heap collection
240        SSGCspy.losNurseryDriver.resetData();
241        los.gcspyGatherData(event, SSGCspy.losNurseryDriver);
242        SSGCspy.losDriver.resetData();
243        los.gcspyGatherData(event, SSGCspy.losDriver, LOS_FROMSPACE);
244        los.gcspyGatherData(event, SSGCspy.losDriver, LOS_TOSPACE);
245
246        // transmit
247        GCspy.server.stopCompensationTimer();
248        SSGCspy.immortalDriver.transmit(event);
249        SSGCspy.losNurseryDriver.transmit(event);
250        SSGCspy.losDriver.transmit(event);
251        SSGCspy.plosNurseryDriver.transmit(event);
252        SSGCspy.plosDriver.transmit(event);
253
254        // As this follows Collector.gcspyGatherData, I'll safepoint here
255        // This is a safepoint for the server, i.e. it is a point at which
256        // the server can pause.
257        GCspy.server.serverSafepoint(event);
258      } else if (event == SSGCspy.AFTER_COLLECTION) {
259        // We have flipped
260        // And toSpace has been rebound
261
262        GCspy.server.startCompensationTimer();
263
264        // -- Handle the semispaces
265        if (DEBUG) debugSpaces(SSGCspy.toSpace());
266
267        // -- Handle the immortal space --
268        gatherImmortal(event);
269
270        // -- Handle the LOSes
271
272        // reset, scan and send the los
273        SSGCspy.losNurseryDriver.resetData();
274        SSGCspy.losDriver.resetData();
275        // no need to scan empty nursery
276        los.gcspyGatherData(event, SSGCspy.losDriver, LOS_TOSPACE);
277
278        //transmit
279        GCspy.server.stopCompensationTimer();
280        SSGCspy.immortalDriver.transmit(event);
281        SSGCspy.losNurseryDriver.transmit(event);
282        SSGCspy.losDriver.transmit(event);
283        SSGCspy.plosNurseryDriver.transmit(event);
284        SSGCspy.plosDriver.transmit(event);
285
286        // Reset fromspace
287        if (DEBUG) {
288          Log.write("SSGCspyMutator.gcspyGatherData: reset and zero range for driver ");
289          Log.write(SSGCspy.toSpace().getName());
290        }
291      }
292
293    }
294    // else Log.write("not transmitting...");
295  }
296
297  /**
298   * Gather data for the immortal space
299   * @param event
300   * The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
301   *          AFTER_COLLECTION
302   */
303  private void gatherImmortal(int event) {
304    // We want to do this at every GCspy event
305    if (DEBUG) {
306      Log.write("SSGCspyMutator.gcspyGatherData: gather data for immortal space ");
307      Log.write(SSGCspy.immortalSpace.getStart()); Log.writeln("-",immortal.getCursor());
308    }
309    SSGCspy.immortalDriver.resetData();
310    immortal.gcspyGatherData(SSGCspy.immortalDriver);
311    if (DEBUG) Log.writeln("Finished immortal space.");
312  }
313
314  /**
315   * Debugging info for the semispaces
316   * @param scannedSpace the space to output debug for.
317   */
318  private void debugSpaces(CopySpace scannedSpace) {
319    Log.write("SSGCspyMutator.gcspyGatherData: gather data for active semispace ");
320    Log.write(scannedSpace.getStart()); Log.write("-",ss.getCursor()); Log.flush();
321    Log.write(". The space is: "); Log.writeln(ss.getSpace().getName());
322    Log.write("scannedSpace is "); Log.writeln(scannedSpace.getName());
323    Log.write("The range is "); Log.write(ss.getSpace().getStart());
324    Log.write(" to "); Log.writeln(ss.getCursor());
325    SSGCspy.reportSpaces();
326  }
327
328  /** @return the driver for toSpace */
329  private LinearSpaceDriver toSpaceDriver() {
330    return SSGCspy.hi ? SSGCspy.ss1Driver : SSGCspy.ss0Driver;
331  }
332
333}