/* * 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.platform.Platform.*; import static com.sun.max.vm.MaxineVM.*; import static com.sun.max.vm.intrinsics.MaxineIntrinsicIDs.*; import java.io.*; import java.lang.reflect.*; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.config.*; import com.sun.max.lang.*; import com.sun.max.program.*; import com.sun.max.vm.*; import com.sun.max.vm.jni.*; import com.sun.max.vm.value.*; /** * A machine-word sized unboxed type. The {@code Word} type itself is mostly opaque, providing operations * to determine the {@linkplain #size() size} (in bytes) and {@linkplain #width() width} (in bits) of a word. * Subclasses define extra operations such as {@linkplain Offset signed} and {@linkplain Address unsigned} * arithmetic, and {@linkplain Pointer pointer} operations. * * The closure of {@code Word} types (i.e. all the classes that subclass {@link Word}) is {@linkplain #getSubclasses() discovered} * during initialization in a hosted environment. This discovery mechanism relies on the same package based * facility used to configure the schemes of a VM. Each package that defines one or more {@code Word} subclasses * must also declare a subclass of {@link BootImagePackage} named "Package" that overrides {@link BootImagePackage#wordSubclasses()}. * * @see WordValue */ public class Word { @HOSTED_ONLY public static final long INT_MASK = 0x00000000ffffffffL; /** * The array of all the subclasses of {@link Word} that are accessible in the VM boot image configuration * in hosted mode. This value of this array is constructed * by scanning the {@link VMConfiguration#bootImagePackages packages} (that subclasses {@link BootImagePackage}). * Any instance that overrides the {@link BootImagePackage#wordSubclasses()} method * has it invoked to obtain the set of classes in the denoted package that subclass {@code Word}. */ @HOSTED_ONLY private static Class[] classes; /** * Gets all the classes VM (boot image) configuration that subclass {@link Word}. */ @HOSTED_ONLY public static Class[] getSubclasses() { if (classes == null) { final ArrayList<Class> list = new ArrayList<Class>(); for (BootImagePackage pkg : VMConfiguration.vmConfig().bootImagePackages) { Class[] wordClasses = pkg.wordSubclasses(); if (wordClasses != null) { for (Class wordClass : wordClasses) { String wordClassName = wordClass.getName(); assert Classes.getPackageName(wordClassName).equals(pkg.name()) : "Word subclass " + wordClass.getName() + " should be registered by " + Classes.getPackageName(wordClassName) + ".Package not " + pkg + ".Package"; list.add(wordClass); } } } classes = list.toArray(new Class[list.size()]); } return classes; } @HOSTED_ONLY public Word(long value) { if (Word.width() == 64) { this.value = value; } else { this.value = value & INT_MASK; } } @INLINE public static Word zero() { return Address.zero(); } @INLINE public static Word allOnes() { return Address.max(); } @FOLD public static Endianness endianness() { return platform().endianness(); } @FOLD public static WordWidth widthValue() { return platform().wordWidth(); } @FOLD public static int width() { return widthValue().numberOfBits; } @FOLD public static int size() { return widthValue().numberOfBytes; } @INTRINSIC(UNSAFE_CAST) public final JniHandle asJniHandle() { if (this instanceof JniHandle) { return (JniHandle) this; } return new JniHandle(value); } @INTRINSIC(UNSAFE_CAST) public final Address asAddress() { if (this instanceof Address) { return (Address) this; } return Address.fromLong(value); } @INTRINSIC(UNSAFE_CAST) public final Offset asOffset() { if (this instanceof Offset) { return (Offset) this; } return Offset.fromLong(value); } @INTRINSIC(UNSAFE_CAST) public final Size asSize() { if (this instanceof Size) { return (Size) this; } return Size.fromLong(value); } @INTRINSIC(UNSAFE_CAST) public final Pointer asPointer() { if (this instanceof Pointer) { return (Pointer) this; } return Pointer.fromLong(value); } /** * @return bit index of the least significant bit set, or -1 if zero. */ @INLINE public final int leastSignificantBitSet() { return Intrinsics.leastSignificantBit(this); } /** * @return bit index of the most significant bit set, or -1 if zero. */ @INLINE public final int mostSignificantBitSet() { return Intrinsics.mostSignificantBit(this); } @HOSTED_ONLY public final <Word_Type extends Word> Word_Type as(Class<Word_Type> wordType) { if (wordType.isInstance(this)) { return wordType.cast(this); } if (Pointer.class.isAssignableFrom(wordType)) { return wordType.cast(asPointer()); } if (Size.class.isAssignableFrom(wordType)) { return wordType.cast(asSize()); } if (Address.class.isAssignableFrom(wordType)) { return wordType.cast(asAddress()); } if (Offset.class.isAssignableFrom(wordType)) { return wordType.cast(asOffset()); } try { final Constructor constructor = wordType.getConstructor(long.class); return wordType.cast(constructor.newInstance(value)); } catch (Throwable throwable) { throw ProgramError.unexpected(throwable); } } /** * Creates a string representation of a {@code Word}. * * @return an unpadded string representation in hex, without "0x" prefix */ @INLINE public final String toHexString() { return toHexString(this); } public static String toHexString(Word value) { String result = Long.toHexString(value.asAddress().toLong()); if (width() == 32 && result.length() > 8) { result = result.substring(result.length() - 8); } return result; } /** * Creates a string representation of a {@code Word}. * * @return an unpadded string representation in hex, with "0x" prefix */ @INLINE public final String to0xHexString() { return to0xHexString(this); } public static String to0xHexString(Word value) { String result = Long.toHexString(value.asAddress().toLong()); if (width() == 32 && result.length() > 8) { result = result.substring(result.length() - 8); } return "0x" + result; } /** * Creates a string representation of a {@code Word}. * * @param pad padding character * @return a padded string representation in hex, without "0x" prefix */ @INLINE public final String toPaddedHexString(char pad) { return toPaddedHexString(this, pad); } public static String toPaddedHexString(Word value, char pad) { if (Word.width() == 64) { return Longs.toPaddedHexString(value.asAddress().toLong(), pad); } return Ints.toPaddedHexString(value.asAddress().toInt(), pad); } /** * Creates a string representation of a {@code Word}. * * @param pad padding character * @return a padded string representation in hex, with "0x" prefix */ @INLINE public final String toPadded0xHexString(char pad) { return toPadded0xHexString(this, pad); } public static String toPadded0xHexString(Word value, char pad) { if (Word.width() == 64) { return "0x" + Longs.toPaddedHexString(value.asAddress().toLong(), pad); } return "0x" + Ints.toPaddedHexString(value.asAddress().toInt(), pad); } @Override @HOSTED_ONLY public String toString() { return "$" + toHexString(); } @Override @HOSTED_ONLY public final int hashCode() { return asOffset().toInt(); } @INLINE public final boolean isZero() { if (isHosted()) { return value == 0; } return equals(Word.zero()); } @INLINE public final boolean isNotZero() { if (isHosted()) { return value != 0; } return !equals(Word.zero()); } @INLINE public final boolean isAllOnes() { if (isHosted()) { return value == -1; } return equals(Word.allOnes()); } @INLINE public final boolean equals(Word other) { if (isHosted()) { return value == other.value; } if (Word.width() == 64) { return asOffset().toLong() == other.asOffset().toLong(); } return asOffset().toInt() == other.asOffset().toInt(); } @INLINE public final boolean equals(CodePointer other) { if (isHosted()) { return value == other.toLong(); } return asAddress().toLong() == other.toLong(); } @Override @HOSTED_ONLY public final boolean equals(Object other) { throw ProgramError.unexpected("must not call equals(Object) with Word argument"); } /** * Reads an address from a given data input stream. */ @INLINE public static Word read(DataInput stream) throws IOException { if (width() == 64) { return Address.fromLong(stream.readLong()); } return Address.fromInt(stream.readInt()); } /** * Writes this address to a given data output stream. */ @INLINE public final void write(DataOutput stream) throws IOException { if (width() == 64) { stream.writeLong(asAddress().toLong()); } else { stream.writeInt(asAddress().toInt()); } } /** * Reads an address from a given input stream using a given endianness. */ @INLINE public static Word read(InputStream inputStream, Endianness endianness) throws IOException { if (width() == 64) { return Address.fromLong(endianness.readLong(inputStream)); } return Address.fromInt(endianness.readInt(inputStream)); } /** * Writes this address to a given output stream using a given endianness. */ @INLINE public final void write(OutputStream outputStream, Endianness endianness) throws IOException { if (width() == 64) { endianness.writeLong(outputStream, asAddress().toLong()); } else { endianness.writeInt(outputStream, asAddress().toInt()); } } @HOSTED_ONLY public final long value; }