/* * 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.gen.semispace; import static com.sun.max.tele.object.ObjectStatus.*; 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.*; /** * Representation of a remote object reference in a generational heap with a non-aging nursery and a semi-space old generation. * A young generation collection evacuates objects from the young generation into the to-space of the old generation using * a copying mechanism that leaves forwarders in the evacuated objects. * The to-space of the old generation is almost never empty. * An old generation collection occurs only when the young generation is empty (i.e., all live young objects have been evacuated), * and proceeds in a classic semi-space fashion: the to and from space swap, * and live objects from the from-space are evacuated in the to-space using * a copying mechanism that leaves forwarders in the evacuated objects. * Complications in the model arise because of the of potential overflow situations: * a young generation collection may overflow into the from space. * a old generation collection may overflow into the young space. */ public class GenSSRemoteReference extends RemoteReference { /** * The origin of an object. * During mutating phases and analysis phase of minor collection, a reference may map to an address in the non-aging nursery (young generation) or the to space of the old generation. * After a minor collection, references can only map to the to space of the old generation. * During analysis of a old collection, a reference may map to an address in to space of the old generation only. */ private Address origin; /** * An additional address the reference may relate to. This is used to keep track of forwarder/forwardee relationship during object relocation to ease debugging of moving collectors. * Only forwarders or forwarded objects have an alternate origin. */ private Address alternateOrigin; /** * State of an object reference. The state indicates where the object is located and its liveness status, */ private RefState refState = null; private ObjectStatus priorStatus = null; private final RemoteGenSSHeapScheme remoteScheme; /** * 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 young reference. * Address is in the allocated part of the young generation. * Valid only during the {@link HeapPhase#MUTATING} phase. */ YOUNG_REF_LIVE("LIVE(young)") { // Properties @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisBegins(GenSSRemoteReference ref, boolean minorCollection) { if (minorCollection) { ref.refState = YOUNG_REF_FROM; return; } TeleError.unexpected("Illegal state transition"); } }, /** * Young reference, not forwarded. * Address is in the allocated part of the young generation. * Valid only during the {@link HeapPhase#ANALYZING} phase. * This is the state {@link #YOUNG_REF_LIVE} changes to when a transition {@link HeapPhase#MUTATING} * to {@link HeapPhase#ANALYZING} is detected. */ YOUNG_REF_FROM("LIVE(Analyzing: young, !forwarder)") { @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { if (minorCollection) { ref.refState = REF_DEAD; return; } TeleError.unexpected("Illegal state transition"); } /** * The reference turns into a PROMOTED_REF. A forwarder will be created separately. */ @Override void discoverForwarded(GenSSRemoteReference ref, Address forwardedOrigin, boolean minorCollection) { if (minorCollection) { // FIXME: should also check the current heap phase! ref.alternateOrigin = ref.origin; // the origin now becomes an alternate as it points to the forwarder ref.origin = forwardedOrigin; // the reference now points to the forwarded address ref.refState = PROMOTED_REF; return; } TeleError.unexpected("Illegal state transition"); } }, /** * Reference to a young forwarding object. * Address is in the young generation, and its header comprises a forwarder to the old generation. * A reference to the forwarded object must be in the @link {@link #PROMOTED_REF} state. */ YOUNG_FORWARDER("FORWARDER(Quasi object, only during minor collection analyzing") { @Override ObjectStatus status() { return FORWARDER; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return ref.alternateOrigin; } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { ref.alternateOrigin = Address.zero(); ref.refState = REF_DEAD; } }, /** * Reference to an object promoted from the young generation to the old generation * whose forwarder is unknown. * Address in the old to-space, or in the from space if a minor evacuation overflow occurred. */ PROMOTED_UNKNOWN_FORWARDER_REF("LIVE(Analyzing: promoted, young forwarder unknown)") { @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { if (minorCollection) { ref.refState = OLD_REF_LIVE; return; } TeleError.unexpected("Illegal state transition"); } @Override void discoverForwarder(GenSSRemoteReference ref, Address fromOrigin, boolean minorCollection) { if (minorCollection) { ref.alternateOrigin = fromOrigin; ref.refState = PROMOTED_REF; return; } TeleError.unexpected("Illegal state transition"); } }, /** * Reference to an object promoted from the young generation to the old generation whose forwarder in young space is known. * Address is in the old to-space. * There must be a reference in the {@link #YOUNG_FORWARDER} for a forwarding object in the young generation. */ PROMOTED_REF("LIVE(Analyzing: promoted, young forwarder known)") { @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return ref.alternateOrigin; } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { if (minorCollection) { ref.alternateOrigin = Address.zero(); ref.refState = OLD_REF_LIVE; return; } TeleError.unexpected("Illegal state transition"); } @Override RefState forwarderState() { return YOUNG_FORWARDER; } }, /** * Reference to an old forwarding object. * The forwarded may be known, in which case, it has a {@link #OLD_SURVIVOR_REF} reference. * Address must be in from-space. * State is valid only during {@link HeapPhase#ANALYZING} of old generation collections. */ OLD_FORWARDER("FORWARDER(Quasi object, old collection analyzing only") { @Override ObjectStatus status() { return FORWARDER; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return ref.alternateOrigin; } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { ref.alternateOrigin = Address.zero(); ref.refState = REF_DEAD; } }, /** * Live old object. * Valid during the {@link HeapPhase#MUTATING}, and {@link HeapPhase#ANALYZING} of minor collections. */ OLD_REF_LIVE("LIVE(old)") { @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisBegins(GenSSRemoteReference ref, boolean minorCollection) { if (minorCollection) { // nothing to do. return; } ref.refState = OLD_REF_FROM; } }, /** * Old reference not forwarded. * Address is in the allocated part of the old from-space. * Valid only during the {@link HeapPhase#ANALYZING} phase of old generation collections. * This is the state {@link #OLD_REF_LIVE} references change to when a transition {@link HeapPhase#MUTATING} * to {@link HeapPhase#ANALYZING} for an old generation collection is detected. */ OLD_REF_FROM("LIVE(Analyzing: old from-only, !forwarder)") { @Override ObjectStatus status() { return LIVE; } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { if (!minorCollection) { ref.refState = REF_DEAD; return; } TeleError.unexpected("Illegal state transition"); } @Override void discoverForwarded(GenSSRemoteReference ref, Address toOrigin, boolean minorCollection) { if (!minorCollection) { ref.alternateOrigin = ref.origin; ref.origin = toOrigin; ref.refState = OLD_SURVIVOR_REF; return; } TeleError.unexpected("Illegal state transition"); } }, /** * Survivor of old collection. * Forwarder is not known. * Address is in survivor range. * State is only valid during the {@link HeapPhase#ANALYZING} of an old generation collection. * Reference is created in this state when a reference in to-space is discovered * during the analyzing phase of an old collection. */ OLD_SURVIVOR_UNKNOWN_FORWARDER_REF("LIVE (Analyzing: old survivor, forwarder unknown)") { @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { if (!minorCollection) { assert ref.alternateOrigin == Address.zero(); ref.refState = ref.remoteScheme.isInOverflowArea(ref.origin) ? YOUNG_REF_LIVE : OLD_REF_LIVE; return; } TeleError.unexpected("Illegal state transition"); } @Override void discoverForwarder(GenSSRemoteReference ref, Address forwarderOrigin, boolean minorCollection) { if (!minorCollection) { ref.alternateOrigin = forwarderOrigin; ref.refState = OLD_SURVIVOR_REF; return; } TeleError.unexpected("Illegal state transition"); } }, /** * Survivor of old collection. * Forwarder is known (there must be an OLD_FORWARDER in the old-from map). * Address is in survivor range. * Reference is in old-to map. * State is only valid during the {@link HeapPhase#ANALYZING} of an old generation collection. */ OLD_SURVIVOR_REF("LIVE (Analyzing: old survivor, forwarder known)") { @Override ObjectStatus status() { return LIVE; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return ref.alternateOrigin; } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } @Override void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { if (!minorCollection) { ref.alternateOrigin = Address.zero(); ref.refState = ref.remoteScheme.isInOverflowArea(ref.origin) ? YOUNG_REF_LIVE : OLD_REF_LIVE; return; } TeleError.unexpected("Illegal state transition"); } @Override RefState forwarderState() { return OLD_FORWARDER; } }, REF_DEAD ("Dead") { // Properties @Override ObjectStatus status() { return DEAD; } @Override Address origin(GenSSRemoteReference ref) { return ref.origin; } @Override Address forwardedFrom(GenSSRemoteReference ref) { return Address.zero(); } @Override Address forwardedTo(GenSSRemoteReference ref) { return Address.zero(); } }; protected final String label; RefState(String label) { this.label = label; } /** * @see RemoteReference#status() */ abstract ObjectStatus status(); /** * @see RemoteReference#origin() */ abstract Address origin(GenSSRemoteReference ref); /** * @see RemoteReference#forwardedFrom() */ abstract Address forwardedFrom(GenSSRemoteReference ref); /** * @see RemoteReference#forwardedTo() */ abstract Address forwardedTo(GenSSRemoteReference ref); String gcDescription(GenSSRemoteReference ref) { return label; } /** * Apply state transition to a reference upon beginning of an analysis phase. * @param ref reference the state transition applies to * @param minorCollection true if the analysis phase if for a minor collection. */ void analysisBegins(GenSSRemoteReference ref, boolean minorCollection) { TeleError.unexpected("Illegal state transition"); } /** * Apply state transition to a reference upon end an analysis phase. * * @param ref reference the state transition applies to * @param minorCollection true if the analysis phase if for a minor collection. */ void analysisEnds(GenSSRemoteReference ref, boolean minorCollection) { TeleError.unexpected("Illegal state transition"); } /** * Notify the discovery of a forwarder for this reference, i.e., a forwarding reference is point this to this reference. * @param ref * @param forwarderOrigin the origin of the forwarder pointing to this reference * @param minorCollection true if the discovery took place at minor collection, false if during full collection. */ void discoverForwarder(GenSSRemoteReference ref, Address forwarderOrigin, boolean minorCollection) { TeleError.unexpected("Illegal state transition"); } /** * Notify the discovery of the forwarded reference for this reference, i.e., this reference must be a forwarding reference. * * @param ref * @param forwardedOrigin the origin of the object this reference forwards to. * @param minorCollection true if the discovery took place at minor collection, false if during full collection. */ void discoverForwarded(GenSSRemoteReference ref, Address forwardedOrigin, boolean minorCollection) { TeleError.unexpected("Illegal state transition"); } RefState forwarderState() { TeleError.unexpected("Reference state without forwarder"); return null; } } protected GenSSRemoteReference(RemoteGenSSHeapScheme remoteScheme, Address origin, Address alternateOrigin) { super(remoteScheme.vm()); this.origin = origin; this.alternateOrigin = alternateOrigin; this.remoteScheme = remoteScheme; } @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); } public void beginAnalyzing(boolean minorCollection) { priorStatus = refState.status(); refState.analysisBegins(this, minorCollection); } public void endAnalyzing(boolean minorCollection) { priorStatus = refState.status(); refState.analysisEnds(this, minorCollection); } public void discoverForwarder(Address fromOrigin, boolean minorCollection) { priorStatus = refState.status(); refState.discoverForwarder(this, fromOrigin, minorCollection); } public void discoverForwarded(Address toOrigin, boolean minorCollection) { priorStatus = refState.status(); refState.discoverForwarded(this, toOrigin, minorCollection); } /** * Creates a reference to a live object, discovered when the heap is <em>not</em> {@link HeapPhase#ANALYZING}. * @param remoteScheme * @param toOrigin the physical location of the object in virtual memory. * @param isYoung true if the object is located in the nursery. Otherwise the object is in the old To-space. * @return a remote reference to an live object */ public static GenSSRemoteReference createLive(RemoteGenSSHeapScheme remoteScheme, Address toOrigin, boolean isYoung) { TeleError.check(remoteScheme.canCreateLive()); final GenSSRemoteReference ref = new GenSSRemoteReference(remoteScheme, toOrigin, Address.zero()); ref.refState = isYoung ? RefState.YOUNG_REF_LIVE : RefState.OLD_REF_LIVE; return ref; } public static GenSSRemoteReference createOldTo(RemoteGenSSHeapScheme remoteScheme, Address toOrigin, boolean isPromoted) { final GenSSRemoteReference ref = new GenSSRemoteReference(remoteScheme, toOrigin, Address.zero()); ref.refState = isPromoted ? RefState.PROMOTED_UNKNOWN_FORWARDER_REF : RefState.OLD_SURVIVOR_UNKNOWN_FORWARDER_REF; return ref; } public static GenSSRemoteReference createFromOnly(RemoteGenSSHeapScheme remoteScheme, Address fromOrigin, boolean isYoung) { final GenSSRemoteReference ref = new GenSSRemoteReference(remoteScheme, fromOrigin, Address.zero()); ref.refState = isYoung ? RefState.YOUNG_REF_FROM : RefState.OLD_REF_FROM; return ref; } public static GenSSRemoteReference createFromTo(RemoteGenSSHeapScheme remoteScheme, Address fromOrigin, Address toOrigin, boolean isYoung) { final GenSSRemoteReference ref = new GenSSRemoteReference(remoteScheme, toOrigin, fromOrigin); ref.refState = isYoung ? RefState.PROMOTED_REF : RefState.OLD_SURVIVOR_REF; return ref; } public static void checkNoLiveRef(WeakRemoteReferenceMap<GenSSRemoteReference> map, boolean isYoung) { final RefState prohibitedRefState = isYoung ? RefState.YOUNG_REF_LIVE : RefState.OLD_REF_LIVE; for (GenSSRemoteReference ref : map.values()) { TeleError.check(ref.refState != prohibitedRefState); } } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append(refState.label); sb.append(" origin: "); sb.append(origin == null ? "<null>" : origin.to0xHexString()); sb.append(" alt: "); sb.append(alternateOrigin == null ? "<null>" : alternateOrigin.to0xHexString()); return sb.toString(); } public static GenSSRemoteReference createForwarder(RemoteGenSSHeapScheme remoteScheme, GenSSRemoteReference forwardedRef) { final GenSSRemoteReference ref = new GenSSRemoteReference(remoteScheme, forwardedRef.alternateOrigin, forwardedRef.origin); ref.refState = forwardedRef.refState.forwarderState(); return ref; } }