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.utility;
014
015import org.mmtk.utility.gcspy.drivers.TreadmillDriver;
016
017import org.vmmagic.unboxed.*;
018import org.vmmagic.pragma.*;
019
020/**
021 * FIXME The DoublyLinkedList class, upon which this depends, must be
022 * re-written as it makes the assumption that the implementation
023 * language (Java) and the language being implemented are the same.
024 * This is true in the case of Jikes RVM, but it is not true for any
025 * VM implementing a language other than Java.<p>
026 *
027 * Each instance of this class is a doubly-linked list, in which
028 * each item or node is a piece of memory.  The first two words of each node
029 * contains the forward and backward links.  The third word contains
030 * the treadmill.  The remaining portion is the payload.<p>
031 *
032 * The treadmill object itself must not be moved.<p>
033 *
034 * Access to the instances may be synchronized depending on the constructor argument.
035 */
036@Uninterruptible
037public final class Treadmill {
038
039  /****************************************************************************
040   *
041   * Instance variables
042   */
043
044  /**
045   *
046   */
047  private DoublyLinkedList fromSpace;
048  private DoublyLinkedList toSpace;
049  private DoublyLinkedList collectNursery;
050  private DoublyLinkedList allocNursery;
051
052  /****************************************************************************
053   *
054   * Initialization
055   */
056
057  /**
058   * @param granularity TODO needs documentation
059   * @param shared <code>true</code> if the created instance will be shared between threads. If it is shared, accesses will be synchronized using locks.
060   */
061  public Treadmill(int granularity, boolean shared) {
062    fromSpace = new DoublyLinkedList(granularity, shared);
063    toSpace = new DoublyLinkedList(granularity, shared);
064    allocNursery = new DoublyLinkedList(granularity, shared);
065    collectNursery = new DoublyLinkedList(granularity, shared);
066  }
067
068  /**
069   * Adds a node to the treadmill. This is usually performed on allocation.
070   *
071   * @param node the node to add
072   * @param nursery whether to add to the nursery or to the to-space
073   */
074  @Inline
075  public void addToTreadmill(Address node, boolean nursery) {
076    if (nursery)
077      allocNursery.add(node);
078    else
079      toSpace.add(node);
080  }
081
082  /**
083   * Removes a node from the nursery list.
084   *
085   * @return the removed node
086   */
087  @Inline
088  public Address popNursery() {
089    return collectNursery.pop();
090  }
091
092  /**
093   * Removes a node from the mature list.
094   *
095   * @return the removed node
096   */
097  @Inline
098  public Address pop() {
099    return fromSpace.pop();
100  }
101
102  /**
103   * Copies a node (during gc tracing).
104   *
105   * @param node the node to copy
106   * @param isInNursery whether the node is in the nursery or the
107   *  from-space
108   */
109  @Inline
110  public void copy(Address node, boolean isInNursery) {
111    if (isInNursery) {
112      collectNursery.remove(node);
113    } else {
114      fromSpace.remove(node);
115    }
116    toSpace.add(node);
117  }
118
119  /**
120   * @return whether the to-space is empty
121   */
122  @Inline
123  public boolean toSpaceEmpty() {
124    return toSpace.isEmpty();
125  }
126
127  /**
128   * @return whether the from-space is empty
129   */
130  @Inline
131  public boolean fromSpaceEmpty() {
132    return fromSpace.isEmpty();
133  }
134
135  /**
136   * @return whether the nursery is empty
137   */
138  @Inline
139  public boolean nurseryEmpty() {
140    return collectNursery.isEmpty();
141  }
142
143  /**
144   * Flips the roles of the spaces in preparation for a collection.
145   *
146   * @param fullHeap whether the collection is full heap
147   */
148  public void flip(boolean fullHeap) {
149    DoublyLinkedList tmp = allocNursery;
150    allocNursery = collectNursery;
151    collectNursery = tmp;
152    if (fullHeap) {
153      tmp = fromSpace;
154      fromSpace = toSpace;
155      toSpace = tmp;
156    }
157  }
158
159  /****************************************************************************
160   *
161   * Misc header manipulation
162   */
163
164  /**
165   * @return the header size
166   */
167  @Inline
168  public static int headerSize() {
169    return DoublyLinkedList.headerSize();
170  }
171
172  @Inline
173  public static Address nodeToPayload(Address payload) {
174    return DoublyLinkedList.nodeToPayload(payload);
175  }
176
177  @Inline
178  public static Address midPayloadToNode(Address payload) {
179    return DoublyLinkedList.midPayloadToNode(payload);
180  }
181
182  /****************************************************************************
183   *
184   * GCSpy
185   */
186
187  /**
188   * Gather data for GCSpy from the nursery
189   * @param event the gc event
190   * @param tmDriver the GCSpy space driver
191   */
192  public void gcspyGatherData(int event, TreadmillDriver tmDriver) {
193    this.allocNursery.gcspyGatherData(tmDriver);
194  }
195
196  /**
197   * Gather data for GCSpy
198   * @param event the gc event
199   * @param tmDriver the GCSpy space driver
200   * @param tospace gather from tospace?
201   */
202  public void gcspyGatherData(int event, TreadmillDriver tmDriver, boolean tospace) {
203    if (tospace)
204      toSpace.gcspyGatherData(tmDriver);
205    else
206      fromSpace.gcspyGatherData(tmDriver);
207  }
208}