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.gctrace;
014    
015    import org.mmtk.plan.semispace.*;
016    import org.mmtk.policy.RawPageSpace;
017    import org.mmtk.policy.Space;
018    import org.mmtk.utility.deque.SortTODSharedDeque;
019    import org.mmtk.utility.heap.VMRequest;
020    import org.mmtk.utility.TraceGenerator;
021    import org.mmtk.utility.options.Options;
022    
023    import org.mmtk.vm.VM;
024    
025    import org.vmmagic.pragma.*;
026    
027    /**
028     * This plan has been modified slightly to perform the processing necessary
029     * for GC trace generation.  To maximize performance, it attempts to remain
030     * as faithful as possible to semiSpace/Plan.java.
031     *
032     * The generated trace format is as follows:
033     * <pre>
034     *    B 345678 12
035     *      (Object 345678 was created in the boot image with a size of 12 bytes)
036     *    U 59843 234 47298
037     *      (Update object 59843 at the slot at offset 234 to refer to 47298)
038     *    S 1233 12345
039     *      (Update static slot 1233 to refer to 12345)
040     *    T 4567 78924
041     *      (The TIB of 4567 is set to refer to 78924)
042     *    D 342789
043     *      (Object 342789 became unreachable)
044     *    A 6860 24 346648 3
045     *      (Object 6860 was allocated, requiring 24 bytes, with fp 346648 on
046     *        thread 3; this allocation has perfect knowledge)
047     *    a 6884 24 346640 5
048     *      (Object 6864 was allocated, requiring 24 bytes, with fp 346640 on
049     * thread 5; this allocation DOES NOT have perfect knowledge)
050     *    I 6860 24 346648 3
051     *      (Object 6860 was allocated into immortal space, requiring 24 bytes,
052     *        with fp 346648 on thread 3; this allocation has perfect knowledge)
053     *    i 6884 24 346640 5
054     *      (Object 6864 was allocated into immortal space, requiring 24 bytes,
055     *        with fp 346640 on thread 5; this allocation DOES NOT have perfect
056     *        knowledge)
057     *    48954->[345]LObject;:blah()V:23   Ljava/lang/Foo;
058     *      (Citation for: a) where the was allocated, fp of 48954,
059     *         at the method with ID 345 -- or void Object.blah() -- and bytecode
060     *         with offset 23; b) the object allocated is of type java.lang.Foo)
061     *    D 342789 361460
062     *      (Object 342789 became unreachable after 361460 was allocated)
063     * </pre>
064     * This class implements a simple semi-space collector. See the Jones
065     * & Lins GC book, section 2.2 for an overview of the basic
066     * algorithm. This implementation also includes a large object space
067     * (LOS), and an uncollected "immortal" space.<p>
068     *
069     * All plans make a clear distinction between <i>global</i> and
070     * <i>thread-local</i> activities.  Global activities must be
071     * synchronized, whereas no synchronization is required for
072     * thread-local activities.  Instances of Plan map 1:1 to "kernel
073     * threads" (aka CPUs).  Thus instance
074     * methods allow fast, unsychronized access to Plan utilities such as
075     * allocation and collection.  Each instance rests on static resources
076     * (such as memory and virtual memory resources) which are "global"
077     * and therefore "static" members of Plan.  This mapping of threads to
078     * instances is crucial to understanding the correctness and
079     * performance proprties of this plan.
080     */
081    @Uninterruptible public class GCTrace extends SS {
082    
083      /****************************************************************************
084       *
085       * Class variables
086       */
087    
088      /* Spaces */
089    
090      /**
091       *
092       */
093      public static final RawPageSpace traceSpace = new RawPageSpace("trace", VMRequest.create());
094      public static final int TRACE = traceSpace.getDescriptor();
095    
096      /* GC state */
097      public static boolean lastGCWasTracing = false; // True when previous GC was for tracing
098      public static boolean traceInducedGC = false; // True if trace triggered GC
099      public static boolean deathScan = false;
100      public static boolean finalDead = false;
101    
102      /****************************************************************************
103       *
104       * Initialization
105       */
106    
107      /**
108       * Constructor
109       */
110      public GCTrace() {
111        SortTODSharedDeque workList = new SortTODSharedDeque("workList",traceSpace, 1);
112        SortTODSharedDeque traceBuf = new SortTODSharedDeque("traceBuf",traceSpace, 1);
113        workList.prepareNonBlocking();
114        traceBuf.prepareNonBlocking();
115        TraceGenerator.init(workList, traceBuf);
116      }
117    
118      @Override
119      @Interruptible
120      public void processOptions() {
121        super.processOptions();
122        Options.noFinalizer.setValue(true);
123      }
124    
125      /**
126       * The planExit method is called at RVM termination to allow the
127       * trace process to finish.
128       */
129      @Override
130      @Interruptible
131      public final void notifyExit(int value) {
132        super.notifyExit(value);
133        finalDead = true;
134        traceInducedGC = false;
135        deathScan = true;
136        TraceGenerator.notifyExit(value);
137      }
138    
139      @Override
140      public final boolean collectionRequired(boolean spaceFull, Space space) {
141        if (super.collectionRequired(spaceFull, space)) {
142          traceInducedGC = false;
143          return true;
144        }
145        return false;
146      }
147    
148      /****************************************************************************
149       *
150       * Collection
151       */
152    
153      /**
154       * {@inheritDoc}
155       */
156      @Override
157      public void collectionPhase(short phaseId) {
158        if (phaseId == PREPARE) {
159          lastGCWasTracing = traceInducedGC;
160        }
161        if (phaseId == RELEASE) {
162          if (traceInducedGC) {
163            /* Clean up following a trace-induced scan */
164            deathScan = false;
165          } else {
166            /* Finish the collection by calculating the unreachable times */
167            deathScan = true;
168            TraceGenerator.postCollection();
169            deathScan = false;
170            /* Perform the semispace collections. */
171            super.collectionPhase(phaseId);
172          }
173        } else if (!traceInducedGC ||
174                   (phaseId == INITIATE) ||
175                   (phaseId == PREPARE_STACKS) ||
176                   (phaseId == ROOTS) ||
177                   (phaseId == STACK_ROOTS) ||
178                   (phaseId == COMPLETE)) {
179          /* Performing normal GC; sponge off of parent's work. */
180          super.collectionPhase(phaseId);
181        }
182      }
183    
184    
185      /****************************************************************************
186       *
187       * Space management
188       */
189    
190      /**
191       * @return Since trace induced collections are not called to free up memory,
192       *         their failure to return memory isn't cause for concern.
193       */
194      public boolean isLastGCFull() {
195        return !lastGCWasTracing;
196      }
197    
198      /**
199       * @return the active Plan as a GCTrace
200       */
201      public static GCTrace global() {
202        return ((GCTrace) VM.activePlan.global());
203      }
204    }