/* * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.max.memory; import static com.sun.max.vm.MaxineVM.*; import java.nio.*; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.program.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.runtime.*; /** * This class provides methods to access raw memory through pointers. * It also provides allocation methods that are expected to be for small quantities * of memory (or quantities that are not multiple of a page) that will be satisfied * by the native allocation library, i.e. malloc/free. * Large amounts of memory should be allocated using the {@link VirtualMemory} class. */ public final class Memory { private Memory() { } @HOSTED_ONLY private static byte[] buf = new byte[1024]; @HOSTED_ONLY public static ByteBuffer memory = ByteBuffer.wrap(buf); public static final OutOfMemoryError OUT_OF_MEMORY_ERROR = new OutOfMemoryError(); /** * Marker used for filling dead heap area when in debug mode. * Note: the low-order bit must be 0 so the marker isn't confused with a forwarder. */ public static final long ZAPPED_MARKER = 0xDEADBEEFCAFEBABEL; @C_FUNCTION private static native Pointer memory_allocate(Size size); /** * Allocates an aligned chunk of memory using a malloc(3)-like facility. * * @param size the size of the chunk of memory to be allocated * @return a pointer to the allocated chunk of memory or {@code Pointer.zero()} if allocation failed */ public static Pointer allocate(Size size) { if (size.toLong() < 0) { throw new IllegalArgumentException(); } if (isHosted()) { return boxedAllocate(size); } return memory_allocate(size); } @HOSTED_ONLY private static synchronized Pointer boxedAllocate(Size size) { int offset = buf.length; int newLength = offset + size.toInt(); buf = Arrays.copyOf(buf, newLength); memory = ByteBuffer.wrap(buf); memory.order(ByteOrder.nativeOrder()); return Pointer.fromInt(offset); } /** * @param size the size of the chunk of memory to be allocated * @return a pointer to the allocated chunk of memory * @throws OutOfMemoryError if allocation failed or log message and VM termination if early in bootstrap */ public static Pointer mustAllocate(Size size) throws OutOfMemoryError, IllegalArgumentException { final Pointer result = isHosted() ? boxedAllocate(size) : memory_allocate(size); if (result.isZero()) { if (MaxineVM.isPrimordialOrPristine()) { MaxineVM.reportPristineMemoryFailure("unknown", "mustAllocate", size); } else { throw OUT_OF_MEMORY_ERROR; } } return result; } /** * @param size the size of the chunk of memory to be allocated * @return a pointer to the allocated chunk of memory * @throws IllegalArgumentException if size is negative * @throws OutOfMemoryError if allocation failed */ public static Pointer mustAllocate(int size) throws OutOfMemoryError, IllegalArgumentException { return mustAllocate(Size.fromInt(size)); } @C_FUNCTION private static native Pointer memory_reallocate(Pointer block, Size size); public static Pointer reallocate(Pointer block, Size size) throws OutOfMemoryError, IllegalArgumentException { if (isHosted()) { Pointer newBlock = allocate(size); Memory.copyBytes(block, newBlock, size); return newBlock; } return memory_reallocate(block, size); } @C_FUNCTION private static native int memory_deallocate(Address pointer); public static void deallocate(Address block) throws IllegalArgumentException { if (block.isZero()) { throw new IllegalArgumentException(); } final int errorCode = isHosted() ? 0 /* TODO (ds): implement a free list */ : memory_deallocate(block); if (errorCode != 0) { throw ProgramError.unexpected("Memory.deallocate() failed with OS error code: " + errorCode); } } @NO_SAFEPOINT_POLLS("speed") public static void setBytes(Pointer pointer, Size numberOfBytes, byte value) { for (Offset i = Offset.zero(); i.lessThan(numberOfBytes.asOffset()); i = i.plus(1)) { pointer.writeByte(i, value); } } @NO_SAFEPOINT_POLLS("speed") public static void setWords(Pointer pointer, int numberOfWords, Word value) { for (int i = 0; i < (numberOfWords * Word.size()); i += Word.size()) { pointer.writeWord(i, value); } } @NO_SAFEPOINT_POLLS("speed, and used in code that shouldn't be interrupted by GC") public static void clearWords(Pointer start, int length) { FatalError.check(start.isWordAligned(), "Can only zero word-aligned region"); for (int i = 0; i < length; i++) { start.setWord(i, Address.zero()); } } @NO_SAFEPOINT_POLLS("speed") public static void setBytes(Pointer pointer, int numberOfBytes, byte value) { for (int i = 0; i < numberOfBytes; i++) { pointer.writeByte(i, value); } } @NO_SAFEPOINT_POLLS("speed") public static void clearBytes(Pointer pointer, int numberOfBytes) { setBytes(pointer, numberOfBytes, (byte) 0); } @NO_SAFEPOINT_POLLS("speed") public static boolean equals(Pointer pointer1, Pointer pointer2, Size numberOfBytes) { for (Offset i = Offset.zero(); i.lessThan(numberOfBytes.asOffset()); i = i.plus(1)) { if (pointer1.readByte(i) != pointer2.readByte(i)) { return false; } } return true; } @NO_SAFEPOINT_POLLS("speed") public static boolean equals(Pointer pointer1, byte[] bytes) { for (int i = 0; i < bytes.length; i++) { if (pointer1.readByte(i) != bytes[i]) { return false; } } return true; } @NO_SAFEPOINT_POLLS("speed") public static void copyBytes(Pointer fromPointer, Pointer toPointer, Size numberOfBytes) { Offset i = Offset.zero(); Size wordBounds = numberOfBytes.alignDown(Word.size()); while (i.lessThan(wordBounds.asOffset())) { toPointer.writeWord(i, fromPointer.readWord(i)); i = i.plus(Word.size()); } while (i.lessThan(numberOfBytes.asOffset())) { toPointer.writeByte(i, fromPointer.readByte(i)); i = i.plus(1); } assert i.equals(numberOfBytes); } @NO_SAFEPOINT_POLLS("speed") public static void readBytes(Pointer fromPointer, int numberOfBytes, byte[] toArray, int startIndex) { for (int i = 0; i < numberOfBytes; i++) { toArray[startIndex + i] = fromPointer.readByte(i); } } @NO_SAFEPOINT_POLLS("speed") public static void readBytes(Pointer fromPointer, int numberOfBytes, byte[] toArray) { readBytes(fromPointer, numberOfBytes, toArray, 0); } @NO_SAFEPOINT_POLLS("speed") public static void readBytes(Pointer fromPointer, byte[] toArray) { readBytes(fromPointer, toArray.length, toArray, 0); } @NO_SAFEPOINT_POLLS("speed") public static void readWords(Pointer fromPointer, int numberOfWords, Word[] toArray, int startIndex) { for (int i = 0; i < numberOfWords; i++) { WordArray.set(toArray, startIndex + i, fromPointer.getWord(i)); } } @NO_SAFEPOINT_POLLS("speed") public static void readWords(Pointer fromPointer, int numberOfWords, Word[] toArray) { readWords(fromPointer, numberOfWords, toArray, 0); } @NO_SAFEPOINT_POLLS("speed") public static void readWords(Pointer fromPointer, Word[] toArray) { readWords(fromPointer, toArray.length, toArray, 0); } @NO_SAFEPOINT_POLLS("speed") public static void writeBytes(byte[] fromArray, int startIndex, int numberOfBytes, Pointer toPointer) { for (int i = 0; i < numberOfBytes; i++) { toPointer.writeByte(i, fromArray[startIndex + i]); } } @NO_SAFEPOINT_POLLS("speed") public static void writeBytes(byte[] fromArray, int numberOfBytes, Pointer toPointer) { writeBytes(fromArray, 0, numberOfBytes, toPointer); } @NO_SAFEPOINT_POLLS("speed") public static void writeBytes(byte[] fromArray, Pointer toPointer) { writeBytes(fromArray, fromArray.length, toPointer); } @NO_SAFEPOINT_POLLS("speed") public static void zapRegion(MemoryRegion region) { FatalError.check(region.start().isWordAligned(), "Can only zap word-aligned region"); FatalError.check(region.size().remainder(Word.size()) == 0, "Can only zap region of words"); setWords(region.start().asPointer(), region.size().dividedBy(Word.size()).toInt(), zappedMarker()); } @FOLD public static Address zappedMarker() { return Address.fromLong(ZAPPED_MARKER); } }