--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java 2016-12-09 00:56:38.248220282 -0800 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.printer; + +import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; +import org.graalvm.compiler.core.common.util.ModuleAPI; +import org.graalvm.compiler.graph.Graph; +import org.graalvm.compiler.nodes.ConstantNode; + +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaUtil; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.runtime.JVMCI; +import jdk.vm.ci.services.Services; + +interface GraphPrinter extends Closeable { + + /** + * Starts a new group of graphs with the given name, short name and method byte code index (BCI) + * as properties. + */ + void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci, Map properties) throws IOException; + + /** + * Prints an entire {@link Graph} with the specified title, optionally using short names for + * nodes. + */ + void print(Graph graph, String title, Map properties) throws IOException; + + SnippetReflectionProvider getSnippetReflectionProvider(); + + /** + * Ends the current group. + */ + void endGroup() throws IOException; + + @Override + void close(); + + /** + * A JVMCI package {@linkplain Services#exportJVMCITo(Class) dynamically exported} to trusted + * modules. + */ + String JVMCI_RUNTIME_PACKAGE = JVMCI.class.getPackage().getName(); + + /** + * {@code jdk.vm.ci} module. + */ + Object JVMCI_MODULE = JAVA_SPECIFICATION_VERSION < 9 ? null : ModuleAPI.getModule.invoke(Services.class); + + /** + * Classes whose {@link #toString()} method does not run any untrusted code. + */ + Set> TRUSTED_CLASSES = new HashSet<>(Arrays.asList( + String.class, + Class.class, + Boolean.class, + Byte.class, + Character.class, + Short.class, + Integer.class, + Float.class, + Long.class, + Double.class)); + int MAX_CONSTANT_TO_STRING_LENGTH = 50; + + /** + * Determines if invoking {@link Object#toString()} on an instance of {@code c} will only run + * trusted code. + */ + static boolean isToStringTrusted(Class c) { + if (TRUSTED_CLASSES.contains(c)) { + return true; + } + if (JAVA_SPECIFICATION_VERSION < 9) { + if (c.getClassLoader() == Services.class.getClassLoader()) { + // Loaded by the JVMCI class loader + return true; + } + } else { + Object module = ModuleAPI.getModule.invoke(c); + if (JVMCI_MODULE == module || (Boolean) ModuleAPI.isExportedTo.invoke(JVMCI_MODULE, JVMCI_RUNTIME_PACKAGE, module)) { + // Can access non-statically-exported package in JVMCI + return true; + } + } + return false; + } + + /** + * Sets or updates the {@code "rawvalue"} and {@code "toString"} properties in {@code props} for + * {@code cn} if it's a boxed Object value and {@code snippetReflection} can access the raw + * value. + */ + default void updateStringPropertiesForConstant(Map props, ConstantNode cn) { + SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider(); + if (snippetReflection != null && cn.getValue() instanceof JavaConstant) { + JavaConstant constant = (JavaConstant) cn.getValue(); + if (constant.getJavaKind() == JavaKind.Object) { + Object obj = snippetReflection.asObject(Object.class, constant); + if (obj != null) { + String toString = GraphPrinter.constantToString(obj); + String rawvalue = GraphPrinter.truncate(toString); + // Overwrite the value inserted by + // ConstantNode.getDebugProperties() + props.put("rawvalue", rawvalue); + if (!rawvalue.equals(toString)) { + props.put("toString", toString); + } + } + } + } + } + + static String truncate(String s) { + if (s.length() > MAX_CONSTANT_TO_STRING_LENGTH) { + return s.substring(0, MAX_CONSTANT_TO_STRING_LENGTH - 3) + "..."; + } + return s; + } + + static String constantToString(Object value) { + Class c = value.getClass(); + if (c.isArray()) { + return constantArrayToString(value); + } else if (value instanceof Enum) { + return ((Enum) value).name(); + } else if (isToStringTrusted(c)) { + return value.toString(); + } + return MetaUtil.getSimpleName(c, true) + "@" + System.identityHashCode(value); + + } + + static String constantArrayToString(Object array) { + Class componentType = array.getClass().getComponentType(); + assert componentType != null; + int arrayLength = Array.getLength(array); + StringBuilder buf = new StringBuilder(MetaUtil.getSimpleName(componentType, true)).append('[').append(arrayLength).append("]{"); + int length = arrayLength; + boolean primitive = componentType.isPrimitive(); + for (int i = 0; i < length; i++) { + if (primitive) { + buf.append(Array.get(array, i)); + } else { + Object o = ((Object[]) array)[i]; + buf.append(o == null ? "null" : constantToString(o)); + } + if (i != length - 1) { + buf.append(", "); + } + } + return buf.append('}').toString(); + } +}