Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/LivenessAnalysis.java
41161 views
1
/*
2
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
package sun.jvm.hotspot.utilities;
26
27
import java.io.*;
28
import java.util.*;
29
import sun.jvm.hotspot.debugger.*;
30
import sun.jvm.hotspot.gc.shared.*;
31
import sun.jvm.hotspot.memory.*;
32
import sun.jvm.hotspot.oops.*;
33
import sun.jvm.hotspot.runtime.*;
34
35
/** Finds all paths from roots to the specified set of objects. NOTE:
36
currently only a subset of the roots known to the VM is exposed to
37
the SA: objects on the stack, static fields in classes, and JNI
38
handles. These should be most of the user-level roots keeping
39
objects alive. */
40
41
public class LivenessAnalysis {
42
// Used for debugging this code
43
private static final boolean DEBUG = false;
44
45
private LivenessAnalysis() {}
46
47
public static LivenessPathList computeAllLivenessPaths(Oop target) {
48
LivenessPathList list = computeAllLivenessPaths(target, true);
49
if ((list == null) || (list.size() == 0)) {
50
// Dead object
51
return null;
52
}
53
return list;
54
}
55
56
//---------------------------------------------------------------------------
57
// Internals only below this point
58
//
59
60
// Returns true if a new path was completed, otherwise false
61
// indicating there were no more paths to complete.
62
//
63
// The trimPathsThroughPopularObjects flag alters the behavior of
64
// the returned results. If true, then if multiple paths to
65
// different roots all go through a particular popular object, those
66
// paths will be truncated and only one (arbitrary one) will be be
67
// returned. On the other hand, if the target object itself is
68
// popular and there are multiple distinct paths to it (indicating
69
// that there are multiple objects pointing directly to it) then all
70
// of those paths will be reported.
71
private static LivenessPathList computeAllLivenessPaths(Oop target, boolean trimPathsThroughPopularObjects) {
72
ReversePtrs rev = VM.getVM().getRevPtrs();
73
if (rev == null) {
74
throw new RuntimeException("LivenessAnalysis requires ReversePtrs to have been computed");
75
}
76
77
// Currently the reverse pointer analysis returns non-null results
78
// only for live objects
79
if (rev.get(target) == null) {
80
// Object is dead
81
return null;
82
}
83
84
// HashSet of Oops acting as a bit mask indicating which ones have
85
// already been traversed
86
Set<Oop> visitedOops = new HashSet<>();
87
88
// IdentityHashMap of LivenessElements acting as a bit mask
89
// indicating which roots have already been traversed
90
Map<LivenessPathElement, LivenessPathElement> visitedRoots =
91
new IdentityHashMap<>();
92
93
visitedOops.add(target);
94
95
// Construct the initial LivenessPath
96
LivenessPathList list = new LivenessPathList();
97
{
98
LivenessPath path = new LivenessPath();
99
path.push(new LivenessPathElement(target, null));
100
list.add(path);
101
}
102
103
// Iterate until done
104
while (true) {
105
// See if there are any incomplete paths left
106
LivenessPath path = null;
107
108
for (int i = list.size() - 1; i >= 0; i--) {
109
LivenessPath tmp = list.get(i);
110
if (!tmp.isComplete()) {
111
path = tmp;
112
break;
113
}
114
}
115
116
// If no incomplete paths left, return
117
if (path == null) {
118
return list;
119
}
120
121
// Try to complete this path
122
123
// Remove the path from the list of reported ones in
124
// anticipation of completing it
125
list.remove(path);
126
127
try {
128
// Fetch next set of reverse pointers for the last object on
129
// the list
130
ArrayList/*<LivenessPathElement>*/ nextPtrs =
131
rev.get(path.peek().getObj());
132
133
// Depending on exactly what the reverse pointers analysis
134
// yields, these results may be null, although currently they
135
// won't be
136
if (nextPtrs != null) {
137
// Iterate these
138
for (Iterator iter = nextPtrs.iterator(); iter.hasNext(); ) {
139
LivenessPathElement nextElement = (LivenessPathElement) iter.next();
140
// See whether we've visited this element yet
141
if ((nextElement.isRoot() && (visitedRoots.get(nextElement) == null)) ||
142
(!nextElement.isRoot() && !visitedOops.contains(nextElement.getObj()))) {
143
// Show we've visited this one
144
if (nextElement.isRoot()) {
145
visitedRoots.put(nextElement, nextElement);
146
} else {
147
visitedOops.add(nextElement.getObj());
148
}
149
150
// Create a new LivenessPath for each one
151
LivenessPath nextPath = path.copy();
152
nextPath.push(nextElement);
153
154
// Regardless of whether we found a root, put the
155
// original path back on the list because we're going to
156
// do depth-first searching rather than breadth-first
157
list.add(path);
158
list.add(nextPath);
159
160
// See whether this path is complete (i.e., it
161
// terminates in a root)
162
if (trimPathsThroughPopularObjects && nextElement.isRoot()) {
163
// Go back through the path list and remove all
164
// incomplete paths ending in any of the intermediate
165
// (non-root and non-terminal) nodes in this path.
166
// This has the effect of removing multiple paths
167
// going through popular objects.
168
for (int i = 1; i < nextPath.size() - 1; i++) {
169
LivenessPathElement el = nextPath.get(i);
170
int j = 0;
171
while (j < list.size()) {
172
LivenessPath curPath = list.get(j);
173
// We can use an object identity since these
174
// intermediate nodes are canonicalized via the
175
// ReversePtrsAnalysis
176
if (curPath.peek() == el) {
177
list.remove(curPath);
178
} else {
179
j++;
180
}
181
}
182
}
183
}
184
185
// Do depth-first searching, not breadth-first
186
break;
187
}
188
}
189
}
190
} catch (Exception e) {
191
System.err.println("LivenessAnalysis: WARNING: " + e +
192
" during traversal");
193
}
194
}
195
}
196
}
197
198