1 /*
2  * Copyright (c) 2013, 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 org.graalvm.compiler.virtual.phases.ea;
26 
27 import static org.graalvm.compiler.core.common.GraalOptions.TraceEscapeAnalysis;
28 
29 import java.util.List;
30 
31 import jdk.internal.vm.compiler.collections.EconomicMap;
32 import jdk.internal.vm.compiler.collections.Equivalence;
33 import org.graalvm.compiler.debug.DebugContext;
34 import org.graalvm.compiler.debug.GraalError;
35 import org.graalvm.compiler.debug.TTY;
36 import org.graalvm.compiler.graph.Node;
37 import org.graalvm.compiler.graph.NodeFlood;
38 import org.graalvm.compiler.nodes.AbstractEndNode;
39 import org.graalvm.compiler.nodes.FixedNode;
40 import org.graalvm.compiler.nodes.StructuredGraph;
41 import org.graalvm.compiler.options.OptionValues;
42 
43 import jdk.vm.ci.meta.ResolvedJavaMethod;
44 
45 public final class VirtualUtil {
46 
VirtualUtil()47     private VirtualUtil() {
48         GraalError.shouldNotReachHere();
49     }
50 
assertNonReachable(StructuredGraph graph, List<Node> obsoleteNodes)51     public static boolean assertNonReachable(StructuredGraph graph, List<Node> obsoleteNodes) {
52         // Helper code that determines the paths that keep obsolete nodes alive.
53         // Nodes with support for GVN can be kept alive by GVN and are therefore not part of the
54         // assertion.
55 
56         DebugContext debug = graph.getDebug();
57         NodeFlood flood = graph.createNodeFlood();
58         EconomicMap<Node, Node> path = EconomicMap.create(Equivalence.IDENTITY);
59         flood.add(graph.start());
60         for (Node current : flood) {
61             if (current instanceof AbstractEndNode) {
62                 AbstractEndNode end = (AbstractEndNode) current;
63                 flood.add(end.merge());
64                 if (!path.containsKey(end.merge())) {
65                     path.put(end.merge(), end);
66                 }
67             } else {
68                 for (Node successor : current.successors()) {
69                     flood.add(successor);
70                     if (!path.containsKey(successor)) {
71                         path.put(successor, current);
72                     }
73                 }
74             }
75         }
76 
77         for (Node node : obsoleteNodes) {
78             if (node instanceof FixedNode && !node.isDeleted()) {
79                 assert !flood.isMarked(node) : node;
80             }
81         }
82 
83         for (Node node : graph.getNodes()) {
84             if (flood.isMarked(node)) {
85                 for (Node input : node.inputs()) {
86                     flood.add(input);
87                     if (!path.containsKey(input)) {
88                         path.put(input, node);
89                     }
90                 }
91             }
92         }
93         for (Node current : flood) {
94             for (Node input : current.inputs()) {
95                 flood.add(input);
96                 if (!path.containsKey(input)) {
97                     path.put(input, current);
98                 }
99             }
100         }
101         boolean success = true;
102         for (Node node : obsoleteNodes) {
103             if (!node.isDeleted() && flood.isMarked(node) && !node.getNodeClass().valueNumberable()) {
104                 TTY.println("offending node path:");
105                 Node current = node;
106                 TTY.print(current.toString());
107                 while (true) {
108                     current = path.get(current);
109                     if (current != null) {
110                         TTY.print(" -> " + current.toString());
111                         if (current instanceof FixedNode && !obsoleteNodes.contains(current)) {
112                             break;
113                         }
114                     }
115                 }
116                 success = false;
117             }
118         }
119         if (!success) {
120             TTY.println();
121             debug.forceDump(graph, "assertNonReachable");
122         }
123         return success;
124     }
125 
trace(OptionValues options, DebugContext debug, String msg)126     public static void trace(OptionValues options, DebugContext debug, String msg) {
127         if (debug.areScopesEnabled() && TraceEscapeAnalysis.getValue(options) && debug.isLogEnabled()) {
128             debug.log(msg);
129         }
130     }
131 
trace(OptionValues options, DebugContext debug, String format, Object obj)132     public static void trace(OptionValues options, DebugContext debug, String format, Object obj) {
133         if (debug.areScopesEnabled() && TraceEscapeAnalysis.getValue(options) && debug.isLogEnabled()) {
134             debug.logv(format, obj);
135         }
136     }
137 
trace(OptionValues options, DebugContext debug, String format, Object obj, Object obj2)138     public static void trace(OptionValues options, DebugContext debug, String format, Object obj, Object obj2) {
139         if (debug.areScopesEnabled() && TraceEscapeAnalysis.getValue(options) && debug.isLogEnabled()) {
140             debug.logv(format, obj, obj2);
141         }
142     }
143 
trace(OptionValues options, DebugContext debug, String format, Object obj, Object obj2, Object obj3)144     public static void trace(OptionValues options, DebugContext debug, String format, Object obj, Object obj2, Object obj3) {
145         if (debug.areScopesEnabled() && TraceEscapeAnalysis.getValue(options) && debug.isLogEnabled()) {
146             debug.logv(format, obj, obj2, obj3);
147         }
148     }
149 
trace(OptionValues options, DebugContext debug, String format, Object obj, Object obj2, Object obj3, Object obj4)150     public static void trace(OptionValues options, DebugContext debug, String format, Object obj, Object obj2, Object obj3, Object obj4) {
151         if (debug.areScopesEnabled() && TraceEscapeAnalysis.getValue(options) && debug.isLogEnabled()) {
152             debug.logv(format, obj, obj2, obj3, obj4);
153         }
154     }
155 
matches(StructuredGraph graph, String filter)156     public static boolean matches(StructuredGraph graph, String filter) {
157         if (filter != null) {
158             return matchesHelper(graph, filter);
159         }
160         return true;
161     }
162 
matchesHelper(StructuredGraph graph, String filter)163     private static boolean matchesHelper(StructuredGraph graph, String filter) {
164         if (filter.startsWith("~")) {
165             ResolvedJavaMethod method = graph.method();
166             return method == null || !method.format("%H.%n").contains(filter.substring(1));
167         } else {
168             ResolvedJavaMethod method = graph.method();
169             return method != null && method.format("%H.%n").contains(filter);
170         }
171     }
172 }
173