|
52 | 52 | import jdk.vm.ci.meta.ResolvedJavaMethod;
|
53 | 53 |
|
54 | 54 | 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; |
55 | 58 |
|
56 |
| - public static void print(BigBang bigbang, String reportsPath, String reportName) { |
| 59 | + public static void print(BigBang bigbang, String printCallTreeMethods, String reportsPath, String reportName) { |
57 | 60 | CallTreePrinter printer = new CallTreePrinter(bigbang);
|
58 | 61 | printer.buildCallTree();
|
59 |
| - |
| 62 | + Arrays.stream(printCallTreeMethods.split(",")).forEach(printMethods::add); |
| 63 | + if (printCallTreeMethods.length() == 0) { |
| 64 | + printAll = true; |
| 65 | + } |
60 | 66 | ReportUtils.report("call tree", reportsPath, "call_tree_" + reportName, "txt",
|
61 | 67 | printer::printMethods);
|
62 | 68 | ReportUtils.report("list of used methods", reportsPath, "used_methods_" + reportName, "txt",
|
@@ -221,40 +227,64 @@ private void printMethods(PrintWriter out) {
|
221 | 227 | while (iterator.hasNext()) {
|
222 | 228 | MethodNode node = iterator.next();
|
223 | 229 | 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); |
226 | 231 | }
|
227 | 232 | out.println();
|
228 | 233 | }
|
229 | 234 |
|
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 | + } |
231 | 244 |
|
232 | 245 | for (int invokeIdx = 0; invokeIdx < node.invokes.size(); invokeIdx++) {
|
233 | 246 | InvokeNode invoke = node.invokes.get(invokeIdx);
|
234 | 247 | boolean lastInvoke = invokeIdx == node.invokes.size() - 1;
|
235 | 248 | if (invoke.isDirectInvoke) {
|
236 | 249 | if (invoke.callees.size() > 0) {
|
237 | 250 | 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); |
242 | 259 | }
|
243 | 260 | }
|
244 | 261 | } 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 | + } |
247 | 266 | for (int calleeIdx = 0; calleeIdx < invoke.callees.size(); calleeIdx++) {
|
248 | 267 | boolean lastCallee = calleeIdx == invoke.callees.size() - 1;
|
249 | 268 | 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 | + } |
252 | 274 | 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); |
254 | 276 | }
|
255 | 277 | }
|
256 | 278 | }
|
257 | 279 | }
|
| 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; |
258 | 288 | }
|
259 | 289 |
|
260 | 290 | private void printUsedMethods(PrintWriter out) {
|
|
0 commit comments