/* * 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; import static org.mmtk.utility.Constants.*; import static org.mmtk.utility.heap.layout.VMLayoutConstants.BYTES_IN_CHUNK; import org.mmtk.utility.heap.layout.VMLayoutConstants; import org.mmtk.vm.VM; import org.vmmagic.unboxed.*; import org.vmmagic.pragma.*; /** * Conversions between different units. */ @Uninterruptible public class Conversions { public static Address roundDownMB(Address addr) { return roundDown(addr.toWord(), LOG_BYTES_IN_MBYTE).toAddress(); } public static Extent roundDownMB(Extent bytes) { return roundDown(bytes.toWord(), LOG_BYTES_IN_MBYTE).toExtent(); } private static Word roundDown(Word value, int logBase) { Word mask = Word.one().lsh(logBase).minus(Word.one()).not(); return value.and(mask); } public static int roundDown(int value, int alignment) { return value & ~(alignment - 1); } // Round up (if necessary) // public static int MBToPages(int megs) { if (LOG_BYTES_IN_PAGE <= LOG_BYTES_IN_MBYTE) return (megs << (LOG_BYTES_IN_MBYTE - LOG_BYTES_IN_PAGE)); else return (megs + ((BYTES_IN_PAGE >>> LOG_BYTES_IN_MBYTE) - 1)) >>> (LOG_BYTES_IN_PAGE - LOG_BYTES_IN_MBYTE); } public static int addressToPagesDown(Address addr) { Word chunk = addr.toWord().rshl(LOG_BYTES_IN_PAGE); return chunk.toInt(); } public static int addressToPages(Address addr) { int page = addressToPagesDown(addr); if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(pagesToAddress(page).EQ(addr)); return page; } public static Address pagesToAddress(int pages) { return Word.fromIntZeroExtend(pages).lsh(LOG_BYTES_IN_PAGE).toAddress(); } public static Extent pagesToBytes(int pages) { return Word.fromIntZeroExtend(pages).lsh(LOG_BYTES_IN_PAGE).toExtent(); } public static Extent pagesToBytes(long pages) { return Word.fromLong(pages).lsh(LOG_BYTES_IN_PAGE).toExtent(); } public static int pagesToMBytes(int pages) { return pages >> (LOG_BYTES_IN_MBYTE - LOG_BYTES_IN_PAGE); } public static int pagesToKBytes(int pages) { return pages << (LOG_BYTES_IN_PAGE - LOG_BYTES_IN_KBYTE); } public static int bytesToPagesUp(Extent bytes) { return bytes.plus(BYTES_IN_PAGE - 1).toWord().rshl(LOG_BYTES_IN_PAGE).toInt(); } public static int bytesToPages(Extent bytes) { int pages = bytesToPagesUp(bytes); if (VM.VERIFY_ASSERTIONS) { Extent computedExtent = pagesToAddress(pages).toWord().toExtent(); boolean bytesMatchPages = computedExtent.EQ(bytes); if (!bytesMatchPages) { Log.writeln("ERROR: number of bytes computed from pages must match original byte amount!"); Log.writeln(" bytes = ", bytes); Log.writeln(" pages = ", pages); Log.writeln(" bytes computed from pages = ", computedExtent); VM.assertions._assert(false); } } return pages; } public static int bytesToPages(Offset bytes) { if (VM.VERIFY_ASSERTIONS) { long val = bytes.toLong(); VM.assertions._assert(val >= ((long)MIN_INT) << LOG_BYTES_IN_PAGE && val <= ((long)MAX_INT) << LOG_BYTES_IN_PAGE); } if (bytes.sGE(Offset.zero())) return bytesToPagesUp(bytes.toWord().toExtent()); else return -bytesToPagesUp(Extent.fromLong(-bytes.toLong())); } public static Address pageAlign(Address address) { return address.toWord().rshl(LOG_BYTES_IN_PAGE).lsh(LOG_BYTES_IN_PAGE).toAddress(); } public static int pageAlign(int value) { return (value >> LOG_BYTES_IN_PAGE) << LOG_BYTES_IN_PAGE; } public static boolean isPageAligned(Address address) { return pageAlign(address).EQ(address); } public static boolean isPageAligned(int value) { return pageAlign(value) == value; } /** * Align an address to a space chunk * * @param addr The address to be aligned * @param down If {@code true} the address will be rounded down, otherwise * it will rounded up. * @return The chunk-aligned address */ public static Address chunkAlign(Address addr, boolean down) { if (!down) addr = addr.plus(BYTES_IN_CHUNK - 1); return addr.toWord().rshl(VMLayoutConstants.LOG_BYTES_IN_CHUNK).lsh(VMLayoutConstants.LOG_BYTES_IN_CHUNK).toAddress(); } /** * Align an extent to a space chunk * * @param bytes The extent to be aligned * @param down If {@code true} the extent will be rounded down, otherwise * it will rounded up. * @return The chunk-aligned extent */ public static Extent chunkAlign(Extent bytes, boolean down) { return alignWord(bytes.toWord(), VMLayoutConstants.LOG_BYTES_IN_CHUNK, down).toExtent(); } /** * Aligns an address to an arbitrary boundary. * * @param addr The address to be aligned * @param bits The log_2 of the boundary size * @return The aligned address */ public static Address alignUp(Address addr, int bits) { return alignWord(addr.toWord(), bits, false).toAddress(); } /** * Align an address to an arbitrary boundary. * * @param addr The address to be aligned * @param bits The log_2 of the boundary size * @return The aligned address */ public static Address alignDown(Address addr, int bits) { return alignWord(addr.toWord(), bits, true).toAddress(); } @Inline public static Word alignWord(Word addr, int bits, boolean down) { if (!down) { if (BITS_IN_ADDRESS == 64 && bits >= 32) { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bits < 64); addr = addr.plus(Word.fromLong((1L << bits) - 1)); } else { if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(bits < 32); addr = addr.plus(Word.fromIntZeroExtend((1 << bits) - 1)); } } return addr.rshl(bits).lsh(bits); } }