GraphPrinter.java revision 13133:9ee4febb41aa
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 java.io.Closeable; 26import java.io.IOException; 27import java.lang.reflect.Array; 28import java.util.Arrays; 29import java.util.List; 30import java.util.Map; 31 32import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 33import org.graalvm.compiler.graph.Graph; 34import org.graalvm.compiler.nodes.ConstantNode; 35import org.graalvm.compiler.serviceprovider.JDK9Method; 36 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, Map<Object, Object> properties, int id, String format, Object... args) 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 dynamically exported to trusted modules. 72 */ 73 String JVMCI_RUNTIME_PACKAGE = JVMCI.class.getPackage().getName(); 74 75 /** 76 * {@code jdk.vm.ci} module. 77 */ 78 Object JVMCI_MODULE = JDK9Method.JAVA_SPECIFICATION_VERSION < 9 ? null : JDK9Method.getModule.invoke(Services.class); 79 80 /** 81 * Classes whose {@link #toString()} method does not run any untrusted code. 82 */ 83 List<Class<?>> TRUSTED_CLASSES = Arrays.asList( 84 String.class, 85 Class.class, 86 Boolean.class, 87 Byte.class, 88 Character.class, 89 Short.class, 90 Integer.class, 91 Float.class, 92 Long.class, 93 Double.class); 94 int MAX_CONSTANT_TO_STRING_LENGTH = 50; 95 96 /** 97 * Determines if invoking {@link Object#toString()} on an instance of {@code c} will only run 98 * trusted code. 99 */ 100 static boolean isToStringTrusted(Class<?> c) { 101 if (TRUSTED_CLASSES.contains(c)) { 102 return true; 103 } 104 if (JDK9Method.JAVA_SPECIFICATION_VERSION < 9) { 105 if (c.getClassLoader() == Services.class.getClassLoader()) { 106 // Loaded by the JVMCI class loader 107 return true; 108 } 109 } else { 110 Object module = JDK9Method.getModule.invoke(c); 111 if (JVMCI_MODULE == module || (Boolean) JDK9Method.isOpenTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) { 112 // Can access non-statically-exported package in JVMCI 113 return true; 114 } 115 } 116 return false; 117 } 118 119 /** 120 * Sets or updates the {@code "rawvalue"} and {@code "toString"} properties in {@code props} for 121 * {@code cn} if it's a boxed Object value and {@code snippetReflection} can access the raw 122 * value. 123 */ 124 default void updateStringPropertiesForConstant(Map<Object, Object> props, ConstantNode cn) { 125 SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider(); 126 if (snippetReflection != null && cn.getValue() instanceof JavaConstant) { 127 JavaConstant constant = (JavaConstant) cn.getValue(); 128 if (constant.getJavaKind() == JavaKind.Object) { 129 Object obj = snippetReflection.asObject(Object.class, constant); 130 if (obj != null) { 131 String toString = GraphPrinter.constantToString(obj); 132 String rawvalue = GraphPrinter.truncate(toString); 133 // Overwrite the value inserted by 134 // ConstantNode.getDebugProperties() 135 props.put("rawvalue", rawvalue); 136 if (!rawvalue.equals(toString)) { 137 props.put("toString", toString); 138 } 139 } 140 } 141 } 142 } 143 144 static String truncate(String s) { 145 if (s.length() > MAX_CONSTANT_TO_STRING_LENGTH) { 146 return s.substring(0, MAX_CONSTANT_TO_STRING_LENGTH - 3) + "..."; 147 } 148 return s; 149 } 150 151 static String constantToString(Object value) { 152 Class<?> c = value.getClass(); 153 if (c.isArray()) { 154 return constantArrayToString(value); 155 } else if (value instanceof Enum) { 156 return ((Enum<?>) value).name(); 157 } else if (isToStringTrusted(c)) { 158 return value.toString(); 159 } 160 return MetaUtil.getSimpleName(c, true) + "@" + Integer.toHexString(System.identityHashCode(value)); 161 162 } 163 164 static String constantArrayToString(Object array) { 165 Class<?> componentType = array.getClass().getComponentType(); 166 assert componentType != null; 167 int arrayLength = Array.getLength(array); 168 StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); 169 int length = arrayLength; 170 boolean primitive = componentType.isPrimitive(); 171 for (int i = 0; i < length; i++) { 172 if (primitive) { 173 buf.append(Array.get(array, i)); 174 } else { 175 Object o = ((Object[]) array)[i]; 176 buf.append(o == null ? "null" : constantToString(o)); 177 } 178 if (i != length - 1) { 179 buf.append(", "); 180 } 181 } 182 return buf.append('}').toString(); 183 } 184} 185