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.heap;
014
015import static org.mmtk.utility.Constants.BITS_IN_INT;
016
017import org.mmtk.policy.Space;
018
019import org.mmtk.vm.VM;
020
021import org.vmmagic.pragma.*;
022import org.vmmagic.unboxed.*;
023
024/**
025 * This class manages the encoding and decoding of space descriptors.<p>
026 *
027 * Space descriptors are integers that encode a space's mapping into
028 * virtual memory.  For discontiguous spaces, they indicate
029 * discontiguity and mapping must be done by consulting the space map.
030 * For contiguous spaces, the space's address range is encoded into
031 * the integer (using a fixed point notation).<p>
032 *
033 * The purpose of this class is to allow <code>static final int</code>
034 * space descriptors to exist for each space, which can then be used
035 * in tests to determine whether an object is in a space.  A good
036 * compiler can perform this decoding at compile time and produce
037 * optimal code for the test.
038 */
039@Uninterruptible public class SpaceDescriptor {
040
041  /****************************************************************************
042   *
043   * Class variables
044   */
045
046  /**
047   *
048   */
049  private static final int TYPE_BITS = 2;
050  private static final int TYPE_SHARED = 0;
051  private static final int TYPE_CONTIGUOUS = 1;
052  private static final int TYPE_CONTIGUOUS_HI = 3;
053  private static final int TYPE_MASK = (1 << TYPE_BITS) - 1;
054  private static final int SIZE_SHIFT = TYPE_BITS;
055  private static final int SIZE_BITS = 10;
056  private static final int SIZE_MASK = ((1 << SIZE_BITS) - 1) << SIZE_SHIFT;
057  private static final int EXPONENT_SHIFT = SIZE_SHIFT + SIZE_BITS;
058  private static final int EXPONENT_BITS = 5;
059  private static final int EXPONENT_MASK = ((1 << EXPONENT_BITS) - 1) << EXPONENT_SHIFT;
060  private static final int MANTISSA_SHIFT = EXPONENT_SHIFT + EXPONENT_BITS;
061  private static final int MANTISSA_BITS = 14;
062  private static final int BASE_EXPONENT = BITS_IN_INT - MANTISSA_BITS;
063
064  private static int discontiguousSpaceIndex = 0;
065  private static final int DISCONTIG_INDEX_INCREMENT = 1 << TYPE_BITS;
066
067  /****************************************************************************
068   *
069   * Descriptor creation
070   */
071
072  /**
073   * Create a descriptor for a <i>contiguous</i> space
074   *
075   * @param start The start address of the space
076   * @param end The end address of the space
077   * @return An integer descriptor encoding the region of virtual
078   * memory occupied by the space
079   */
080  public static int createDescriptor(Address start, Address end) {
081    int chunks = end.diff(start).toWord().rshl(Space.LOG_BYTES_IN_CHUNK).toInt();
082    if (VM.VERIFY_ASSERTIONS)
083      VM.assertions._assert(!start.isZero() && chunks > 0 && chunks < (1 << SIZE_BITS));
084    boolean top = end.EQ(Space.HEAP_END);
085    Word tmp = start.toWord();
086    tmp = tmp.rshl(BASE_EXPONENT);
087    int exponent = 0;
088    while (!tmp.isZero() && tmp.and(Word.one()).isZero()) {
089      tmp = tmp.rshl(1);
090      exponent++;
091    }
092    int mantissa = tmp.toInt();
093    if (VM.VERIFY_ASSERTIONS)
094      VM.assertions._assert(tmp.lsh(BASE_EXPONENT + exponent).EQ(start.toWord()));
095    return (mantissa << MANTISSA_SHIFT) |
096           (exponent << EXPONENT_SHIFT) |
097           (chunks << SIZE_SHIFT) |
098           ((top) ? TYPE_CONTIGUOUS_HI : TYPE_CONTIGUOUS);
099  }
100
101  /**
102   * Create a descriptor for a <i>dis-contiguous</i> (shared) space
103   *
104   * @return An integer descriptor reflecting the fact that this space
105   * is shared (and thus discontiguous and so must be established via
106   * maps).
107   */
108  public static int createDescriptor() {
109    discontiguousSpaceIndex += DISCONTIG_INDEX_INCREMENT;
110    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((discontiguousSpaceIndex & TYPE_CONTIGUOUS) != TYPE_CONTIGUOUS);
111    return discontiguousSpaceIndex;
112  }
113
114  /****************************************************************************
115   *
116   * Descriptor interrogation
117   */
118
119  /**
120   * @param descriptor a descriptor for a space
121   * @return {@code true} if this descriptor describes a contiguous space
122   */
123  @Inline
124  public static boolean isContiguous(int descriptor) {
125    return ((descriptor & TYPE_CONTIGUOUS) == TYPE_CONTIGUOUS);
126  }
127
128  /**
129   * @param descriptor a descriptor for a space
130   * @return {@code true} if this descriptor describes a contiguous space that
131   * is at the top of the virtual address space
132   */
133  @Inline
134  public static boolean isContiguousHi(int descriptor) {
135    return ((descriptor & TYPE_MASK) == TYPE_CONTIGUOUS_HI);
136  }
137
138  /**
139   * @param descriptor a descriptor for a space
140   * @return The start of this region of memory encoded in this descriptor
141   */
142  @Inline
143  public static Address getStart(int descriptor) {
144    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
145    Word mantissa = Word.fromIntSignExtend(descriptor >>> MANTISSA_SHIFT);
146    int exponent = (descriptor & EXPONENT_MASK) >>> EXPONENT_SHIFT;
147    return mantissa.lsh(BASE_EXPONENT + exponent).toAddress();
148  }
149
150  /**
151   * @param descriptor a descriptor for a space
152   * @return The size of the region of memory encoded in this
153   * descriptor, in chunks
154   */
155  @Inline
156  public static int getChunks(int descriptor) {
157    if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
158    return (descriptor & SIZE_MASK) >>> SIZE_SHIFT;
159  }
160}