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 }