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