/*
* 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.jikesrvm.runtime;
import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT;
import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_DOUBLE;
import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_SHORT;
import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
import org.jikesrvm.VM;
import org.vmmagic.pragma.Inline;
import org.vmmagic.pragma.Uninterruptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Extent;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
/**
* Low level memory management functions.
* <p>
* Note that this class is "uninterruptible" - calling its methods will never
* cause the current thread to yield the CPU to another thread (one that
* might cause a GC, for example).
*/
@Uninterruptible
public class Memory {
private static final int UNKNOWN = -1;
////////////////////////
// (1) Utilities for copying/filling/zeroing memory
////////////////////////
/**
* How many bytes is considered large enough to justify the transition to
* C code to use memcpy?
*/
private static final int NATIVE_THRESHOLD = 512;
/**
* Allow the use of C based memcpy
*/
private static final boolean USE_NATIVE = true;
/**
* Number of bytes used when copying larger chunks of memory. Normally 8 bytes
* except on x87 Intel
*/
private static final int BYTES_IN_COPY = VM.BuildForIA32 && !VM.BuildForSSE2 ? 4 : 8;
@Inline
private static void copy8Bytes(Address dstPtr, Address srcPtr) {
if (BYTES_IN_COPY == 8) {
if (VM.BuildForIA32) {
dstPtr.store(srcPtr.loadLong());
} else {
dstPtr.store(srcPtr.loadDouble());
}
} else {
copy4Bytes(dstPtr, srcPtr);
copy4Bytes(dstPtr.plus(4), srcPtr.plus(4));
}
}
@Inline
private static void copy4Bytes(Address dstPtr, Address srcPtr) {
dstPtr.store(srcPtr.loadInt());
}
@Inline
private static void copy2Bytes(Address dstPtr, Address srcPtr) {
dstPtr.store(srcPtr.loadChar());
}
@Inline
private static void copy1Bytes(Address dstPtr, Address srcPtr) {
dstPtr.store(srcPtr.loadByte());
}
/**
* Low level copy of len elements from src[srcPos] to dst[dstPos].
*
* Assumptions: <code> src != dst || (scrPos >= dstPos + 4) </code>
* and src and dst are 8Bit arrays.
* @param src the source array
* @param srcPos index in the source array to begin copy
* @param dst the destination array
* @param dstPos index in the destination array to being copy
* @param len number of array elements to copy
*/
public static void arraycopy8Bit(Object src, int srcPos, Object dst, int dstPos, int len) {
Address srcPtr = Magic.objectAsAddress(src).plus(srcPos);
Address dstPtr = Magic.objectAsAddress(dst).plus(dstPos);
aligned8Copy(dstPtr, srcPtr, len);
}
/**
* Low level copy of <code>copyBytes</code> bytes from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
*
* Assumption <code>src != dst || (srcPos >= dstPos)</code> and element size is 4 bytes.
*
* @param dstPtr The destination start address
* @param srcPtr The source start address
* @param copyBytes The number of bytes to be copied
*/
public static void aligned8Copy(Address dstPtr, Address srcPtr, int copyBytes) {
if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
memcopy(dstPtr, srcPtr, copyBytes);
} else {
if (copyBytes >= BYTES_IN_COPY &&
(srcPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)).EQ(
(dstPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)))))) {
// relative alignment is the same
Address endPtr = srcPtr.plus(copyBytes);
Address wordEndPtr = endPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1).not()).toAddress();
if (BYTES_IN_COPY == 8) {
if (srcPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
copy1Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(1);
dstPtr = dstPtr.plus(1);
}
if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
if (srcPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
copy4Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(4);
dstPtr = dstPtr.plus(4);
}
} else {
if (srcPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
copy1Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(1);
dstPtr = dstPtr.plus(1);
}
if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
}
while (srcPtr.LT(wordEndPtr)) {
if (BYTES_IN_COPY == 8) {
copy8Bytes(dstPtr, srcPtr);
} else {
copy4Bytes(dstPtr, srcPtr);
}
srcPtr = srcPtr.plus(BYTES_IN_COPY);
dstPtr = dstPtr.plus(BYTES_IN_COPY);
}
// if(VM.VerifyAssertions) VM._assert(wordEndPtr.EQ(srcPtr));
if (BYTES_IN_COPY == 8) {
if (endPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
copy4Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(4);
dstPtr = dstPtr.plus(4);
}
if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
if (endPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
copy1Bytes(dstPtr, srcPtr);
}
} else {
if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
if (endPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
copy1Bytes(dstPtr, srcPtr);
}
}
} else {
Address endPtr = srcPtr.plus(copyBytes);
while (srcPtr.LT(endPtr)) {
dstPtr.store(srcPtr.loadByte());
srcPtr = srcPtr.plus(1);
dstPtr = dstPtr.plus(1);
}
}
}
}
/**
* Low level copy of len elements from src[srcPos] to dst[dstPos].
* <p>
* Assumption; {@code src != dst || (srcPos >= dstPos + 2)}.
*
* @param src the source array
* @param srcPos index in the source array to begin copy
* @param dst the destination array
* @param dstPos index in the destination array to being copy
* @param len number of array elements to copy
*/
public static void arraycopy16Bit(Object src, int srcPos, Object dst, int dstPos, int len) {
Address srcPtr = Magic.objectAsAddress(src).plus(srcPos << LOG_BYTES_IN_SHORT);
Address dstPtr = Magic.objectAsAddress(dst).plus(dstPos << LOG_BYTES_IN_SHORT);
int copyBytes = len << LOG_BYTES_IN_SHORT;
aligned16Copy(dstPtr, srcPtr, copyBytes);
}
/**
* Low level copy of <code>copyBytes</code> bytes from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
* <p>
* Assumption: <code>src != dst || (srcPos >= dstPos)</code> and element size is 2 bytes.
*
* @param dstPtr The destination start address
* @param srcPtr The source start address
* @param copyBytes The number of bytes to be copied
*/
public static void aligned16Copy(Address dstPtr, Address srcPtr, int copyBytes) {
if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
memcopy(dstPtr, srcPtr, copyBytes);
} else {
if (copyBytes >= BYTES_IN_COPY &&
(srcPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)).EQ(
(dstPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)))))) {
// relative alignment is the same
Address endPtr = srcPtr.plus(copyBytes);
Address wordEndPtr = endPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1).not()).toAddress();
if (BYTES_IN_COPY == 8) {
if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
if (srcPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
copy4Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(4);
dstPtr = dstPtr.plus(4);
}
} else {
if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
}
while (srcPtr.LT(wordEndPtr)) {
if (BYTES_IN_COPY == 8) {
copy8Bytes(dstPtr, srcPtr);
} else {
copy4Bytes(dstPtr, srcPtr);
}
srcPtr = srcPtr.plus(BYTES_IN_COPY);
dstPtr = dstPtr.plus(BYTES_IN_COPY);
}
// if(VM.VerifyAssertions) VM._assert(wordEndPtr.EQ(srcPtr));
if (BYTES_IN_COPY == 8) {
if (endPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
copy4Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(4);
dstPtr = dstPtr.plus(4);
}
if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
}
} else {
if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
copy2Bytes(dstPtr, srcPtr);
}
}
} else {
Address endPtr = srcPtr.plus(copyBytes);
while (srcPtr.LT(endPtr)) {
copy2Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(2);
dstPtr = dstPtr.plus(2);
}
}
}
}
/**
* Low level copy of <code>len</code> elements from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
* <p>
* Assumption: <code>src != dst || (srcPos >= dstPos)</code> and element size is 4 bytes.
*
* @param src the source array
* @param srcIdx index in the source array to begin copy
* @param dst the destination array
* @param dstIdx index in the destination array to being copy
* @param len number of array elements to copy
*/
public static void arraycopy32Bit(Object src, int srcIdx, Object dst, int dstIdx, int len) {
Address srcPtr = Magic.objectAsAddress(src).plus(srcIdx << LOG_BYTES_IN_INT);
Address dstPtr = Magic.objectAsAddress(dst).plus(dstIdx << LOG_BYTES_IN_INT);
int copyBytes = len << LOG_BYTES_IN_INT;
aligned32Copy(dstPtr, srcPtr, copyBytes);
}
/**
* Low level copy of <code>len</code> elements from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
* <p>
* Assumption: <code>src != dst || (srcPos >= dstPos)</code> and element size is 8 bytes.
*
* @param src the source array
* @param srcIdx index in the source array to begin copy
* @param dst the destination array
* @param dstIdx index in the destination array to being copy
* @param len number of array elements to copy
*/
public static void arraycopy64Bit(Object src, int srcIdx, Object dst, int dstIdx, int len) {
Offset srcOffset = Offset.fromIntZeroExtend(srcIdx << LOG_BYTES_IN_DOUBLE);
Offset dstOffset = Offset.fromIntZeroExtend(dstIdx << LOG_BYTES_IN_DOUBLE);
int copyBytes = len << LOG_BYTES_IN_DOUBLE;
aligned64Copy(Magic.objectAsAddress(dst).plus(dstOffset), Magic.objectAsAddress(src).plus(srcOffset), copyBytes);
}
/**
* Low level copy of <code>copyBytes</code> bytes from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
*
* Assumption <code>src != dst || (srcPos >= dstPos)</code> and element size is 8 bytes.
*
* @param dstPtr The destination start address
* @param srcPtr The source start address
* @param copyBytes The number of bytes to be copied
*/
public static void aligned64Copy(Address dstPtr, Address srcPtr, int copyBytes) {
if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
memcopy(dstPtr, srcPtr, copyBytes);
} else {
// The elements of long[] and double[] are always doubleword aligned
// therefore we can do 64 bit load/stores without worrying about alignment.
Address endPtr = srcPtr.plus(copyBytes);
while (srcPtr.LT(endPtr)) {
copy8Bytes(dstPtr, srcPtr);
srcPtr = srcPtr.plus(8);
dstPtr = dstPtr.plus(8);
}
}
}
/**
* Copy copyBytes from src to dst.
* Assumption: either the ranges are non overlapping, or {@code src >= dst + 4}.
* Also, src and dst are 4 byte aligned and numBytes is a multiple of 4.
*
* @param dst the destination addr
* @param src the source addr
* @param copyBytes the number of bytes top copy
*/
public static void aligned32Copy(Address dst, Address src, int copyBytes) {
if (VM.VerifyAssertions) {
VM._assert(copyBytes >= 0);
VM._assert((copyBytes & (BYTES_IN_INT - 1)) == 0);
VM._assert(src.toWord().and(Word.fromIntZeroExtend(BYTES_IN_INT - 1)).isZero());
VM._assert(dst.toWord().and(Word.fromIntZeroExtend(BYTES_IN_INT - 1)).isZero());
VM._assert(src.plus(copyBytes).LE(dst) || src.GE(dst.plus(BYTES_IN_INT)));
}
if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
memcopy(dst, src, copyBytes);
} else {
Offset numBytes = Offset.fromIntSignExtend(copyBytes);
if (BYTES_IN_COPY == 8 && copyBytes != 0) {
Word wordMask = Word.fromIntZeroExtend(BYTES_IN_COPY - 1);
Word srcAlignment = src.toWord().and(wordMask);
if (srcAlignment.EQ(dst.toWord().and(wordMask))) {
Offset i = Offset.zero();
if (srcAlignment.EQ(Word.fromIntZeroExtend(BYTES_IN_INT))) {
copy4Bytes(dst.plus(i), src.plus(i));
i = i.plus(BYTES_IN_INT);
}
Word endAlignment = srcAlignment.plus(numBytes).and(wordMask);
numBytes = numBytes.minus(endAlignment.toOffset());
for (; i.sLT(numBytes); i = i.plus(BYTES_IN_COPY)) {
copy8Bytes(dst.plus(i), src.plus(i));
}
if (!endAlignment.isZero()) {
copy4Bytes(dst.plus(i), src.plus(i));
}
return;
}
}
//normal case: 32 bit or (64 bit not aligned)
for (Offset i = Offset.zero(); i.sLT(numBytes); i = i.plus(BYTES_IN_INT)) {
copy4Bytes(dst.plus(i), src.plus(i));
}
}
}
/**
* Copy numbytes from src to dst.
* Assumption: either the ranges are non overlapping, or {@code src >= dst + BYTES_IN_ADDRESS}.
* Also, src and dst are word aligned and numBytes is a multiple of BYTES_IN_ADDRESS.
* @param dst the destination addr
* @param src the source addr
* @param numBytes the number of bytes top copy
*/
public static void alignedWordCopy(Address dst, Address src, int numBytes) {
if (USE_NATIVE && numBytes > NATIVE_THRESHOLD) {
memcopy(dst, src, numBytes);
} else {
internalAlignedWordCopy(dst, src, numBytes);
}
}
/**
* Copy <code>numbytes</code> from <code>src</code> to <code>dst</code>.
* Assumption either the ranges are non overlapping, or <code>src >= dst + BYTES_IN_ADDRESS</code>.
* @param dst The destination addr
* @param src The source addr
* @param numBytes The number of bytes to copy
*/
private static void internalAlignedWordCopy(Address dst, Address src, int numBytes) {
Address end = src.plus(numBytes);
while (src.LT(end)) {
dst.store(src.loadWord());
src = src.plus(BYTES_IN_ADDRESS);
dst = dst.plus(BYTES_IN_ADDRESS);
}
}
/**
* Copies a region of memory.
*
* @param dst Destination address
* @param src Source address
* @param cnt Number of bytes to copy
*/
public static void memcopy(Address dst, Address src, Extent cnt) {
Address srcEnd = src.plus(cnt);
Address dstEnd = dst.plus(cnt);
boolean overlap = !srcEnd.LE(dst) && !dstEnd.LE(src);
if (overlap) {
SysCall.sysCall.sysMemmove(dst, src, cnt);
} else {
SysCall.sysCall.sysCopy(dst, src, cnt);
}
}
/**
* Wrapper method for {@link #memcopy(Address, Address, Extent)}.
*
* @param dst Destination address
* @param src Source address
* @param cnt Number of bytes to copy
*/
public static void memcopy(Address dst, Address src, int cnt) {
memcopy(dst, src, Extent.fromIntSignExtend(cnt));
}
/**
* Zero a region of memory.
*
* @param useNT use non-temporal instructions (if available)
* @param start of address range (inclusive)
* @param len extent to zero.
*/
public static void zero(boolean useNT, Address start, Extent len) {
if (useNT) {
SysCall.sysCall.sysZeroNT(start, len);
} else {
SysCall.sysCall.sysZero(start, len);
}
}
////////////////////////
// (2) Cache management
////////////////////////
/**
* Synchronize a region of memory: force data in dcache to be written out to main
* memory so that it will be seen by icache when instructions are fetched back.
* @param address Start of address range
* @param size Size of address range (bytes)
*/
public static void sync(Address address, int size) {
SysCall.sysCall.sysSyncCache(address, size);
}
////////////////////////
// (3) MMap
////////////////////////
// constants for protection and mapping calls
public static final int PROT_NONE = 0;
public static final int PROT_READ = 1;
public static final int PROT_WRITE = 2;
public static final int PROT_EXEC = 4;
public static final int MAP_PRIVATE = 2;
public static final int MAP_FIXED = (VM.BuildForLinux) ? 16 : (VM.BuildForOsx) ? 16 : (VM.BuildForSolaris) ? 0x10 : 256;
public static final int MAP_ANONYMOUS = (VM.BuildForLinux) ? 32 : (VM.BuildForOsx) ? 0x1000 : (VM.BuildForSolaris) ? 0x100 : 16;
public static boolean isPageMultiple(int val) {
int pagesizeMask = getPagesize() - 1;
return ((val & pagesizeMask) == 0);
}
public static boolean isPageMultiple(Extent val) {
Word pagesizeMask = Word.fromIntZeroExtend(getPagesize() - 1);
return val.toWord().and(pagesizeMask).isZero();
}
public static boolean isPageMultiple(Offset val) {
Word pagesizeMask = Word.fromIntZeroExtend(getPagesize() - 1);
return val.toWord().and(pagesizeMask).isZero();
}
public static boolean isPageAligned(Address addr) {
Word pagesizeMask = Word.fromIntZeroExtend(getPagesize() - 1);
return addr.toWord().and(pagesizeMask).isZero();
}
/**
* Do generic mmap non-file memory mapping call
* @param address Start of address range (Address)
* @param size Size of address range
* @param prot Protection (int)
* @param flags (int)
* @return Address (of region) if successful; errno (1 to 127) otherwise
*/
public static Address mmap(Address address, Extent size, int prot, int flags) {
if (VM.VerifyAssertions) {
VM._assert(isPageAligned(address) && isPageMultiple(size));
}
return SysCall.sysCall.sysMMapErrno(address, size, prot, flags, -1, Offset.zero());
}
/**
* Do mmap demand zero fixed address memory mapping call
* @param address Start of address range
* @param size Size of address range
* @return Address (of region) if successful; errno (1 to 127) otherwise
*/
public static Address dzmmap(Address address, Extent size) {
if (VM.VerifyAssertions) {
VM._assert(isPageAligned(address) && isPageMultiple(size));
}
int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
return mmap(address, size, prot, flags);
}
/**
* Do mprotect system call
* @param address Start of address range (Address)
* @param size Size of address range
* @param prot Protection (int)
* @return true iff success
*/
public static boolean mprotect(Address address, Extent size, int prot) {
if (VM.VerifyAssertions) {
VM._assert(isPageAligned(address) && isPageMultiple(size));
}
return SysCall.sysCall.sysMProtect(address, size, prot) == 0;
}
private static int pagesize = UNKNOWN;
private static int pagesizeLog = UNKNOWN;
/**
* Sets the page size.
* <p>
* Note: this method may only be called once, at boot time. Multithreading is not
* yet enabled at this point, so no synchronization is necessary.
* @param pageSizeFromBootRecord the page size
*/
public static void setPageSize(Extent pageSizeFromBootRecord) {
if (pagesize == UNKNOWN) {
int newPageSize = pageSizeFromBootRecord.toInt();
if (VM.VerifyAssertions) VM._assert(Extent.fromIntSignExtend(newPageSize).EQ(pageSizeFromBootRecord));
pagesize = newPageSize;
pagesizeLog = UNKNOWN;
int temp = pagesize;
while (temp > 0) {
temp >>>= 1;
pagesizeLog++;
}
if (VM.VerifyAssertions) VM._assert((1 << pagesizeLog) == pagesize);
return;
}
if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
}
public static int getPagesize() {
if (VM.VerifyAssertions) VM._assert(pagesize != UNKNOWN);
return pagesize;
}
public static int getPagesizeLog() {
if (VM.VerifyAssertions) VM._assert(pagesizeLog != UNKNOWN);
return pagesizeLog;
}
public static byte getPagesizeLogAsByte() {
int pageSizeLog = getPagesizeLog();
byte pageSizeLogByte = (byte) pageSizeLog;
if (VM.VerifyAssertions) VM._assert(pageSizeLog == pageSizeLogByte);
return pageSizeLogByte;
}
public static void dumpMemory(Address start, int beforeBytes, int afterBytes) {
beforeBytes = alignDown(beforeBytes, BYTES_IN_ADDRESS);
afterBytes = alignUp(afterBytes, BYTES_IN_ADDRESS);
VM.sysWrite("---- Dumping memory from ");
VM.sysWrite(start.minus(beforeBytes));
VM.sysWrite(" to ");
VM.sysWrite(start.plus(afterBytes));
VM.sysWriteln(" ----");
for (int i = -beforeBytes; i < afterBytes; i += BYTES_IN_ADDRESS) {
VM.sysWrite(i, ": ");
VM.sysWrite(start.plus(i));
Word value = start.plus(i).loadWord();
VM.sysWriteln(" ", value);
}
}
@Inline
public static Address alignUp(Address address, int alignment) {
return address.plus(alignment - 1).toWord().and(Word.fromIntSignExtend(~(alignment - 1))).toAddress();
}
@Inline
public static Address alignUp(Address address, Extent alignment) {
return address.plus(alignment.minus(1)).toWord().and(alignment.minus(1).toWord().not()).toAddress();
}
@Inline
public static Address alignDown(Address address, int alignment) {
return address.toWord().and(Word.fromIntSignExtend(~(alignment - 1))).toAddress();
}
// These versions are here to accommodate the boot image writer
@Inline
public static int alignUp(int address, int alignment) {
return ((address + alignment - 1) & ~(alignment - 1));
}
@Inline
public static int alignDown(int address, int alignment) {
return (address & ~(alignment - 1));
}
/**
* For use in test cases only.
* @return native threshold (number in bytes before copying uses C code)
*/
static int getNativeThreshold() {
return NATIVE_THRESHOLD;
}
}