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.gctrace;
014
015import org.mmtk.plan.semispace.*;
016import org.mmtk.policy.RawPageSpace;
017import org.mmtk.policy.Space;
018import org.mmtk.utility.deque.SortTODSharedDeque;
019import org.mmtk.utility.heap.VMRequest;
020import org.mmtk.utility.TraceGenerator;
021import org.mmtk.utility.options.Options;
022
023import org.mmtk.vm.VM;
024
025import 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-&gt;[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 * &amp; 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.discontiguous());
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}