/* * 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.tele; import java.util.*; import com.sun.max.annotate.*; import com.sun.max.memory.*; import com.sun.max.unsafe.*; import com.sun.max.vm.heap.*; import com.sun.max.vm.heap.HeapScheme.Inspect; /** * Makes critical state information about the object heap * remotely inspectable. * <p> * Active only when VM is being inspected. * <p> * Dynamic object allocation is to be avoided. * <p> * The methods in this with names inspectable* are intended to act as a kind of hook for the Inspector, so that it * can interrupt the VM at certain interesting moments. This could also be used as a kind of low-wattage event * mechanism. * <p> * The inspectable* methods here are distinct from those with similar or identical names in {@link Inspect}, * which are intended to act as convenient places for a user to set a breakpoint, perhaps from a menu of standard * locations. The intention is that those locations would not land the user in this class. */ public final class InspectableHeapInfo { private InspectableHeapInfo() { } /** * Should inspectable information about heap regions be allocated in immortal memory. */ private static boolean useImmortalMemory = false; /** * Inspectable array of memory regions allocated dynamically for heap memory management. * @see com.sun.max.vm.heap.HeapScheme */ @INSPECTED private static MemoryRegion[] dynamicHeapMemoryRegions; /** * The ordinal value of the enum describing the current heap phase. * This permits inspection of the phase at any time and, if needed, * detection of phase change by watchpoint. */ @INSPECTED private static int heapPhaseOrdinal = HeapPhase.MUTATING.ordinal(); /** * Inspectable counter of the number of Garbage Collections that have <strong>begun</strong>. * <p> * Used by the Inspector to determine if the VM is currently collecting. */ @INSPECTED private static long gcStartedCounter; /** * Inspectable counter of the number of Garbage Collections that have <strong>completed</strong>. * <p> * Used by the Inspector to determine if the VM is currently collecting, and to * determine if the Inspector's cache of the root locations is current. */ @INSPECTED private static long gcCompletedCounter; /** * Heap size most recently requested. */ @INSPECTED private static long recentHeapSizeRequest; /** * Sets up root table and other information needed for heap inspection. * <p> * No-op when VM is not being inspected. * @param useImmortalMemory should allocations should be made in immortal memory. */ public static void init(boolean useImmortalMemory) { if (Inspectable.isVmInspected()) { InspectableHeapInfo.useImmortalMemory = useImmortalMemory; } } /** * <strong>This is scheduled for retirement.</strong> * <p> The new heap scheme support * classes in the Inspector locate the memory regions for each heap scheme * implementation directly from the implementation class. This notification * call is only in place to support legacy support for "attach" mode in the * SemiSpace support, which will also cease to depend on this notification. * (mlvdv 4/22/12). * <p> * Stores descriptions of memory allocated by the heap in a location that can * be inspected easily. * <p> * It is a good idea to use instances of {@link MemoryRegion} that have * been allocated in the boot heap if at all possible, thus avoiding having * meta information about the dynamic heap being described by objects * in the dynamic heap. * <p> * No-op when VM is not being inspected. * @param memoryRegions regions allocated by the heap implementation */ public static void setMemoryRegions(MemoryRegion[] memoryRegions) { if (Inspectable.isVmInspected()) { if (useImmortalMemory) { try { Heap.enableImmortalMemoryAllocation(); dynamicHeapMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length); } finally { Heap.disableImmortalMemoryAllocation(); } } else { dynamicHeapMemoryRegions = memoryRegions; } } } @INSPECTED @NEVER_INLINE private static void inspectableObjectRelocated(Address oldCellLocation, Address newCellLocation) { } public static void notifyPhaseChange(HeapPhase phase) { heapPhaseOrdinal = phase.ordinal(); switch (phase) { case ANALYZING: gcStartedCounter++; // From the Inspector's perspective, a GC begins when // the epoch counter gets incremented. inspectableGCAnalyzing(gcStartedCounter); break; case RECLAIMING: inspectableGCReclaiming(gcStartedCounter); break; case MUTATING: gcCompletedCounter++; // From the Inspector's perspective, a GC is complete when // the two epoch counters become equal. inspectableGCMutating(gcCompletedCounter); break; } } /** * An empty method whose purpose is to be interrupted by the Inspector * when it needs to observe the VM at the beginning of a GC, i.e. when * it enters the {@link HeapPhase#ANALYZING}. * <p> * This particular method is intended for internal use by the inspector. * Should a user wish to break at the beginning of GC, another, more * convenient inspectable method is provided * <p> * <strong>Important:</strong> The Inspector assumes that this method is loaded * and compiled in the boot image and that it will never be dynamically recompiled. * * @param gcStartedCounter the GC epoch that is starting. */ @INSPECTED @NEVER_INLINE private static void inspectableGCAnalyzing(long gcStartedCounter) { } /** * An empty method whose purpose is to be interrupted by the Inspector * when it needs to observe the VM when GC is ready to start reclaiming, * i.e. when it enters the {@link HeapPhase#RECLAIMING}. * <p> * This particular method is intended for internal use by the inspector. * Should a user wish to break at this phase, another, more * convenient inspectable method is provided * <p> * <strong>Important:</strong> The Inspector assumes that this method is loaded * and compiled in the boot image and that it will never be dynamically recompiled. * * @param gcStartedCounter the GC epoch that is starting. */ @INSPECTED @NEVER_INLINE private static void inspectableGCReclaiming(long gcStartedCounter) { } /** * An empty method whose purpose is to be interrupted by the Inspector * when it needs to observe the VM at the conclusion of a GC, i.e. hwen * it enters the {@link HeapPhase#MUTATING}. * <p> * This particular method is intended for internal use by the inspector. * Should a user wish to break at the conclusion of GC, another, more * convenient inspectable method is provided * <p> * <strong>Important:</strong> The Inspector assumes that this method is loaded * and compiled in the boot image and that it will never be dynamically recompiled. * * @param gcCompletedCounter the GC epoch that is ending. */ @INSPECTED @NEVER_INLINE private static void inspectableGCMutating(long gcCompletedCounter) { } /** * Records that an increase of heap size has been requested. * * @param size the desired new heap size. */ public static void notifyIncreaseMemoryRequested(Size size) { recentHeapSizeRequest = size.toLong(); inspectableIncreaseMemoryRequested(size); } /** * An empty method whose purpose is to be interrupted by the Inspector * when it needs to observe a request for heap memory size increase. * <p> * This particular method is intended for internal use by the inspector. * Should a user wish to break at the request, another, more * convenient inspectable method is provided * <p> * <strong>Important:</strong> The Inspector assumes that this method is loaded * and compiled in the boot image and that it will never be dynamically recompiled. * * @param * @see HeapScheme.Inspect#inspectableIncreaseMemoryRequestedCriticalMethod() */ @INSPECTED @NEVER_INLINE private static void inspectableIncreaseMemoryRequested(Size size) { } /** * Records that an decrease of heap size has been requested. * * @param size the desired new heap size. */ public static void notifyDecreaseMemoryRequested(Size size) { recentHeapSizeRequest = size.toLong(); inspectableDecreaseMemoryRequested(size); } /** * An empty method whose purpose is to be interrupted by the Inspector * when it needs to observe a request for heap memory size decrease. * <p> * This particular method is intended for internal use by the inspector. * Should a user wish to break at the request, another, more * convenient inspectable method is provided * <p> * <strong>Important:</strong> The Inspector assumes that this method is loaded * and compiled in the boot image and that it will never be dynamically recompiled. * * @param size the desired new heap size * @see HeapScheme.Inspect#inspectableDecreaseMemoryRequestedCriticalMethod() */ @INSPECTED @NEVER_INLINE private static void inspectableDecreaseMemoryRequested(Size size) { } }