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.gcspy;
014
015import org.mmtk.utility.Log;
016import org.mmtk.vm.gcspy.Util;
017
018import org.vmmagic.unboxed.*;
019import org.vmmagic.pragma.*;
020
021
022
023/**
024 * This class is an abstraction of a contiguous region of a Space.  For
025 * example, a semispace collector might choose to model the heap as a
026 * single Space, but within that Space it could model each semispace by
027 * a Subspace.<p>
028 * Subspace provides a number of useful facilities to many drivers, and
029 * is useful even if the Space comprises just a single contiguous region.<p>
030 *
031 * A subspace keeps track of the start and end address of the region,
032 * the index of its first block, the size of the blocks in this space,
033 * and the number of blocks in this subspace.
034 */
035@Uninterruptible public class Subspace {
036
037  /** start address of the subspace. A subspace spans the address
038   *  range <code>[start_, end_)</code> **/
039  private Address start_;
040  /** end address of the subspace. A subspace spans the address
041   *  range <code>[start_, end_)</code> **/
042  private Address end_;
043  /** The index of the block in which {@code start_} lies */
044  private int firstIndex_;
045  /** the block size */
046  private int blockSize_;
047  /** the number of blocks in this space */
048  private int blockNum_;
049
050  private static final boolean DEBUG = false;
051
052  /**
053   * Create a new subspace
054   *
055   * @param start The address of the start of the subspace
056   * @param end The address of the end of the subspace
057   * @param firstIndex The index of the first block of the subspace
058   * @param blockSize The size of blocks in this space
059   * @param blockNum The number of blocks in this subspace
060   */
061  public Subspace(Address start,
062                  Address end,
063                  int firstIndex,
064                  int blockSize,
065                  int blockNum) {
066    reset(start, end, firstIndex, blockSize, blockNum);
067  }
068
069
070  //------------------Methods to reset a subspace----------------------
071
072  /**
073   * Reset a subspace.
074   *
075   * @param start The address of the start of the subspace
076   * @param end The address of the end of the subspace
077   * @param firstIndex The index of the first block of the subspace
078   * @param blockSize The size of blocks in this subspace
079   * @param blockNum The number of blocks in this subspace
080   */
081  private void reset(Address start,
082                     Address end,
083                     int firstIndex,
084                     int blockSize,
085                     int blockNum) {
086    //TODO sanity check on addresses and block size and number
087    reset(start, end, firstIndex, blockNum);
088    blockSize_ = blockSize;
089
090    if (DEBUG) dump();
091  }
092
093  /**
094   * Reset a new subspace
095   *
096   * @param start The address of the start of the subspace
097   * @param end The address of the end of the subspace
098   * @param firstIndex The index of the first block of the subspace
099   * @param blockNum The number of blocks in this subspace
100   */
101  public void reset(Address start,
102                    Address end,
103                    int firstIndex,
104                    int blockNum) {
105    start_ = start;
106    end_ = end;
107    firstIndex_ = firstIndex;
108    blockNum_ = blockNum;
109  }
110
111  /**
112   * Reset a new subspace.
113   *
114   * @param start The address of the start of the subspace
115   * @param end The address of the end of the subspace
116   * @param blockNum The number of blocks in this subspace
117   */
118  public void reset(Address start, Address end, int blockNum) {
119    start_ = start;
120    end_ = end;
121    blockNum_ = blockNum;
122  }
123
124  /**
125   * Reset a new subspace.
126   *
127   * @param firstIndex The index of the first block of the subspace
128   * @param blockNum The number of blocks in this subspace
129   */
130  public void reset(int firstIndex, int blockNum) {
131    firstIndex_ = firstIndex;
132    blockNum_ = blockNum;
133  }
134
135
136  //----------------Facilities to query a subspace-----------------
137
138  /**
139   * Is an index in the range of this subspace?
140   *
141   * @param index The index of the block
142   * @return {@code true} if this block lies in this subspace
143   */
144  public boolean indexInRange(int index) {
145    return index >= firstIndex_ &&
146           index < firstIndex_ + blockNum_;
147  }
148
149  /**
150   * Is address in the range of this subspace?
151   *
152   * @param addr An address
153   * @return {@code true} if this address is in a block in this subspace
154   */
155  public boolean addressInRange(Address addr) {
156    return addr.GE(start_) && addr.LT(end_);
157  }
158
159
160  /**
161   * Get the block index from an address
162   *
163   * @param addr The address
164   * @return The index of the block holding this address
165   */
166  public int getIndex(Address addr) {
167    if (DEBUG) {
168      Log.write("start_ ", start_);
169      Log.write(" end_ ", end_);
170      Log.write(" blockSize_ ", blockSize_);
171      Log.write(" firstIndex_ ", firstIndex_);
172      Log.write(" + ", addr.diff(start_).toInt() / blockSize_);
173      Log.writeln(" addr ", addr);
174    }
175    return firstIndex_ + addr.diff(start_).toInt() / blockSize_;
176  }
177
178  /**
179   * Get the address of start of block from its index
180   *
181   * @param index The index of the block
182   * @return The address of the start of the block
183   */
184  public Address getAddress(int index) {
185    return start_.plus(index - firstIndex_ * blockSize_);
186  }
187
188  //--------------Accessors-------------------------
189
190  /**
191   * Get the start of the subspace
192   * @return The start of this subspace
193   */
194  public Address getStart() {
195    return start_;
196  }
197
198  /**
199   * Get the end of this subspace
200   * @return The address of the end of this subspace
201   */
202  public Address getEnd() {
203    return end_;
204  }
205
206  /**
207   * Get the first index of subspace
208   * @return the firstIndex of this subspace
209   */
210  public int getFirstIndex() {
211    return firstIndex_;
212  }
213
214  /**
215   * Get the blocksize for this subspace
216   * @return The size of a tile
217   */
218  public int getBlockSize() {
219    return blockSize_;
220  }
221
222  /**
223   * Get the number of tiles in this subspace
224   * @return The number of tiles in this subspace
225   */
226  public int getBlockNum() {
227    return blockNum_;
228  }
229
230  /**
231   * Calculate the space remaining in a block after this address
232   *
233   * @param addr the Address
234   * @return the remainder
235   */
236  public int spaceRemaining(Address addr) {
237    int nextIndex = getIndex(addr) + 1;
238    Address nextTile = start_.plus(blockSize_ * (nextIndex - firstIndex_));
239    return nextTile.diff(addr).toInt();
240  }
241
242  /**
243   * Dump a representation of the subspace
244   */
245  private void dump() {
246    Log.write("GCspy Subspace: ");
247    Util.dumpRange(start_, end_);
248    Log.writeln("\n  -- firstIndex=", firstIndex_);
249    Log.writeln("  -- blockNum=", blockNum_);
250  }
251}
252
253