/* * 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.vm.MaxineVM.*; import java.math.*; import com.oracle.max.cri.intrinsics.*; import com.sun.max.annotate.*; import com.sun.max.lang.*; import com.sun.max.program.*; /** * A machine word interpreted as a linear address. * An Address is unsigned and arithmetic is supported. */ public class Address extends Word { @INLINE public static Address zero() { return isHosted() ? ZERO : fromInt(0); } @INLINE public static Address max() { return isHosted() ? MAX : fromLong(-1L); } /** * Creates an Address value from a given int value. Note that unlike {@link #fromInt(int)}, * the given int value is not sign extended. Also note that on 32-bit platforms, this operation * is effectively a no-op. * * @param value the value to be converted to an Address */ @INLINE public static Address fromUnsignedInt(int value) { if (isHosted()) { final long longValue = value; final long n = longValue & 0xffffffffL; return fromLong(n); } if (Word.width() == 64) { final long longValue = value; final long n = longValue & 0xffffffffL; return UnsafeCast.asAddress(n); } return UnsafeCast.asAddress(value); } /** * Creates an Address value from a given int value. Note that unlike {@link #fromUnsignedInt(int)}, * the given int value is sign extended first. Also note that on 32-bit platforms, this operation * is effectively a no-op. * * @param value the value to be converted to an Address */ @INLINE public static Address fromInt(int value) { if (isHosted()) { return Address.fromLong(value & INT_MASK); } if (Word.width() == 64) { final long n = value; return UnsafeCast.asAddress(n); } return UnsafeCast.asAddress(value); } @INLINE public static Address fromLong(long value) { if (isHosted()) { if (value == 0) { return ZERO; } if (value >= 0 && value <= Cache.HIGHEST_VALUE) { return Cache.cache[(int) value]; } if (value == -1L) { return MAX; } return new Address(value); } if (Word.width() == 64) { return UnsafeCast.asAddress(value); } final int n = (int) value; return UnsafeCast.asAddress(n); } @Override @HOSTED_ONLY public String toString() { return "@" + toHexString(); } @HOSTED_ONLY public final String toUnsignedString(int radix) { if (radix == 16) { if (Word.width() == 64) { return Long.toHexString(toLong()); } assert Word.width() == 32; return Integer.toHexString(toInt()); } if (radix == 8) { if (Word.width() == 64) { return Long.toOctalString(toLong()); } assert Word.width() == 32; return Integer.toOctalString(toInt()); } if (radix == 2) { if (Word.width() == 64) { return Long.toBinaryString(toLong()); } assert Word.width() == 32; return Integer.toBinaryString(toInt()); } assert radix == 10; final long n = toLong(); if (Word.width() == 32) { if (n <= Integer.MAX_VALUE && n >= 0) { return Integer.toString(toInt()); } return Long.toString(n & 0xffffffffL); } final long low = n & 0xffffffffL; final long high = n >>> 32; return BigInteger.valueOf(high).shiftLeft(32).or(BigInteger.valueOf(low)).toString(); } @HOSTED_ONLY public static Address parse(String s, int radix) { Address result = Address.zero(); for (int i = 0; i < s.length(); i++) { result = result.times(radix); result = result.plus(Integer.parseInt(String.valueOf(s.charAt(i)), radix)); } return result; } @INLINE public final int toInt() { if (isHosted()) { return (int) value; } if (Word.width() == 64) { final long n = UnsafeCast.asLong(this); return (int) n; } return UnsafeCast.asInt(this); } @INLINE public final long toLong() { if (isHosted()) { return value; } if (Word.width() == 64) { return UnsafeCast.asLong(this); } return 0xffffffffL & UnsafeCast.asInt(this); } @INLINE public final int compareTo(Address other) { if (greaterThan(other)) { return 1; } if (lessThan(other)) { return -1; } return 0; } @INLINE public final boolean equals(int other) { if (isHosted()) { return toLong() == other; } return fromInt(other) == this; } @INLINE public final boolean greaterThan(Address other) { if (Word.width() == 64) { return UnsignedMath.aboveThan(toLong(), other.toLong()); } return UnsignedMath.aboveThan(toInt(), other.toInt()); } @INLINE public final boolean greaterThan(int other) { return greaterThan(fromInt(other)); } @INLINE public final boolean greaterEqual(Address other) { if (Word.width() == 64) { return UnsignedMath.aboveOrEqual(toLong(), other.toLong()); } return UnsignedMath.aboveOrEqual(toInt(), other.toInt()); } @INLINE public final boolean greaterEqual(int other) { return greaterEqual(fromInt(other)); } @INLINE public final boolean lessThan(Address other) { if (Word.width() == 64) { return UnsignedMath.belowThan(toLong(), other.toLong()); } return UnsignedMath.belowThan(toInt(), other.toInt()); } @INLINE public final boolean lessThan(int other) { return lessThan(fromInt(other)); } @INLINE public final boolean lessEqual(Address other) { if (Word.width() == 64) { return UnsignedMath.belowOrEqual(toLong(), other.toLong()); } return UnsignedMath.belowOrEqual(toInt(), other.toInt()); } @INLINE public final boolean lessEqual(int other) { return lessEqual(fromInt(other)); } @INLINE public Address plus(Address addend) { return asOffset().plus(addend.asOffset()).asAddress(); } @INLINE public Address plus(Offset offset) { return asOffset().plus(offset).asAddress(); } @INLINE public Address plus(int addend) { return asOffset().plus(addend).asAddress(); } @INLINE public Address plus(long addend) { return asOffset().plus(addend).asAddress(); } @INLINE public Address minus(Address subtrahend) { return asOffset().minus(subtrahend.asOffset()).asAddress(); } @INLINE public Address minus(Offset offset) { return asOffset().minus(offset).asAddress(); } @INLINE public Address plusWords(int nWords) { return plus(nWords * Word.size()); } @INLINE public Address minus(int subtrahend) { return asOffset().minus(subtrahend).asAddress(); } @INLINE public Address minusWords(int nWords) { return minus(nWords * Word.size()); } @INLINE public Address minus(long subtrahend) { return asOffset().minus(subtrahend).asAddress(); } @INLINE public Address times(Address factor) { return asOffset().times(factor.asOffset()).asAddress(); } @INLINE public Address times(int factor) { return asOffset().times(factor).asAddress(); } @INLINE public Address dividedBy(Address divisor) { if (Word.width() == 64) { return fromLong(UnsignedMath.divide(toLong(), divisor.toLong())); } return fromInt(UnsignedMath.divide(toInt(), divisor.toInt())); } @INLINE public Address dividedBy(int divisor) { return dividedBy(fromInt(divisor)); } @INLINE public Address remainder(Address divisor) { if (Word.width() == 64) { return fromLong(UnsignedMath.remainder(toLong(), divisor.toLong())); } return fromInt(UnsignedMath.remainder(toInt(), divisor.toInt())); } @INLINE public final int remainder(int divisor) { return remainder(fromInt(divisor)).toInt(); } @INLINE public final boolean isRoundedBy(Address nBytes) { return remainder(nBytes).isZero(); } @INLINE public final boolean isRoundedBy(int nBytes) { return remainder(nBytes) == 0; } @INLINE public Address roundedUpBy(Address nBytes) { if (isRoundedBy(nBytes)) { return this; } return plus(nBytes.minus(remainder(nBytes))); } @INLINE public Address roundedUpBy(int nBytes) { if (isRoundedBy(nBytes)) { return this; } return plus(nBytes - remainder(nBytes)); } @INLINE public Address roundedDownBy(int nBytes) { return minus(remainder(nBytes)); } @INLINE public Address wordAligned() { return alignUp(Word.size()); } @INLINE public Address alignUp(int alignment) { return plus(alignment - 1).alignDown(alignment); } @INLINE public Address alignDown(int alignment) { return and(Address.fromInt(alignment - 1).not()); } @INLINE public boolean isWordAligned() { final int n = Word.size(); return and(n - 1).equals(Address.zero()); } @INLINE public boolean isAligned(int alignment) { return and(alignment - 1).equals(Address.zero()); } @INLINE public final boolean isBitSet(int index) { return (toLong() & (1L << index)) != 0; } @INLINE public Address bitSet(int index) { return fromLong(toLong() | (1L << index)); } @INLINE public Address bitClear(int index) { return fromLong(toLong() & ~(1L << index)); } @INLINE public Address and(Address operand) { if (Word.width() == 64) { return fromLong(toLong() & operand.toLong()); } return fromInt(toInt() & operand.toInt()); } @INLINE public Address and(int operand) { return and(fromInt(operand)); } @INLINE public Address and(long operand) { return and(fromLong(operand)); } @INLINE public Address or(Address operand) { if (Word.width() == 64) { return fromLong(toLong() | operand.toLong()); } return fromInt(toInt() | operand.toInt()); } @INLINE public Address or(int operand) { return or(fromInt(operand)); } @INLINE public Address or(long operand) { return or(fromLong(operand)); } @INLINE public Address not() { if (Word.width() == 64) { return fromLong(~toLong()); } return fromInt(~toInt()); } @INLINE public Address shiftedLeft(int nBits) { if (Word.width() == 64) { return fromLong(toLong() << nBits); } return fromInt(toInt() << nBits); } @INLINE public Address unsignedShiftedRight(int nBits) { if (Word.width() == 64) { return fromLong(toLong() >>> nBits); } return fromInt(toInt() >>> nBits); } @INLINE public final int numberOfEffectiveBits() { if (Word.width() == 64) { return 64 - Long.numberOfLeadingZeros(toLong()); } return 32 - Integer.numberOfLeadingZeros(toInt()); } @HOSTED_ONLY public final WordWidth effectiveWidth() { final int bit = numberOfEffectiveBits(); for (WordWidth width : WordWidth.VALUES) { if (bit < width.numberOfBits) { return width; } } throw ProgramError.unexpected(); } @HOSTED_ONLY private static final Address ZERO = new Address(0); @HOSTED_ONLY private static final Address MAX = new Address(-1L); @HOSTED_ONLY private static final class Cache { private Cache() { } static final int HIGHEST_VALUE = 1000; static final Address[] cache = new Address[HIGHEST_VALUE + 1]; static { for (int i = 0; i < cache.length; i++) { cache[i] = new Address(i); } } } @HOSTED_ONLY public Address(long value) { super(value); } }