/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.mmtk.utility.heap;
import static org.mmtk.utility.Constants.BITS_IN_INT;
import static org.mmtk.utility.heap.layout.VMLayoutConstants.LOG_BYTES_IN_CHUNK;
import org.mmtk.utility.Log;
import org.mmtk.utility.heap.layout.HeapParameters;
import org.mmtk.utility.heap.layout.Map64;
import org.mmtk.utility.heap.layout.VMLayoutConstants;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.*;
import org.vmmagic.unboxed.*;
/**
* This class manages the encoding and decoding of space descriptors.<p>
*
* Space descriptors are integers that encode a space's mapping into
* virtual memory. For discontiguous spaces, they indicate
* discontiguity and mapping must be done by consulting the space map.
* For contiguous spaces, the space's address range is encoded into
* the integer (using a fixed point notation).<p>
*
* The purpose of this class is to allow <code>static final int</code>
* space descriptors to exist for each space, which can then be used
* in tests to determine whether an object is in a space. A good
* compiler can perform this decoding at compile time and produce
* optimal code for the test.
*/
@Uninterruptible public class SpaceDescriptor {
/****************************************************************************
*
* Class variables
*/
/**
*
*/
private static final int TYPE_BITS = 2;
@SuppressWarnings("unused") private static final int TYPE_SHARED = 0;
private static final int TYPE_CONTIGUOUS = 1;
private static final int TYPE_CONTIGUOUS_HI = 3;
private static final int TYPE_MASK = (1 << TYPE_BITS) - 1;
private static final int SIZE_SHIFT = TYPE_BITS;
private static final int SIZE_BITS = 10;
private static final int SIZE_MASK = ((1 << SIZE_BITS) - 1) << SIZE_SHIFT;
private static final int EXPONENT_SHIFT = SIZE_SHIFT + SIZE_BITS;
private static final int EXPONENT_BITS = 5;
private static final int EXPONENT_MASK = ((1 << EXPONENT_BITS) - 1) << EXPONENT_SHIFT;
private static final int MANTISSA_SHIFT = EXPONENT_SHIFT + EXPONENT_BITS;
private static final int MANTISSA_BITS = 14;
private static final int BASE_EXPONENT = BITS_IN_INT - MANTISSA_BITS;
/* 64-bit */
private static final int INDEX_MASK = ~TYPE_MASK;
private static final int INDEX_SHIFT = TYPE_BITS;
private static int discontiguousSpaceIndex = 0;
private static final int DISCONTIG_INDEX_INCREMENT = 1 << TYPE_BITS;
/****************************************************************************
*
* Descriptor creation
*/
/**
* Create a descriptor for a <i>contiguous</i> space
*
* @param start The start address of the space
* @param end The end address of the space
* @return An integer descriptor encoding the region of virtual
* memory occupied by the space
*/
public static int createDescriptor(Address start, Address end) {
boolean top = end.EQ(VMLayoutConstants.HEAP_END);
if (VM.HEAP_LAYOUT_64BIT) {
return Map64.spaceIndex(start) << INDEX_SHIFT |
((top) ? TYPE_CONTIGUOUS_HI : TYPE_CONTIGUOUS);
}
int chunks = end.diff(start).toWord().rshl(LOG_BYTES_IN_CHUNK).toInt();
if (VM.VERIFY_ASSERTIONS) {
if (!start.isZero() && (chunks <= 0 || chunks >= (1 << SIZE_BITS))) {
Log.write("SpaceDescriptor.createDescriptor(", start);
Log.write(",", end);
Log.writeln(")");
Log.writeln("chunks = ", chunks);
}
VM.assertions._assert(!start.isZero() && chunks > 0 && chunks < (1 << SIZE_BITS));
}
Word tmp = start.toWord();
tmp = tmp.rshl(BASE_EXPONENT);
int exponent = 0;
while (!tmp.isZero() && tmp.and(Word.one()).isZero()) {
tmp = tmp.rshl(1);
exponent++;
}
int mantissa = tmp.toInt();
if (VM.VERIFY_ASSERTIONS)
VM.assertions._assert(tmp.lsh(BASE_EXPONENT + exponent).EQ(start.toWord()));
return (mantissa << MANTISSA_SHIFT) |
(exponent << EXPONENT_SHIFT) |
(chunks << SIZE_SHIFT) |
((top) ? TYPE_CONTIGUOUS_HI : TYPE_CONTIGUOUS);
}
/**
* Create a descriptor for a <i>dis-contiguous</i> (shared) space
*
* @return An integer descriptor reflecting the fact that this space
* is shared (and thus discontiguous and so must be established via
* maps).
*/
public static int createDescriptor() {
discontiguousSpaceIndex += DISCONTIG_INDEX_INCREMENT;
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((discontiguousSpaceIndex & TYPE_CONTIGUOUS) != TYPE_CONTIGUOUS);
return discontiguousSpaceIndex;
}
/****************************************************************************
*
* Descriptor interrogation
*/
/**
* @param descriptor a descriptor for a space
* @return {@code true} if this descriptor describes a contiguous space
*/
@Inline
public static boolean isContiguous(int descriptor) {
return ((descriptor & TYPE_CONTIGUOUS) == TYPE_CONTIGUOUS);
}
/**
* @param descriptor a descriptor for a space
* @return {@code true} if this descriptor describes a contiguous space that
* is at the top of the virtual address space
*/
@Inline
public static boolean isContiguousHi(int descriptor) {
return ((descriptor & TYPE_MASK) == TYPE_CONTIGUOUS_HI);
}
/**
* @param descriptor a descriptor for a space
* @return The start of this region of memory encoded in this descriptor
*/
@Inline
public static Address getStart(int descriptor) {
if (VM.HEAP_LAYOUT_64BIT) {
return Word.fromIntZeroExtend(getIndex(descriptor)).lsh(HeapParameters.LOG_SPACE_SIZE_64).toAddress();
}
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
Word mantissa = Word.fromIntSignExtend(descriptor >>> MANTISSA_SHIFT);
int exponent = (descriptor & EXPONENT_MASK) >>> EXPONENT_SHIFT;
return mantissa.lsh(BASE_EXPONENT + exponent).toAddress();
}
/**
* @param descriptor a descriptor for a space
* @return The size of the region of memory encoded in this descriptor
*/
@Inline
public static Extent getExtent(int descriptor) {
if (VM.HEAP_LAYOUT_64BIT) {
return VMLayoutConstants.SPACE_SIZE_64;
}
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isContiguous(descriptor));
int chunks = (descriptor & SIZE_MASK) >>> SIZE_SHIFT;
Extent size = Word.fromIntSignExtend(chunks).lsh(LOG_BYTES_IN_CHUNK).toExtent();
return size;
}
/**
* @param descriptor a descriptor for a space
* @return The index (in 64-bit layout) of the space
*/
@Inline
public static int getIndex(int descriptor) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(VM.HEAP_LAYOUT_64BIT);
return (descriptor & INDEX_MASK) >> INDEX_SHIFT;
}
}