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