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 }