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    }