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.SS;
017import org.mmtk.plan.semispace.SSCollector;
018import org.mmtk.policy.CopySpace;
019import org.mmtk.utility.Log;
020import org.mmtk.utility.gcspy.GCspy;
021import org.mmtk.utility.gcspy.drivers.LinearSpaceDriver;
022import org.mmtk.vm.VM;
023
024import org.vmmagic.unboxed.*;
025import org.vmmagic.pragma.*;
026
027/**
028 * This class implements <i>per-collector thread</i> behavior and state for the
029 * <i>SSGCspy</i> plan.<p>
030 *
031 * See {@link SSGCspy} for an overview of the GC-spy mechanisms.
032 *
033 * @see SSCollector
034 * @see SSGCspy
035 * @see SSGCspyMutator
036 * @see org.mmtk.plan.StopTheWorldCollector
037 * @see org.mmtk.plan.CollectorContext
038 * @see org.mmtk.plan.SimplePhase
039 */
040@Uninterruptible public class SSGCspyCollector extends SSCollector {
041
042  /****************************************************************************
043   *
044   * Initialization
045   */
046
047  /*****************************************************************************
048   * Instance fields
049   */
050
051  /**
052   *
053   */
054  private static final boolean DEBUG = false;
055
056  /**
057   * Constructor
058   */
059  public SSGCspyCollector() {
060    super(new SSGCspyTraceLocal(global().ssTrace));
061  }
062
063
064  /****************************************************************************
065   *
066   * Data gathering
067   */
068
069  /**
070   * Perform a (local) collection phase.
071   * Before a collection, we need to discover
072   * <ul>
073   * <li>the tospace objects copied by the collector in the last GC cycle
074   * <li>the semispace objects allocated since by the mutator.
075   * <li>all immortal objects allocated by the mutator
076   * <li>all large objects allocated by the mutator
077   * </ul>
078   * After the semispace has been copied, we need to discover
079   * <ul>
080   * <li>the tospace objects copied by the collector
081   * <li>all immortal objects allocated by the mutator
082   * <li>all large objects allocated by the mutator
083   * </ul>
084   */
085  @Override
086  @Inline
087  public final void collectionPhase(short phaseId, boolean primary) {
088    if (DEBUG) {
089      Log.write("--Phase Collector.");
090      Log.writeln(Phase.getName(phaseId));
091    }
092
093    //TODO do we need to worry any longer about primary??
094    if (phaseId == SS.PREPARE) {
095      //if (primary)
096        gcspyGatherData(SSGCspy.BEFORE_COLLECTION);
097      super.collectionPhase(phaseId, primary);
098      return;
099    }
100
101    if (phaseId == SS.FORWARD_FINALIZABLE) {
102      super.collectionPhase(phaseId, primary);
103      //if (primary)
104        gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
105      return;
106    }
107
108    if (phaseId == SS.RELEASE) {
109      //if (primary)
110        //gcspyGatherData(SSGCspy.SEMISPACE_COPIED);
111      super.collectionPhase(phaseId, primary);
112      //if (primary)
113        gcspyGatherData(SSGCspy.AFTER_COLLECTION);
114      return;
115    }
116
117    super.collectionPhase(phaseId, primary);
118  }
119
120  /**
121   * Gather data for GCspy for the semispaces only.
122   * <p>
123   * This method sweeps the semispace under consideration to gather data.
124   * Alternatively and more efficiently, 'used space' can obviously be
125   * discovered in constant time simply by comparing the start and the end
126   * addresses of the semispace. However, per-object information can only be
127   * gathered by sweeping through the space and we do this here for tutorial
128   * purposes.
129   *
130   * @param event
131   *          The event, either BEFORE_COLLECTION, SEMISPACE_COPIED or
132   *          AFTER_COLLECTION
133   */
134  private void gcspyGatherData(int event) {
135    if (DEBUG) {
136      Log.writeln("SSGCspyCollector.gcspyGatherData, event=", event);
137      Log.writeln("SSGCspyCollector.gcspyGatherData, port=", GCspy.getGCspyPort());
138    }
139
140    // If port = 0 there can be no GCspy client connected
141    if (GCspy.getGCspyPort() == 0)
142      return;
143
144    // If the server is connected to a client that is interested in this
145    // event, then we gather data. But first we start a timer to
146    // compensate for the time spent gathering data here.
147    if (GCspy.server.isConnected(event)) {
148
149      if (DEBUG) {
150        if (SSGCspy.hi)
151          Log.write("\nCollector Examining Lowspace (event ", event);
152        else
153          Log.write("\nCollector Examining Highspace (event ", event);
154        Log.write(")");
155        SSGCspy.reportSpaces(); Log.writeln();
156      }
157
158      if (event == SSGCspy.BEFORE_COLLECTION) {
159        if (DEBUG) debugSpaces(SSGCspy.fromSpace());
160
161        // Just send the old values again
162        if (DEBUG) {
163          Log.write("SSGCspyCollector.gcspyGatherData transmit driver, ");
164          Log.writeln(SSGCspy.fromSpace().getName());
165        }
166
167        fromSpaceDriver().transmit(event);
168        // Mutator.gcspyGatherData follows so leave safepoint to there.
169      } else if (event == SSGCspy.SEMISPACE_COPIED) {
170        if (DEBUG) debugSpaces(SSGCspy.toSpace());
171
172        // We need to reset, scan and send values for tospace
173        // We'll leave resetting fromspace to AFTER_COLLECTION
174        if (DEBUG) {
175          Log.write("SSGCspyCollector.gcspyGatherData reset, gather and transmit driver ");
176          Log.writeln(SSGCspy.toSpace().getName());
177        }
178
179        GCspy.server.startCompensationTimer();
180        toSpaceDriver().resetData();
181        ss.gcspyGatherData(toSpaceDriver(), SSGCspy.toSpace());
182        GCspy.server.stopCompensationTimer();
183        toSpaceDriver().transmit(event);
184
185        // We'll leave the safepoint to RELEASE
186      } else if (event == SSGCspy.AFTER_COLLECTION) {
187        if (DEBUG) {
188          Log.write("SSGCspyCollector.gcspyGatherData transmit toSpaceDriver, ");
189          Log.writeln(SSGCspy.toSpace().getName());
190          Log.write("SSGCspyCollector.gcspyGatherData reset fromSpaceDriver, ");
191          Log.writeln(SSGCspy.fromSpace().getName());
192        }
193
194        toSpaceDriver().transmit(event);
195
196        // Here we reset fromspace data
197        fromSpaceDriver().resetData();
198        Address start = SSGCspy.fromSpace().getStart();
199        fromSpaceDriver().setRange(start, start);
200        fromSpaceDriver().transmit(event);
201      }
202
203    }
204    // else Log.write("not transmitting...");
205  }
206
207  /**
208   * Prints some debugging info.
209   * @param scannedSpace the space that was scanned
210   */
211  private void debugSpaces(CopySpace scannedSpace) {
212    Log.write("SSGCspyCollector.gcspyGatherData: gather data for active semispace ");
213    Log.write(scannedSpace.getStart()); Log.write("-",ss.getCursor()); Log.flush();
214    Log.write(". The space is: "); Log.writeln(ss.getSpace().getName());
215    Log.write("scannedSpace is "); Log.writeln(scannedSpace.getName());
216    Log.write("The range is "); Log.write(ss.getSpace().getStart());
217    Log.write(" to "); Log.writeln(ss.getCursor());
218    SSGCspy.reportSpaces();
219  }
220
221  /**
222   * Reset all root streams.
223   */
224  void resetRootStreams() {
225    SSGCspy.ss0Driver.resetRootsStream();
226    SSGCspy.ss1Driver.resetRootsStream();
227    SSGCspy.immortalDriver.resetRootsStream();
228    SSGCspy.losNurseryDriver.resetRootsStream();
229    SSGCspy.losDriver.resetRootsStream();
230    SSGCspy.plosNurseryDriver.resetRootsStream();
231    SSGCspy.plosDriver.resetRootsStream();
232    ss.getCursor();
233  }
234
235  /**
236   * Pass a root to all drivers.<p>
237   * @param addr The Address of the object to be checked
238   */
239  protected void checkAllDriversForRootAddress(Address addr) {
240    if (addr.isZero())
241      return;
242
243    SSGCspy.ss0Driver.handleRoot(addr);
244    SSGCspy.ss1Driver.handleRoot(addr);
245    SSGCspy.immortalDriver.handleRoot(addr);
246    SSGCspy.losNurseryDriver.handleRoot(addr);
247    SSGCspy.losDriver.handleRoot(addr);
248    SSGCspy.plosNurseryDriver.handleRoot(addr);
249    SSGCspy.plosDriver.handleRoot(addr);
250  }
251
252  /****************************************************************************
253   *
254   * Miscellaneous
255   */
256
257  /** @return The active global plan as an <code>SSGCspy</code> instance. */
258  @Inline
259  private static SSGCspy global() {
260    return (SSGCspy) VM.activePlan.global();
261  }
262
263  /** @return the driver for toSpace */
264  private LinearSpaceDriver toSpaceDriver() {
265    return SSGCspy.hi ? SSGCspy.ss1Driver : SSGCspy.ss0Driver;
266  }
267
268  /** @return the driver for fromSpace */
269  private LinearSpaceDriver fromSpaceDriver() {
270    return SSGCspy.hi ? SSGCspy.ss0Driver : SSGCspy.ss1Driver;
271  }
272}