/* * 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.tele.reference.direct; import java.lang.reflect.*; import com.sun.max.annotate.*; import com.sun.max.tele.*; import com.sun.max.tele.data.*; import com.sun.max.tele.interpreter.*; import com.sun.max.tele.object.*; import com.sun.max.tele.reference.*; import com.sun.max.tele.reference.LocalObjectRemoteReferenceManager.LocalObjectRemoteReference; import com.sun.max.tele.util.*; import com.sun.max.tele.value.*; import com.sun.max.unsafe.*; import com.sun.max.vm.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.hosted.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.reference.direct.*; import com.sun.max.vm.type.*; import com.sun.max.vm.value.*; /** * A specific implementation of the {@link ReferenceScheme} interface for remote access to objects in the VM. It * presumes that the VM is built with the {@link DirectReferenceScheme}. * <p> * This implementation is designed to work in the Inspection environment where all of the references are instances of * {@link RemoteReference}, an extension of {@link Reference} that in most cases encapsulates the current address of an * object origin in VM memory. There are exceptions: * <ul> * <li>{@code null} references are implemented as instances of {@link NullReference} that hold {@link Address#zero()} * and may in some situations hold extra information useful for debugging the Inspector.</li> * <li>Instances of {@link LocalObjectRemoteReference}, which allows a local object in the Inspector to masquerade as a * remote object, used mainly in the Inspector's {@link TeleInterpreter}.</li> * </ul> * <p> * Substituting this implementation of {@link ReferenceScheme} in the Inspector's emulation of the VM's static environment * allows reuse of considerable VM code, notably in the {@link Layout} and {@link Reference} classes. Whenever methods in * those (and related) classes are used, for example {@link Reference#readReference(int)}, * operations concerning {@link Reference}s are routed through this scheme implementation. * <p> * <strong>Important:</strong> the default behavior of most methods routed through this scheme implementation, in particular those * with return type {@link Reference} is to: * <ul> * <li>return only instances of {@link RemoteReference}; and</li> * <li>return a {@code null} reference ({@code isZero() == true}) if no {@link ObjectStatus#LIVE} object can be detected * at the encapsulated VM memory address.</li> * </ul> * * <p> * TODO (mlvdv) This should be generalized to work with other {@link ReferenceScheme} implementations. * * @see RemoteReference * @see VmReferenceManager */ public final class RemoteReferenceScheme extends AbstractVMScheme implements ReferenceScheme { // TODO (mlvdv) generalize to support ReferenceScheme implementations other than DirectRefer /** * The default implementation of {@link Reference#zero()}, used as a {@code null} remote reference. It always holds * the {@linkplain Address#zero() null address} and always has status {@linkplain ObjectStatus#DEAD DEAD}. */ private static class NullReference extends ConstantRemoteReference { NullReference(TeleVM vm) { super(vm, Address.zero()); } @Override public final ObjectStatus status() { return ObjectStatus.DEAD; } @Override public ObjectStatus priorStatus() { return null; } @Override public String toString() { return "null Remote Reference"; } } /** * A specialized implementation of {@link Reference#zero()}, used as a {@code null} remote reference. It carries * with it the history of why it was created: a textual explanation, along with the location in memory where the * creation of a remote reference was attempted and whose failure resulted in creation of this null reference. */ private static final class AnnotatedNullReference extends NullReference { private final String description; private final Address failedOrigin; AnnotatedNullReference(TeleVM vm, String description, Address failedOrigin) { super(vm); this.description = description; this.failedOrigin = failedOrigin; } @Override public String toString() { return "ZeroRef: " + description + failedOrigin.to0xHexString(); } } private TeleVM vm; private DataAccess dataAccess; private RemoteReference zero; protected LocalObjectRemoteReferenceManager localTeleReferenceManager; // TODO (mlvdv) (pass in data access specifically) public void setContext(TeleVM vm) { this.vm = vm; this.localTeleReferenceManager = new LocalObjectRemoteReferenceManager(vm); this.dataAccess = vm.memoryIO().access(); this.zero = new NullReference(vm); assert dataAccess != null; } /** * Creates a null reference (implementation of {@link Reference#zero()} that carries with it the history * of a failed attempt to create a reference. An override of {@link Object#toString()} prints out a message * containing this information. * * @param description a description of what part of the system attempted the reference creation, and why it failed * @param failedOrigin the location in VM memory at which the reference creation was attempted * @return a null reference annotated with historical information */ public RemoteReference makeZeroReference(String description, Address failedOrigin) { return new AnnotatedNullReference(vm, description, failedOrigin); } /** * {@inheritDoc} * <p> * Gets the origin of a {@link RemoteReference}. * <p> * @return the origin of an object referred to; {@link Pointer#zero()} if the * reference is {@linkplain ObjectStatus#DEAD DEAD}. */ public Pointer toOrigin(Reference ref) { final RemoteReference remoteRef = (RemoteReference) ref; if (isZero(remoteRef)) { // A {@link RemoteReference} with zero raw value is by definition DEAD. return Pointer.zero(); } if (remoteRef instanceof LocalObjectRemoteReference) { throw new UnsupportedOperationException(); } return remoteRef.origin().asPointer(); } /** * {@inheritDoc} * <p> * Create a {@link RemoteReference} that refers to a {@linkplain ObjectStatus#LIVE live} object in VM memory at a * specified origin. * <p> * If there is no {@linkplain ObjectStatus#LIVE live} object at the origin, then the result is {@link #zero()}. * <p> * * @param origin address in VM memory * @return a reference to the object identified by the specified origin in VM memory. */ public RemoteReference fromOrigin(Pointer origin) { return vm.referenceManager().makeReference(origin); } public RemoteReference fromJava(Object object) { return localTeleReferenceManager.make(object); } public Object toJava(Reference ref) { if (ref instanceof LocalObjectRemoteReference) { final LocalObjectRemoteReference inspectorLocalTeleRef = (LocalObjectRemoteReference) ref; return inspectorLocalTeleRef.object(); } throw new UnsupportedOperationException(); } /** * {@inheritDoc} * <p> * <strong>Note:</strong> Unlike the VM implementation of {@link Reference}, there is no * <em>canonical</em> {@code null} reference. This is done to permit subclasses of the * null reference to be created for debugging. */ public Reference zero() { return zero; } /** * {@inheritDoc} * <p> * We admit to multiple implementations of the zero reference * for debugging purposes (some may be annotated). The * test for a null/zero reference is defined in terms of the * actually origin being stored. No legitimate reference may * have this location. */ public boolean isZero(Reference ref) { final RemoteReference remoteRef = (RemoteReference) ref; return remoteRef.origin().isZero(); } @INLINE public boolean isAllOnes(Reference ref) { if (ref.isZero()) { return false; } else if (ref instanceof LocalObjectRemoteReference) { TeleError.unexpected(); } return toOrigin(ref).isAllOnes(); } public boolean equals(Reference ref1, Reference ref2) { return ref1.equals(ref2); } /** * {@inheritDoc} * <p> * Is the reference a forwarding address? * * Uses the same marking information forwarding that * the VM does in normal operation. * * @see DirectReferenceScheme#isMarked */ public boolean isMarked(Reference ref) { return toOrigin(ref).isBitSet(0); } public boolean isTagged(Reference ref) { throw new UnsupportedOperationException(); } public Reference marked(Reference ref) { throw new UnsupportedOperationException(); } public Reference unmarked(Reference ref) { throw new UnsupportedOperationException(); } private Object readField(Reference ref, int offset) { final Object object = toJava(ref); if (object instanceof StaticTuple) { final StaticTuple staticTuple = (StaticTuple) object; final FieldActor fieldActor = staticTuple.findStaticFieldActor(offset); final Class javaClass = staticTuple.classActor().toJava(); try { return WithoutAccessCheck.getStaticField(javaClass, fieldActor.name.toString()); } catch (Throwable throwable) { TeleError.unexpected("could not access static field: " + fieldActor.name, throwable); } } final Class javaClass = object.getClass(); final ClassActor classActor = ClassActor.fromJava(javaClass); if (classActor.isArrayClass()) { return Array.getLength(object); } final FieldActor fieldActor = classActor.findInstanceFieldActor(offset); try { return WithoutAccessCheck.getInstanceField(object, fieldActor.name.toString()); } catch (Throwable throwable) { throw TeleError.unexpected("could not access field: " + fieldActor.name, throwable); } } public byte readByte(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readByte(ref, offset.toInt()); } return dataAccess.readByte(toOrigin(ref), offset); } public byte readByte(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Byte result = (Byte) readField(ref, offset); return result.byteValue(); } return dataAccess.readByte(toOrigin(ref), offset); } public byte getByte(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final byte[] array = (byte[]) ref.toJava(); return array[index]; } return dataAccess.getByte(toOrigin(ref), displacement, index); } public boolean readBoolean(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readBoolean(ref, offset.toInt()); } return dataAccess.readBoolean(toOrigin(ref), offset); } public boolean readBoolean(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Boolean result = (Boolean) readField(ref, offset); return result.booleanValue(); } return dataAccess.readBoolean(toOrigin(ref), offset); } public boolean getBoolean(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final boolean[] array = (boolean[]) ref.toJava(); return array[index]; } return dataAccess.getBoolean(toOrigin(ref), displacement, index); } public short readShort(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readShort(ref, offset.toInt()); } return dataAccess.readShort(toOrigin(ref), offset); } public short readShort(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Short result = (Short) readField(ref, offset); return result.shortValue(); } return dataAccess.readShort(toOrigin(ref), offset); } public short getShort(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final short[] array = (short[]) ref.toJava(); return array[index]; } return dataAccess.getShort(toOrigin(ref), displacement, index); } public char readChar(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readChar(ref, offset.toInt()); } return dataAccess.readChar(toOrigin(ref), offset); } public char readChar(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Character result = (Character) readField(ref, offset); return result.charValue(); } return dataAccess.readChar(toOrigin(ref), offset); } public char getChar(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final char[] array = (char[]) ref.toJava(); return array[index]; } return dataAccess.getChar(toOrigin(ref), displacement, index); } public int readInt(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readInt(ref, offset.toInt()); } return dataAccess.readInt(toOrigin(ref), offset); } public int readInt(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Integer result = (Integer) readField(ref, offset); return result.intValue(); } return dataAccess.readInt(toOrigin(ref), offset); } public int getInt(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final int[] array = (int[]) ref.toJava(); return array[index]; } return dataAccess.getInt(toOrigin(ref), displacement, index); } public float readFloat(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readFloat(ref, offset.toInt()); } return dataAccess.readFloat(toOrigin(ref), offset); } public float readFloat(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Float result = (Float) readField(ref, offset); return result.floatValue(); } return dataAccess.readFloat(toOrigin(ref), offset); } public float getFloat(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final float[] array = (float[]) ref.toJava(); return array[index]; } return dataAccess.getFloat(toOrigin(ref), displacement, index); } public long readLong(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readLong(ref, offset.toInt()); } return dataAccess.readLong(toOrigin(ref), offset); } public long readLong(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Long result = (Long) readField(ref, offset); return result.longValue(); } return dataAccess.readLong(toOrigin(ref), offset); } public long getLong(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final long[] array = (long[]) ref.toJava(); return array[index]; } return dataAccess.getLong(toOrigin(ref), displacement, index); } public double readDouble(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readDouble(ref, offset.toInt()); } return dataAccess.readDouble(toOrigin(ref), offset); } public double readDouble(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { final Double result = (Double) readField(ref, offset); return result.doubleValue(); } return dataAccess.readDouble(toOrigin(ref), offset); } public double getDouble(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final double[] array = (double[]) ref.toJava(); return array[index]; } return dataAccess.getDouble(toOrigin(ref), displacement, index); } public Word readWord(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readWord(ref, offset.toInt()); } return dataAccess.readWord(toOrigin(ref), offset); } public Word readWord(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { return (Word) readField(ref, offset); } return dataAccess.readWord(toOrigin(ref), offset); } public Word getWord(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final Word[] array = (Word[]) ref.toJava(); return array[index]; } return dataAccess.getWord(toOrigin(ref), displacement, index); } public Reference readReference(Reference ref, Offset offset) { if (ref instanceof LocalObjectRemoteReference) { return readReference(ref, offset.toInt()); } return fromOrigin(readWord(ref, offset).asPointer()); } public Reference readReference(Reference ref, int offset) { if (ref instanceof LocalObjectRemoteReference) { return fromJava(readField(ref, offset)); } return fromOrigin(readWord(ref, offset).asPointer()); } public Reference getReference(Reference ref, int displacement, int index) { if (ref instanceof LocalObjectRemoteReference) { final Object[] array = (Object[]) toJava(ref); return fromJava(array[index]); } return fromOrigin(getWord(ref, displacement, index).asPointer()); } private void writeField(Reference ref, int offset, Object value) { final Object object = toJava(ref); if (object instanceof StaticTuple) { final StaticTuple staticTuple = (StaticTuple) object; final FieldActor fieldActor = staticTuple.findStaticFieldActor(offset); final Class javaClass = staticTuple.classActor().toJava(); try { WithoutAccessCheck.setStaticField(javaClass, fieldActor.name.toString(), value); } catch (Throwable throwable) { TeleError.unexpected("could not access static field: " + fieldActor.name, throwable); } } else { final Class javaClass = object.getClass(); final TupleClassActor tupleClassActor = (TupleClassActor) ClassActor.fromJava(javaClass); final FieldActor fieldActor = tupleClassActor.findInstanceFieldActor(offset); WithoutAccessCheck.setInstanceField(object, fieldActor.name.toString(), value); } } public void writeByte(Reference ref, Offset offset, byte value) { if (ref instanceof LocalObjectRemoteReference) { writeByte(ref, offset.toInt(), value); return; } dataAccess.writeByte(toOrigin(ref), offset, value); } public void writeByte(Reference ref, int offset, byte value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Byte(value)); return; } dataAccess.writeByte(toOrigin(ref), offset, value); } public void setByte(Reference ref, int displacement, int index, byte value) { if (ref instanceof LocalObjectRemoteReference) { final byte[] array = (byte[]) ref.toJava(); array[index] = value; return; } dataAccess.setByte(toOrigin(ref), displacement, index, value); } public void writeBoolean(Reference ref, Offset offset, boolean value) { if (ref instanceof LocalObjectRemoteReference) { writeBoolean(ref, offset.toInt(), value); return; } dataAccess.writeBoolean(toOrigin(ref), offset, value); } public void writeBoolean(Reference ref, int offset, boolean value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Boolean(value)); return; } dataAccess.writeBoolean(toOrigin(ref), offset, value); } public void setBoolean(Reference ref, int displacement, int index, boolean value) { if (ref instanceof LocalObjectRemoteReference) { final boolean[] array = (boolean[]) ref.toJava(); array[index] = value; return; } dataAccess.setBoolean(toOrigin(ref), displacement, index, value); } public void writeShort(Reference ref, Offset offset, short value) { if (ref instanceof LocalObjectRemoteReference) { writeShort(ref, offset.toInt(), value); return; } dataAccess.writeShort(toOrigin(ref), offset, value); } public void writeShort(Reference ref, int offset, short value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Short(value)); return; } dataAccess.writeShort(toOrigin(ref), offset, value); } public void setShort(Reference ref, int displacement, int index, short value) { if (ref instanceof LocalObjectRemoteReference) { final short[] array = (short[]) ref.toJava(); array[index] = value; return; } dataAccess.setShort(toOrigin(ref), displacement, index, value); } public void writeChar(Reference ref, Offset offset, char value) { if (ref instanceof LocalObjectRemoteReference) { writeChar(ref, offset.toInt(), value); return; } dataAccess.writeChar(toOrigin(ref), offset, value); } public void writeChar(Reference ref, int offset, char value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Character(value)); return; } dataAccess.writeChar(toOrigin(ref), offset, value); } public void setChar(Reference ref, int displacement, int index, char value) { if (ref instanceof LocalObjectRemoteReference) { final char[] array = (char[]) ref.toJava(); array[index] = value; return; } dataAccess.setChar(toOrigin(ref), displacement, index, value); } public void writeInt(Reference ref, Offset offset, int value) { if (ref instanceof LocalObjectRemoteReference) { writeInt(ref, offset.toInt(), value); return; } dataAccess.writeInt(toOrigin(ref), offset, value); } public void writeInt(Reference ref, int offset, int value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Integer(value)); return; } dataAccess.writeInt(toOrigin(ref), offset, value); } public void setInt(Reference ref, int displacement, int index, int value) { if (ref instanceof LocalObjectRemoteReference) { final int[] array = (int[]) ref.toJava(); array[index] = value; return; } dataAccess.setInt(toOrigin(ref), displacement, index, value); } public void writeFloat(Reference ref, Offset offset, float value) { if (ref instanceof LocalObjectRemoteReference) { writeFloat(ref, offset.toInt(), value); return; } dataAccess.writeFloat(toOrigin(ref), offset, value); } public void writeFloat(Reference ref, int offset, float value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Float(value)); return; } dataAccess.writeFloat(toOrigin(ref), offset, value); } public void setFloat(Reference ref, int displacement, int index, float value) { if (ref instanceof LocalObjectRemoteReference) { final float[] array = (float[]) ref.toJava(); array[index] = value; return; } dataAccess.setFloat(toOrigin(ref), displacement, index, value); } public void writeLong(Reference ref, Offset offset, long value) { if (ref instanceof LocalObjectRemoteReference) { writeLong(ref, offset.toInt(), value); return; } dataAccess.writeLong(toOrigin(ref), offset, value); } public void writeLong(Reference ref, int offset, long value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Long(value)); return; } dataAccess.writeLong(toOrigin(ref), offset, value); } public void setLong(Reference ref, int displacement, int index, long value) { if (ref instanceof LocalObjectRemoteReference) { final long[] array = (long[]) ref.toJava(); array[index] = value; return; } dataAccess.setLong(toOrigin(ref), displacement, index, value); } public void writeDouble(Reference ref, Offset offset, double value) { if (ref instanceof LocalObjectRemoteReference) { writeDouble(ref, offset.toInt(), value); return; } dataAccess.writeDouble(toOrigin(ref), offset, value); } public void writeDouble(Reference ref, int offset, double value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, new Double(value)); return; } dataAccess.writeDouble(toOrigin(ref), offset, value); } public void setDouble(Reference ref, int displacement, int index, double value) { if (ref instanceof LocalObjectRemoteReference) { final double[] array = (double[]) ref.toJava(); array[index] = value; return; } dataAccess.setDouble(toOrigin(ref), displacement, index, value); } public void writeWord(Reference ref, Offset offset, Word value) { if (ref instanceof LocalObjectRemoteReference) { writeWord(ref, offset.toInt(), value); return; } dataAccess.writeWord(toOrigin(ref), offset, value); } public void writeWord(Reference ref, int offset, Word value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, value); return; } dataAccess.writeWord(toOrigin(ref), offset, value); } public void setWord(Reference ref, int displacement, int index, Word value) { if (ref instanceof LocalObjectRemoteReference) { final Word[] array = (Word[]) ref.toJava(); WordArray.set(array, index, value); return; } dataAccess.setWord(toOrigin(ref), displacement, index, value); } public void writeReference(Reference ref, Offset offset, Reference value) { if (ref instanceof LocalObjectRemoteReference) { writeReference(ref, offset.toInt(), value); return; } writeWord(ref, offset, value.toOrigin()); } public void writeReference(Reference ref, int offset, Reference value) { if (ref instanceof LocalObjectRemoteReference) { writeField(ref, offset, value.toJava()); return; } writeWord(ref, offset, value.toOrigin()); } public void setReference(Reference ref, int displacement, int index, Reference value) { if (ref instanceof LocalObjectRemoteReference) { final Object[] array = (Object[]) toJava(ref); array[index] = value.toJava(); return; } setWord(ref, displacement, index, value.toOrigin()); } public int compareAndSwapInt(Reference ref, Offset offset, int expectedValue, int newValue) { return toOrigin(ref).compareAndSwapInt(offset, expectedValue, newValue); } public int compareAndSwapInt(Reference ref, int offset, int expectedValue, int newValue) { return toOrigin(ref).compareAndSwapInt(offset, expectedValue, newValue); } public Word compareAndSwapWord(Reference ref, Offset offset, Word expectedValue, Word newValue) { TeleError.unimplemented(); return Word.zero(); } public Word compareAndSwapWord(Reference ref, int offset, Word expectedValue, Word newValue) { TeleError.unimplemented(); return Word.zero(); } public Reference compareAndSwapReference(Reference ref, Offset offset, Reference expectedValue, Reference newValue) { TeleError.unimplemented(); return null; } public Reference compareAndSwapReference(Reference ref, int offset, Reference expectedValue, Reference newValue) { TeleError.unimplemented(); return null; } public void copyElements(int displacement, Reference src, int srcIndex, Object dst, int dstIndex, int length) { if (src instanceof LocalObjectRemoteReference) { System.arraycopy(toJava(src), srcIndex, dst, dstIndex, length); } else { dataAccess.copyElements(toOrigin(src), displacement, srcIndex, dst, dstIndex, length); } } @Override public byte[] asBytes(Pointer origin) { throw TeleError.unimplemented(); } @Override public byte[] nullAsBytes() { throw TeleError.unimplemented(); } /** * Reads the {@link Hub} word from an object's header field in VM memory. * Return's {@link Word#zero()} if the reference is zero.. * * @param remoteRef reference to an object in VM memory * @return contents of the object's hub field */ public Word readHubAsWord(RemoteReference remoteRef) { if (remoteRef instanceof LocalObjectRemoteReference) { throw new UnsupportedOperationException(); } if (remoteRef.isZero()) { return Word.zero(); } return Layout.readHubReferenceAsWord(remoteRef); } /** * Reads the {@link Hub} word from an object's header field in VM memory, determines if the word's value * does in fact point at a live object (possibly via a forwarder), and if so create a new * {@link RemoteReference} for the live hub. Return's {@link Reference#zero()} if the word cannot be read or if the * word's value does not point to an object. * * @param remoteRef reference to an object in VM memory * @return a reference to the object's hub, traversing a forwarder if needed. */ public RemoteReference readHubAsRemoteReference(RemoteReference remoteRef) { if (remoteRef.isZero()) { return zero; } if (remoteRef instanceof LocalObjectRemoteReference) { throw new UnsupportedOperationException(); } final Address hubOrigin = Layout.readHubReferenceAsWord(remoteRef).asAddress(); if (hubOrigin.isZero()) { return zero; } final ObjectStatus objectStatus = vm.objects().objectStatusAt(hubOrigin); switch(objectStatus) { case LIVE: return fromOrigin(hubOrigin.asPointer()); case FORWARDER: final RemoteReference forwarderReference = vm.referenceManager().makeQuasiReference(hubOrigin); return fromOrigin(forwarderReference.forwardedTo().asPointer()); } return makeZeroReference("RemoteReferenceScheme.readRemoteReferenceHub() unsupported object status @", hubOrigin); } /** * Reads a word from an object field in VM memory that is presumed to hold a reference, determines if the word's * value does in fact point at a live object (possibly via a forwarder), and if so create a new * {@link RemoteReference} for the live object. Return's {@link Reference#zero()} if the word cannot be read or if * the word's value does not point to an object. * * @param remoteRef reference to an object in VM memory * @param fieldActor descriptor of the field from which to read * @return a reference to the object pointed to by the word's value, traversing a forwarder if needed. */ public RemoteReference readFieldAsRemoteReference(RemoteReference remoteRef, FieldActor fieldActor) { if (remoteRef.isZero()) { return zero; } if (remoteRef instanceof LocalObjectRemoteReference) { return fromJava(readField(remoteRef, fieldActor.offset())); } final Address fieldValueOrigin = readWord(remoteRef, fieldActor.offset()).asAddress(); if (fieldValueOrigin.isZero()) { return zero; } final ObjectStatus objectStatus = vm.objects().objectStatusAt(fieldValueOrigin); switch(objectStatus) { case LIVE: return fromOrigin(fieldValueOrigin.asPointer()); case FORWARDER: final RemoteReference forwarderReference = vm.referenceManager().makeQuasiReference(fieldValueOrigin); return fromOrigin(forwarderReference.forwardedTo().asPointer()); } return makeZeroReference("RemoteReferenceScheme.readRemoteReferenceField() unsupported object status @", fieldValueOrigin); } /** * Reads a word from what is presumed to be an array element in VM memory that holds a reference, determines if the * word's value does in fact point at a live object (possibly via a forwarder), and if so create a new * {@link RemoteReference} for the live object. Return's {@link Reference#zero()} if the word cannot be read or if * the word's value does not point to an object. * * @param remoteRef reference to an array in VM memory * @param index the array element presumed to hold a reference * @return a reference to the object pointed to by the word's value, traversing a forwarder if needed. */ public RemoteReference readArrayAsRemoteReference(RemoteReference remoteRef, int index) { if (remoteRef.isZero()) { return zero; } if (remoteRef instanceof LocalObjectRemoteReference) { final Object[] array = (Object[]) toJava(remoteRef); return fromJava(array[index]); } final Address elementValueOrigin = Layout.getWord(remoteRef, index).asAddress(); if (elementValueOrigin.isZero()) { return zero; } final ObjectStatus objectStatus = vm.objects().objectStatusAt(elementValueOrigin); switch(objectStatus) { case LIVE: return fromOrigin(elementValueOrigin.asPointer()); case FORWARDER: final RemoteReference forwarderReference = vm.referenceManager().makeQuasiReference(elementValueOrigin); return fromOrigin(forwarderReference.forwardedTo().asPointer()); } return makeZeroReference("RemoteReferenceScheme.readRemoteReference() unsupported object status @", elementValueOrigin); } public Value readArrayAsValue(Kind kind, RemoteReference remoteRef, int index) { switch (kind.asEnum) { case BYTE: return ByteValue.from(Layout.getByte(remoteRef, index)); case BOOLEAN: return BooleanValue.from(Layout.getBoolean(remoteRef, index)); case SHORT: return ShortValue.from(Layout.getShort(remoteRef, index)); case CHAR: return CharValue.from(Layout.getChar(remoteRef, index)); case INT: return IntValue.from(Layout.getInt(remoteRef, index)); case FLOAT: return FloatValue.from(Layout.getFloat(remoteRef, index)); case LONG: return LongValue.from(Layout.getLong(remoteRef, index)); case DOUBLE: return DoubleValue.from(Layout.getDouble(remoteRef, index)); case WORD: return new WordValue(Layout.getWord(remoteRef, index)); case REFERENCE: try { return TeleReferenceValue.from(vm, readArrayAsRemoteReference(remoteRef, index)); } catch (DataIOError err) { final Address elementEntryAddress = remoteRef.toOrigin().plus(Layout.referenceArrayLayout().getElementOffsetInCell(index)); TeleWarning.message("RemoteReferenceScheme: Can't access reference array element at " + elementEntryAddress.to0xHexString()); return TeleReferenceValue.zero(vm); } default: throw TeleError.unknownCase("unknown array kind"); } } }