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.jikesrvm.runtime;
014
015import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT;
016import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_DOUBLE;
017import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
018import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_SHORT;
019import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
020
021import org.jikesrvm.VM;
022import org.vmmagic.pragma.Inline;
023import org.vmmagic.pragma.Uninterruptible;
024import org.vmmagic.unboxed.Address;
025import org.vmmagic.unboxed.Extent;
026import org.vmmagic.unboxed.Offset;
027import org.vmmagic.unboxed.Word;
028
029/**
030 * Low level memory management functions.
031 * <p>
032 * Note that this class is "uninterruptible" - calling its methods will never
033 * cause the current thread to yield the CPU to another thread (one that
034 * might cause a GC, for example).
035 */
036@Uninterruptible
037public class Memory {
038
039  private static final int UNKNOWN = -1;
040
041  ////////////////////////
042  // (1) Utilities for copying/filling/zeroing memory
043  ////////////////////////
044
045  /**
046   * How many bytes is considered large enough to justify the transition to
047   * C code to use memcpy?
048   */
049  private static final int NATIVE_THRESHOLD = 512;
050
051  /**
052   * Allow the use of C based memcpy
053   */
054  private static final boolean USE_NATIVE = true;
055
056  /**
057   * Number of bytes used when copying larger chunks of memory. Normally 8 bytes
058   * except on x87 Intel
059   */
060  private static final int BYTES_IN_COPY = VM.BuildForIA32 && !VM.BuildForSSE2 ? 4 : 8;
061
062  @Inline
063  private static void copy8Bytes(Address dstPtr, Address srcPtr) {
064    if (BYTES_IN_COPY == 8) {
065      if (VM.BuildForIA32) {
066        dstPtr.store(srcPtr.loadLong());
067      } else {
068        dstPtr.store(srcPtr.loadDouble());
069      }
070    } else {
071      copy4Bytes(dstPtr, srcPtr);
072      copy4Bytes(dstPtr.plus(4), srcPtr.plus(4));
073    }
074  }
075  @Inline
076  private static void copy4Bytes(Address dstPtr, Address srcPtr) {
077    dstPtr.store(srcPtr.loadInt());
078  }
079  @Inline
080  private static void copy2Bytes(Address dstPtr, Address srcPtr) {
081    dstPtr.store(srcPtr.loadChar());
082  }
083  @Inline
084  private static void copy1Bytes(Address dstPtr, Address srcPtr) {
085    dstPtr.store(srcPtr.loadByte());
086  }
087  /**
088   * Low level copy of len elements from src[srcPos] to dst[dstPos].
089   *
090   * Assumptions: <code> src != dst || (scrPos &gt;= dstPos + 4) </code>
091   *              and src and dst are 8Bit arrays.
092   * @param src     the source array
093   * @param srcPos  index in the source array to begin copy
094   * @param dst     the destination array
095   * @param dstPos  index in the destination array to being copy
096   * @param len     number of array elements to copy
097   */
098  public static void arraycopy8Bit(Object src, int srcPos, Object dst, int dstPos, int len) {
099    Address srcPtr = Magic.objectAsAddress(src).plus(srcPos);
100    Address dstPtr = Magic.objectAsAddress(dst).plus(dstPos);
101    aligned8Copy(dstPtr, srcPtr, len);
102  }
103
104  /**
105   * Low level copy of <code>copyBytes</code> bytes from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
106   *
107   * Assumption <code>src != dst || (srcPos &gt;= dstPos)</code> and element size is 4 bytes.
108   *
109   * @param dstPtr The destination start address
110   * @param srcPtr The source start address
111   * @param copyBytes The number of bytes to be copied
112   */
113  public static void aligned8Copy(Address dstPtr, Address srcPtr, int copyBytes) {
114    if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
115      memcopy(dstPtr, srcPtr, copyBytes);
116    } else {
117      if (copyBytes >= BYTES_IN_COPY &&
118          (srcPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)).EQ(
119          (dstPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)))))) {
120        // relative alignment is the same
121        Address endPtr = srcPtr.plus(copyBytes);
122        Address wordEndPtr = endPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1).not()).toAddress();
123
124        if (BYTES_IN_COPY == 8) {
125          if (srcPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
126            copy1Bytes(dstPtr, srcPtr);
127            srcPtr = srcPtr.plus(1);
128            dstPtr = dstPtr.plus(1);
129          }
130          if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
131            copy2Bytes(dstPtr, srcPtr);
132            srcPtr = srcPtr.plus(2);
133            dstPtr = dstPtr.plus(2);
134          }
135          if (srcPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
136            copy4Bytes(dstPtr, srcPtr);
137            srcPtr = srcPtr.plus(4);
138            dstPtr = dstPtr.plus(4);
139          }
140        } else {
141          if (srcPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
142            copy1Bytes(dstPtr, srcPtr);
143            srcPtr = srcPtr.plus(1);
144            dstPtr = dstPtr.plus(1);
145          }
146          if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
147            copy2Bytes(dstPtr, srcPtr);
148            srcPtr = srcPtr.plus(2);
149            dstPtr = dstPtr.plus(2);
150          }
151        }
152        while (srcPtr.LT(wordEndPtr)) {
153          if (BYTES_IN_COPY == 8) {
154            copy8Bytes(dstPtr, srcPtr);
155          } else {
156            copy4Bytes(dstPtr, srcPtr);
157          }
158          srcPtr = srcPtr.plus(BYTES_IN_COPY);
159          dstPtr = dstPtr.plus(BYTES_IN_COPY);
160        }
161        // if(VM.VerifyAssertions) VM._assert(wordEndPtr.EQ(srcPtr));
162        if (BYTES_IN_COPY == 8) {
163          if (endPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
164            copy4Bytes(dstPtr, srcPtr);
165            srcPtr = srcPtr.plus(4);
166            dstPtr = dstPtr.plus(4);
167          }
168          if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
169            copy2Bytes(dstPtr, srcPtr);
170            srcPtr = srcPtr.plus(2);
171            dstPtr = dstPtr.plus(2);
172          }
173          if (endPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
174            copy1Bytes(dstPtr, srcPtr);
175          }
176        } else {
177          if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
178            copy2Bytes(dstPtr, srcPtr);
179            srcPtr = srcPtr.plus(2);
180            dstPtr = dstPtr.plus(2);
181          }
182          if (endPtr.toWord().and(Word.fromIntZeroExtend(1)).NE(Word.zero())) {
183            copy1Bytes(dstPtr, srcPtr);
184          }
185        }
186      } else {
187        Address endPtr = srcPtr.plus(copyBytes);
188        while (srcPtr.LT(endPtr)) {
189          dstPtr.store(srcPtr.loadByte());
190          srcPtr = srcPtr.plus(1);
191          dstPtr = dstPtr.plus(1);
192        }
193      }
194    }
195  }
196
197  /**
198   * Low level copy of len elements from src[srcPos] to dst[dstPos].
199   * <p>
200   * Assumption; {@code src != dst || (srcPos &gt;= dstPos + 2)}.
201   *
202   * @param src     the source array
203   * @param srcPos  index in the source array to begin copy
204   * @param dst     the destination array
205   * @param dstPos  index in the destination array to being copy
206   * @param len     number of array elements to copy
207   */
208  public static void arraycopy16Bit(Object src, int srcPos, Object dst, int dstPos, int len) {
209    Address srcPtr = Magic.objectAsAddress(src).plus(srcPos << LOG_BYTES_IN_SHORT);
210    Address dstPtr = Magic.objectAsAddress(dst).plus(dstPos << LOG_BYTES_IN_SHORT);
211    int copyBytes = len << LOG_BYTES_IN_SHORT;
212    aligned16Copy(dstPtr, srcPtr, copyBytes);
213  }
214  /**
215   * Low level copy of <code>copyBytes</code> bytes from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
216   * <p>
217   * Assumption: <code>src != dst || (srcPos &gt;= dstPos)</code> and element size is 2 bytes.
218   *
219   * @param dstPtr The destination start address
220   * @param srcPtr The source start address
221   * @param copyBytes The number of bytes to be copied
222   */
223  public static void aligned16Copy(Address dstPtr, Address srcPtr, int copyBytes) {
224    if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
225      memcopy(dstPtr, srcPtr, copyBytes);
226    } else {
227      if (copyBytes >= BYTES_IN_COPY &&
228          (srcPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)).EQ(
229          (dstPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1)))))) {
230        // relative alignment is the same
231        Address endPtr = srcPtr.plus(copyBytes);
232        Address wordEndPtr = endPtr.toWord().and(Word.fromIntZeroExtend(BYTES_IN_COPY - 1).not()).toAddress();
233
234        if (BYTES_IN_COPY == 8) {
235          if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
236            copy2Bytes(dstPtr, srcPtr);
237            srcPtr = srcPtr.plus(2);
238            dstPtr = dstPtr.plus(2);
239          }
240          if (srcPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
241            copy4Bytes(dstPtr, srcPtr);
242            srcPtr = srcPtr.plus(4);
243            dstPtr = dstPtr.plus(4);
244          }
245        } else {
246          if (srcPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
247            copy2Bytes(dstPtr, srcPtr);
248            srcPtr = srcPtr.plus(2);
249            dstPtr = dstPtr.plus(2);
250          }
251        }
252        while (srcPtr.LT(wordEndPtr)) {
253          if (BYTES_IN_COPY == 8) {
254            copy8Bytes(dstPtr, srcPtr);
255          } else {
256            copy4Bytes(dstPtr, srcPtr);
257          }
258          srcPtr = srcPtr.plus(BYTES_IN_COPY);
259          dstPtr = dstPtr.plus(BYTES_IN_COPY);
260        }
261        // if(VM.VerifyAssertions) VM._assert(wordEndPtr.EQ(srcPtr));
262        if (BYTES_IN_COPY == 8) {
263          if (endPtr.toWord().and(Word.fromIntZeroExtend(4)).NE(Word.zero())) {
264            copy4Bytes(dstPtr, srcPtr);
265            srcPtr = srcPtr.plus(4);
266            dstPtr = dstPtr.plus(4);
267          }
268          if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
269            copy2Bytes(dstPtr, srcPtr);
270          }
271        } else {
272          if (endPtr.toWord().and(Word.fromIntZeroExtend(2)).NE(Word.zero())) {
273            copy2Bytes(dstPtr, srcPtr);
274          }
275        }
276      } else {
277        Address endPtr = srcPtr.plus(copyBytes);
278        while (srcPtr.LT(endPtr)) {
279          copy2Bytes(dstPtr, srcPtr);
280          srcPtr = srcPtr.plus(2);
281          dstPtr = dstPtr.plus(2);
282        }
283      }
284    }
285  }
286
287  /**
288   * Low level copy of <code>len</code> elements from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
289   * <p>
290   * Assumption: <code>src != dst || (srcPos &gt;= dstPos)</code> and element size is 4 bytes.
291   *
292   * @param src     the source array
293   * @param srcIdx  index in the source array to begin copy
294   * @param dst     the destination array
295   * @param dstIdx  index in the destination array to being copy
296   * @param len     number of array elements to copy
297   */
298  public static void arraycopy32Bit(Object src, int srcIdx, Object dst, int dstIdx, int len) {
299    Address srcPtr = Magic.objectAsAddress(src).plus(srcIdx << LOG_BYTES_IN_INT);
300    Address dstPtr = Magic.objectAsAddress(dst).plus(dstIdx << LOG_BYTES_IN_INT);
301    int copyBytes = len << LOG_BYTES_IN_INT;
302    aligned32Copy(dstPtr, srcPtr, copyBytes);
303  }
304
305  /**
306   * Low level copy of <code>len</code> elements from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
307   * <p>
308   * Assumption: <code>src != dst || (srcPos &gt;= dstPos)</code> and element size is 8 bytes.
309   *
310   * @param src     the source array
311   * @param srcIdx  index in the source array to begin copy
312   * @param dst     the destination array
313   * @param dstIdx  index in the destination array to being copy
314   * @param len     number of array elements to copy
315   */
316  public static void arraycopy64Bit(Object src, int srcIdx, Object dst, int dstIdx, int len) {
317    Offset srcOffset = Offset.fromIntZeroExtend(srcIdx << LOG_BYTES_IN_DOUBLE);
318    Offset dstOffset = Offset.fromIntZeroExtend(dstIdx << LOG_BYTES_IN_DOUBLE);
319    int copyBytes = len << LOG_BYTES_IN_DOUBLE;
320    aligned64Copy(Magic.objectAsAddress(dst).plus(dstOffset), Magic.objectAsAddress(src).plus(srcOffset), copyBytes);
321  }
322
323  /**
324   * Low level copy of <code>copyBytes</code> bytes from <code>src[srcPos]</code> to <code>dst[dstPos]</code>.
325   *
326   * Assumption <code>src != dst || (srcPos &gt;= dstPos)</code> and element size is 8 bytes.
327   *
328   * @param dstPtr The destination start address
329   * @param srcPtr The source start address
330   * @param copyBytes The number of bytes to be copied
331   */
332  public static void aligned64Copy(Address dstPtr, Address srcPtr, int copyBytes) {
333    if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
334      memcopy(dstPtr, srcPtr, copyBytes);
335    } else {
336      // The elements of long[] and double[] are always doubleword aligned
337      // therefore we can do 64 bit load/stores without worrying about alignment.
338      Address endPtr = srcPtr.plus(copyBytes);
339      while (srcPtr.LT(endPtr)) {
340        copy8Bytes(dstPtr, srcPtr);
341        srcPtr = srcPtr.plus(8);
342        dstPtr = dstPtr.plus(8);
343      }
344    }
345  }
346
347
348  /**
349   * Copy copyBytes from src to dst.
350   * Assumption: either the ranges are non overlapping, or {@code src &gt;= dst + 4}.
351   * Also, src and dst are 4 byte aligned and numBytes is a multiple of 4.
352   *
353   * @param dst the destination addr
354   * @param src the source addr
355   * @param copyBytes the number of bytes top copy
356   */
357  public static void aligned32Copy(Address dst, Address src, int copyBytes) {
358    if (VM.VerifyAssertions) {
359      VM._assert(copyBytes >= 0);
360      VM._assert((copyBytes & (BYTES_IN_INT - 1)) == 0);
361      VM._assert(src.toWord().and(Word.fromIntZeroExtend(BYTES_IN_INT - 1)).isZero());
362      VM._assert(dst.toWord().and(Word.fromIntZeroExtend(BYTES_IN_INT - 1)).isZero());
363      VM._assert(src.plus(copyBytes).LE(dst) || src.GE(dst.plus(BYTES_IN_INT)));
364    }
365    if (USE_NATIVE && copyBytes > NATIVE_THRESHOLD) {
366      memcopy(dst, src, copyBytes);
367    } else {
368      Offset numBytes = Offset.fromIntSignExtend(copyBytes);
369      if (BYTES_IN_COPY == 8 && copyBytes != 0) {
370        Word wordMask = Word.fromIntZeroExtend(BYTES_IN_COPY - 1);
371        Word srcAlignment = src.toWord().and(wordMask);
372        if (srcAlignment.EQ(dst.toWord().and(wordMask))) {
373          Offset i = Offset.zero();
374          if (srcAlignment.EQ(Word.fromIntZeroExtend(BYTES_IN_INT))) {
375            copy4Bytes(dst.plus(i), src.plus(i));
376            i = i.plus(BYTES_IN_INT);
377          }
378          Word endAlignment = srcAlignment.plus(numBytes).and(wordMask);
379          numBytes = numBytes.minus(endAlignment.toOffset());
380          for (; i.sLT(numBytes); i = i.plus(BYTES_IN_COPY)) {
381            copy8Bytes(dst.plus(i), src.plus(i));
382          }
383          if (!endAlignment.isZero()) {
384            copy4Bytes(dst.plus(i), src.plus(i));
385          }
386          return;
387        }
388      }
389      //normal case: 32 bit or (64 bit not aligned)
390      for (Offset i = Offset.zero(); i.sLT(numBytes); i = i.plus(BYTES_IN_INT)) {
391        copy4Bytes(dst.plus(i), src.plus(i));
392      }
393    }
394  }
395
396  /**
397   * Copy numbytes from src to dst.
398   * Assumption: either the ranges are non overlapping, or {@code src &gt;= dst + BYTES_IN_ADDRESS}.
399   * Also, src and dst are word aligned and numBytes is a multiple of BYTES_IN_ADDRESS.
400   * @param dst the destination addr
401   * @param src the source addr
402   * @param numBytes the number of bytes top copy
403   */
404  public static void alignedWordCopy(Address dst, Address src, int numBytes) {
405    if (USE_NATIVE && numBytes > NATIVE_THRESHOLD) {
406      memcopy(dst, src, numBytes);
407    } else {
408      internalAlignedWordCopy(dst, src, numBytes);
409    }
410  }
411
412  /**
413   * Copy <code>numbytes</code> from <code>src</code> to <code>dst</code>.
414   * Assumption either the ranges are non overlapping, or <code>src &gt;= dst + BYTES_IN_ADDRESS</code>.
415   * @param dst     The destination addr
416   * @param src     The source addr
417   * @param numBytes The number of bytes to copy
418   */
419  private static void internalAlignedWordCopy(Address dst, Address src, int numBytes) {
420    Address end = src.plus(numBytes);
421    while (src.LT(end)) {
422      dst.store(src.loadWord());
423      src = src.plus(BYTES_IN_ADDRESS);
424      dst = dst.plus(BYTES_IN_ADDRESS);
425    }
426  }
427
428  /**
429   * Copies a region of memory.
430   *
431   * @param dst   Destination address
432   * @param src   Source address
433   * @param cnt   Number of bytes to copy
434   */
435  public static void memcopy(Address dst, Address src, Extent cnt) {
436    Address srcEnd = src.plus(cnt);
437    Address dstEnd = dst.plus(cnt);
438    boolean overlap = !srcEnd.LE(dst) && !dstEnd.LE(src);
439    if (overlap) {
440      SysCall.sysCall.sysMemmove(dst, src, cnt);
441    } else {
442      SysCall.sysCall.sysCopy(dst, src, cnt);
443    }
444  }
445
446  /**
447   * Wrapper method for {@link #memcopy(Address, Address, Extent)}.
448   *
449   * @param dst   Destination address
450   * @param src   Source address
451   * @param cnt   Number of bytes to copy
452   */
453  public static void memcopy(Address dst, Address src, int cnt) {
454    memcopy(dst, src, Extent.fromIntSignExtend(cnt));
455  }
456
457
458  /**
459   * Zero a region of memory.
460   *
461   * @param useNT use non-temporal instructions (if available)
462   * @param start of address range (inclusive)
463   * @param len extent to zero.
464   */
465  public static void zero(boolean useNT, Address start, Extent len) {
466    if (useNT) {
467      SysCall.sysCall.sysZeroNT(start, len);
468    } else {
469      SysCall.sysCall.sysZero(start, len);
470    }
471  }
472
473  ////////////////////////
474  // (2) Cache management
475  ////////////////////////
476
477  /**
478   * Synchronize a region of memory: force data in dcache to be written out to main
479   * memory so that it will be seen by icache when instructions are fetched back.
480   * @param address  Start of address range
481   * @param size     Size of address range (bytes)
482   */
483  public static void sync(Address address, int size) {
484    SysCall.sysCall.sysSyncCache(address, size);
485  }
486
487  ////////////////////////
488  // (3) MMap
489  ////////////////////////
490
491  // constants for protection and mapping calls
492  public static final int PROT_NONE = 0;
493  public static final int PROT_READ = 1;
494  public static final int PROT_WRITE = 2;
495  public static final int PROT_EXEC = 4;
496
497  public static final int MAP_PRIVATE = 2;
498  public static final int MAP_FIXED     = (VM.BuildForLinux) ? 16 : (VM.BuildForOsx) ?     16 : (VM.BuildForSolaris) ? 0x10 : 256;
499  public static final int MAP_ANONYMOUS = (VM.BuildForLinux) ? 32 : (VM.BuildForOsx) ? 0x1000 : (VM.BuildForSolaris) ? 0x100 : 16;
500
501  public static boolean isPageMultiple(int val) {
502    int pagesizeMask = getPagesize() - 1;
503    return ((val & pagesizeMask) == 0);
504  }
505
506  public static boolean isPageMultiple(Extent val) {
507    Word pagesizeMask = Word.fromIntZeroExtend(getPagesize() - 1);
508    return val.toWord().and(pagesizeMask).isZero();
509  }
510
511  public static boolean isPageMultiple(Offset val) {
512    Word pagesizeMask = Word.fromIntZeroExtend(getPagesize() - 1);
513    return val.toWord().and(pagesizeMask).isZero();
514  }
515
516  public static boolean isPageAligned(Address addr) {
517    Word pagesizeMask = Word.fromIntZeroExtend(getPagesize() - 1);
518    return addr.toWord().and(pagesizeMask).isZero();
519  }
520
521  /**
522   * Do generic mmap non-file memory mapping call
523   * @param address  Start of address range (Address)
524   * @param size    Size of address range
525   * @param prot    Protection (int)
526   * @param flags (int)
527   * @return Address (of region) if successful; errno (1 to 127) otherwise
528   */
529  public static Address mmap(Address address, Extent size, int prot, int flags) {
530    if (VM.VerifyAssertions) {
531      VM._assert(isPageAligned(address) && isPageMultiple(size));
532    }
533    return SysCall.sysCall.sysMMapErrno(address, size, prot, flags, -1, Offset.zero());
534  }
535
536  /**
537   * Do mmap demand zero fixed address memory mapping call
538   * @param address  Start of address range
539   * @param size     Size of address range
540   * @return Address (of region) if successful; errno (1 to 127) otherwise
541   */
542  public static Address dzmmap(Address address, Extent size) {
543    if (VM.VerifyAssertions) {
544      VM._assert(isPageAligned(address) && isPageMultiple(size));
545    }
546    int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
547    int flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED;
548    return mmap(address, size, prot, flags);
549  }
550
551  /**
552   * Do mprotect system call
553   * @param address Start of address range (Address)
554   * @param size Size of address range
555   * @param prot Protection (int)
556   * @return true iff success
557   */
558  public static boolean mprotect(Address address, Extent size, int prot) {
559    if (VM.VerifyAssertions) {
560      VM._assert(isPageAligned(address) && isPageMultiple(size));
561    }
562    return SysCall.sysCall.sysMProtect(address, size, prot) == 0;
563  }
564
565  private static int pagesize = UNKNOWN;
566  private static int pagesizeLog = UNKNOWN;
567
568  /**
569   * Sets the page size.
570   * <p>
571   * Note: this method may only be called once, at boot time. Multithreading is not
572   * yet enabled at this point, so no synchronization is necessary.
573   * @param pageSizeFromBootRecord the page size
574   */
575  public static void setPageSize(Extent pageSizeFromBootRecord) {
576    if (pagesize == UNKNOWN) {
577      int newPageSize = pageSizeFromBootRecord.toInt();
578      if (VM.VerifyAssertions) VM._assert(Extent.fromIntSignExtend(newPageSize).EQ(pageSizeFromBootRecord));
579      pagesize = newPageSize;
580      pagesizeLog = UNKNOWN;
581      int temp = pagesize;
582      while (temp > 0) {
583        temp >>>= 1;
584        pagesizeLog++;
585      }
586      if (VM.VerifyAssertions) VM._assert((1 << pagesizeLog) == pagesize);
587      return;
588    }
589    if (VM.VerifyAssertions) VM._assert(VM.NOT_REACHED);
590  }
591
592  public static int getPagesize() {
593    if (VM.VerifyAssertions) VM._assert(pagesize != UNKNOWN);
594    return pagesize;
595  }
596
597  public static int getPagesizeLog() {
598    if (VM.VerifyAssertions) VM._assert(pagesizeLog != UNKNOWN);
599    return pagesizeLog;
600  }
601
602  public static byte getPagesizeLogAsByte() {
603    int pageSizeLog = getPagesizeLog();
604    byte pageSizeLogByte = (byte) pageSizeLog;
605    if (VM.VerifyAssertions) VM._assert(pageSizeLog == pageSizeLogByte);
606    return pageSizeLogByte;
607  }
608
609  public static void dumpMemory(Address start, int beforeBytes, int afterBytes) {
610
611    beforeBytes = alignDown(beforeBytes, BYTES_IN_ADDRESS);
612    afterBytes = alignUp(afterBytes, BYTES_IN_ADDRESS);
613    VM.sysWrite("---- Dumping memory from ");
614    VM.sysWrite(start.minus(beforeBytes));
615    VM.sysWrite(" to ");
616    VM.sysWrite(start.plus(afterBytes));
617    VM.sysWrite(" ----\n");
618    for (int i = -beforeBytes; i < afterBytes; i += BYTES_IN_ADDRESS) {
619      VM.sysWrite(i, ": ");
620      VM.sysWrite(start.plus(i));
621      Word value = start.plus(i).loadWord();
622      VM.sysWriteln("  ", value);
623    }
624  }
625
626  @Inline
627  public static Address alignUp(Address address, int alignment) {
628    return address.plus(alignment - 1).toWord().and(Word.fromIntSignExtend(~(alignment - 1))).toAddress();
629  }
630
631  @Inline
632  public static Address alignDown(Address address, int alignment) {
633    return address.toWord().and(Word.fromIntSignExtend(~(alignment - 1))).toAddress();
634  }
635
636  // These versions are here to accommodate the boot image writer
637  @Inline
638  public static int alignUp(int address, int alignment) {
639    return ((address + alignment - 1) & ~(alignment - 1));
640  }
641
642  @Inline
643  public static int alignDown(int address, int alignment) {
644    return (address & ~(alignment - 1));
645  }
646
647  /**
648   * For use in test cases only.
649   * @return native threshold (number in bytes before copying uses C code)
650   */
651  static int getNativeThreshold() {
652    return NATIVE_THRESHOLD;
653  }
654
655}