/* * 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.unsafe; import static com.sun.max.memory.Memory.*; import static com.sun.max.vm.MaxineVM.*; import static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*; import com.oracle.max.cri.intrinsics.*; import com.sun.max.annotate.*; import com.sun.max.lang.*; import com.sun.max.platform.*; import com.sun.max.program.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.runtime.*; import com.sun.max.vm.type.*; /** * Pointers are addresses with extra methods to access memory. */ public final class Pointer extends Address implements Accessor { private static final int FLOAT_SIZE = 4; private static final int DOUBLE_SIZE = 8; @HOSTED_ONLY public Pointer(long value) { super(value); } public interface Procedure { void run(Pointer pointer); } public interface Predicate { boolean evaluate(Pointer pointer); } @INLINE public static Pointer zero() { return isHosted() ? ZERO : fromInt(0); } @INLINE public static Pointer fromUnsignedInt(int value) { if (isHosted()) { final long longValue = value; final long n = longValue & 0xffffffffL; return fromLong(n); } return Address.fromUnsignedInt(value).asPointer(); } @INLINE public static Pointer fromInt(int value) { if (isHosted()) { return fromLong(value & INT_MASK); } return Address.fromInt(value).asPointer(); } @INLINE public static Pointer fromLong(long value) { if (isHosted()) { if (value == 0) { return ZERO; } if (value == -1L) { return MAX; } return new Pointer(value); } return Address.fromLong(value).asPointer(); } @Override @HOSTED_ONLY public String toString() { return "^" + toHexString(); } @Override @INLINE public Pointer plus(int addend) { return super.plus(addend).asPointer(); } @Override @INLINE public Pointer plus(long addend) { return super.plus(addend).asPointer(); } @Override @INLINE public Pointer plus(Address addend) { return super.plus(addend).asPointer(); } @Override @INLINE public Pointer plus(Offset addend) { return super.plus(addend).asPointer(); } @Override @INLINE public Pointer plusWords(int nWords) { return super.plusWords(nWords).asPointer(); } @Override @INLINE public Pointer minus(Address subtrahend) { return super.minus(subtrahend).asPointer(); } @Override @INLINE public Pointer minus(int subtrahend) { return super.minus(subtrahend).asPointer(); } @Override @INLINE public Pointer minus(long subtrahend) { return super.minus(subtrahend).asPointer(); } @Override @INLINE public Pointer minusWords(int nWords) { return super.minusWords(nWords).asPointer(); } @Override @INLINE public Pointer minus(Offset subtrahend) { return super.minus(subtrahend).asPointer(); } @Override @INLINE public Pointer times(Address factor) { return super.times(factor).asPointer(); } @Override @INLINE public Pointer times(int factor) { return super.times(factor).asPointer(); } @Override @INLINE public Pointer dividedBy(Address divisor) { return super.dividedBy(divisor).asPointer(); } @Override @INLINE public Pointer dividedBy(int divisor) { return super.dividedBy(divisor).asPointer(); } @Override @INLINE public Pointer remainder(Address divisor) { return super.remainder(divisor).asPointer(); } @Override @INLINE public Pointer roundedUpBy(Address nBytes) { return super.roundedUpBy(nBytes).asPointer(); } @Override @INLINE public Pointer roundedUpBy(int nBytes) { return super.roundedUpBy(nBytes).asPointer(); } @Override @INLINE public Pointer roundedDownBy(int nBytes) { return super.roundedDownBy(nBytes).asPointer(); } @Override @INLINE public Pointer wordAligned() { return super.wordAligned().asPointer(); } @Override @INLINE public boolean isWordAligned() { return super.isWordAligned(); } @Override @INLINE public Pointer bitSet(int index) { return super.bitSet(index).asPointer(); } @Override @INLINE public Pointer bitClear(int index) { return super.bitClear(index).asPointer(); } @Override @INLINE public Pointer and(Address operand) { return super.and(operand).asPointer(); } @Override @INLINE public Pointer and(int operand) { return super.and(operand).asPointer(); } @Override @INLINE public Pointer and(long operand) { return super.and(operand).asPointer(); } @Override @INLINE public Pointer or(Address operand) { return super.or(operand).asPointer(); } @Override @INLINE public Pointer or(int operand) { return super.or(operand).asPointer(); } @Override @INLINE public Pointer or(long operand) { return super.or(operand).asPointer(); } @Override @INLINE public Pointer not() { return super.not().asPointer(); } @Override @INLINE public Pointer shiftedLeft(int nBits) { return super.shiftedLeft(nBits).asPointer(); } @Override @INLINE public Pointer unsignedShiftedRight(int nBits) { return super.unsignedShiftedRight(nBits).asPointer(); } @FOLD private static boolean risc() { return Platform.platform().isa.category == ISA.Category.RISC; } @INTRINSIC(PREAD_OFF) public byte readByte(int offset) { return readByte(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public byte readByte(Offset offset) { return memory.get(address(offset)); } @INTRINSIC(PREAD_IDX) public byte getByte(int displacement, int index) { return readByte(Offset.fromInt(index).plus(displacement)); } @INLINE public byte getByte(int index) { return getByte(0, index); } @INLINE public byte getByte() { return getByte(0); } @INLINE public boolean readBoolean(Offset offset) { return UnsafeCast.asBoolean(readByte(offset)); } @INLINE public boolean readBoolean(int offset) { return UnsafeCast.asBoolean(readByte(offset)); } @INLINE public boolean getBoolean(int displacement, int index) { return UnsafeCast.asBoolean(getByte(displacement, index)); } @INLINE public boolean getBoolean(int index) { return getBoolean(0, index); } @INLINE public boolean getBoolean() { return getBoolean(0); } @INTRINSIC(PREAD_OFF) public short readShort(int offset) { return readShort(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public short readShort(Offset offset) { return memory.getShort(address(offset)); } @INTRINSIC(PREAD_IDX) public short getShort(int displacement, int index) { return readShort(Offset.fromInt(index).times(Shorts.SIZE).plus(displacement)); } @INLINE public short getShort(int index) { return getShort(0, index); } @INLINE public short getShort() { return getShort(0); } @INTRINSIC(PREAD_OFF) public char readChar(int offset) { return readChar(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public char readChar(Offset offset) { return memory.getChar(address(offset)); } @INTRINSIC(PREAD_IDX) public char getChar(int displacement, int index) { return readChar(Offset.fromInt(index).times(Chars.SIZE).plus(displacement)); } @INLINE public char getChar(int index) { return getChar(0, index); } @INLINE public char getChar() { return getChar(0); } @INTRINSIC(PREAD_OFF) public int readInt(int offset) { return readInt(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public int readInt(Offset offset) { return memory.getInt(address(offset)); } @INTRINSIC(PREAD_IDX) public int getInt(int displacement, int index) { return readInt(Offset.fromInt(index).times(Ints.SIZE).plus(displacement)); } @INLINE public int getInt(int index) { return getInt(0, index); } @INLINE public int getInt() { return getInt(0); } @INTRINSIC(PREAD_OFF) public float readFloat(int offset) { return readFloat(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public float readFloat(Offset offset) { return memory.getFloat(address(offset)); } @INTRINSIC(PREAD_IDX) public float getFloat(int displacement, int index) { return readFloat(Offset.fromInt(index).times(FLOAT_SIZE).plus(displacement)); } @INLINE public float getFloat(int index) { return getFloat(0, index); } @INLINE public float getFloat() { return getFloat(0); } @INTRINSIC(PREAD_OFF) public long readLong(int offset) { return readLong(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public long readLong(Offset offset) { return memory.getLong(address(offset)); } @INTRINSIC(PREAD_IDX) public long getLong(int displacement, int index) { return readLong(Offset.fromInt(index).times(Longs.SIZE).plus(displacement)); } @INLINE public long getLong(int index) { return getLong(0, index); } @INLINE public long getLong() { return getLong(0); } @INTRINSIC(PREAD_OFF) public double readDouble(int offset) { return readDouble(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public double readDouble(Offset offset) { return memory.getDouble(address(offset)); } @INTRINSIC(PREAD_IDX) public double getDouble(int displacement, int index) { return readDouble(Offset.fromInt(index).times(DOUBLE_SIZE).plus(displacement)); } @INLINE public double getDouble(int index) { return getDouble(0, index); } @INLINE public double getDouble() { return getDouble(0); } @INTRINSIC(PREAD_OFF) public Word readWord(int offset) { return readWord(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public Word readWord(Offset offset) { if (Word.width() == 64) { return Address.fromLong(readLong(offset)); } return Address.fromInt(readInt(offset)); } @INTRINSIC(PREAD_IDX) public Word getWord(int displacement, int index) { return readWord(Offset.fromInt(index).times(Word.size()).plus(displacement)); } @INLINE public Word getWord(int index) { return getWord(0, index); } @INLINE public Word getWord() { return getWord(0); } @INTRINSIC(PREAD_OFF) public Reference readReference(int offset) { return readReference(Offset.fromInt(offset)); } @INTRINSIC(PREAD_OFF) public Reference readReference(Offset offset) { throw ProgramError.unexpected(); } @INTRINSIC(PREAD_IDX) public Reference getReference(int displacement, int index) { return readReference(Offset.fromInt(index).times(Word.size()).plus(displacement)); } @INLINE public Reference getReference(int index) { return getReference(0, index); } @INLINE public Reference getReference() { return getReference(0); } @INTRINSIC(PWRITE_OFF) public void writeByte(int offset, byte value) { writeByte(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeByte(Offset offset, byte value) { memory.put(address(offset), value); } @INTRINSIC(PWRITE_IDX) public void setByte(int displacement, int index, byte value) { writeByte(Offset.fromInt(index).plus(displacement), value); } @INLINE public void setByte(int index, byte value) { setByte(0, index, value); } @INLINE public void setByte(byte value) { setByte(0, value); } @INLINE public void writeBoolean(Offset offset, boolean value) { writeByte(offset, UnsafeCast.asByte(value)); } @INLINE public void writeBoolean(int offset, boolean value) { writeByte(offset, UnsafeCast.asByte(value)); } @INLINE public void setBoolean(int displacement, int index, boolean value) { setByte(displacement, index, UnsafeCast.asByte(value)); } @INLINE public void setBoolean(int index, boolean value) { setBoolean(0, index, value); } @INLINE public void setBoolean(boolean value) { setBoolean(0, value); } @INTRINSIC(PWRITE_OFF) public void writeShort(int offset, short value) { writeShort(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeShort(Offset offset, short value) { memory.putShort(address(offset), value); } @INTRINSIC(PWRITE_IDX) public void setShort(int displacement, int index, short value) { writeShort(Offset.fromInt(index).times(Shorts.SIZE).plus(displacement), value); } @INLINE public void setShort(int index, short value) { setShort(0, index, value); } @INLINE public void setShort(short value) { setShort(0, value); } @INLINE public void writeChar(Offset offset, char value) { writeShort(offset, UnsafeCast.asShort(value)); } @INLINE public void writeChar(int offset, char value) { writeShort(offset, UnsafeCast.asShort(value)); } @INLINE public void setChar(int displacement, int index, char value) { setShort(displacement, index, UnsafeCast.asShort(value)); } @INLINE public void setChar(int index, char value) { setChar(0, index, value); } @INLINE public void setChar(char value) { setChar(0, value); } @INTRINSIC(PWRITE_OFF) public void writeInt(int offset, int value) { writeInt(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeInt(Offset offset, int value) { memory.putInt(address(offset), value); } @INTRINSIC(PWRITE_IDX) public void setInt(int displacement, int index, int value) { writeInt(Offset.fromInt(index).times(Ints.SIZE).plus(displacement), value); } @INLINE public void setInt(int index, int value) { setInt(0, index, value); } @INLINE public void setInt(int value) { setInt(0, value); } @INTRINSIC(PWRITE_OFF) public void writeFloat(int offset, float value) { writeFloat(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeFloat(Offset offset, float value) { memory.putFloat(address(offset), value); } @INTRINSIC(PWRITE_IDX) public void setFloat(int displacement, int index, float value) { writeFloat(Offset.fromInt(index).times(FLOAT_SIZE).plus(displacement), value); } @INLINE public void setFloat(int index, float value) { setFloat(0, index, value); } @INLINE public void setFloat(float value) { setFloat(0, value); } @INTRINSIC(PWRITE_OFF) public void writeLong(int offset, long value) { writeLong(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeLong(Offset offset, long value) { memory.putLong(address(offset), value); } @INTRINSIC(PWRITE_IDX) public void setLong(int displacement, int index, long value) { writeLong(Offset.fromInt(index).times(Longs.SIZE).plus(displacement), value); } @INLINE public void setLong(int index, long value) { setLong(0, index, value); } @INLINE public void setLong(long value) { setLong(0, value); } @INTRINSIC(PWRITE_OFF) public void writeDouble(int offset, double value) { writeDouble(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeDouble(Offset offset, double value) { memory.putDouble(address(offset), value); } @INTRINSIC(PWRITE_IDX) public void setDouble(int displacement, int index, double value) { writeDouble(Offset.fromInt(index).times(DOUBLE_SIZE).plus(displacement), value); } @INLINE public void setDouble(int index, double value) { setDouble(0, index, value); } @INLINE public void setDouble(double value) { setDouble(0, value); } @INTRINSIC(PWRITE_OFF) public void writeWord(int offset, Word value) { writeWord(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeWord(Offset offset, Word value) { if (Word.width() == 64) { writeLong(offset, value.asOffset().toLong()); } else { writeInt(offset, value.asOffset().toInt()); } } @INTRINSIC(PWRITE_IDX) public void setWord(int displacement, int index, Word value) { writeWord(Offset.fromInt(index).times(Word.size()).plus(displacement), value); } @INLINE public void setWord(int index, Word value) { setWord(0, index, value); } @INLINE public void setWord(Word value) { setWord(0, value); } @INLINE public void writeObject(int offset, Object value) { writeReference(Offset.fromInt(offset), Reference.fromJava(value)); } @INTRINSIC(PWRITE_OFF) public void writeReference(int offset, Reference value) { writeReference(Offset.fromInt(offset), value); } @INTRINSIC(PWRITE_OFF) public void writeReference(Offset offset, Reference value) { throw ProgramError.unexpected(); } @INTRINSIC(PWRITE_IDX) public void setReference(int displacement, int index, Reference value) { writeReference(Offset.fromInt(index).times(Word.size()).plus(displacement), value); } @INLINE public void setReference(int index, Reference value) { setReference(0, index, value); } @INLINE public void setReference(Reference value) { setReference(0, value); } /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INTRINSIC(PCMPSWP) public native int compareAndSwapInt(int offset, int expectedValue, int newValue); /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INTRINSIC(PCMPSWP) public native int compareAndSwapInt(Offset offset, int expectedValue, int newValue); /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INTRINSIC(PCMPSWP) public native long compareAndSwapLong(int offset, long expectedValue, long newValue); /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INTRINSIC(PCMPSWP) public native long compareAndSwapLong(Offset offset, long expectedValue, long newValue); /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INLINE public Word compareAndSwapWord(int offset, Word expectedValue, Word newValue) { if (Word.width() == 64) { return fromLong(compareAndSwapLong(offset, expectedValue.asAddress().toLong(), newValue.asAddress().toLong())); } return fromInt(compareAndSwapInt(offset, expectedValue.asAddress().toInt(), newValue.asAddress().toInt())); } /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INLINE public Word compareAndSwapWord(Offset offset, Word expectedValue, Word newValue) { if (Word.width() == 64) { return fromLong(compareAndSwapLong(offset, expectedValue.asAddress().toLong(), newValue.asAddress().toLong())); } return fromInt(compareAndSwapInt(offset, expectedValue.asAddress().toInt(), newValue.asAddress().toInt())); } /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INTRINSIC(PCMPSWP) public native Reference compareAndSwapReference(int offset, Reference expectedValue, Reference newValue); /** * @see Accessor#compareAndSwapInt(Offset, int, int) */ @INTRINSIC(PCMPSWP) public native Reference compareAndSwapReference(Offset offset, Reference expectedValue, Reference newValue); /** * Sets a bit in the bit map whose base is denoted by the value of this pointer. * * ATTENTION: There is no protection against concurrent access to the affected byte. * * This method may read the affected byte first, then set the bit in it and then write the byte back. * * @param bitIndex the index of the bit to set */ @INLINE public void setBit(int bitIndex) { final int byteIndex = UnsignedMath.divide(bitIndex, Bytes.WIDTH); byte byteValue = getByte(byteIndex); byteValue |= 1 << (bitIndex % Bytes.WIDTH); setByte(byteIndex, byteValue); } /** * Modifies up to 8 bits in the bit map whose base is denoted by the value of this pointer * by OR'ing in a given 8-bit mask. * * ATTENTION: There is no protection against concurrent access to affected bytes. * * This method may read each affected byte first, then set some bits in it and then write the byte back. * There are either 1 or 2 affected bytes, depending on alignment of the bit index to bytes in memory. * * @param bitIndex the index of the first bit to set * @param bits a mask of 8 bits OR'ed with the 8 bits in this bit map starting at {@code bitIndex} */ @INLINE public void setBits(int bitIndex, byte bits) { // If we do not mask off the leading bits after a conversion to int right here, // then the arithmetic operations below will convert implicitly to int and may insert sign bits. final int intBits = bits & 0xff; int byteIndex = UnsignedMath.divide(bitIndex, Bytes.WIDTH); final int rest = bitIndex % Bytes.WIDTH; byte byteValue = getByte(byteIndex); byteValue |= intBits << rest; setByte(byteIndex, byteValue); if (rest > 0) { byteIndex++; byteValue = getByte(byteIndex); byteValue |= intBits >>> (Bytes.WIDTH - rest); setByte(byteIndex, byteValue); } } @HOSTED_ONLY public void copyElements(int displacement, int srcIndex, Object dst, int dstIndex, int length) { Kind kind = Kind.fromJava(dst.getClass().getComponentType()); switch (kind.asEnum) { case BOOLEAN: { boolean[] arr = (boolean[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getBoolean(displacement, srcIndex + i); } break; } case BYTE: { byte[] arr = (byte[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getByte(displacement, srcIndex + i); } break; } case CHAR: { char[] arr = (char[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getChar(displacement, srcIndex + i); } break; } case SHORT: { short[] arr = (short[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getShort(displacement, srcIndex + i); } break; } case INT: { int[] arr = (int[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getInt(displacement, srcIndex + i); } break; } case FLOAT: { float[] arr = (float[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getFloat(displacement, srcIndex + i); } break; } case LONG: { long[] arr = (long[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getLong(displacement, srcIndex + i); } break; } case DOUBLE: { double[] arr = (double[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getDouble(displacement, srcIndex + i); } break; } case REFERENCE: { Reference[] arr = (Reference[]) dst; for (int i = 0; i < length; ++i) { arr[dstIndex + i] = getReference(displacement, srcIndex + i); } break; } case WORD: { Word[] arr = (Word[]) dst; for (int i = 0; i < length; ++i) { WordArray.set(arr, dstIndex + i, getWord(displacement, srcIndex + i)); } break; } default: throw FatalError.unexpected("invalid type"); } } @HOSTED_ONLY private static final Pointer ZERO = new Pointer(0); @HOSTED_ONLY private static final Pointer MAX = new Pointer(-1L); @HOSTED_ONLY private static final int HIGHEST_CACHED_VALUE = 1000000; @HOSTED_ONLY private static final Pointer[] cache = new Pointer[HIGHEST_CACHED_VALUE + 1]; @HOSTED_ONLY public static Pointer from(long value) { if (value == 0) { return ZERO; } if (value >= 0 && value <= HIGHEST_CACHED_VALUE) { int cacheIndex = (int) value; Pointer ptr = cache[cacheIndex]; if (ptr == null) { ptr = new Pointer(value); cache[cacheIndex] = ptr; } return ptr; } if (value == -1L) { return MAX; } return new Pointer(value); } @HOSTED_ONLY private int address(Offset offset) { assert (int) value == value; return (int) value + offset.toInt(); } }