Mercurial > hg > truffle
view agent/src/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java @ 17716:cdb71841f4bc
6498581: ThreadInterruptTest3 produces wrong output on Windows
Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Reviewed-by: acorn, kvn
Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
author | minqi |
---|---|
date | Wed, 26 Feb 2014 15:20:41 -0800 |
parents | c18cbe5936b8 |
children |
line wrap: on
line source
/* * Copyright (c) 2001, 2006, 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 sun.jvm.hotspot.utilities; import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.gc_interface.*; import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; /** Finds all paths from roots to the specified set of objects. NOTE: currently only a subset of the roots known to the VM is exposed to the SA: objects on the stack, static fields in classes, and JNI handles. These should be most of the user-level roots keeping objects alive. */ public class LivenessAnalysis { // Used for debugging this code private static final boolean DEBUG = false; private LivenessAnalysis() {} public static LivenessPathList computeAllLivenessPaths(Oop target) { LivenessPathList list = computeAllLivenessPaths(target, true); if ((list == null) || (list.size() == 0)) { // Dead object return null; } return list; } //--------------------------------------------------------------------------- // Internals only below this point // // Returns true if a new path was completed, otherwise false // indicating there were no more paths to complete. // // The trimPathsThroughPopularObjects flag alters the behavior of // the returned results. If true, then if multiple paths to // different roots all go through a particular popular object, those // paths will be truncated and only one (arbitrary one) will be be // returned. On the other hand, if the target object itself is // popular and there are multiple distinct paths to it (indicating // that there are multiple objects pointing directly to it) then all // of those paths will be reported. private static LivenessPathList computeAllLivenessPaths(Oop target, boolean trimPathsThroughPopularObjects) { ReversePtrs rev = VM.getVM().getRevPtrs(); if (rev == null) { throw new RuntimeException("LivenessAnalysis requires ReversePtrs to have been computed"); } // Currently the reverse pointer analysis returns non-null results // only for live objects if (rev.get(target) == null) { // Object is dead return null; } // HashSet of Oops acting as a bit mask indicating which ones have // already been traversed Set/*<Oop>*/ visitedOops = new HashSet/*<Oop>*/(); // IdentityHashMap of LivenessElements acting as a bit mask // indicating which roots have already been traversed Map/*<LivenessElement, LivenessElement>*/ visitedRoots = new IdentityHashMap/*<LivenessElement, LivenessElement>*/(); visitedOops.add(target); // Construct the initial LivenessPath LivenessPathList list = new LivenessPathList(); { LivenessPath path = new LivenessPath(); path.push(new LivenessPathElement(target, null)); list.add(path); } // Iterate until done while (true) { // See if there are any incomplete paths left LivenessPath path = null; for (int i = list.size() - 1; i >= 0; i--) { LivenessPath tmp = list.get(i); if (!tmp.isComplete()) { path = tmp; break; } } // If no incomplete paths left, return if (path == null) { return list; } // Try to complete this path // Remove the path from the list of reported ones in // anticipation of completing it list.remove(path); try { // Fetch next set of reverse pointers for the last object on // the list ArrayList/*<LivenessPathElement>*/ nextPtrs = rev.get(path.peek().getObj()); // Depending on exactly what the reverse pointers analysis // yields, these results may be null, although currently they // won't be if (nextPtrs != null) { // Iterate these for (Iterator iter = nextPtrs.iterator(); iter.hasNext(); ) { LivenessPathElement nextElement = (LivenessPathElement) iter.next(); // See whether we've visited this element yet if ((nextElement.isRoot() && (visitedRoots.get(nextElement) == null)) || (!nextElement.isRoot() && !visitedOops.contains(nextElement.getObj()))) { // Show we've visited this one if (nextElement.isRoot()) { visitedRoots.put(nextElement, nextElement); } else { visitedOops.add(nextElement.getObj()); } // Create a new LivenessPath for each one LivenessPath nextPath = path.copy(); nextPath.push(nextElement); // Regardless of whether we found a root, put the // original path back on the list because we're going to // do depth-first searching rather than breadth-first list.add(path); list.add(nextPath); // See whether this path is complete (i.e., it // terminates in a root) if (trimPathsThroughPopularObjects && nextElement.isRoot()) { // Go back through the path list and remove all // incomplete paths ending in any of the intermediate // (non-root and non-terminal) nodes in this path. // This has the effect of removing multiple paths // going through popular objects. for (int i = 1; i < nextPath.size() - 1; i++) { LivenessPathElement el = nextPath.get(i); int j = 0; while (j < list.size()) { LivenessPath curPath = list.get(j); // We can use an object identity since these // intermediate nodes are canonicalized via the // ReversePtrsAnalysis if (curPath.peek() == el) { list.remove(curPath); } else { j++; } } } } // Do depth-first searching, not breadth-first break; } } } } catch (Exception e) { System.err.println("LivenessAnalysis: WARNING: " + e + " during traversal"); } } } }