/* * 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.vm.layout.hom; import static com.sun.max.vm.VMConfiguration.*; import com.sun.max.annotate.*; import com.sun.max.program.*; import com.sun.max.unsafe.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.layout.*; import com.sun.max.vm.layout.Layout.HeaderField; import com.sun.max.vm.layout.SpecificLayout.ObjectCellVisitor; import com.sun.max.vm.layout.SpecificLayout.ObjectMirror; import com.sun.max.vm.object.*; import com.sun.max.vm.reference.*; import com.sun.max.vm.type.*; import com.sun.max.vm.value.*; /** * Header, Origin, Mixed. * * Tuple header words: hub, misc * Array header words: length, hub, misc * * The low bit in the misc word can potentially sometimes be non-zero. * The low bit in the hub word is always zero. * * When scanning cells and encountering the first word of a cell, * one can tell whether a tuple or an array follows by testing the low bit: * - if it's zero, this is the beginning of a tuple cell, * - if it's one, this is the beginning of an array cell. * * To support this, array length is always encoded in the length word * by shifting 1 to the left and then adding 1. * * See the package level documentation for a more detailed description. */ public class HomGeneralLayout extends AbstractLayout implements GeneralLayout { public boolean isTupleLayout() { return false; } public boolean isHybridLayout() { return false; } public boolean isArrayLayout() { return false; } public boolean isReferenceArrayLayout() { return false; } /** * The offset of the hub pointer. */ final int hubOffset; /** * The offset of the extras (i.e. monitor and hashcode info). */ final int miscOffset; /** * The offset of the array length. */ protected final int arrayLengthOffset; public HomGeneralLayout() { this.miscOffset = 0 - Word.size(); this.hubOffset = miscOffset - Word.size(); this.arrayLengthOffset = hubOffset - Word.size(); } @INLINE public Pointer cellToOrigin(Pointer cell) { return cell.readWord(0).asAddress().isBitSet(0) ? cell.plus(-arrayLengthOffset) : cell.plus(-hubOffset); } @ACCESSOR(Pointer.class) @INLINE public Pointer originToCell(Pointer origin) { return !isTuple(origin) ? origin.plus(arrayLengthOffset) : origin.plus(hubOffset); } public Offset getOffsetFromOrigin(HeaderField headerField) { if (headerField == HeaderField.HUB) { return Offset.fromInt(hubOffset); } else if (headerField == HeaderField.MISC) { return Offset.fromInt(miscOffset); } throw new IllegalArgumentException(getClass().getSimpleName() + " does not know about header field: " + headerField); } @INLINE private Hub getHub(Accessor accessor) { return UnsafeCast.asHub(readHubReference(accessor).toJava()); } public Layout.Category category(Accessor accessor) { final Hub hub = getHub(accessor); return hub.layoutCategory; } @INLINE public final boolean isArray(Accessor accessor) { return specificLayout(accessor).isArrayLayout(); } @INLINE public final boolean isTuple(Accessor accessor) { return specificLayout(accessor).isTupleLayout(); } @INLINE public final boolean isHybrid(Accessor accessor) { return specificLayout(accessor).isHybridLayout(); } @INLINE public final SpecificLayout specificLayout(Accessor accessor) { return getHub(accessor).specificLayout; } @INLINE public final Size size(Accessor accessor) { final Hub hub = getHub(accessor); switch (hub.layoutCategory) { case TUPLE: return Layout.tupleLayout().specificSize(accessor); case ARRAY: return Layout.arrayLayout().getArraySize(hub.classActor.componentClassActor().kind, Layout.arrayLayout().readLength(accessor)); case HYBRID: return Layout.hybridLayout().specificSize(accessor); } throw ProgramError.unknownCase(); } @INLINE public final Reference readHubReference(Accessor accessor) { return accessor.readReference(hubOffset); } @INLINE public final Word readHubReferenceAsWord(Accessor accessor) { return accessor.readWord(hubOffset); } @INLINE public final void writeHubReference(Accessor accessor, Reference hub) { accessor.writeReference(hubOffset, hub); } @INLINE public final Word readMisc(Accessor accessor) { return accessor.readWord(miscOffset); } @INLINE public final void writeMisc(Accessor accessor, Word value) { accessor.writeWord(miscOffset, value); } @INLINE public final Word compareAndSwapMisc(Accessor accessor, Word expectedValue, Word newValue) { return accessor.compareAndSwapWord(miscOffset, expectedValue, newValue); } @INLINE public final Reference forwarded(Reference ref) { if (ref.isMarked()) { return ref.readReference(hubOffset).unmarked(); } return ref; } @INLINE public final Reference readForwardRef(Accessor accessor) { final Reference forwardRef = accessor.readReference(hubOffset); if (forwardRef.isMarked()) { return forwardRef.unmarked(); } // no forward reference has been stored return Reference.zero(); } @INLINE public final Reference readForwardRefValue(Accessor accessor) { final Reference forwardRef = accessor.readReference(hubOffset); if (forwardRef.isMarked()) { return forwardRef.unmarked(); } // no forward reference has been stored return Reference.zero(); } @INLINE public final void writeForwardRef(Accessor accessor, Reference forwardRef) { accessor.writeReference(hubOffset, forwardRef.marked()); } @INLINE public final Reference compareAndSwapForwardRef(Accessor accessor, Reference suspectedRef, Reference forwardRef) { return accessor.compareAndSwapReference(hubOffset, suspectedRef, forwardRef.marked()); } @HOSTED_ONLY public void visitHeader(ObjectCellVisitor visitor, Object object) { final Hub hub = ObjectAccess.readHub(object); final int origin = hub.specificLayout.headerSize(); visitor.visitHeaderField(origin + hubOffset, "hub", JavaTypeDescriptor.forJavaClass(hub.getClass()), ReferenceValue.from(hub)); visitor.visitHeaderField(origin + miscOffset, "misc", JavaTypeDescriptor.WORD, new WordValue(vmConfig().monitorScheme().createMisc(object))); } @HOSTED_ONLY protected Value readHeaderValue(ObjectMirror mirror, int offset) { if (offset == hubOffset) { return mirror.readHub(); } else if (offset == arrayLengthOffset) { return WordValue.from(HomArrayLayout.lengthToWord(mirror.readArrayLength())); } else if (offset == miscOffset) { return mirror.readMisc(); } return null; } @HOSTED_ONLY protected boolean writeHeaderValue(ObjectMirror mirror, int offset, Value value) { if (offset == hubOffset) { mirror.writeHub(value); } else if (offset == arrayLengthOffset) { mirror.writeArrayLength(value); } else if (offset == miscOffset) { mirror.writeMisc(value); } else { return false; } return true; } }