org.graalvm.graphio.GraphOutput Maven / Gradle / Ivy
Show all versions of compiler Show documentation
/*
* Copyright (c) 2011, 2020, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.graphio;
import java.io.Closeable;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Instance of output to dump informations about a compiler compilations.
*
* @param the type of graph this instance handles
* @param the type of methods this instance handles
* @since 19.0 a {@link WritableByteChannel} is implemented
*/
public final class GraphOutput implements Closeable, WritableByteChannel {
private final GraphProtocol printer;
/**
* Name of stream attribute to identify the VM execution, allows to join different GraphOutput
* streams. The value should be the same for all related {@link GraphOutput}s.
*
* @since 20.2.0
*/
public static final String ATTR_VM_ID = "vm.uuid";
private GraphOutput(GraphProtocol p) {
this.printer = p;
}
/**
* Creates new builder to configure a future instance of {@link GraphOutput}.
*
* @param the type of the graph
* @param the type of the nodes
* @param the type of the node classes
* @param the type of the ports
*
* @param structure description of the structure of the graph
* @return the builder to configure
*/
public static Builder newBuilder(GraphStructure structure) {
return new Builder<>(structure);
}
/**
* Begins a compilation group.
*
* @param forGraph
* @param name
* @param shortName
* @param method
* @param bci
* @param properties
* @throws IOException
*/
public void beginGroup(G forGraph, String name, String shortName, M method, int bci, Map extends Object, ? extends Object> properties) throws IOException {
printer.beginGroup(forGraph, name, shortName, method, bci, properties);
}
/**
* Prints a single graph.
*
* @param graph
* @param properties
* @param id
* @param format
* @param args
* @throws IOException
*/
public void print(G graph, Map extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException {
printer.print(graph, properties, id, format, args);
}
/**
* Ends compilation group.
*
* @throws IOException
*/
public void endGroup() throws IOException {
printer.endGroup();
}
/**
* Closes the output. Closes allocated resources and associated output channel.
*/
@Override
public void close() {
printer.close();
}
/**
* Checks if the {@link GraphOutput} is open.
*
* @return true if the {@link GraphOutput} is open.
* @since 19.0
*/
@Override
public boolean isOpen() {
return printer.isOpen();
}
/**
* Writes raw bytes into {@link GraphOutput}.
*
* @param src the bytes to write
* @return the number of bytes written, possibly zero
* @throws IOException in case of IO error
* @since 19.0
*/
@Override
public int write(ByteBuffer src) throws IOException {
return printer.write(src);
}
/**
* Builder to configure and create an instance of {@link GraphOutput}.
*
* @param the type of the (root element of) graph
* @param the type of the nodes
* @param the type of the methods
*/
public static final class Builder {
private static final int DEFAULT_MAJOR_VERSION = 8;
private static final int DEFAULT_MINOR_VERSION = 0;
private final GraphStructure structure;
private ElementsAndLocations elementsAndLocations;
private GraphTypes types = DefaultGraphTypes.DEFAULT;
private GraphBlocks blocks = DefaultGraphBlocks.empty();
/**
* The major version. Negative values mean automatically assigned version, implied by
* Builder functions.
*/
private int major = 0;
private int minor = 0;
private boolean explicitVersionSet;
private boolean embeddedGraphOutput;
private Map properties;
Builder(GraphStructure structure) {
this.structure = structure;
}
/**
* Chooses which version of the protocol to use. The default version is 7.0
* (when the {@link GraphOutput} & co. classes were introduced). The default can be changed
* to other known versions manually by calling this method.
*
* Note: the the default version is 7.0 since version 20.2. Previous versions used default
* version 4.0
*
* @param majorVersion by default 7, newer version may be known
* @param minorVersion usually 0
* @return this builder
* @since 0.28
*/
public Builder protocolVersion(int majorVersion, int minorVersion) {
assert majorVersion >= 1 : "Major must be positive";
assert minorVersion >= 0 : "Minor must not be negative";
if (!(explicitVersionSet ||
(majorVersion == 0) ||
(majorVersion > major) ||
((majorVersion == major) && (minorVersion >= minor)))) {
throw new IllegalArgumentException("Cannot downgrade from minimum required version " + (-major) + "." + minor);
}
this.major = majorVersion;
this.minor = minorVersion;
explicitVersionSet = true;
return this;
}
/**
* Asserts a specific version of the protocol. If not specified explicitly, upgrades the
* protocol version.
*
* @param reqMajor The required major version
* @param reqMinor the required minor version
*/
private void requireVersion(int reqMajor, int reqMinor) {
assert reqMajor >= 1 : "Major must be positive";
assert reqMinor >= 0 : "Minor must not be negative";
if (explicitVersionSet) {
if (major < reqMajor || (major == reqMajor && minor < reqMinor)) {
throw new IllegalStateException("Feature unsupported in version " + major + "." + minor);
}
} else {
if (major < reqMajor) {
major = reqMajor;
minor = reqMinor;
} else if (major == reqMajor) {
minor = Math.max(minor, reqMinor);
}
}
}
/**
* Sets {@link GraphOutput} as embedded. The embedded {@link GraphOutput} shares
* {@link WritableByteChannel channel} with another already open non parent
* {@link GraphOutput}. The embedded {@link GraphOutput} flushes data after each
* {@link GraphOutput#print print}, {@link GraphOutput#beginGroup beginGroup} and
* {@link GraphOutput#endGroup endGroup} call.
*
* @param embedded if {@code true} the builder creates an embedded {@link GraphOutput}
* @return this builder
* @since 19.0
*/
public Builder embedded(boolean embedded) {
this.embeddedGraphOutput = embedded;
return this;
}
/**
* Associates different implementation of types.
*
* @param graphTypes implementation of types and enum recognition
* @return this builder
*/
public Builder types(GraphTypes graphTypes) {
this.types = graphTypes;
return this;
}
/**
* Associates implementation of blocks.
*
* @param graphBlocks the blocks implementation
* @return this builder
*/
public Builder blocks(GraphBlocks graphBlocks) {
this.blocks = graphBlocks;
return this;
}
/**
* Associates implementation of graph elements.
*
* @param graphElements the elements implementation
* @return this builder
*/
public Builder elements(GraphElements graphElements) {
StackLocations loc = new StackLocations<>(graphElements);
return elementsAndLocations(graphElements, loc);
}
/**
* Associates implementation of graph elements and an advanced way to interpret their
* locations.
*
* @param graphElements the elements implementation
* @param graphLocations the locations for the elements
* @return this builder
* @since 0.33 GraalVM 0.33
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public Builder elementsAndLocations(GraphElements graphElements, GraphLocations graphLocations) {
ElementsAndLocations both = new ElementsAndLocations<>(graphElements, graphLocations);
this.elementsAndLocations = both;
return (Builder) this;
}
/**
* Attaches metadata to the dump. The method may be called more times, subsequent calls will
* overwrite previous values of matching keys.
*
* @param name key name
* @param value value for the key
* @return this builder
* @since 20.1.0
*/
public Builder attr(String name, Object value) {
requireVersion(7, 0);
if (properties == null) {
properties = new HashMap<>(5);
}
properties.put(name, value);
return this;
}
/**
* Creates new {@link GraphOutput} to output to provided channel. The output will use
* interfaces currently associated with this builder.
*
* @param channel the channel to output to
* @return new graph output
* @throws IOException if something goes wrong when writing to the channel
*/
public GraphOutput build(WritableByteChannel channel) throws IOException {
return buildImpl(elementsAndLocations, channel);
}
/**
* Support for nesting heterogenous graphs. The newly created output uses all the interfaces
* currently associated with this builder, but shares with {@code parent} the output
* {@code channel}, internal constant pool and {@link #protocolVersion(int, int) protocol
* version}.
*
* Both GraphOutput (the {@code parent} and the returned one) has to be used in
* synchronization - e.g. only one
* {@link GraphOutput#beginGroup(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object, int, java.util.Map)
* begin}, {@link GraphOutput#endGroup() end} of group or
* {@link GraphOutput#print(java.lang.Object, java.util.Map, int, java.lang.String, java.lang.Object...)
* printing} can be on at a given moment.
*
* @param parent the output to inherit {@code channel} and protocol version from
* @return new output sharing {@code channel} and other internals with {@code parent}
*/
public GraphOutput build(GraphOutput, ?> parent) {
return buildImpl(elementsAndLocations, parent);
}
private GraphOutput buildImpl(ElementsAndLocations e, WritableByteChannel channel) throws IOException {
int m = major;
int n = minor;
if (m == 0) {
m = DEFAULT_MAJOR_VERSION;
n = DEFAULT_MINOR_VERSION;
}
// @formatter:off
ProtocolImpl p = new ProtocolImpl<>(
m, n, embeddedGraphOutput, structure, types, blocks,
e == null ? null : e.elements,
e == null ? null : e.locations, channel
);
// @formatter:on
if (properties != null) {
p.startDocument(properties);
}
return new GraphOutput<>(p);
}
private GraphOutput buildImpl(ElementsAndLocations e, GraphOutput, ?> parent) {
// @formatter:off
ProtocolImpl p = new ProtocolImpl<>(
parent.printer, structure, types, blocks,
e == null ? null : e.elements,
e == null ? null : e.locations
);
// @formatter:on
return new GraphOutput<>(p);
}
}
private static final class ElementsAndLocations {
final GraphElements elements;
final GraphLocations locations;
ElementsAndLocations(GraphElements elements, GraphLocations locations) {
elements.getClass();
locations.getClass();
this.elements = elements;
this.locations = locations;
}
}
private static final class StackLocations implements GraphLocations {
private final GraphElements graphElements;
StackLocations(GraphElements graphElements) {
this.graphElements = graphElements;
}
@Override
public Iterable methodLocation(M method, int bci, P pos) {
StackTraceElement ste = this.graphElements.methodStackTraceElement(method, bci, pos);
return Collections.singleton(ste);
}
@Override
public URI locationURI(StackTraceElement location) {
String path = location.getFileName();
try {
return path == null ? null : new URI(null, null, path, null);
} catch (URISyntaxException ex) {
throw new IllegalArgumentException(ex);
}
}
@Override
public int locationLineNumber(StackTraceElement location) {
return location.getLineNumber();
}
@Override
public String locationLanguage(StackTraceElement location) {
return "Java";
}
@Override
public int locationOffsetStart(StackTraceElement location) {
return -1;
}
@Override
public int locationOffsetEnd(StackTraceElement location) {
return -1;
}
}
}