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.<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
037    public final class Treadmill implements Constants {
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
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       */
062      public Treadmill(int granularity, boolean shared) {
063        fromSpace = new DoublyLinkedList(granularity, shared);
064        toSpace = new DoublyLinkedList(granularity, shared);
065        allocNursery = new DoublyLinkedList(granularity, shared);
066        collectNursery = new DoublyLinkedList(granularity, shared);
067      }
068    
069      /**
070       * Add a node to the treadmill. This is usually performed on allocation.
071       */
072      @Inline
073      public void addToTreadmill(Address node, boolean nursery) {
074        if (nursery)
075          allocNursery.add(node);
076        else
077          toSpace.add(node);
078      }
079    
080      /**
081       * Remove a node from the nursery list.
082       */
083      @Inline
084      public Address popNursery() {
085        return collectNursery.pop();
086      }
087    
088      /**
089       * Remove a node from the mature list.
090       */
091      @Inline
092      public Address pop() {
093        return fromSpace.pop();
094      }
095    
096      /**
097       * Copy a node (during gc tracing).
098       */
099      @Inline
100      public void copy(Address node, boolean isInNursery) {
101        if (isInNursery) {
102          collectNursery.remove(node);
103        } else {
104          fromSpace.remove(node);
105        }
106        toSpace.add(node);
107      }
108    
109      /**
110       * Is the to-space empty?
111       */
112      @Inline
113      public boolean toSpaceEmpty() {
114        return toSpace.isEmpty();
115      }
116    
117      /**
118       * Is the from-space empty?
119       */
120      @Inline
121      public boolean fromSpaceEmpty() {
122        return fromSpace.isEmpty();
123      }
124    
125      /**
126       * Is the nursery empty?
127       */
128      @Inline
129      public boolean nurseryEmpty() {
130        return collectNursery.isEmpty();
131      }
132    
133      /**
134       * Flip the roles of the spaces in preparation for a collection.
135       */
136      public void flip(boolean fullHeap) {
137        DoublyLinkedList tmp = allocNursery;
138        allocNursery = collectNursery;
139        collectNursery = tmp;
140        if (fullHeap) {
141          tmp = fromSpace;
142          fromSpace = toSpace;
143          toSpace = tmp;
144        }
145      }
146    
147      /****************************************************************************
148       *
149       * Misc header manipulation
150       */
151    
152      /**
153       *
154       */
155      @Inline
156      public static int headerSize() {
157        return DoublyLinkedList.headerSize();
158      }
159    
160      @Inline
161      public static Address nodeToPayload(Address payload) {
162        return DoublyLinkedList.nodeToPayload(payload);
163      }
164    
165      @Inline
166      public static Address midPayloadToNode(Address payload) {
167        return DoublyLinkedList.midPayloadToNode(payload);
168      }
169    
170      /****************************************************************************
171       *
172       * GCSpy
173       */
174    
175      /**
176       * Gather data for GCSpy from the nursery
177       * @param event the gc event
178       * @param tmDriver the GCSpy space driver
179       */
180      public void gcspyGatherData(int event, TreadmillDriver tmDriver) {
181        this.allocNursery.gcspyGatherData(tmDriver);
182      }
183    
184      /**
185       * Gather data for GCSpy
186       * @param event the gc event
187       * @param tmDriver the GCSpy space driver
188       * @param tospace gather from tospace?
189       */
190      public void gcspyGatherData(int event, TreadmillDriver tmDriver, boolean tospace) {
191        if (tospace)
192          toSpace.gcspyGatherData(tmDriver);
193        else
194          fromSpace.gcspyGatherData(tmDriver);
195      }
196    }