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      private static final int TYPE_BITS = 2;
046      private static final int TYPE_SHARED = 0;
047      private static final int TYPE_CONTIGUOUS = 1;
048      private static final int TYPE_CONTIGUOUS_HI = 3;
049      private static final int TYPE_MASK = (1 << TYPE_BITS) - 1;
050      private static final int SIZE_SHIFT = TYPE_BITS;
051      private static final int SIZE_BITS = 10;
052      private static final int SIZE_MASK = ((1 << SIZE_BITS) - 1) << SIZE_SHIFT;
053      private static final int EXPONENT_SHIFT = SIZE_SHIFT + SIZE_BITS;
054      private static final int EXPONENT_BITS = 5;
055      private static final int EXPONENT_MASK = ((1 << EXPONENT_BITS) - 1) << EXPONENT_SHIFT;
056      private static final int MANTISSA_SHIFT = EXPONENT_SHIFT + EXPONENT_BITS;
057      private static final int MANTISSA_BITS = 14;
058      private static final int BASE_EXPONENT = BITS_IN_INT - MANTISSA_BITS;
059    
060      private static int discontiguousSpaceIndex = 0;
061      private static final int DISCONTIG_INDEX_INCREMENT = 1<<TYPE_BITS;
062    
063      /****************************************************************************
064       *
065       * Descriptor creation
066       */
067    
068      /**
069       * Create a descriptor for a <i>contiguous</i> space
070       *
071       * @param start The start address of the space
072       * @param end The end address of the space
073       * @return An integer descriptor encoding the region of virtual
074       * memory occupied by the space
075       */
076      public static int createDescriptor(Address start, Address end) {
077        int chunks = end.diff(start).toWord().rshl(Space.LOG_BYTES_IN_CHUNK).toInt();
078        if (VM.VERIFY_ASSERTIONS)
079          VM.assertions._assert(!start.isZero() && chunks > 0 && chunks < (1 << SIZE_BITS));
080        boolean top = end.EQ(Space.HEAP_END);
081        Word tmp = start.toWord();
082        tmp = tmp.rshl(BASE_EXPONENT);
083        int exponent = 0;
084        while (!tmp.isZero() && tmp.and(Word.one()).isZero()) {
085          tmp = tmp.rshl(1);
086          exponent++;
087        }
088        int mantissa = tmp.toInt();
089        if (VM.VERIFY_ASSERTIONS)
090          VM.assertions._assert(tmp.lsh(BASE_EXPONENT + exponent).EQ(start.toWord()));
091        return (mantissa<<MANTISSA_SHIFT) |
092               (exponent<<EXPONENT_SHIFT) |
093               (chunks << SIZE_SHIFT) |
094               ((top) ? TYPE_CONTIGUOUS_HI : TYPE_CONTIGUOUS);
095      }
096    
097      /**
098       * Create a descriptor for a <i>dis-contiguous</i> (shared) space
099       *
100       * @return An integer descriptor reflecting the fact that this space
101       * is shared (and thus discontiguous and so must be established via
102       * maps).
103       */
104      public static int createDescriptor() {
105        discontiguousSpaceIndex += DISCONTIG_INDEX_INCREMENT;
106        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((discontiguousSpaceIndex & TYPE_CONTIGUOUS) != TYPE_CONTIGUOUS);
107        return discontiguousSpaceIndex;
108      }
109    
110      /****************************************************************************
111       *
112       * Descriptor interrogation
113       */
114    
115      /**
116       * Return true if this descriptor describes a contiguous space
117       *
118       * @param descriptor
119       * @return True if this descriptor describes a contiguous space
120       */
121      @Inline
122      public static boolean isContiguous(int descriptor) {
123        return ((descriptor & TYPE_CONTIGUOUS) == TYPE_CONTIGUOUS);
124      }
125    
126      /**
127       * Return true if this descriptor describes a contiguous space that
128       * is at the top of the virtual address space
129       *
130       * @param descriptor
131       * @return True if this descriptor describes a contiguous space that
132       * is at the top of the virtual address space
133       */
134      @Inline
135      public static boolean isContiguousHi(int descriptor) {
136        return ((descriptor & TYPE_MASK) == TYPE_CONTIGUOUS_HI);
137      }
138    
139      /**
140       * Return the start of this region of memory encoded in this descriptor
141       *
142       * @param descriptor
143       * @return The start of this region of memory encoded in this descriptor
144       */
145      @Inline
146      public static Address getStart(int descriptor) {
147        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
148        Word mantissa = Word.fromIntSignExtend(descriptor >>> MANTISSA_SHIFT);
149        int exponent = (descriptor & EXPONENT_MASK) >>> EXPONENT_SHIFT;
150        return mantissa.lsh(BASE_EXPONENT + exponent).toAddress();
151      }
152    
153      /**
154       * Return the size of the region of memory encoded in this
155       * descriptor, in chunks
156       *
157       * @param descriptor
158       * @return The size of the region of memory encoded in this
159       * descriptor, in chunks
160       */
161      @Inline
162      public static int getChunks(int descriptor) {
163        if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
164        return (descriptor & SIZE_MASK) >>> SIZE_SHIFT;
165      }
166    }