/* * 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 com.sun.max.lang.*; import com.sun.max.program.*; import com.sun.max.tele.*; import com.sun.max.tele.reference.*; import com.sun.max.tele.util.*; import com.sun.max.tele.value.*; import com.sun.max.unsafe.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.compiler.target.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.layout.Layout.HeaderField; import com.sun.max.vm.value.*; /** * Canonical surrogate for an object implemented as a tuple in the VM, * one of the three kinds of low level Maxine heap implementation objects. */ public class TeleTupleObject extends TeleObject { /** * Creates a surrogate for an ordinary (non-array) Java object in the VM. * <p> * Most Java objects in the VM are represented by this type. The exceptions are those types that carry important * information about the execution state of the VM, for which specific subclasses of this type are declared. The * factory method {@link TeleObjectFactory#make(RemoteReference)} creates an instance of {@link TeleObject} of the most * specific subtype corresponding to the VM object to which the {@link RemoteReference} refers. * <p> * Note also that there is one exceptional subclass; {@link TeleStaticTuple} represents {@link StaticTuple} objects * in the VM, objects for which there is no type expressible in the (extended) Java type system. * <p> * This constructor follows no {@linkplain RemoteReference references}. This avoids the infinite regress that can occur when the VM * object and another are mutually referential. * * @see TeleObjectFactory * @see TeleStaticTuple */ protected TeleTupleObject(TeleVM vm, RemoteReference reference) { super(vm, reference, vm.layoutScheme().tupleLayout); } @Override public ObjectKind kind() { return ObjectKind.TUPLE; } @Override public HeaderField[] headerFields() { return Layout.tupleLayout().headerFields(); } @Override public int objectSize() { return classActorForObjectType().dynamicTupleSize().toInt(); } @Override public Address fieldAddress(FieldActor fieldActor) { return origin().plus(fieldActor.offset()); } @Override public int fieldSize(FieldActor fieldActor) { return fieldActor.kind.width.numberOfBytes; } /** * {@inheritDoc} * <p> * When the field is a reference, this does <em>not</em> follow forwarding pointers. */ @Override public Value readFieldValue(FieldActor fieldActor) { if (fieldActor.kind.isReference) { // Does not follow forwarding pointers return TeleReferenceValue.from(vm(), reference().readReference(fieldActor.offset())); } return fieldActor.readValue(reference()); } @Override public TeleClassMethodActor getTeleClassMethodActorForObject() { final Class<?> javaClass = classActorForObjectType().toJava(); if (TargetMethod.class.isAssignableFrom(javaClass)) { final RemoteReference classMethodActorReference = fields().TargetMethod_classMethodActor.readRemoteReference(reference()); return (TeleClassMethodActor) objects().makeTeleObject(classMethodActorReference); } return null; } @Override public Object shallowCopy() { final ClassActor classActor = classActorForObjectType(); final Class<?> javaClass = classActor.toJava(); try { final Object newTupleObject = ObjectUtils.allocateInstance(javaClass); ClassActor holderClassActor = classActor; do { for (FieldActor fieldActor : holderClassActor.localInstanceFieldActors()) { if (!(fieldActor.kind.isReference || fieldActor.isInjected())) { final Field field = fieldActor.toJava(); field.setAccessible(true); final Value fieldValue = readFieldValue(fieldActor); final Object asBoxedJavaValue = fieldValue.asBoxedJavaValue(); try { field.set(newTupleObject, asBoxedJavaValue); } catch (IllegalAccessException illegalAccessException) { TeleError.unexpected("could not access field: " + field, illegalAccessException); } catch (IllegalArgumentException illegalArgumentException) { TeleError.unexpected("illegal argument field: " + field, illegalArgumentException); } } } holderClassActor = holderClassActor.superClassActor; } while (holderClassActor != null); return newTupleObject; } catch (InstantiationException instantiationException) { TeleError.unexpected("could not allocate instance: " + javaClass, instantiationException); return null; } } /** * {@inheritDoc} * <p> * The default for tuples is to generate a warning message about deep copying instances of * most {@code java.lang} classes. */ @Override protected String deepCopyWarning() { final Class<?> javaClass = classActorForObjectType().toJava(); if (javaClass.getName().startsWith("java.lang") && !Number.class.isAssignableFrom(javaClass)) { return "Deep copying instance of " + javaClass.getName(); } return null; } protected static Object createDeepCopy(TeleTupleObject teleTupleObject, DeepCopier context) { final ClassActor classActor = teleTupleObject.classActorForObjectType(); final Class<?> javaClass = classActor.toJava(); final String classMessage = "Copying instance fields of " + javaClass + " from VM"; Trace.begin(COPY_TRACE_VALUE, classMessage); try { final Object newTuple = ObjectUtils.allocateInstance(javaClass); context.register(teleTupleObject, newTuple, true); ClassActor holderClassActor = classActor; do { for (FieldActor fieldActor : holderClassActor.localInstanceFieldActors()) { final String fieldMessage = fieldActor.format("Copying instance field '%n' of type '%t' from VM"); Trace.begin(COPY_TRACE_VALUE, fieldMessage); context.copyField(teleTupleObject, newTuple, fieldActor); Trace.end(COPY_TRACE_VALUE, fieldMessage); } holderClassActor = holderClassActor.superClassActor; } while (holderClassActor != null); return newTuple; } catch (InstantiationException instantiationException) { TeleError.unexpected("could not allocate instance: " + javaClass, instantiationException); return null; } finally { Trace.end(COPY_TRACE_VALUE, classMessage); } } @Override protected Object createDeepCopy(DeepCopier context) { return createDeepCopy(this, context); } }