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 */ 013package org.mmtk.utility; 014 015import static org.mmtk.utility.Constants.*; 016 017import org.mmtk.vm.VM; 018 019import org.vmmagic.unboxed.*; 020import org.vmmagic.pragma.*; 021 022/** 023 * This class implements basic memory copying, setting and clearing 024 * operations.<p> 025 * 026 * NOTE: Most of the operations in this class are performed at the 027 * granularity of a Java integer (ie 4-byte units)<p> 028 * 029 * FIXME: Why can't these operations be performed at word-granularity? 030 */ 031@Uninterruptible 032public class Memory { 033 034 /**************************************************************************** 035 * 036 * Class variables 037 */ 038 039 /** zero operations greater than this size are done using the 040 * underlying OS implementation of zero() */ 041 private static final int SMALL_REGION_THRESHOLD = 1 << 8; // empirically chosen 042 043 044 /**************************************************************************** 045 * 046 * Basic memory setting and zeroing operations 047 */ 048 049 /** 050 * Zero a region of memory 051 * 052 * @param start The start of the region to be zeroed (must be 4-byte aligned) 053 * @param bytes The number of bytes to be zeroed (must be 4-byte aligned) 054 */ 055 @Inline 056 public static void zero(Address start, Extent bytes) { 057 if (VM.VERIFY_ASSERTIONS) { 058 assertAligned(start); 059 assertAligned(bytes); 060 } 061 if (bytes.GT(Extent.fromIntZeroExtend(SMALL_REGION_THRESHOLD))) 062 VM.memory.zero(false, start, bytes); 063 else 064 zeroSmall(start, bytes); 065 } 066 067 /** 068 * Zero a small region of memory 069 * 070 * @param start The start of the region to be zeroed (must be 4-byte aligned) 071 * @param bytes The number of bytes to be zeroed (must be 4-byte aligned) 072 */ 073 @Inline 074 public static void zeroSmall(Address start, Extent bytes) { 075 if (VM.VERIFY_ASSERTIONS) { 076 assertAligned(start); 077 assertAligned(bytes); 078 } 079 Address end = start.plus(bytes); 080 for (Address addr = start; addr.LT(end); addr = addr.plus(BYTES_IN_INT)) 081 addr.store(0); 082 } 083 084 /** 085 * Set a region of memory 086 * 087 * @param start The start of the region to be zeroed (must be 4-byte aligned) 088 * @param bytes The number of bytes to be zeroed (must be 4-byte aligned) 089 * @param value The value to which the integers in the region should be set 090 */ 091 @Inline 092 public static void set(Address start, int bytes, int value) { 093 if (VM.VERIFY_ASSERTIONS) { 094 assertAligned(start); 095 assertAligned(bytes); 096 } 097 Address end = start.plus(bytes); 098 for (Address addr = start; addr.LT(end); addr = addr.plus(BYTES_IN_INT)) 099 addr.store(value); 100 } 101 102 103 /**************************************************************************** 104 * 105 * Helper methods 106 */ 107 108 /** 109 * Check that a memory range is zeroed 110 * 111 * @param start The start address of the range to be checked 112 * @param bytes The size of the region to be checked, in bytes 113 * @return {@code true} if the region is zeroed 114 */ 115 @Inline 116 public static boolean isZeroed(Address start, int bytes) { 117 return isSet(start, bytes, false, 0); 118 } 119 120 /** 121 * Assert that a memory range is zeroed. An assertion failure will 122 * occur if the region is not zeroed.<p> 123 * 124 * this is in the inline allocation sequence when 125 * VM.VERIFY_ASSERTIONS is {@code true}, it is carefully written to 126 * reduce the impact on code space. 127 * 128 * @param start The start address of the range to be checked 129 * @param bytes The size of the region to be checked, in bytes 130 */ 131 @NoInline 132 public static void assertIsZeroed(Address start, int bytes) { 133 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isSet(start, bytes, true, 0)); 134 } 135 136 /** 137 * Verbosely check and return {@code true} if a memory range is set to some 138 * integer value 139 * 140 * @param start The start address of the range to be checked 141 * @param bytes The size of the region to be checked, in bytes 142 * @param value The value to which this region should be set 143 * @return {@code true} if the region has been correctly set 144 */ 145 @Inline 146 public static boolean isSet(Address start, int bytes, int value) { 147 return isSet(start, bytes, true, value); 148 } 149 150 /** 151 * Assert appropriate alignment, triggering an assertion failure if 152 * the value does not satisfy the alignment requirement of the 153 * memory operations. 154 * 155 * @param value The value to be tested 156 */ 157 private static void assertAligned(int value) { 158 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert((value & (BYTES_IN_INT - 1)) == 0); 159 } 160 161 private static void assertAligned(Word value) { 162 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(value.and(Word.fromIntSignExtend(BYTES_IN_INT - 1)).isZero()); 163 } 164 165 private static void assertAligned(Extent value) { 166 assertAligned(value.toWord()); 167 } 168 169 private static void assertAligned(Address value) { 170 assertAligned(value.toWord()); 171 } 172 173 /** 174 * Test whether a memory range is set to a given integer value 175 * 176 * @param start The address to start checking at 177 * @param bytes The size of the region to check, in bytes 178 * @param verbose If {@code true}, produce verbose output 179 * @param value The value to which the memory should be set 180 * @return {@code true} if the memory range is set to the given value, 181 * {@code false} if there's at least one address where another value 182 * is saved 183 */ 184 @NoInline 185 private static boolean isSet(Address start, int bytes, boolean verbose, 186 int value) 187 /* Inlining this loop into the uninterruptible code can 188 * cause/encourage the GCP into moving a get_obj_tib into the 189 * interruptible region where the TIB is being installed via an 190 * int_store 191 */ { 192 if (VM.VERIFY_ASSERTIONS) assertAligned(bytes); 193 for (int i = 0; i < bytes; i += BYTES_IN_INT) 194 if (start.loadInt(Offset.fromIntSignExtend(i)) != value) { 195 if (verbose) { 196 Log.prependThreadId(); 197 Log.write("VM range does not contain only value "); 198 Log.writeln(value); 199 Log.write("Non-zero range: "); Log.write(start); 200 Log.write(" .. "); Log.writeln(start.plus(bytes)); 201 Log.write("First bad value at "); Log.writeln(start.plus(i)); 202 dumpMemory(start, 0, bytes); 203 } 204 return false; 205 } 206 return true; 207 } 208 209 /** 210 * Dump the contents of memory around a given address 211 * 212 * @param addr The address around which the memory should be dumped 213 * @param beforeBytes The number of bytes before the address to be 214 * included in the dump 215 * @param afterBytes The number of bytes after the address to be 216 * included in the dump 217 */ 218 public static void dumpMemory(Address addr, int beforeBytes, int afterBytes) { 219 VM.memory.dumpMemory(addr, beforeBytes, afterBytes); 220 } 221}