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