1 /* 2 * Copyright (c) 2011, 2017, 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.graphio; 26 27 import java.io.Closeable; 28 import java.io.IOException; 29 import java.net.URI; 30 import java.net.URISyntaxException; 31 import java.nio.channels.WritableByteChannel; 32 import java.util.Collections; 33 import java.util.Map; 34 35 /** 36 * Instance of output to dump informations about a compiler compilations. 37 * 38 * @param <G> the type of graph this instance handles 39 * @param <M> the type of methods this instance handles 40 */ 41 public final class GraphOutput<G, M> implements Closeable { 42 private final GraphProtocol<G, ?, ?, ?, ?, M, ?, ?, ?, ?> printer; 43 GraphOutput(GraphProtocol<G, ?, ?, ?, ?, M, ?, ?, ?, ?> p)44 private GraphOutput(GraphProtocol<G, ?, ?, ?, ?, M, ?, ?, ?, ?> p) { 45 this.printer = p; 46 } 47 48 /** 49 * Creates new builder to configure a future instance of {@link GraphOutput}. 50 * 51 * @param <G> the type of the graph 52 * @param <N> the type of the nodes 53 * @param <C> the type of the node classes 54 * @param <P> the type of the ports 55 * 56 * @param structure description of the structure of the graph 57 * @return the builder to configure 58 */ newBuilder(GraphStructure<G, N, C, P> structure)59 public static <G, N, C, P> Builder<G, N, ?> newBuilder(GraphStructure<G, N, C, P> structure) { 60 return new Builder<>(structure); 61 } 62 63 /** 64 * Begins a compilation group. 65 * 66 * @param forGraph 67 * @param name 68 * @param shortName 69 * @param method 70 * @param bci 71 * @param properties 72 * @throws IOException 73 */ beginGroup(G forGraph, String name, String shortName, M method, int bci, Map<? extends Object, ? extends Object> properties)74 public void beginGroup(G forGraph, String name, String shortName, M method, int bci, Map<? extends Object, ? extends Object> properties) throws IOException { 75 printer.beginGroup(forGraph, name, shortName, method, bci, properties); 76 } 77 78 /** 79 * Prints a single graph. 80 * 81 * @param graph 82 * @param properties 83 * @param id 84 * @param format 85 * @param args 86 * @throws IOException 87 */ print(G graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args)88 public void print(G graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException { 89 printer.print(graph, properties, id, format, args); 90 } 91 92 /** 93 * Ends compilation group. 94 * 95 * @throws IOException 96 */ endGroup()97 public void endGroup() throws IOException { 98 printer.endGroup(); 99 } 100 101 /** 102 * Closes the output. Closes allocated resources and associated output channel. 103 */ 104 @Override close()105 public void close() { 106 printer.close(); 107 } 108 109 /** 110 * Builder to configure and create an instance of {@link GraphOutput}. 111 * 112 * @param <G> the type of the (root element of) graph 113 * @param <N> the type of the nodes 114 * @param <M> the type of the methods 115 */ 116 public static final class Builder<G, N, M> { 117 private final GraphStructure<G, N, ?, ?> structure; 118 private ElementsAndLocations<M, ?, ?> elementsAndLocations; 119 120 private GraphTypes types = DefaultGraphTypes.DEFAULT; 121 private GraphBlocks<G, ?, N> blocks = DefaultGraphBlocks.empty(); 122 private int major = 4; 123 private int minor = 0; 124 Builder(GraphStructure<G, N, ?, ?> structure)125 Builder(GraphStructure<G, N, ?, ?> structure) { 126 this.structure = structure; 127 } 128 129 /** 130 * Chooses which version of the protocol to use. The default version is <code>4.0</code> 131 * (when the {@link GraphOutput} & co. classes were introduced). The default can be changed 132 * to other known versions manually by calling this method. 133 * 134 * @param majorVersion by default 4, newer version may be known 135 * @param minorVersion usually 0 136 * @return this builder 137 * @since 0.28 138 */ protocolVersion(int majorVersion, int minorVersion)139 public Builder<G, N, M> protocolVersion(int majorVersion, int minorVersion) { 140 this.major = majorVersion; 141 this.minor = minorVersion; 142 return this; 143 } 144 145 /** 146 * Associates different implementation of types. 147 * 148 * @param graphTypes implementation of types and enum recognition 149 * @return this builder 150 */ types(GraphTypes graphTypes)151 public Builder<G, N, M> types(GraphTypes graphTypes) { 152 this.types = graphTypes; 153 return this; 154 } 155 156 /** 157 * Associates implementation of blocks. 158 * 159 * @param graphBlocks the blocks implementation 160 * @return this builder 161 */ blocks(GraphBlocks<G, ?, N> graphBlocks)162 public Builder<G, N, M> blocks(GraphBlocks<G, ?, N> graphBlocks) { 163 this.blocks = graphBlocks; 164 return this; 165 } 166 167 /** 168 * Associates implementation of graph elements. 169 * 170 * @param graphElements the elements implementation 171 * @return this builder 172 */ elements(GraphElements<E, ?, ?, P> graphElements)173 public <E, P> Builder<G, N, E> elements(GraphElements<E, ?, ?, P> graphElements) { 174 StackLocations<E, P> loc = new StackLocations<>(graphElements); 175 return elementsAndLocations(graphElements, loc); 176 } 177 178 /** 179 * Associates implementation of graph elements and an advanced way to interpret their 180 * locations. 181 * 182 * @param graphElements the elements implementation 183 * @param graphLocations the locations for the elements 184 * @return this builder 185 * @since 0.33 GraalVM 0.33 186 */ 187 @SuppressWarnings({"unchecked", "rawtypes"}) elementsAndLocations(GraphElements<E, ?, ?, P> graphElements, GraphLocations<E, P, ?> graphLocations)188 public <E, P> Builder<G, N, E> elementsAndLocations(GraphElements<E, ?, ?, P> graphElements, GraphLocations<E, P, ?> graphLocations) { 189 ElementsAndLocations both = new ElementsAndLocations<>(graphElements, graphLocations); 190 this.elementsAndLocations = both; 191 return (Builder<G, N, E>) this; 192 } 193 194 /** 195 * Creates new {@link GraphOutput} to output to provided channel. The output will use 196 * interfaces currently associated with this builder. 197 * 198 * @param channel the channel to output to 199 * @return new graph output 200 * @throws IOException if something goes wrong when writing to the channel 201 */ build(WritableByteChannel channel)202 public GraphOutput<G, M> build(WritableByteChannel channel) throws IOException { 203 return buildImpl(elementsAndLocations, channel); 204 } 205 206 /** 207 * Support for nesting heterogenous graphs. The newly created output uses all the interfaces 208 * currently associated with this builder, but shares with {@code parent} the output 209 * {@code channel}, internal constant pool and {@link #protocolVersion(int, int) protocol 210 * version}. 211 * <p> 212 * Both GraphOutput (the {@code parent} and the returned one) has to be used in 213 * synchronization - e.g. only one 214 * {@link #beginGroup(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object, int, java.util.Map) 215 * begin}, {@link #endGroup() end} of group or 216 * {@link #print(java.lang.Object, java.util.Map, int, java.lang.String, java.lang.Object...) 217 * printing} can be on at a given moment. 218 * 219 * @param parent the output to inherit {@code channel} and protocol version from 220 * @return new output sharing {@code channel} and other internals with {@code parent} 221 */ build(GraphOutput<?, ?> parent)222 public GraphOutput<G, M> build(GraphOutput<?, ?> parent) { 223 return buildImpl(elementsAndLocations, parent); 224 } 225 buildImpl(ElementsAndLocations<M, L, P> e, WritableByteChannel channel)226 private <L, P> GraphOutput<G, M> buildImpl(ElementsAndLocations<M, L, P> e, WritableByteChannel channel) throws IOException { 227 // @formatter:off 228 ProtocolImpl<G, N, ?, ?, ?, M, ?, ?, ?, ?> p = new ProtocolImpl<>( 229 major, minor, structure, types, blocks, 230 e == null ? null : e.elements, 231 e == null ? null : e.locations, channel 232 ); 233 // @formatter:on 234 return new GraphOutput<>(p); 235 } 236 buildImpl(ElementsAndLocations<M, L, P> e, GraphOutput<?, ?> parent)237 private <L, P> GraphOutput<G, M> buildImpl(ElementsAndLocations<M, L, P> e, GraphOutput<?, ?> parent) { 238 // @formatter:off 239 ProtocolImpl<G, N, ?, ?, ?, M, ?, ?, ?, ?> p = new ProtocolImpl<>( 240 parent.printer, structure, types, blocks, 241 e == null ? null : e.elements, 242 e == null ? null : e.locations 243 ); 244 // @formatter:on 245 return new GraphOutput<>(p); 246 } 247 } 248 249 private static final class ElementsAndLocations<M, P, L> { 250 final GraphElements<M, ?, ?, P> elements; 251 final GraphLocations<M, P, L> locations; 252 ElementsAndLocations(GraphElements<M, ?, ?, P> elements, GraphLocations<M, P, L> locations)253 ElementsAndLocations(GraphElements<M, ?, ?, P> elements, GraphLocations<M, P, L> locations) { 254 elements.getClass(); 255 locations.getClass(); 256 this.elements = elements; 257 this.locations = locations; 258 } 259 } 260 261 private static final class StackLocations<M, P> implements GraphLocations<M, P, StackTraceElement> { 262 private final GraphElements<M, ?, ?, P> graphElements; 263 StackLocations(GraphElements<M, ?, ?, P> graphElements)264 StackLocations(GraphElements<M, ?, ?, P> graphElements) { 265 this.graphElements = graphElements; 266 } 267 268 @Override methodLocation(M method, int bci, P pos)269 public Iterable<StackTraceElement> methodLocation(M method, int bci, P pos) { 270 StackTraceElement ste = this.graphElements.methodStackTraceElement(method, bci, pos); 271 return Collections.singleton(ste); 272 } 273 274 @Override locationURI(StackTraceElement location)275 public URI locationURI(StackTraceElement location) { 276 String path = location.getFileName(); 277 try { 278 return path == null ? null : new URI(null, null, path, null); 279 } catch (URISyntaxException ex) { 280 throw new IllegalArgumentException(ex); 281 } 282 } 283 284 @Override locationLineNumber(StackTraceElement location)285 public int locationLineNumber(StackTraceElement location) { 286 return location.getLineNumber(); 287 } 288 289 @Override locationLanguage(StackTraceElement location)290 public String locationLanguage(StackTraceElement location) { 291 return "Java"; 292 } 293 294 @Override locationOffsetStart(StackTraceElement location)295 public int locationOffsetStart(StackTraceElement location) { 296 return -1; 297 } 298 299 @Override locationOffsetEnd(StackTraceElement location)300 public int locationOffsetEnd(StackTraceElement location) { 301 return -1; 302 } 303 } 304 } 305