/*
* 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.object;
import java.lang.reflect.*;
import java.util.*;
import java.util.logging.*;
import com.sun.max.jdwp.vm.proxy.*;
import com.sun.max.tele.*;
import com.sun.max.tele.reference.*;
import com.sun.max.tele.util.*;
import com.sun.max.unsafe.*;
import com.sun.max.vm.actor.member.*;
import com.sun.max.vm.layout.*;
import com.sun.max.vm.layout.Layout.HeaderField;
import com.sun.max.vm.type.*;
import com.sun.max.vm.value.*;
/**
* Inspector's canonical surrogate for an object implemented as an {@link Array} in the {@link TeleVM},
* one of the three kinds of low level Maxine heap implementation objects.
*/
public class TeleArrayObject extends TeleObject implements ArrayProvider {
private static final HashSet<FieldActor> EMPTY_FIELD_ACTOR_SET = new HashSet<FieldActor>();
private static final Logger LOGGER = Logger.getLogger(TeleArrayObject.class.getName());
private int length = -1;
private final Kind componentKind;
private String maxineRole = null;
protected TeleArrayObject(TeleVM vm, RemoteReference reference, Kind componentKind, SpecificLayout layout) {
super(vm, reference, layout);
this.componentKind = componentKind;
}
public ObjectKind kind() {
return ObjectKind.ARRAY;
}
public HeaderField[] headerFields() {
return objects().arrayLayout().headerFields();
}
/**
* Gets the number of elements contained in the array; -1 if not yet available. Once available, this
* value will be reported every time, even if the object dies and the length field is overwritten.
*
* @return length of this array in the VM when it was created.
*/
public int length() {
if (length < 0) {
length = objects().unsafeReadArrayLength(reference());
}
return length;
}
public TypeDescriptor componentType() {
return classActorForObjectType().componentClassActor().typeDescriptor;
}
public Kind componentKind() {
return componentKind;
}
public int arrayOffsetFromOrigin() {
return objects().arrayLayout(componentKind()).getElementOffsetFromOrigin(0).toInt();
}
@Override
public int objectSize() {
return Layout.getArraySize(componentKind(), length()).toInt();
}
@Override
public Set<FieldActor> getFieldActors() {
return EMPTY_FIELD_ACTOR_SET;
}
@Override
public boolean hasTextualVisualization() {
return classActorForObjectType().javaClass() == char[].class;
}
@Override
public String textualVisualization() {
if (hasTextualVisualization()) {
final char[] chars = (char[]) shallowCopy();
return new String(chars);
}
return null;
}
/**
* Reads an array element from VM memory as a boxed value.
*
* @param index
* @return the value read from the specified field in this array in the VM
* @throws ArrayIndexOutOfBoundsException if the index is out of bounds
*/
public Value readElementValue(int index) {
if (index < 0 || index >= length()) {
throw new ArrayIndexOutOfBoundsException();
}
return reference().readArrayAsValue(componentKind(), index);
}
/**
* From a reference array in VM memory, gets the value of an element interpreted as a
* reference, traversing a forwarder if present; returns {@linkplain RemoteReference#zero()} if the
* value does not point at a live object.
*
* @param index the
* @return the value of the array element, interpreted as a reference.
* @throws UnsupportedOperationException if not a reference array
* @throws ArrayIndexOutOfBoundsException if the index is out of bounds
*/
public RemoteReference readRemoteReference(int index) {
if (!componentKind().isReference) {
throw new UnsupportedOperationException();
}
if (index < 0 || index >= length()) {
throw new ArrayIndexOutOfBoundsException();
}
return reference().readArrayAsRemoteReference(index);
}
@Override
public Address fieldAddress(FieldActor fieldActor) {
throw TeleError.unexpected("Maxine Array objects don't contain fields");
}
@Override
public int fieldSize(FieldActor fieldActor) {
throw TeleError.unexpected("Maxine Array objects don't contain fields");
}
@Override
public Value readFieldValue(FieldActor fieldActor) {
throw TeleError.unexpected("Maxine Array objects don't contain fields");
}
@Override
public Object shallowCopy() {
final int length = length();
if (componentKind().isReference) {
final RemoteReference[] newRefArray = new RemoteReference[length];
for (int index = 0; index < length; index++) {
newRefArray[index] = (RemoteReference) readElementValue(index).asReference();
}
return newRefArray;
}
final Class<?> componentJavaClass = classActorForObjectType().componentClassActor().toJava();
final Object newArray = Array.newInstance(componentJavaClass, length);
for (int index = 0; index < length; index++) {
Array.set(newArray, index, readElementValue(index).asBoxedJavaValue());
}
return newArray;
}
@Override
protected Object createDeepCopy(DeepCopier context) {
final Kind componentKind = componentKind();
final int length = length();
final Class<?> componentJavaClass = classActorForObjectType().componentClassActor().toJava();
final Object newArray = Array.newInstance(componentJavaClass, length);
context.register(this, newArray, true);
if (length != 0) {
if (componentKind != Kind.REFERENCE) {
objects().unsafeCopyElements(componentKind, reference(), 0, newArray, 0, length);
} else {
Object[] referenceArray = (Object[]) newArray;
for (int index = 0; index < length; index++) {
final Value value = readElementValue(index);
final TeleObject teleValueObject = objects().makeTeleObject((RemoteReference) value.asReference());
if (teleValueObject != null) {
referenceArray[index] = teleValueObject.makeDeepCopy(context);
}
}
}
}
return newArray;
}
public ArrayTypeProvider getArrayType() {
return (ArrayTypeProvider) this.getReferenceType();
}
public VMValue getValue(int i) {
return vm().maxineValueToJDWPValue(readElementValue(i));
}
public void setValue(int i, VMValue value) {
LOGGER.info("Command received to SET ARRAY at index " + i + " + to + " + value);
}
@Override
public String maxineRole() {
return maxineRole;
}
/**
* Assign to this array object a short description of the role played by this specific
* array in the VM, suitable for textual annotation where mention of the object appears.
*
* @param role a short string describing the role played by this array in the VM.
*/
public void setMaxineRole(String role) {
this.maxineRole = role;
}
}