blob: fb863ef83884466244c770cb6c9512b2f5283a1c [file] [log] [blame]
/*
* 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 org.mmtk.vm.VM;
import org.vmmagic.unboxed.*;
import org.vmmagic.pragma.*;
/**
* This class implements basic memory copying, setting and clearing
* operations.
*
* NOTE: Most of the operations in this class are performed at teh
* granularity of a Java integer (ie 4-byte units)
*
* FIXME: Why can't these operations be performed at word-granularity?
*/
@Uninterruptible
public class Memory implements Constants {
/****************************************************************************
*
* Class variables
*/
/** zero operations greater than this size are done using the
* underlying OS implementation of zero() */
private static final int SMALL_REGION_THRESHOLD = 1<<8; // empirically chosen
/****************************************************************************
*
* Basic memory setting and zeroing operations
*/
/**
* Zero a region of memory
*
* @param start The start of the region to be zeroed (must be 4-byte aligned)
* @param bytes The number of bytes to be zeroed (must be 4-byte aligned)
*/
@Inline
public static void zero(Address start, Extent bytes) {
if (VM.VERIFY_ASSERTIONS) {
assertAligned(start);
assertAligned(bytes);
}
if (bytes.GT(Extent.fromIntZeroExtend(SMALL_REGION_THRESHOLD)))
VM.memory.zero(start, bytes);
else
zeroSmall(start, bytes);
}
/**
* Zero a small region of memory
*
* @param start The start of the region to be zeroed (must be 4-byte aligned)
* @param bytes The number of bytes to be zeroed (must be 4-byte aligned)
*/
@Inline
public static void zeroSmall(Address start, Extent bytes) {
if (VM.VERIFY_ASSERTIONS) {
assertAligned(start);
assertAligned(bytes);
}
Address end = start.plus(bytes);
for (Address addr = start; addr.LT(end); addr = addr.plus(BYTES_IN_INT))
addr.store(0);
}
/**
* Set a region of memory
*
* @param start The start of the region to be zeroed (must be 4-byte aligned)
* @param bytes The number of bytes to be zeroed (must be 4-byte aligned)
* @param value The value to which the integers in the region should be set
*/
@Inline
public static void set(Address start, int bytes, int value) {
if (VM.VERIFY_ASSERTIONS) {
assertAligned(start);
assertAligned(bytes);
}
Address end = start.plus(bytes);
for (Address addr = start; addr.LT(end); addr = addr.plus(BYTES_IN_INT))
addr.store(value);
}
/****************************************************************************
*
* Helper methods
*/
/**
* Check that a memory range is zeroed
*
* @param start The start address of the range to be checked
* @param bytes The size of the region to be checked, in bytes
* @return True if the region is zeroed
*/
@Inline
public static boolean IsZeroed(Address start, int bytes) {
return isSet(start, bytes, false, 0);
}
/**
* Assert that a memory range is zeroed. An assertion failure will
* occur if the region is not zeroed.
*
* this is in the inline allocation sequence when
* VM.VERIFY_ASSERTIONS is true, it is carefully written to
* reduce the impact on code space.
*
* @param start The start address of the range to be checked
* @param bytes The size of the region to be checked, in bytes
*/
@NoInline
public static void assertIsZeroed(Address start, int bytes) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isSet(start, bytes, true, 0));
}
/**
* Verbosely check and return true if a memory range is set to some
* integer value
*
* @param start The start address of the range to be checked
* @param bytes The size of the region to be checked, in bytes
* @param value The value to which this region should be set
* @return True if the region has been correctly set
*/
@Inline
public static boolean isSet(Address start, int bytes, int value) {
return isSet(start, bytes, true, value);
}
/**
* Assert appropriate alignment, triggering an assertion failure if
* the value does not satisify the alignment requirement of the
* memory operations.
*
* @param value The value to be tested
*/
private static void assertAligned(int value) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((value & (BYTES_IN_INT - 1)) == 0);
}
private static void assertAligned(Word value) {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(Word.fromIntSignExtend(BYTES_IN_INT-1)).isZero());
}
private static void assertAligned(Extent value) {
assertAligned(value.toWord());
}
private static void assertAligned(Address value) {
assertAligned(value.toWord());
}
/**
* Test whether a memory range is set to a given integer value
*
* @param start The address to start checking at
* @param bytes The size of the region to check, in bytes
* @param verbose If true, produce verbose output
* @param value The value to which the memory should be set
*/
@NoInline
private static boolean isSet(Address start, int bytes, boolean verbose,
int value)
/* Inlining this loop into the uninterruptible code can
* cause/encourage the GCP into moving a get_obj_tib into the
* interruptible region where the tib is being installed via an
* int_store
*/ {
if (VM.VERIFY_ASSERTIONS) assertAligned(bytes);
for (int i = 0; i < bytes; i += BYTES_IN_INT)
if (start.loadInt(Offset.fromIntSignExtend(i)) != value) {
if (verbose) {
Log.prependThreadId();
Log.write("VM range does not contain only value ");
Log.writeln(value);
Log.write("Non-zero range: "); Log.write(start);
Log.write(" .. "); Log.writeln(start.plus(bytes));
Log.write("First bad value at "); Log.writeln(start.plus(i));
dumpMemory(start, 0, bytes);
}
return false;
}
return true;
}
/**
* Dump the contents of memory around a given address
*
* @param addr The address around which the memory should be dumped
* @param beforeBytes The number of bytes before the address to be
* included in the dump
* @param afterBytes The number of bytes after the address to be
* included in the dump
*/
public static void dumpMemory(Address addr, int beforeBytes, int afterBytes) {
VM.memory.dumpMemory(addr, beforeBytes, afterBytes);
}
}