/* * 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.semispace; import static com.sun.max.tele.object.ObjectStatus.*; import java.util.*; import com.sun.max.tele.heap.*; import com.sun.max.tele.object.*; import com.sun.max.tele.reference.*; import com.sun.max.tele.util.*; import com.sun.max.unsafe.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.heap.sequential.semiSpace.*; /** * Representation of a remote object reference in a heap region managed by a semispace GC. The states of the reference * represent possible states of knowledge about the particular object, especially those relevant during the * {@link HeapPhase#ANALYZING} phase of the heap, and what changes (transitions) to the objects * are legitimate for this collector. * * @see <a href="http://en.wikipedia.org/wiki/State_pattern">"State" design pattern</a> * @see SemiSpaceHeapScheme * @see RemoteSemiSpaceHeapScheme */ public class SemiSpaceRemoteReference extends RemoteReference { /** * An enumeration of possible states of a remote reference for this kind of collector, based on the heap phase and * what is known at any given time. * <p> * Each member encapsulates the <em>behavior</em> associated with a state, including both the interpretation of * the data held by the reference and by allowable state transitions. */ private static enum RefState { /** * Live reference in To-Space, heap not {@linkplain HeapPhase#ANALYZING analyzing}, not forwarded. */ SS_LIVE ("LIVE (not Analyzing)"){ // Properties @Override ObjectStatus status() { return LIVE; } @Override Address origin(SemiSpaceRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(SemiSpaceRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(SemiSpaceRemoteReference ref) { return Address.zero(); } // Transitions @Override void beginAnalyzing(SemiSpaceRemoteReference ref) { ref.refState = SS_FROM; } }, /** * Reference in From-Space, heap {@linkplain HeapPhase#ANALYZING analyzing}, not forwarded. */ SS_FROM ("LIVE (Analyzing: From-only), not forwarded"){ // Properties @Override ObjectStatus status() { return LIVE; } @Override Address origin(SemiSpaceRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(SemiSpaceRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(SemiSpaceRemoteReference ref) { return Address.zero(); } // Transitions @Override void discoverForwarded(SemiSpaceRemoteReference ref, Address newOrigin) { ref.alternateOrigin = ref.origin; ref.origin = newOrigin; ref.refState = SS_FROM_TO; } @Override void endAnalyzing(SemiSpaceRemoteReference ref) { ref.refState = SS_DEAD; } }, /** * Reference in To-Space, heap {@linkplain HeapPhase#ANALYZING analyzing}, * presumed to be forwarded new copy, location of original copy is unknown. */ SS_TO("LIVE (Analyzing: To only)") { // Properties @Override ObjectStatus status() { return LIVE; } @Override Address origin(SemiSpaceRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(SemiSpaceRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(SemiSpaceRemoteReference ref) { return Address.zero(); } // Transitions @Override void discoverOldOrigin(SemiSpaceRemoteReference ref, Address oldOrigin) { ref.alternateOrigin = oldOrigin; ref.refState = SS_FROM_TO; } @Override void endAnalyzing(SemiSpaceRemoteReference ref) { ref.refState = SS_LIVE; } }, /** * Reference in To-Space, heap {@linkplain HeapPhase#ANALYZING analyzing}, * forwarded from a known location in From-Space. */ SS_FROM_TO ("LIVE (Analyzing: From+To)") { // Properties @Override ObjectStatus status() { return LIVE; } @Override Address origin(SemiSpaceRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(SemiSpaceRemoteReference ref) { return ref.alternateOrigin; } @Override Address forwardedTo(SemiSpaceRemoteReference ref) { return Address.zero(); } // Transitions @Override void endAnalyzing(SemiSpaceRemoteReference ref) { ref.alternateOrigin = Address.zero(); ref.refState = SS_LIVE; } }, /** * Reference to a quasi-object <em>forwarder</em> in From-Space, * heap {@linkplain HeapPhase#ANALYZING analyzing}, location of * new copy in To-space known. */ SS_FORWARDER ("FORWARDER (Quasi object, only during Analyzing)") { // Properties @Override ObjectStatus status() { return FORWARDER; } @Override Address origin(SemiSpaceRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(SemiSpaceRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(SemiSpaceRemoteReference ref) { return ref.alternateOrigin; } // Transitions @Override void endAnalyzing(SemiSpaceRemoteReference ref) { ref.alternateOrigin = Address.zero(); ref.refState = SS_DEAD; } }, /** * Reference to a formerly live object that has been determined unreachable or to * a <em>forwarder</em>, once heap {@linkplain HeapPhase#ANALYZING analyzing is complete}, * and which should be forgotten. No assumptions may be made about memory contents at the location. */ SS_DEAD ("Dead") { // Properties @Override ObjectStatus status() { return DEAD; } @Override Address origin(SemiSpaceRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(SemiSpaceRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(SemiSpaceRemoteReference ref) { return Address.zero(); } // Transitions (none: alas, death is final) }; protected final String label; RefState(String label) { this.label = label; } // Properties. For clarity in the description of each state, no defaults specified. /** * @see RemoteReference#status() */ abstract ObjectStatus status(); /** * @see RemoteReference#origin() */ abstract Address origin(SemiSpaceRemoteReference ref); /** * @see RemoteReference#forwardedFrom() */ abstract Address forwardedFrom(SemiSpaceRemoteReference ref); /** * @see RemoteReference#forwardedTo() */ abstract Address forwardedTo(SemiSpaceRemoteReference ref); /** * @see RemoteReference#gcDescription() */ String gcDescription(SemiSpaceRemoteReference ref) { return label; } // Transitions: default is Illegal /** * @see SemiSpaceRemoteReference#beginAnalyzing() */ void beginAnalyzing(SemiSpaceRemoteReference ref) { TeleError.unexpected("Illegal state transition"); } /** * @see SemiSpaceRemoteReference#forwardedFrom() */ void discoverOldOrigin(SemiSpaceRemoteReference ref, Address fromOrigin) { TeleError.unexpected("Illegal state transition"); } /** * @see SemiSpaceRemoteReference#forwardedTo() */ void discoverForwarded(SemiSpaceRemoteReference ref, Address toOrigin) { TeleError.unexpected("Illegal state transition"); } /** * @see SemiSpaceRemoteReference#endAnalyzing() */ void endAnalyzing(SemiSpaceRemoteReference ref) { TeleError.unexpected("Illegal state transition"); } } public static final class RefStateCount { public final String stateName; public final long count; private RefStateCount(RefState state, long count) { this.stateName = state.label; this.count = count; } } public static List<RefStateCount> getStateCounts(List<SemiSpaceRemoteReference> refs) { final long[] refCounts = new long[RefState.values().length]; final List<RefStateCount> stateCounts = new ArrayList<RefStateCount>(); for (SemiSpaceRemoteReference ref : refs) { refCounts[ref.refState.ordinal()]++; } for (int i = 0; i < RefState.values().length; i++) { stateCounts.add(new RefStateCount(RefState.values()[i], refCounts[i])); } return stateCounts; } /** * Creates a new reference to an object, discovered in To-Space when the heap is <em>not</em> {@link HeapPhase#ANALYZING}. * * @param origin the location of the object in VM To-Space. * @return a remote reference to an ordinary live object */ public static SemiSpaceRemoteReference createLive(AbstractRemoteHeapScheme remoteScheme, Address origin) { return new SemiSpaceRemoteReference(remoteScheme, RefState.SS_LIVE, origin); } /** * Creates a reference to an object discovered in From-Space when the heap is {@link HeapPhase#ANALYZING}, but * without a forwarding pointer. * In this situation, the object is presumed to be in an unknown state with respect to reachability. * * @param origin the location of the object in VM From-Space. * @return a remote reference to the an object in From-Space with unknown reachability */ public static SemiSpaceRemoteReference createInFromOnly(AbstractRemoteHeapScheme remoteScheme, Address origin) { return new SemiSpaceRemoteReference(remoteScheme, RefState.SS_FROM, origin); } /** * Creates a reference to an object discovered in To-Space when the heap is {@link HeapPhase#ANALYZING}. * In this situation, the object is presumed to be a forwarded copy of an object in From-Space, even though * the location of the old copy is not (yet) known. * * @param origin the location of the object in VM To-Space. * @return a remote reference to the new copy of a forwarded object in To-Space */ public static SemiSpaceRemoteReference createInToOnly(AbstractRemoteHeapScheme remoteScheme, Address origin) { return new SemiSpaceRemoteReference(remoteScheme, RefState.SS_TO, origin); } /** * Creates a reference to a forwarded object discovered when the heap is {@link HeapPhase#ANALYZING}. * @param fromSpaceOrigin the location of the old copy in VM From-Space. * @param toSpaceOrigin the location of the new, live copy of the object in VM To-Space. * * @return a remote reference to the new copy of the forwarded object */ public static SemiSpaceRemoteReference createInFromTo(AbstractRemoteHeapScheme remoteScheme, Address fromSpaceOrigin, Address toSpaceOrigin) { return new SemiSpaceRemoteReference(remoteScheme, RefState.SS_FROM_TO, toSpaceOrigin, fromSpaceOrigin); } /** * Creates a quasi-reference to the old copy of a forwarded object. * * @param fromSpaceOrigin the location of the forwarding object in VM From-Space * @param toSpaceOrigin the location of the new, live copy in VM To-Space * @return a quasi remote reference to the forwarding object in From-Space, which will only live until the heap * is finished {@link HeapPhase#ANALYZING}. */ public static SemiSpaceRemoteReference createForwarder(AbstractRemoteHeapScheme remoteScheme, Address fromSpaceOrigin, Address toSpaceOrigin) { return new SemiSpaceRemoteReference(remoteScheme, RefState.SS_FORWARDER, fromSpaceOrigin, toSpaceOrigin); } /** * The origin of the object, usually in To-Space but possibly in From-Space * during ANALYZING. */ private Address origin; private ObjectStatus priorStatus; /** * During ANALYZING, when the object is known to have been forwarded, the location of the <em>other</em> copy of the object. */ private Address alternateOrigin; /** * The current state of the reference with respect to * where the object is located, what heap phase we might * be in, and whether the object is live, forwarded, or dead. */ private RefState refState = null; private final AbstractRemoteHeapScheme remoteScheme; private SemiSpaceRemoteReference(AbstractRemoteHeapScheme remoteScheme, RefState refState, Address origin, Address alternateOrigin) { super(remoteScheme.vm()); this.remoteScheme = remoteScheme; this.refState = refState; this.origin = origin; this.alternateOrigin = alternateOrigin; } private SemiSpaceRemoteReference(AbstractRemoteHeapScheme remoteScheme, RefState refState, Address origin) { this(remoteScheme, refState, origin, Address.zero()); } // Remote Reference properties @Override public ObjectStatus status() { return refState.status(); } @Override public ObjectStatus priorStatus() { return priorStatus; } @Override public Address origin() { return refState.origin(this); } @Override public Address forwardedFrom() { return refState.forwardedFrom(this); } @Override public Address forwardedTo() { return refState.forwardedTo(this); } @Override public String gcDescription() { return remoteScheme.heapSchemeClass().getSimpleName() + " state=" + refState.gcDescription(this); } // Reference state transitions /** * State transition on an ordinary live reference in To-Space when an {@link HeapPhase#ANALYZING} phase is discovered to * have begun, and in particular when the heap spaces have been swapped. This transition happens before any * attempt is made to discover the outcome of any tracing and possible forwarding; it models the state of a * live reference immediately after the spaces are swapped. * <p> * <strong>Pre:</strong> An ordinary {@link #LIVE} object in To-Space, not forwarded, with the heap phase * {@link HeapPhase#MUTATING} (or possibly in the latter part of {@link HeapPhase#RECLAIMING}). * <p> * <strong>Post:</strong> An object whose origin is in From-Space and presumed to be {@link #LIVE} during * an {@link HeapPhase#ANALYZING} heap phase in which the object's reachability has not yet been determined. */ public void beginAnalyzing() { priorStatus = refState.status(); refState.beginAnalyzing(this); } /** * State transition during {@link HeapPhase#ANALYZING} when the previously unknown original copy of a * forwarded object is discovered. * <p> * <strong>Pre:</strong> A reference to an object in To-Space, during {@link HeapPhase#ANALYZING}, that * is assumed to be a forwarded copy of some object, but the location of the original copy * in From-Space is unknown. * <p> * <strong>Post:</strong> A forwarded object in To-Space, during {@link HeapPhase#ANALYZING}, whose original * location in From-Space is known. * * @param oldOrigin newly discovered old copy in From-Space of a forwarded object */ public void discoverOldOrigin(Address oldOrigin) { priorStatus = refState.status(); refState.discoverOldOrigin(this, oldOrigin); } /** * State transition during {@link HeapPhase#ANALYZING} when an object in From-Space is first discovered to be forwarded. * <p> * <strong>Pre:</strong> A reference to an object in From-Space, during {@link HeapPhase#ANALYZING}, that has not * yet been discovered to be forwarded, i.e. in an unknown state of reachability. * <p> * <strong>Post:</strong> A reference to an object in To-Space (by definition forwarded and thus reachable), whose * original location (the previously value of the origin) is also known. * * @param newOrigin location of the new copy of the forwarded object in To-Space */ public void discoverForwarded(Address newOrigin) { priorStatus = refState.status(); refState.discoverForwarded(this, newOrigin); } /** * State transition on a reference at the end of an {@link HeapPhase#ANALYZING} phase, when * all the tracing and forwarding is complete. * <p> * <strong>Pre:</strong> A reference held during an {@link HeapPhase#ANALYZING} heap phase. * <p> * <strong>Post:</strong> A reference that is either {@link #LIVE} or {@link #DEAD}, * depending on its reachability discovered during {@link HeapPhase#ANALYZING} */ public void endAnalyzing() { priorStatus = refState.status(); refState.endAnalyzing(this); } }