Skip to content

Commit c73cd5a

Browse files
committed
Extend PrintAnalysisCallTree option
PrintAnalysisCallTree option accept a list of methods to print the call tree of them, or an empty string to print all call trees.
1 parent 42c83e1 commit c73cd5a

File tree

4 files changed

+51
-18
lines changed

4 files changed

+51
-18
lines changed

docs/reference-manual/native-image/Reports.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@ the image heap, respectively.
1717
The call tree is a a breadth-first tree reduction of the call graph as seen by the points-to analysis.
1818
The points-to analysis eliminates calls to methods that it determines cannot be reachable at runtime, based on the analysed receiver types.
1919
It also completely eliminates invocations in unreachable code blocks, e.g., blocks guarded by a type check that always fails.
20-
The call tree report is enabled using the `-H:+PrintAnalysisCallTree` option.
20+
The call tree report is enabled using the `-H:PrintAnalysisCallTree=<comma-separated method list>` option.
21+
Only the specified methods' call tree will be printed out, while `-H:PrintAnalysisCallTree=` prints call tree for all entry methods.
22+
The method should be specified with its full qualified name, such as `java.lang.String.hashCode()` for normal method
23+
and `java.lang.String.<clinit>()` for class static initialization method.
2124
It produces a file with the structure:
2225

2326
```

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/AnalysisReportsOptions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class AnalysisReportsOptions {
3636
public static final OptionKey<String> AnalysisStatisticsFile = new OptionKey<>(null);
3737

3838
@Option(help = "Print analysis call tree, a breadth-first tree reduction of the call graph.")//
39-
public static final OptionKey<Boolean> PrintAnalysisCallTree = new OptionKey<>(false);
39+
public static final OptionKey<String> PrintAnalysisCallTree = new OptionKey<>(null);
4040

4141
@Option(help = "Print image object hierarchy.")//
4242
public static final OptionKey<Boolean> PrintImageObjectTree = new OptionKey<>(false);

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/reports/CallTreePrinter.java

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,17 @@
5252
import jdk.vm.ci.meta.ResolvedJavaMethod;
5353

5454
public final class CallTreePrinter {
55+
private static Set<String> printMethods = new HashSet<>();
56+
private static Set<Integer> printedID = new HashSet<>();
57+
private static boolean printAll = false;
5558

56-
public static void print(BigBang bigbang, String reportsPath, String reportName) {
59+
public static void print(BigBang bigbang, String printCallTreeMethods, String reportsPath, String reportName) {
5760
CallTreePrinter printer = new CallTreePrinter(bigbang);
5861
printer.buildCallTree();
59-
62+
Arrays.stream(printCallTreeMethods.split(",")).forEach(printMethods::add);
63+
if (printCallTreeMethods.length() == 0) {
64+
printAll = true;
65+
}
6066
ReportUtils.report("call tree", reportsPath, "call_tree_" + reportName, "txt",
6167
printer::printMethods);
6268
ReportUtils.report("list of used methods", reportsPath, "used_methods_" + reportName, "txt",
@@ -221,40 +227,64 @@ private void printMethods(PrintWriter out) {
221227
while (iterator.hasNext()) {
222228
MethodNode node = iterator.next();
223229
boolean lastEntryPoint = !iterator.hasNext();
224-
out.format("%s%s %s %n", lastEntryPoint ? LAST_CHILD : CHILD, "entry", node.format());
225-
printCallTreeNode(out, lastEntryPoint ? EMPTY_INDENT : CONNECTING_INDENT, node);
230+
printCallTreeNode(out, lastEntryPoint ? EMPTY_INDENT : CONNECTING_INDENT, node, false, lastEntryPoint ? LAST_CHILD : CHILD);
226231
}
227232
out.println();
228233
}
229234

230-
private static void printCallTreeNode(PrintWriter out, String prefix, MethodNode node) {
235+
private static void printCallTreeNode(PrintWriter out, String prefix, MethodNode node, boolean shouldPrint, String beginning) {
236+
boolean print = shouldPrint;
237+
if (!shouldPrint) {
238+
String methodName = node.method.getQualifiedName();
239+
if (printAll || printMethods.remove(methodName)) {
240+
print = true;
241+
out.format("%s%s %s %n", beginning, "entry", node.format());
242+
}
243+
}
231244

232245
for (int invokeIdx = 0; invokeIdx < node.invokes.size(); invokeIdx++) {
233246
InvokeNode invoke = node.invokes.get(invokeIdx);
234247
boolean lastInvoke = invokeIdx == node.invokes.size() - 1;
235248
if (invoke.isDirectInvoke) {
236249
if (invoke.callees.size() > 0) {
237250
Node calleeNode = invoke.callees.get(0);
238-
out.format("%s%s%s %s @bci=%s %n", prefix, (lastInvoke ? LAST_CHILD : CHILD),
239-
"directly calls", calleeNode.format(), invoke.formatLocation());
240-
if (calleeNode instanceof MethodNode) {
241-
printCallTreeNode(out, prefix + (lastInvoke ? EMPTY_INDENT : CONNECTING_INDENT), (MethodNode) calleeNode);
251+
boolean isNative = invoke.targetMethod.wrapped.getClass().getName().equals("com.oracle.svm.jni.hosted.JNINativeCallWrapperMethod");
252+
if (print) {
253+
calleeNode = extendNodeReference(calleeNode);
254+
out.format("%s%s%s %s @bci=%s %s %n", prefix, (lastInvoke ? LAST_CHILD : CHILD),
255+
"directly calls", calleeNode.format(), invoke.formatLocation(), isNative ? "(Native Method)" : "");
256+
}
257+
if (!isNative && calleeNode instanceof MethodNode) {
258+
printCallTreeNode(out, prefix + (lastInvoke ? EMPTY_INDENT : CONNECTING_INDENT), (MethodNode) calleeNode, print, beginning);
242259
}
243260
}
244261
} else {
245-
out.format("%s%s%s %s @bci=%s%n", prefix, (lastInvoke ? LAST_CHILD : CHILD),
246-
"virtually calls", invoke.formatTarget(), invoke.formatLocation());
262+
if (print) {
263+
out.format("%s%s%s %s @bci=%s%n", prefix, (lastInvoke ? LAST_CHILD : CHILD),
264+
"virtually calls", invoke.formatTarget(), invoke.formatLocation());
265+
}
247266
for (int calleeIdx = 0; calleeIdx < invoke.callees.size(); calleeIdx++) {
248267
boolean lastCallee = calleeIdx == invoke.callees.size() - 1;
249268
Node calleeNode = invoke.callees.get(calleeIdx);
250-
out.format("%s%s%s %s %n", prefix + (lastInvoke ? EMPTY_INDENT : CONNECTING_INDENT), (lastCallee ? LAST_CHILD : CHILD),
251-
"is overridden by", calleeNode.format());
269+
if (print) {
270+
calleeNode = extendNodeReference(calleeNode);
271+
out.format("%s%s%s %s %n", prefix + (lastInvoke ? EMPTY_INDENT : CONNECTING_INDENT), (lastCallee ? LAST_CHILD : CHILD),
272+
"is overridden by", calleeNode.format());
273+
}
252274
if (calleeNode instanceof MethodNode) {
253-
printCallTreeNode(out, prefix + (lastInvoke ? EMPTY_INDENT : CONNECTING_INDENT) + (lastCallee ? EMPTY_INDENT : CONNECTING_INDENT), (MethodNode) calleeNode);
275+
printCallTreeNode(out, prefix + (lastInvoke ? EMPTY_INDENT : CONNECTING_INDENT) + (lastCallee ? EMPTY_INDENT : CONNECTING_INDENT), (MethodNode) calleeNode, print, beginning);
254276
}
255277
}
256278
}
257279
}
280+
281+
}
282+
283+
private static Node extendNodeReference(Node calleeNode) {
284+
if (calleeNode instanceof MethodNodeReference && printedID.add(((MethodNodeReference) calleeNode).methodNode.id)) {
285+
calleeNode = ((MethodNodeReference) calleeNode).methodNode;
286+
}
287+
return calleeNode;
258288
}
259289

260290
private void printUsedMethods(PrintWriter out) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -776,8 +776,8 @@ private boolean runPointsToAnalysis(String imageName, OptionValues options, Debu
776776
StatisticsPrinter.print(bigbang, SubstrateOptions.reportsPath(), ReportUtils.extractImageName(imageName));
777777
}
778778

779-
if (AnalysisReportsOptions.PrintAnalysisCallTree.getValue(options)) {
780-
CallTreePrinter.print(bigbang, SubstrateOptions.reportsPath(), ReportUtils.extractImageName(imageName));
779+
if (AnalysisReportsOptions.PrintAnalysisCallTree.hasBeenSet(options)) {
780+
CallTreePrinter.print(bigbang, AnalysisReportsOptions.PrintAnalysisCallTree.getValue(options), SubstrateOptions.reportsPath(), ReportUtils.extractImageName(imageName));
781781
}
782782

783783
if (AnalysisReportsOptions.PrintImageObjectTree.getValue(options)) {

0 commit comments

Comments
 (0)