/* * 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.vm.heap; import java.util.*; import com.oracle.max.cri.intrinsics.*; import com.sun.max.unsafe.*; import com.sun.max.vm.actor.holder.*; import com.sun.max.vm.actor.member.*; import com.sun.max.vm.runtime.*; import com.sun.max.vm.type.*; /** * A facility for building and traversing the reference map for a {@linkplain TupleClassActor tuple} object. * A reference map is an ordered list of word-scaled offsets relative to an object's origin describing the * object slots containing references. * The reference maps copied into hubs are ordered by increasing offsets. */ public class TupleReferenceMap { /** * The set of word-scaled offsets to references. * The list is built so that offsets are ordered from highest to lowest. * The list will be traversed from last to first when copying offsets into a hub's reference map. */ private List<Integer> indexes = new LinkedList<Integer>(); /** * Builds a reference map for a given set of static fields. This is the reference map that * will be {@linkplain #copyIntoHub(Hub) copied} into the {@linkplain ClassActor#staticHub() static hub} * of a class to cover the fields in its {@linkplain ClassActor#staticTuple() static tuple}. */ public TupleReferenceMap(FieldActor[] staticFieldActors) { // Iterate from last to first to insert reference fields in decreasing order to enable sharing the code of copyIntoHub with instance field reference maps. int i = staticFieldActors.length - 1; while (i >= 0) { final FieldActor staticFieldActor = staticFieldActors[i--]; assert !staticFieldActor.descriptor().equals(JavaTypeDescriptor.CODE_POINTER) : "there must be no fields of type CodePointer"; if (staticFieldActor.kind.isReference) { final int fieldIndex = UnsignedMath.divide(staticFieldActor.offset(), Word.size()); indexes.add(fieldIndex); } } } /** * Builds a reference map for the instance fields of a given class. This is the reference map that * will be {@linkplain #copyIntoHub(Hub) copied} into the {@linkplain ClassActor#dynamicHub() dynamic hub} * of the class. To ease visiting references of a tuple within a region of heap space, field indexes are ordered by increasing * value in the reference map. */ public TupleReferenceMap(ClassActor classActor) { ClassActor c = classActor; do { final FieldActor [] fieldActors = c.localInstanceFieldActors(); int i = fieldActors.length - 1; while (i >= 0) { final FieldActor instanceFieldActor = fieldActors[i--]; if (instanceFieldActor.kind.isReference && instanceFieldActor != ClassRegistry.JLRReference_referent) { final int fieldIndex = UnsignedMath.divide(instanceFieldActor.offset(), Word.size()); indexes.add(fieldIndex); } } c = c.superClassActor; } while (c != null); // The indexes list is ordered from higher to lower offsets. // This means that when copying it into a hub, the list will be scanned from last to first. } public static final TupleReferenceMap EMPTY = new TupleReferenceMap(new FieldActor[0]); /** * Gets the number of entries in this reference map. */ public int numberOfEntries() { return indexes.size(); } /** * Copy the reference map into the specified hub. The copied map is ordered by increasing offsets. * @param hub */ public void copyIntoHub(Hub hub) { int index = hub.referenceMapStartIndex; ListIterator<Integer> iterator = indexes.listIterator(indexes.size()); int lastRefIndex = 0; while (iterator.hasPrevious()) { int refIndex = iterator.previous(); FatalError.check(refIndex > lastRefIndex, "Reference index in tuple reference maps must be ordered"); lastRefIndex = refIndex; hub.setInt(index, refIndex); index++; } } /** * Visits all the references in a given object described by a given hub. * * @param hub a hub describing where the references are in the object at {@code origin} * @param origin the origin of an object * @param visitor the visitor to notify of each reference in the object denoted by {@code origin} */ public static void visitReferences(Hub hub, Pointer origin, PointerIndexVisitor visitor) { final int n = hub.referenceMapStartIndex + hub.referenceMapLength; for (int i = hub.referenceMapStartIndex; i < n; i++) { final int index = hub.getInt(i); visitor.visit(origin, index); } } /** * Visits all the references within a range of heap space in a given object described by a given hub. * * @param hub a hub describing where the references are in the object at {@code origin} * @param origin the origin of an object * @param visitor the visitor to notify of each reference in the object denoted by {@code origin} * @param startOfRange start of the range of heap space (inclusive) * @param endOfRange end of the range of heap space (exclusive) */ public static void visitReferences(Hub hub, Pointer origin, PointerIndexVisitor visitor, Address startOfRange, Address endOfRange) { final int l = hub.referenceMapLength; if (l == 0) { return; } // compute the bounds in the map that corresponds to references in the range. // This code assumes that the reference maps is ordered by increasing offsets. final int n = hub.referenceMapStartIndex + l; int firstInRange = hub.referenceMapStartIndex; do { final int index = hub.getInt(firstInRange); if (origin.plusWords(index).greaterEqual(startOfRange)) { break; } firstInRange++; } while (firstInRange < n); int lastInRange = n - 1; while (lastInRange > firstInRange) { final int index = hub.getInt(lastInRange); if (origin.plusWords(index).lessThan(endOfRange)) { break; } lastInRange--; } // Visit the references in the range. for (int i = firstInRange; i <= lastInRange; i++) { visitor.visit(origin, hub.getInt(i)); } } }