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.utility;
014    
015    import org.mmtk.utility.gcspy.drivers.TreadmillDriver;
016    
017    import org.vmmagic.unboxed.*;
018    import 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.
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.
031     *
032     * The treadmill object itself must not be moved.
033     *
034     * Access to the instances may be synchronized depending on the constructor argument.
035     */
036    @Uninterruptible
037    public final class Treadmill implements Constants {
038    
039      /****************************************************************************
040       *
041       * Instance variables
042       */
043      private DoublyLinkedList fromSpace;
044      private DoublyLinkedList toSpace;
045      private DoublyLinkedList collectNursery;
046      private DoublyLinkedList allocNursery;
047    
048      /****************************************************************************
049       *
050       * Initialization
051       */
052    
053      /**
054       * Constructor
055       */
056      public Treadmill(int granularity, boolean shared) {
057        fromSpace = new DoublyLinkedList(granularity, shared);
058        toSpace = new DoublyLinkedList(granularity, shared);
059        allocNursery = new DoublyLinkedList(granularity, shared);
060        collectNursery = new DoublyLinkedList(granularity, shared);
061      }
062    
063      /**
064       * Add a node to the treadmill. This is usually performed on allocation.
065       */
066      @Inline
067      public void addToTreadmill(Address node, boolean nursery) {
068        if (nursery)
069          allocNursery.add(node);
070        else
071          toSpace.add(node);
072      }
073    
074      /**
075       * Remove a node from the nursery list.
076       */
077      @Inline
078      public Address popNursery() {
079        return collectNursery.pop();
080      }
081    
082      /**
083       * Remove a node from the mature list.
084       */
085      @Inline
086      public Address pop() {
087        return fromSpace.pop();
088      }
089    
090      /**
091       * Copy a node (during gc tracing).
092       */
093      @Inline
094      public void copy(Address node, boolean isInNursery) {
095        if (isInNursery) {
096          collectNursery.remove(node);
097        } else {
098          fromSpace.remove(node);
099        }
100        toSpace.add(node);
101      }
102    
103      /**
104       * Is the to-space empty?
105       */
106      @Inline
107      public boolean toSpaceEmpty() {
108        return toSpace.isEmpty();
109      }
110    
111      /**
112       * Is the from-space empty?
113       */
114      @Inline
115      public boolean fromSpaceEmpty() {
116        return fromSpace.isEmpty();
117      }
118    
119      /**
120       * Is the nursery empty?
121       */
122      @Inline
123      public boolean nurseryEmpty() {
124        return collectNursery.isEmpty();
125      }
126    
127      /**
128       * Flip the roles of the spaces in preparation for a collection.
129       */
130      public void flip(boolean fullHeap) {
131        DoublyLinkedList tmp = allocNursery;
132        allocNursery = collectNursery;
133        collectNursery = tmp;
134        if (fullHeap) {
135          tmp = fromSpace;
136          fromSpace = toSpace;
137          toSpace = tmp;
138        }
139      }
140    
141      /****************************************************************************
142       *
143       * Misc header manipulation
144       */
145    
146      @Inline
147      public static int headerSize() {
148        return DoublyLinkedList.headerSize();
149      }
150    
151      @Inline
152      public static Address nodeToPayload(Address payload) {
153        return DoublyLinkedList.nodeToPayload(payload);
154      }
155    
156      @Inline
157      public static Address midPayloadToNode(Address payload) {
158        return DoublyLinkedList.midPayloadToNode(payload);
159      }
160    
161      /****************************************************************************
162       *
163       * GCSpy
164       */
165    
166      /**
167       * Gather data for GCSpy from the nursery
168       * @param event the gc event
169       * @param tmDriver the GCSpy space driver
170       */
171      public void gcspyGatherData(int event, TreadmillDriver tmDriver) {
172        this.allocNursery.gcspyGatherData(tmDriver);
173      }
174    
175      /**
176       * Gather data for GCSpy
177       * @param event the gc event
178       * @param tmDriver the GCSpy space driver
179       * @param tospace gather from tospace?
180       */
181      public void gcspyGatherData(int event, TreadmillDriver tmDriver, boolean tospace) {
182        if (tospace)
183          toSpace.gcspyGatherData(tmDriver);
184        else
185          fromSpace.gcspyGatherData(tmDriver);
186      }
187    }