/*
* Copyright (c) 2007, 2011, 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 com.sun.max.annotate.*;
import com.sun.max.program.*;
import com.sun.max.vm.*;
import com.sun.max.vm.code.*;
import com.sun.max.vm.compiler.target.*;
import com.sun.max.vm.reference.*;
/**
* A {@code CodePointer} is a tagged pointer that is known to reference native code.
*
* The least significant bit is 1. The remaining 63 bits are interpreted as an offset from the lowest existing {@link CodeRegion}
* start address. This is typically the start address of the {@linkplain Code#bootCodeRegion() boot code region}.
*
* Note that the interpretation as a 63-bit offset from the boot code region start is solely internal. All values passed into
* creation methods are supposed to be full 64-bit pointers. All values returned from conversion methods are full 64-bit pointers.
*
* {@code CodePointer}s, in spite of their pointer characteristics, inherit from {@link Object} instead of {@link Word} to remain
* visible to the memory manager. They are recognised as references but treated specially.
*/
public final class CodePointer {
private static long BASE_ADDRESS = MaxineVM.isHosted() ? 0x1000000000000000L : Code.bootCodeRegion().start().toLong();
/**
* Set the base address. This is needed since the static field will otherwise not be properly initialised
* if the VM is running properly. Initialisation is done along with code manager initialisation in
* {@link Code#initialize()}.
*/
public static void initialize(Address baseAddress) {
BASE_ADDRESS = baseAddress.toLong();
}
@HOSTED_ONLY
private long tagged;
private CodePointer() { }
@HOSTED_ONLY
private CodePointer(long value) {
tagged = value;
}
@Override
public int hashCode() {
return (int) toTaggedLong();
}
@INLINE
public boolean equals(CodePointer other) {
if (isHosted()) {
return this.tagged == other.tagged;
}
return this.toTaggedLong() == other.toTaggedLong();
}
@INLINE
public boolean equals(Word other) {
return this.toAddress().equals(other.asAddress());
}
@Override
public boolean equals(Object other) {
throw ProgramError.unexpected("must not call equals(Object) with CodePointer argument");
}
@INLINE
public boolean isZero() {
return toLong() == 0L;
}
@INLINE
public static CodePointer zero() {
return from(0L);
}
@INLINE
private static long tag(long value) {
return ((value - BASE_ADDRESS) << 1) | 1;
}
@INLINE
private static long untag(long value) {
return BASE_ADDRESS + (value >> 1);
}
/**
* Relocates a {@code CodePointer} by a given {@link Offset}.
*
* @param offset the offset by which the value is to be relocated
* @return the relocated raw tagged value
*/
@INLINE
public CodePointer relocate(Offset offset) {
return from(toLong() + offset.toLong());
}
@INLINE
public static CodePointer from(long value) {
if (isHosted()) {
return new CodePointer(tag(value));
}
return UnsafeCast.asCodePointer(tag(value));
}
@INLINE
public static CodePointer from(Address address) {
return from(address.toLong());
}
@INLINE
public static CodePointer from(Word word) {
return from(word.asAddress());
}
/**
* Cast an already tagged word into a {@code CodePointer}.
*/
@INLINE
public static CodePointer fromTaggedLong(long value) {
if (isHosted()) {
return new CodePointer(value);
}
return UnsafeCast.asCodePointerTagged(value);
}
/**
* Get the tagged raw value of a {@code CodePointer}.
*/
@INLINE
public long toTaggedLong() {
if (isHosted()) {
return tagged;
}
return UnsafeCast.asTaggedLong(this);
}
@INLINE
public long toLong() {
if (isHosted()) {
return untag(tagged);
}
return untag(UnsafeCast.asLong(this));
}
@INLINE
public int toInt() {
return (int) toLong();
}
@INLINE
public Address toAddress() {
return Address.fromLong(toLong());
}
@INLINE
public Pointer toPointer() {
return Pointer.fromLong(toLong());
}
@INLINE
public Offset toOffset() {
return Offset.fromLong(toLong());
}
@INLINE
public TargetMethod toTargetMethod() {
return Code.codePointerToTargetMethod(this.toPointer());
}
@INLINE
public static boolean isCodePointer(Reference ref) {
return ref.isTagged();
}
@INLINE
public CodePointer plus(CodePointer cp) {
return from(toLong() + cp.toLong());
}
@INLINE
public CodePointer plus(int d) {
return from(toLong() + d);
}
@INLINE
public CodePointer plus(long d) {
return from(toLong() + d);
}
@INLINE
public CodePointer plus(Offset d) {
return from(toLong() + d.toLong());
}
@INLINE
public CodePointer minus(CodePointer cp) {
return from(toLong() - cp.toLong());
}
@INLINE
public CodePointer minus(int d) {
return from(toLong() - d);
}
@INLINE
public CodePointer minus(Offset d) {
return from(toLong() - d.toLong());
}
@INLINE
public CodePointer minus(Address d) {
return from(toLong() - d.toLong());
}
@INLINE
public String toHexString() {
return toPointer().toHexString();
}
@INLINE
public String to0xHexString() {
return toPointer().to0xHexString();
}
@INLINE
@Override
public String toString() {
return to0xHexString();
}
}