GraphPrinter.java revision 12968:4d8a004e5c6d
1/*
2 * Copyright (c) 2012, 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 */
23package org.graalvm.compiler.printer;
24
25import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
26
27import java.io.Closeable;
28import java.io.IOException;
29import java.lang.reflect.Array;
30import java.util.Arrays;
31import java.util.List;
32import java.util.Map;
33import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
34import org.graalvm.compiler.core.common.util.ModuleAPI;
35import org.graalvm.compiler.graph.Graph;
36import org.graalvm.compiler.nodes.ConstantNode;
37import jdk.vm.ci.meta.JavaConstant;
38import jdk.vm.ci.meta.JavaKind;
39import jdk.vm.ci.meta.MetaUtil;
40import jdk.vm.ci.meta.ResolvedJavaMethod;
41import jdk.vm.ci.runtime.JVMCI;
42import jdk.vm.ci.services.Services;
43
44interface GraphPrinter extends Closeable {
45
46    /**
47     * Starts a new group of graphs with the given name, short name and method byte code index (BCI)
48     * as properties.
49     */
50    void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException;
51
52    /**
53     * Prints an entire {@link Graph} with the specified title, optionally using short names for
54     * nodes.
55     */
56    void print(Graph graph, String title, Map<Object, Object> properties) throws IOException;
57
58    SnippetReflectionProvider getSnippetReflectionProvider();
59
60    void setSnippetReflectionProvider(SnippetReflectionProvider snippetReflection);
61
62    /**
63     * Ends the current group.
64     */
65    void endGroup() throws IOException;
66
67    @Override
68    void close();
69
70    /**
71     * A JVMCI package {@linkplain Services#exportJVMCITo(Class) dynamically exported} to trusted
72     * modules.
73     */
74    String JVMCI_RUNTIME_PACKAGE = JVMCI.class.getPackage().getName();
75
76    /**
77     * {@code jdk.vm.ci} module.
78     */
79    Object JVMCI_MODULE = JAVA_SPECIFICATION_VERSION < 9 ? null : ModuleAPI.getModule.invoke(Services.class);
80
81    /**
82     * Classes whose {@link #toString()} method does not run any untrusted code.
83     */
84    List<Class<?>> TRUSTED_CLASSES = Arrays.asList(
85                    String.class,
86                    Class.class,
87                    Boolean.class,
88                    Byte.class,
89                    Character.class,
90                    Short.class,
91                    Integer.class,
92                    Float.class,
93                    Long.class,
94                    Double.class);
95    int MAX_CONSTANT_TO_STRING_LENGTH = 50;
96
97    /**
98     * Determines if invoking {@link Object#toString()} on an instance of {@code c} will only run
99     * trusted code.
100     */
101    static boolean isToStringTrusted(Class<?> c) {
102        if (TRUSTED_CLASSES.contains(c)) {
103            return true;
104        }
105        if (JAVA_SPECIFICATION_VERSION < 9) {
106            if (c.getClassLoader() == Services.class.getClassLoader()) {
107                // Loaded by the JVMCI class loader
108                return true;
109            }
110        } else {
111            Object module = ModuleAPI.getModule.invoke(c);
112            if (JVMCI_MODULE == module || (Boolean) ModuleAPI.isExportedTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) {
113                // Can access non-statically-exported package in JVMCI
114                return true;
115            }
116        }
117        return false;
118    }
119
120    /**
121     * Sets or updates the {@code "rawvalue"} and {@code "toString"} properties in {@code props} for
122     * {@code cn} if it's a boxed Object value and {@code snippetReflection} can access the raw
123     * value.
124     */
125    default void updateStringPropertiesForConstant(Map<Object, Object> props, ConstantNode cn) {
126        SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider();
127        if (snippetReflection != null && cn.getValue() instanceof JavaConstant) {
128            JavaConstant constant = (JavaConstant) cn.getValue();
129            if (constant.getJavaKind() == JavaKind.Object) {
130                Object obj = snippetReflection.asObject(Object.class, constant);
131                if (obj != null) {
132                    String toString = GraphPrinter.constantToString(obj);
133                    String rawvalue = GraphPrinter.truncate(toString);
134                    // Overwrite the value inserted by
135                    // ConstantNode.getDebugProperties()
136                    props.put("rawvalue", rawvalue);
137                    if (!rawvalue.equals(toString)) {
138                        props.put("toString", toString);
139                    }
140                }
141            }
142        }
143    }
144
145    static String truncate(String s) {
146        if (s.length() > MAX_CONSTANT_TO_STRING_LENGTH) {
147            return s.substring(0, MAX_CONSTANT_TO_STRING_LENGTH - 3) + "...";
148        }
149        return s;
150    }
151
152    static String constantToString(Object value) {
153        Class<?> c = value.getClass();
154        if (c.isArray()) {
155            return constantArrayToString(value);
156        } else if (value instanceof Enum) {
157            return ((Enum<?>) value).name();
158        } else if (isToStringTrusted(c)) {
159            return value.toString();
160        }
161        return MetaUtil.getSimpleName(c, true) + "@" + System.identityHashCode(value);
162
163    }
164
165    static String constantArrayToString(Object array) {
166        Class<?> componentType = array.getClass().getComponentType();
167        assert componentType != null;
168        int arrayLength = Array.getLength(array);
169        StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{");
170        int length = arrayLength;
171        boolean primitive = componentType.isPrimitive();
172        for (int i = 0; i < length; i++) {
173            if (primitive) {
174                buf.append(Array.get(array, i));
175            } else {
176                Object o = ((Object[]) array)[i];
177                buf.append(o == null ? "null" : constantToString(o));
178            }
179            if (i != length - 1) {
180                buf.append(", ");
181            }
182        }
183        return buf.append('}').toString();
184    }
185}
186