Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java
41161 views
/*1* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.utilities;2526import java.io.*;27import java.util.*;28import sun.jvm.hotspot.debugger.*;29import sun.jvm.hotspot.gc.shared.*;30import sun.jvm.hotspot.memory.*;31import sun.jvm.hotspot.oops.*;32import sun.jvm.hotspot.runtime.*;3334/** Finds all paths from roots to the specified set of objects. NOTE:35currently only a subset of the roots known to the VM is exposed to36the SA: objects on the stack, static fields in classes, and JNI37handles. These should be most of the user-level roots keeping38objects alive. */3940public class LivenessAnalysis {41// Used for debugging this code42private static final boolean DEBUG = false;4344private LivenessAnalysis() {}4546public static LivenessPathList computeAllLivenessPaths(Oop target) {47LivenessPathList list = computeAllLivenessPaths(target, true);48if ((list == null) || (list.size() == 0)) {49// Dead object50return null;51}52return list;53}5455//---------------------------------------------------------------------------56// Internals only below this point57//5859// Returns true if a new path was completed, otherwise false60// indicating there were no more paths to complete.61//62// The trimPathsThroughPopularObjects flag alters the behavior of63// the returned results. If true, then if multiple paths to64// different roots all go through a particular popular object, those65// paths will be truncated and only one (arbitrary one) will be be66// returned. On the other hand, if the target object itself is67// popular and there are multiple distinct paths to it (indicating68// that there are multiple objects pointing directly to it) then all69// of those paths will be reported.70private static LivenessPathList computeAllLivenessPaths(Oop target, boolean trimPathsThroughPopularObjects) {71ReversePtrs rev = VM.getVM().getRevPtrs();72if (rev == null) {73throw new RuntimeException("LivenessAnalysis requires ReversePtrs to have been computed");74}7576// Currently the reverse pointer analysis returns non-null results77// only for live objects78if (rev.get(target) == null) {79// Object is dead80return null;81}8283// HashSet of Oops acting as a bit mask indicating which ones have84// already been traversed85Set<Oop> visitedOops = new HashSet<>();8687// IdentityHashMap of LivenessElements acting as a bit mask88// indicating which roots have already been traversed89Map<LivenessPathElement, LivenessPathElement> visitedRoots =90new IdentityHashMap<>();9192visitedOops.add(target);9394// Construct the initial LivenessPath95LivenessPathList list = new LivenessPathList();96{97LivenessPath path = new LivenessPath();98path.push(new LivenessPathElement(target, null));99list.add(path);100}101102// Iterate until done103while (true) {104// See if there are any incomplete paths left105LivenessPath path = null;106107for (int i = list.size() - 1; i >= 0; i--) {108LivenessPath tmp = list.get(i);109if (!tmp.isComplete()) {110path = tmp;111break;112}113}114115// If no incomplete paths left, return116if (path == null) {117return list;118}119120// Try to complete this path121122// Remove the path from the list of reported ones in123// anticipation of completing it124list.remove(path);125126try {127// Fetch next set of reverse pointers for the last object on128// the list129ArrayList/*<LivenessPathElement>*/ nextPtrs =130rev.get(path.peek().getObj());131132// Depending on exactly what the reverse pointers analysis133// yields, these results may be null, although currently they134// won't be135if (nextPtrs != null) {136// Iterate these137for (Iterator iter = nextPtrs.iterator(); iter.hasNext(); ) {138LivenessPathElement nextElement = (LivenessPathElement) iter.next();139// See whether we've visited this element yet140if ((nextElement.isRoot() && (visitedRoots.get(nextElement) == null)) ||141(!nextElement.isRoot() && !visitedOops.contains(nextElement.getObj()))) {142// Show we've visited this one143if (nextElement.isRoot()) {144visitedRoots.put(nextElement, nextElement);145} else {146visitedOops.add(nextElement.getObj());147}148149// Create a new LivenessPath for each one150LivenessPath nextPath = path.copy();151nextPath.push(nextElement);152153// Regardless of whether we found a root, put the154// original path back on the list because we're going to155// do depth-first searching rather than breadth-first156list.add(path);157list.add(nextPath);158159// See whether this path is complete (i.e., it160// terminates in a root)161if (trimPathsThroughPopularObjects && nextElement.isRoot()) {162// Go back through the path list and remove all163// incomplete paths ending in any of the intermediate164// (non-root and non-terminal) nodes in this path.165// This has the effect of removing multiple paths166// going through popular objects.167for (int i = 1; i < nextPath.size() - 1; i++) {168LivenessPathElement el = nextPath.get(i);169int j = 0;170while (j < list.size()) {171LivenessPath curPath = list.get(j);172// We can use an object identity since these173// intermediate nodes are canonicalized via the174// ReversePtrsAnalysis175if (curPath.peek() == el) {176list.remove(curPath);177} else {178j++;179}180}181}182}183184// Do depth-first searching, not breadth-first185break;186}187}188}189} catch (Exception e) {190System.err.println("LivenessAnalysis: WARNING: " + e +191" during traversal");192}193}194}195}196197198