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