/* * 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.ms; 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.gcx.*; /** * Representation of a remote object reference in a heap region managed by a mark sweep GC. The states of the reference * represents what can be known about the object at any given time, 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 MSHeapScheme * @see RemoteMSHeapScheme */ public final class MSRemoteReference extends RemoteReference { /** * A internal 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> * <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.</p> * <p> * This set of states actually defines two independent state models: one for ordinary objects (which might be live * or unreachable) and one for <em>free space</em> quasi-objects * (instances of {@link HeapFreeChunk} or {@link DarkMatter}) used by the collector to represent * unallocated memory in a fashion similar to ordinary objects. These can be treated as ordinary references for some * purposes, but not all.</p> */ private static enum RefState { /** * Reference to an object known to be reachable (during {@linkplain HeapPhase#MUTATION mutation} and {@linkplain HeapPhase#RECLAIMING reclaiming} * phases, or not yet determined unreachable during {@linkplain HeapPhase#ANALYZING analyzing}. */ MS_LIVE ("LIVE object"){ // Properties @Override ObjectStatus status() { return LIVE; } // Transitions @Override void discoveredUnreachable(MSRemoteReference ref) { ref.refState = MS_UNREACHABLE; } @Override void die(MSRemoteReference ref) { ref.refState = MS_DEAD; } }, /** * Reference to an object found unreachable during heap {@linkplain HeapPhase#ANALYZING analyzing}. * It is a <em>quasi-object</em> until it is overwritten by the GC with some representation * of <em>free space</em>, at which time this quasi-object dies. This state should not occur * during other heap phases. */ MS_UNREACHABLE ("UNREACHABLE object (during RECLAIMING only)") { // Properties @Override ObjectStatus status() { return UNREACHABLE; } // Transitions @Override void die(MSRemoteReference ref) { ref.refState = MS_DEAD; } }, /** * Reference to a free space <em>quasi-object</em>: one that fills a region of unallocated memory and which is available for * allocation. When this memory is <em>overwritten</em>, either by allocation of a new object or merged with some other * representation of free space, then this quasi-object dies. */ MS_FREE_CHUNK ("Chunk of allocatable free memory") { // Properties; @Override ObjectStatus status() { return FREE; } // Transitions @Override void die(MSRemoteReference ref) { ref.refState = MS_DEAD; } }, /** * Reference to a <em>quasi-object</em> that fills a region of unallocated memory and which is <em>not</em> available for * allocation. */ MS_DARK_MATTER ("Chunk of unallocatable free memory") { // Properties; @Override ObjectStatus status() { return DARK; } // Transitions @Override void die(MSRemoteReference ref) { ref.refState = MS_DEAD; } }, /** * Reference to a formerly live or quasi-object that has been determined unreachable, and which should be * forgotten. No assumptions may be made about memory contents at the location. */ MS_DEAD ("DEAD object or quasi-object") { // Properties @Override ObjectStatus status() { return DEAD; } // Transitions (alas, death is final) }; protected final String label; RefState(String label) { this.label = label; } // Properties /** * @see RemoteReference#status() */ abstract ObjectStatus status(); /** * @see RemoteReference#origin() */ Address origin(MSRemoteReference ref) { return ref.origin; } /** * @see RemoteReference#gcDescription() */ String gcDescription(MSRemoteReference ref) { return label; } // Transitions: default is Illegal /** * @see MSRemoteReference#discoveredUnreachable() */ void discoveredUnreachable(MSRemoteReference ref) { TeleError.unexpected("Illegal state transition on:" + ref); } /** * @see MSRemoteReference#die() */ void die(MSRemoteReference ref) { TeleError.unexpected("Illegal state transition on: " + ref); } } public static final class RefStateCount { public final String stateName; public final long count; private RefStateCount(MSRemoteReference.RefState state, long count) { this.stateName = state.label; this.count = count; } } public static List<MSRemoteReference.RefStateCount> getStateCounts(List<MSRemoteReference> refs) { final long[] refCounts = new long[RefState.values().length]; final List<MSRemoteReference.RefStateCount> stateCounts = new ArrayList<MSRemoteReference.RefStateCount>(); for (MSRemoteReference 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 {@linkplain RemoteReference reference} to a {@linkplain ObjectStatus#LIVE LIVE} object. */ public static MSRemoteReference createLive(RemoteMSHeapScheme remoteScheme, Address origin) { final MSRemoteReference ref = new MSRemoteReference(remoteScheme, origin); ref.refState = RefState.MS_LIVE; return ref; } /** * Creates a new {@linkplain RemoteReference reference} to a {@linkplain ObjectStatus#UNREACHABLE UNREACHABLE} object. */ public static MSRemoteReference createUnreachable(RemoteMSHeapScheme remoteScheme, Address origin) { final MSRemoteReference ref = new MSRemoteReference(remoteScheme, origin); ref.refState = RefState.MS_UNREACHABLE; return ref; } /** * Creates a new {@linkplain RemoteReference reference} to a {@linkplain ObjectStatus#FREE FREE} object. */ public static MSRemoteReference createFree(RemoteMSHeapScheme remoteScheme, Address origin) { final MSRemoteReference ref = new MSRemoteReference(remoteScheme, origin); ref.refState = RefState.MS_FREE_CHUNK; return ref; } /** * Creates a new {@linkplain RemoteReference reference} to a {@linkplain ObjectStatus#DARK DARK} object. */ public static MSRemoteReference createDark(RemoteMSHeapScheme remoteScheme, Address origin) { final MSRemoteReference ref = new MSRemoteReference(remoteScheme, origin); ref.refState = RefState.MS_DARK_MATTER; return ref; } private Address origin; private ObjectStatus priorStatus = null; /** * The current state of the reference with respect to where the object is located, what heap phase we might be in, * and its status. */ private MSRemoteReference.RefState refState = null; private final RemoteMSHeapScheme remoteScheme; private MSRemoteReference(RemoteMSHeapScheme remoteScheme, Address origin) { super(remoteScheme.vm()); this.origin = origin; this.remoteScheme = remoteScheme; } // Remote Reference properties @Override public ObjectStatus status() { return refState.status(); } @Override public ObjectStatus priorStatus() { return priorStatus; } @Override public Address origin() { return origin; } @Override public Address forwardedFrom() { return Address.zero(); } @Override public Address forwardedTo() { return Address.zero(); } @Override public String gcDescription() { return remoteScheme.heapSchemeClass().getSimpleName() + " state=" + refState.gcDescription(this); } // Reference state transitions /** * State transition on an ordinary live object reference during {@link HeapPhase#ANALYZING} when an object is found to be unreachable. */ public void discoveredUnreachable() { priorStatus = refState.status(); refState.discoveredUnreachable(this); } /** * State transition on any kind of object when it has been determined to be unreachable and should be forgotten. */ public void die() { priorStatus = refState.status(); refState.die(this); } }