< prev index next >

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java

Print this page




   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 package org.graalvm.compiler.printer;
  24 
  25 import static org.graalvm.compiler.graph.Edges.Type.Inputs;
  26 import static org.graalvm.compiler.graph.Edges.Type.Successors;
  27 
  28 import java.io.IOException;
  29 import java.nio.ByteBuffer;
  30 import java.nio.channels.WritableByteChannel;
  31 import java.nio.charset.Charset;
  32 import java.util.Arrays;
  33 import java.util.HashMap;
  34 import java.util.LinkedHashMap;
  35 import java.util.LinkedList;
  36 import java.util.List;
  37 import java.util.Map;
  38 import java.util.Map.Entry;
  39 
  40 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  41 import org.graalvm.compiler.bytecode.Bytecode;
  42 import org.graalvm.compiler.core.common.cfg.BlockMap;
  43 import org.graalvm.compiler.debug.DebugContext;
  44 import org.graalvm.compiler.debug.DebugOptions;
  45 import org.graalvm.compiler.graph.CachedGraph;
  46 import org.graalvm.compiler.graph.Edges;
  47 import org.graalvm.compiler.graph.Graph;
  48 import org.graalvm.compiler.graph.InputEdges;
  49 import org.graalvm.compiler.graph.Node;
  50 import org.graalvm.compiler.graph.NodeClass;
  51 import org.graalvm.compiler.graph.NodeList;
  52 import org.graalvm.compiler.graph.NodeMap;
  53 import org.graalvm.compiler.nodes.AbstractBeginNode;
  54 import org.graalvm.compiler.nodes.AbstractEndNode;
  55 import org.graalvm.compiler.nodes.AbstractMergeNode;
  56 import org.graalvm.compiler.nodes.ConstantNode;
  57 import org.graalvm.compiler.nodes.ControlSinkNode;
  58 import org.graalvm.compiler.nodes.ControlSplitNode;
  59 import org.graalvm.compiler.nodes.FixedNode;
  60 import org.graalvm.compiler.nodes.PhiNode;
  61 import org.graalvm.compiler.nodes.ProxyNode;
  62 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
  63 import org.graalvm.compiler.nodes.VirtualState;
  64 import org.graalvm.compiler.nodes.cfg.Block;
  65 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
  66 
  67 import jdk.vm.ci.meta.JavaType;
  68 import jdk.vm.ci.meta.ResolvedJavaField;
  69 import jdk.vm.ci.meta.ResolvedJavaMethod;

  70 import jdk.vm.ci.meta.Signature;

  71 import org.graalvm.compiler.graph.NodeSourcePosition;
  72 
  73 public class BinaryGraphPrinter implements GraphPrinter {
  74 
  75     private static final int CONSTANT_POOL_MAX_SIZE = 8000;
  76 
  77     private static final int BEGIN_GROUP = 0x00;
  78     private static final int BEGIN_GRAPH = 0x01;
  79     private static final int CLOSE_GROUP = 0x02;
  80 
  81     private static final int POOL_NEW = 0x00;
  82     private static final int POOL_STRING = 0x01;
  83     private static final int POOL_ENUM = 0x02;
  84     private static final int POOL_CLASS = 0x03;
  85     private static final int POOL_METHOD = 0x04;
  86     private static final int POOL_NULL = 0x05;
  87     private static final int POOL_NODE_CLASS = 0x06;
  88     private static final int POOL_FIELD = 0x07;
  89     private static final int POOL_SIGNATURE = 0x08;
  90     private static final int POOL_NODE_SOURCE_POSITION = 0x09;
  91 
  92     private static final int PROPERTY_POOL = 0x00;
  93     private static final int PROPERTY_INT = 0x01;
  94     private static final int PROPERTY_LONG = 0x02;
  95     private static final int PROPERTY_DOUBLE = 0x03;
  96     private static final int PROPERTY_FLOAT = 0x04;
  97     private static final int PROPERTY_TRUE = 0x05;
  98     private static final int PROPERTY_FALSE = 0x06;
  99     private static final int PROPERTY_ARRAY = 0x07;
 100     private static final int PROPERTY_SUBGRAPH = 0x08;
 101 
 102     private static final int KLASS = 0x00;
 103     private static final int ENUM_KLASS = 0x01;
 104 
 105     static final int CURRENT_MAJOR_VERSION = 4;
 106     static final int CURRENT_MINOR_VERSION = 0;
 107 
 108     static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'};
 109 
 110     private void writeVersion() throws IOException {
 111         writeBytesRaw(MAGIC_BYTES);
 112         writeByte(CURRENT_MAJOR_VERSION);
 113         writeByte(CURRENT_MINOR_VERSION);
 114     }
 115 
 116     private static final class ConstantPool extends LinkedHashMap<Object, Character> {
 117 
 118         private final LinkedList<Character> availableIds;
 119         private char nextId;
 120         private static final long serialVersionUID = -2676889957907285681L;
 121 
 122         ConstantPool() {
 123             super(50, 0.65f);
 124             availableIds = new LinkedList<>();
 125         }
 126 
 127         @Override
 128         protected boolean removeEldestEntry(java.util.Map.Entry<Object, Character> eldest) {
 129             if (size() > CONSTANT_POOL_MAX_SIZE) {
 130                 availableIds.addFirst(eldest.getValue());
 131                 return true;
 132             }
 133             return false;
 134         }
 135 
 136         private Character nextAvailableId() {
 137             if (!availableIds.isEmpty()) {
 138                 return availableIds.removeFirst();
 139             }
 140             return nextId++;
 141         }
 142 
 143         public char add(Object obj) {
 144             Character id = nextAvailableId();
 145             put(obj, id);
 146             return id;
 147         }
 148     }
 149 
 150     private final ConstantPool constantPool;
 151     private final ByteBuffer buffer;
 152     private final WritableByteChannel channel;
 153     private final SnippetReflectionProvider snippetReflection;
 154 
 155     private static final Charset utf8 = Charset.forName("UTF-8");
 156 
 157     public BinaryGraphPrinter(WritableByteChannel channel, SnippetReflectionProvider snippetReflection) throws IOException {
 158         constantPool = new ConstantPool();
 159         this.snippetReflection = snippetReflection;
 160         buffer = ByteBuffer.allocateDirect(256 * 1024);
 161         this.channel = channel;
 162         writeVersion();
 163     }
 164 
 165     @Override
 166     public SnippetReflectionProvider getSnippetReflectionProvider() {
 167         return snippetReflection;
 168     }
 169 
 170     @SuppressWarnings("all")
 171     @Override
 172     public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException {
 173         writeByte(BEGIN_GRAPH);
 174         if (CURRENT_MAJOR_VERSION >= 3) {
 175             writeInt(id);
 176             writeString(format);
 177             writeInt(args.length);
 178             for (Object a : args) {
 179                 writePropertyObject(debug, a);
 180             }
 181         } else {
 182             writePoolObject(id + ": " + String.format(format, simplifyClassArgs(args)));
 183         }
 184         writeGraph(debug, graph, properties);
 185         flush();
 186     }
 187 
 188     private void writeGraph(DebugContext debug, Graph graph, Map<Object, Object> properties) throws IOException {
 189         boolean needSchedule = DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null;
 190         ScheduleResult scheduleResult = needSchedule ? GraphPrinter.getScheduleOrNull(graph) : null;
 191         ControlFlowGraph cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG();
 192         BlockMap<List<Node>> blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap();
 193         NodeMap<Block> nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap();
 194         List<Block> blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks());
 195         writeProperties(debug, properties);
 196         writeNodes(debug, graph, nodeToBlocks, cfg);
 197         writeBlocks(blocks, blockToNodes);
 198     }
 199 
 200     private void flush() throws IOException {
 201         buffer.flip();
 202         /*
 203          * Try not to let interrupted threads abort the write. There's still a race here but an
 204          * interrupt that's been pending for a long time shouldn't stop this writing.
 205          */
 206         boolean interrupted = Thread.interrupted();
 207         try {
 208             channel.write(buffer);
 209         } finally {
 210             if (interrupted) {
 211                 Thread.currentThread().interrupt();
 212             }
 213         }
 214         buffer.compact();
 215     }
 216 
 217     private void ensureAvailable(int i) throws IOException {
 218         assert buffer.capacity() >= i : "Can not make " + i + " bytes available, buffer is too small";
 219         while (buffer.remaining() < i) {
 220             flush();
 221         }
 222     }
 223 
 224     private void writeByte(int b) throws IOException {
 225         ensureAvailable(1);
 226         buffer.put((byte) b);





 227     }
 228 
 229     private void writeInt(int b) throws IOException {
 230         ensureAvailable(4);
 231         buffer.putInt(b);
 232     }
 233 
 234     private void writeLong(long b) throws IOException {
 235         ensureAvailable(8);
 236         buffer.putLong(b);

 237     }
 238 
 239     private void writeDouble(double b) throws IOException {
 240         ensureAvailable(8);
 241         buffer.putDouble(b);
 242     }
 243 
 244     private void writeFloat(float b) throws IOException {
 245         ensureAvailable(4);
 246         buffer.putFloat(b);
 247     }
 248 
 249     private void writeShort(char b) throws IOException {
 250         ensureAvailable(2);
 251         buffer.putChar(b);
 252     }
 253 
 254     private void writeString(String str) throws IOException {
 255         byte[] bytes = str.getBytes(utf8);
 256         writeBytes(bytes);
 257     }
 258 
 259     private void writeBytes(byte[] b) throws IOException {
 260         if (b == null) {
 261             writeInt(-1);



 262         } else {
 263             writeInt(b.length);
 264             writeBytesRaw(b);
 265         }
 266     }
 267 
 268     private void writeBytesRaw(byte[] b) throws IOException {
 269         int bytesWritten = 0;
 270         while (bytesWritten < b.length) {
 271             int toWrite = Math.min(b.length - bytesWritten, buffer.capacity());
 272             ensureAvailable(toWrite);
 273             buffer.put(b, bytesWritten, toWrite);
 274             bytesWritten += toWrite;
 275         }
 276     }
 277 
 278     private void writeInts(int[] b) throws IOException {
 279         if (b == null) {
 280             writeInt(-1);
 281         } else {
 282             writeInt(b.length);
 283             int sizeInBytes = b.length * 4;
 284             ensureAvailable(sizeInBytes);
 285             buffer.asIntBuffer().put(b);
 286             buffer.position(buffer.position() + sizeInBytes);
 287         }
 288     }
 289 
 290     private void writeDoubles(double[] b) throws IOException {
 291         if (b == null) {
 292             writeInt(-1);
 293         } else {
 294             writeInt(b.length);
 295             int sizeInBytes = b.length * 8;
 296             ensureAvailable(sizeInBytes);
 297             buffer.asDoubleBuffer().put(b);
 298             buffer.position(buffer.position() + sizeInBytes);
 299         }
 300     }
 301 
 302     private void writePoolObject(Object object) throws IOException {
 303         if (object == null) {
 304             writeByte(POOL_NULL);
 305             return;
 306         }
 307         Character id = constantPool.get(object);
 308         if (id == null) {
 309             addPoolEntry(object);
 310         } else {
 311             if (object instanceof Enum<?>) {
 312                 writeByte(POOL_ENUM);
 313             } else if (object instanceof Class<?> || object instanceof JavaType) {
 314                 writeByte(POOL_CLASS);
 315             } else if (object instanceof NodeClass) {
 316                 writeByte(POOL_NODE_CLASS);
 317             } else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) {
 318                 writeByte(POOL_METHOD);
 319             } else if (object instanceof ResolvedJavaField) {
 320                 writeByte(POOL_FIELD);
 321             } else if (object instanceof Signature) {
 322                 writeByte(POOL_SIGNATURE);
 323             } else if (CURRENT_MAJOR_VERSION >= 4 && object instanceof NodeSourcePosition) {
 324                 writeByte(POOL_NODE_SOURCE_POSITION);
 325             } else {
 326                 writeByte(POOL_STRING);
 327             }
 328             writeShort(id.charValue());
 329         }
 330     }
 331 
 332     private static String getClassName(Class<?> klass) {
 333         if (!klass.isArray()) {
 334             return klass.getName();
 335         }
 336         return getClassName(klass.getComponentType()) + "[]";
 337     }
 338 
 339     @SuppressWarnings("all")
 340     private void addPoolEntry(Object object) throws IOException {
 341         char index = constantPool.add(object);
 342         writeByte(POOL_NEW);
 343         writeShort(index);
 344         if (object instanceof Class<?>) {
 345             Class<?> klass = (Class<?>) object;
 346             writeByte(POOL_CLASS);
 347             writeString(getClassName(klass));
 348             if (klass.isEnum()) {
 349                 writeByte(ENUM_KLASS);
 350                 Object[] enumConstants = klass.getEnumConstants();
 351                 writeInt(enumConstants.length);
 352                 for (Object o : enumConstants) {
 353                     writePoolObject(((Enum<?>) o).name());
 354                 }
 355             } else {
 356                 writeByte(KLASS);
 357             }
 358         } else if (object instanceof Enum<?>) {
 359             writeByte(POOL_ENUM);
 360             writePoolObject(object.getClass());
 361             writeInt(((Enum<?>) object).ordinal());
 362         } else if (object instanceof JavaType) {
 363             JavaType type = (JavaType) object;
 364             writeByte(POOL_CLASS);
 365             writeString(type.toJavaName());
 366             writeByte(KLASS);
 367         } else if (object instanceof NodeClass) {
 368             NodeClass<?> nodeClass = (NodeClass<?>) object;
 369             writeByte(POOL_NODE_CLASS);
 370             if (CURRENT_MAJOR_VERSION >= 3) {
 371                 writePoolObject(nodeClass.getJavaClass());
 372                 writeString(nodeClass.getNameTemplate());
 373             } else {
 374                 writeString(nodeClass.getJavaClass().getSimpleName());
 375                 String nameTemplate = nodeClass.getNameTemplate();
 376                 writeString(nameTemplate.isEmpty() ? nodeClass.shortName() : nameTemplate);
 377             }
 378             writeEdgesInfo(nodeClass, Inputs);
 379             writeEdgesInfo(nodeClass, Successors);
 380         } else if (object instanceof ResolvedJavaMethod || object instanceof Bytecode) {
 381             writeByte(POOL_METHOD);
 382             ResolvedJavaMethod method;
 383             if (object instanceof Bytecode) {
 384                 method = ((Bytecode) object).getMethod();
 385             } else {
 386                 method = ((ResolvedJavaMethod) object);
 387             }
 388             writePoolObject(method.getDeclaringClass());
 389             writePoolObject(method.getName());
 390             writePoolObject(method.getSignature());
 391             writeInt(method.getModifiers());
 392             writeBytes(method.getCode());
 393         } else if (object instanceof ResolvedJavaField) {
 394             writeByte(POOL_FIELD);
 395             ResolvedJavaField field = ((ResolvedJavaField) object);
 396             writePoolObject(field.getDeclaringClass());
 397             writePoolObject(field.getName());
 398             writePoolObject(field.getType().getName());
 399             writeInt(field.getModifiers());
 400         } else if (object instanceof Signature) {
 401             writeByte(POOL_SIGNATURE);
 402             Signature signature = ((Signature) object);
 403             int args = signature.getParameterCount(false);
 404             writeShort((char) args);
 405             for (int i = 0; i < args; i++) {
 406                 writePoolObject(signature.getParameterType(i, null).getName());
 407             }
 408             writePoolObject(signature.getReturnType(null).getName());
 409         } else if (CURRENT_MAJOR_VERSION >= 4 && object instanceof NodeSourcePosition) {
 410             writeByte(POOL_NODE_SOURCE_POSITION);
 411             NodeSourcePosition pos = (NodeSourcePosition) object;
 412             ResolvedJavaMethod method = pos.getMethod();
 413             writePoolObject(method);
 414             final int bci = pos.getBCI();
 415             writeInt(bci);
 416             StackTraceElement ste = method.asStackTraceElement(bci);
 417             if (ste != null) {
 418                 String fn = ste.getFileName();
 419                 writePoolObject(fn);
 420                 if (fn != null) {
 421                     writeInt(ste.getLineNumber());
 422                 }
 423             } else {
 424                 writePoolObject(null);
 425             }
 426             writePoolObject(pos.getCaller());
 427         } else {
 428             writeByte(POOL_STRING);
 429             writeString(object.toString());
 430         }



 431     }
 432 
 433     private void writeEdgesInfo(NodeClass<?> nodeClass, Edges.Type type) throws IOException {
 434         Edges edges = nodeClass.getEdges(type);
 435         writeShort((char) edges.getCount());
 436         for (int i = 0; i < edges.getCount(); i++) {
 437             writeByte(i < edges.getDirectCount() ? 0 : 1);
 438             writePoolObject(edges.getName(i));
 439             if (type == Inputs) {
 440                 writePoolObject(((InputEdges) edges).getInputType(i));
 441             }
 442         }
 443     }
 444 
 445     private void writePropertyObject(DebugContext debug, Object obj) throws IOException {
 446         if (obj instanceof Integer) {
 447             writeByte(PROPERTY_INT);
 448             writeInt(((Integer) obj).intValue());
 449         } else if (obj instanceof Long) {
 450             writeByte(PROPERTY_LONG);
 451             writeLong(((Long) obj).longValue());
 452         } else if (obj instanceof Double) {
 453             writeByte(PROPERTY_DOUBLE);
 454             writeDouble(((Double) obj).doubleValue());
 455         } else if (obj instanceof Float) {
 456             writeByte(PROPERTY_FLOAT);
 457             writeFloat(((Float) obj).floatValue());
 458         } else if (obj instanceof Boolean) {
 459             if (((Boolean) obj).booleanValue()) {
 460                 writeByte(PROPERTY_TRUE);
 461             } else {
 462                 writeByte(PROPERTY_FALSE);
 463             }
 464         } else if (obj instanceof Graph) {
 465             writeByte(PROPERTY_SUBGRAPH);
 466             writeGraph(debug, (Graph) obj, null);
 467         } else if (obj instanceof CachedGraph) {
 468             writeByte(PROPERTY_SUBGRAPH);
 469             writeGraph(debug, ((CachedGraph<?>) obj).getReadonlyCopy(), null);
 470         } else if (obj != null && obj.getClass().isArray()) {
 471             Class<?> componentType = obj.getClass().getComponentType();
 472             if (componentType.isPrimitive()) {
 473                 if (componentType == Double.TYPE) {
 474                     writeByte(PROPERTY_ARRAY);
 475                     writeByte(PROPERTY_DOUBLE);
 476                     writeDoubles((double[]) obj);
 477                 } else if (componentType == Integer.TYPE) {
 478                     writeByte(PROPERTY_ARRAY);
 479                     writeByte(PROPERTY_INT);
 480                     writeInts((int[]) obj);
 481                 } else {
 482                     writeByte(PROPERTY_POOL);
 483                     writePoolObject(obj);
 484                 }
 485             } else {
 486                 writeByte(PROPERTY_ARRAY);
 487                 writeByte(PROPERTY_POOL);
 488                 Object[] array = (Object[]) obj;
 489                 writeInt(array.length);
 490                 for (Object o : array) {
 491                     writePoolObject(o);
 492                 }
 493             }
 494         } else {
 495             writeByte(PROPERTY_POOL);
 496             writePoolObject(obj);
 497         }
 498     }
 499 
 500     @SuppressWarnings("deprecation")
 501     private static int getNodeId(Node node) {
 502         return node.getId();
 503     }
 504 
 505     private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) {
 506         if (nodeToBlocks.isNew(node)) {
 507             return "NEW (not in schedule)";
 508         } else {
 509             Block block = nodeToBlocks.get(node);
 510             if (block != null) {
 511                 return block.getId();
 512             } else if (node instanceof PhiNode) {
 513                 return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks);
 514             }
 515         }
 516         return null;
 517     }
 518 
 519     private void writeNodes(DebugContext debug, Graph graph, NodeMap<Block> nodeToBlocks, ControlFlowGraph cfg) throws IOException {
 520         Map<Object, Object> props = new HashMap<>();
 521 
 522         writeInt(graph.getNodeCount());
 523 
 524         for (Node node : graph.getNodes()) {
 525             NodeClass<?> nodeClass = node.getNodeClass();
 526             node.getDebugProperties(props);
 527             if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) {
 528                 try {
 529                     props.put("probability", cfg.blockFor(node).probability());
 530                 } catch (Throwable t) {
 531                     props.put("probability", 0.0);
 532                     props.put("probability-exception", t);
 533                 }
 534             }
 535 
 536             try {
 537                 props.put("NodeCost-Size", node.estimatedNodeSize());
 538                 props.put("NodeCost-Cycles", node.estimatedNodeCycles());
 539             } catch (Throwable t) {
 540                 props.put("node-cost-exception", t.getMessage());
 541             }
 542 
 543             if (nodeToBlocks != null) {
 544                 Object block = getBlockForNode(node, nodeToBlocks);
 545                 if (block != null) {
 546                     props.put("node-to-block", block);


 551                 props.put("category", "controlSink");
 552             } else if (node instanceof ControlSplitNode) {
 553                 props.put("category", "controlSplit");
 554             } else if (node instanceof AbstractMergeNode) {
 555                 props.put("category", "merge");
 556             } else if (node instanceof AbstractBeginNode) {
 557                 props.put("category", "begin");
 558             } else if (node instanceof AbstractEndNode) {
 559                 props.put("category", "end");
 560             } else if (node instanceof FixedNode) {
 561                 props.put("category", "fixed");
 562             } else if (node instanceof VirtualState) {
 563                 props.put("category", "state");
 564             } else if (node instanceof PhiNode) {
 565                 props.put("category", "phi");
 566             } else if (node instanceof ProxyNode) {
 567                 props.put("category", "proxy");
 568             } else {
 569                 if (node instanceof ConstantNode) {
 570                     ConstantNode cn = (ConstantNode) node;
 571                     updateStringPropertiesForConstant(props, cn);
 572                 }
 573                 props.put("category", "floating");
 574             }

 575 
 576             writeInt(getNodeId(node));
 577             writePoolObject(nodeClass);
 578             writeByte(node.predecessor() == null ? 0 : 1);
 579             writeProperties(debug, props);
 580             writeEdges(node, Inputs);
 581             writeEdges(node, Successors);
 582 
 583             props.clear();












 584         }
 585     }
 586 
 587     private void writeProperties(DebugContext debug, Map<Object, Object> props) throws IOException {
 588         if (props == null) {
 589             writeShort((char) 0);
 590             return;
 591         }
 592         // properties
 593         writeShort((char) props.size());
 594         for (Entry<Object, Object> entry : props.entrySet()) {
 595             String key = entry.getKey().toString();
 596             writePoolObject(key);
 597             writePropertyObject(debug, entry.getValue());
 598         }




 599     }
 600 
 601     private void writeEdges(Node node, Edges.Type type) throws IOException {
 602         NodeClass<?> nodeClass = node.getNodeClass();
 603         Edges edges = nodeClass.getEdges(type);
 604         final long[] curOffsets = edges.getOffsets();
 605         for (int i = 0; i < edges.getDirectCount(); i++) {
 606             writeNodeRef(Edges.getNode(node, curOffsets, i));
 607         }
 608         for (int i = edges.getDirectCount(); i < edges.getCount(); i++) {
 609             NodeList<Node> list = Edges.getNodeList(node, curOffsets, i);
 610             if (list == null) {
 611                 writeShort((char) 0);
 612             } else {
 613                 int listSize = list.count();
 614                 assert listSize == ((char) listSize);
 615                 writeShort((char) listSize);
 616                 for (Node edge : list) {
 617                     writeNodeRef(edge);
 618                 }









 619             }




 620         }




 621     }
 622 
 623     private void writeNodeRef(Node edge) throws IOException {
 624         if (edge != null) {
 625             writeInt(getNodeId(edge));


 626         } else {
 627             writeInt(-1);
 628         }
 629     }
 630 
 631     private void writeBlocks(List<Block> blocks, BlockMap<List<Node>> blockToNodes) throws IOException {
 632         if (blocks != null && blockToNodes != null) {
 633             for (Block block : blocks) {
 634                 List<Node> nodes = blockToNodes.get(block);
 635                 if (nodes == null) {
 636                     writeInt(0);
 637                     return;
 638                 }

 639             }
 640             writeInt(blocks.size());
 641             for (Block block : blocks) {
 642                 List<Node> nodes = blockToNodes.get(block);
 643                 List<Node> extraNodes = new LinkedList<>();
 644                 writeInt(block.getId());
 645                 for (Node node : nodes) {
 646                     if (node instanceof AbstractMergeNode) {
 647                         AbstractMergeNode merge = (AbstractMergeNode) node;
 648                         for (PhiNode phi : merge.phis()) {
 649                             if (!nodes.contains(phi)) {
 650                                 extraNodes.add(phi);
 651                             }

 652                         }











 653                     }

 654                 }
 655                 writeInt(nodes.size() + extraNodes.size());
 656                 for (Node node : nodes) {
 657                     writeInt(getNodeId(node));
 658                 }
 659                 for (Node node : extraNodes) {
 660                     writeInt(getNodeId(node));
 661                 }
 662                 writeInt(block.getSuccessors().length);
 663                 for (Block sux : block.getSuccessors()) {
 664                     writeInt(sux.getId());


 665                 }


 666             }
 667         } else {
 668             writeInt(0);
 669         }




 670     }
 671 
 672     @Override
 673     public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException {
 674         writeByte(BEGIN_GROUP);
 675         writePoolObject(name);
 676         writePoolObject(shortName);
 677         writePoolObject(method);
 678         writeInt(bci);
 679         writeProperties(debug, properties);
 680     }
 681 
 682     @Override
 683     public void endGroup() throws IOException {
 684         writeByte(CLOSE_GROUP);
 685     }
 686 
 687     @Override
 688     public void close() {











































































































 689         try {
 690             flush();
 691             channel.close();
 692         } catch (IOException ex) {
 693             throw new Error(ex);



 694         }
 695     }







 696 }


   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 package org.graalvm.compiler.printer;
  24 
  25 import static org.graalvm.compiler.graph.Edges.Type.Inputs;
  26 import static org.graalvm.compiler.graph.Edges.Type.Successors;
  27 
  28 import java.io.IOException;

  29 import java.nio.channels.WritableByteChannel;

  30 import java.util.Arrays;
  31 import java.util.Collection;
  32 import java.util.Collections;
  33 import java.util.LinkedList;
  34 import java.util.List;
  35 import java.util.Map;
  36 import jdk.vm.ci.meta.ResolvedJavaField;
  37 
  38 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
  39 import org.graalvm.compiler.bytecode.Bytecode;
  40 import org.graalvm.compiler.core.common.cfg.BlockMap;

  41 import org.graalvm.compiler.debug.DebugOptions;
  42 import org.graalvm.compiler.graph.CachedGraph;
  43 import org.graalvm.compiler.graph.Edges;
  44 import org.graalvm.compiler.graph.Graph;
  45 import org.graalvm.compiler.graph.InputEdges;
  46 import org.graalvm.compiler.graph.Node;
  47 import org.graalvm.compiler.graph.NodeClass;

  48 import org.graalvm.compiler.graph.NodeMap;
  49 import org.graalvm.compiler.nodes.AbstractBeginNode;
  50 import org.graalvm.compiler.nodes.AbstractEndNode;
  51 import org.graalvm.compiler.nodes.AbstractMergeNode;
  52 import org.graalvm.compiler.nodes.ConstantNode;
  53 import org.graalvm.compiler.nodes.ControlSinkNode;
  54 import org.graalvm.compiler.nodes.ControlSplitNode;
  55 import org.graalvm.compiler.nodes.FixedNode;
  56 import org.graalvm.compiler.nodes.PhiNode;
  57 import org.graalvm.compiler.nodes.ProxyNode;

  58 import org.graalvm.compiler.nodes.VirtualState;
  59 import org.graalvm.compiler.nodes.cfg.Block;
  60 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;



  61 import jdk.vm.ci.meta.ResolvedJavaMethod;
  62 import jdk.vm.ci.meta.ResolvedJavaType;
  63 import jdk.vm.ci.meta.Signature;
  64 import org.graalvm.compiler.debug.DebugContext;
  65 import org.graalvm.compiler.graph.NodeSourcePosition;
  66 import org.graalvm.compiler.nodes.StructuredGraph;
  67 import org.graalvm.compiler.phases.schedule.SchedulePhase;
  68 import org.graalvm.graphio.GraphBlocks;
  69 import org.graalvm.graphio.GraphElements;
  70 import org.graalvm.graphio.GraphOutput;
  71 import org.graalvm.graphio.GraphStructure;
  72 import org.graalvm.graphio.GraphTypes;
  73 
  74 public class BinaryGraphPrinter implements
  75                 GraphStructure<BinaryGraphPrinter.GraphInfo, Node, NodeClass<?>, Edges>,
  76                 GraphBlocks<BinaryGraphPrinter.GraphInfo, Block, Node>,
  77                 GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition>,
  78                 GraphTypes, GraphPrinter {




































































  79     private final SnippetReflectionProvider snippetReflection;
  80     private final GraphOutput<BinaryGraphPrinter.GraphInfo, ResolvedJavaMethod> output;

  81 
  82     public BinaryGraphPrinter(WritableByteChannel channel, SnippetReflectionProvider snippetReflection) throws IOException {
  83         this.output = GraphOutput.newBuilder(this).blocks(this).elements(this).types(this).build(channel);
  84         this.snippetReflection = snippetReflection;



  85     }
  86 
  87     @Override
  88     public SnippetReflectionProvider getSnippetReflectionProvider() {
  89         return snippetReflection;
  90     }
  91 

  92     @Override
  93     public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) throws IOException {
  94         output.beginGroup(new GraphInfo(debug, null), name, shortName, method, bci, properties);












  95     }
  96 
  97     @Override
  98     public void endGroup() throws IOException {
  99         output.endGroup();
























 100     }
 101 
 102     @Override
 103     public void close() {
 104         output.close();


 105     }
 106 
 107     @Override
 108     public ResolvedJavaMethod method(Object object) {
 109         if (object instanceof Bytecode) {
 110             return ((Bytecode) object).getMethod();
 111         } else if (object instanceof ResolvedJavaMethod) {
 112             return ((ResolvedJavaMethod) object);
 113         } else {
 114             return null;
 115         }




 116     }
 117 
 118     @Override
 119     public NodeClass<?> nodeClass(Object obj) {
 120         if (obj instanceof NodeClass<?>) {
 121             return (NodeClass<?>) obj;
 122         }
 123         if (obj instanceof Node) {
 124             return ((Node) obj).getNodeClass();


 125         }
 126         return null;



 127     }
 128 
 129     @Override
 130     public Object nodeClassType(NodeClass<?> node) {
 131         return node.getJavaClass();
 132     }
 133 
 134     @Override
 135     public String nameTemplate(NodeClass<?> nodeClass) {
 136         return nodeClass.getNameTemplate();
 137     }
 138 
 139     @Override
 140     public final GraphInfo graph(GraphInfo currrent, Object obj) {
 141         if (obj instanceof Graph) {
 142             return new GraphInfo(currrent.debug, (Graph) obj);
 143         } else if (obj instanceof CachedGraph) {
 144             return new GraphInfo(currrent.debug, ((CachedGraph<?>) obj).getReadonlyCopy());
 145         } else {
 146             return null;

 147         }
 148     }
 149 
 150     @Override
 151     public int nodeId(Node n) {
 152         return getNodeId(n);





 153     }
 154 
 155     @Override
 156     public Edges portInputs(NodeClass<?> nodeClass) {
 157         return nodeClass.getEdges(Inputs);







 158     }
 159 
 160     @Override
 161     public Edges portOutputs(NodeClass<?> nodeClass) {
 162         return nodeClass.getEdges(Successors);







 163     }
 164 
 165     @SuppressWarnings("deprecation")
 166     private static int getNodeId(Node node) {
 167         return node == null ? -1 : node.getId();

























 168     }
 169 
 170     @Override
 171     public List<Node> blockNodes(GraphInfo info, Block block) {
 172         List<Node> nodes = info.blockToNodes.get(block);
 173         if (nodes == null) {
 174             return null;
























































































 175         }
 176         List<Node> extraNodes = new LinkedList<>();
 177         for (Node node : nodes) {
 178             findExtraNodes(node, extraNodes);

 179         }
 180         extraNodes.removeAll(nodes);
 181         extraNodes.addAll(0, nodes);
 182         return extraNodes;
 183     }
 184 
 185     @Override
 186     public int blockId(Block sux) {
 187         return sux.getId();







 188     }
 189 
 190     @Override
 191     public List<Block> blockSuccessors(Block block) {
 192         return Arrays.asList(block.getSuccessors());


















































 193     }
 194 
 195     @Override
 196     public Iterable<Node> nodes(GraphInfo info) {
 197         return info.graph.getNodes();
 198     }
 199 
 200     @Override
 201     public int nodesCount(GraphInfo info) {
 202         return info.graph.getNodeCount();









 203     }
 204 
 205     @Override
 206     @SuppressWarnings({"unchecked", "rawtypes"})
 207     public void nodeProperties(GraphInfo info, Node node, Map<String, Object> props) {
 208         node.getDebugProperties((Map) props);
 209         Graph graph = info.graph;
 210         ControlFlowGraph cfg = info.cfg;
 211         NodeMap<Block> nodeToBlocks = info.nodeToBlocks;

 212         if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) {
 213             try {
 214                 props.put("probability", cfg.blockFor(node).probability());
 215             } catch (Throwable t) {
 216                 props.put("probability", 0.0);
 217                 props.put("probability-exception", t);
 218             }
 219         }
 220 
 221         try {
 222             props.put("NodeCost-Size", node.estimatedNodeSize());
 223             props.put("NodeCost-Cycles", node.estimatedNodeCycles());
 224         } catch (Throwable t) {
 225             props.put("node-cost-exception", t.getMessage());
 226         }
 227 
 228         if (nodeToBlocks != null) {
 229             Object block = getBlockForNode(node, nodeToBlocks);
 230             if (block != null) {
 231                 props.put("node-to-block", block);


 236             props.put("category", "controlSink");
 237         } else if (node instanceof ControlSplitNode) {
 238             props.put("category", "controlSplit");
 239         } else if (node instanceof AbstractMergeNode) {
 240             props.put("category", "merge");
 241         } else if (node instanceof AbstractBeginNode) {
 242             props.put("category", "begin");
 243         } else if (node instanceof AbstractEndNode) {
 244             props.put("category", "end");
 245         } else if (node instanceof FixedNode) {
 246             props.put("category", "fixed");
 247         } else if (node instanceof VirtualState) {
 248             props.put("category", "state");
 249         } else if (node instanceof PhiNode) {
 250             props.put("category", "phi");
 251         } else if (node instanceof ProxyNode) {
 252             props.put("category", "proxy");
 253         } else {
 254             if (node instanceof ConstantNode) {
 255                 ConstantNode cn = (ConstantNode) node;
 256                 updateStringPropertiesForConstant((Map) props, cn);
 257             }
 258             props.put("category", "floating");
 259         }
 260     }
 261 
 262     private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) {
 263         if (nodeToBlocks.isNew(node)) {
 264             return "NEW (not in schedule)";
 265         } else {
 266             Block block = nodeToBlocks.get(node);
 267             if (block != null) {
 268                 return block.getId();
 269             } else if (node instanceof PhiNode) {
 270                 return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks);
 271             }
 272         }
 273         return null;
 274     }
 275 
 276     private static void findExtraNodes(Node node, Collection<? super Node> extraNodes) {
 277         if (node instanceof AbstractMergeNode) {
 278             AbstractMergeNode merge = (AbstractMergeNode) node;
 279             for (PhiNode phi : merge.phis()) {
 280                 extraNodes.add(phi);
 281             }
 282         }
 283     }
 284 
 285     @Override
 286     public boolean nodeHasPredecessor(Node node) {
 287         return node.predecessor() != null;








 288     }
 289 
 290     @Override
 291     public List<Block> blocks(GraphInfo graph) {
 292         return graph.blocks;
 293     }
 294 
 295     @Override
 296     public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) throws IOException {
 297         output.print(new GraphInfo(debug, graph), properties, id, format, args);














 298     }
 299 
 300     @Override
 301     public int portSize(Edges port) {
 302         return port.getCount();
 303     }
 304 
 305     @Override
 306     public boolean edgeDirect(Edges port, int index) {
 307         return index < port.getDirectCount();
 308     }
 309 
 310     @Override
 311     public String edgeName(Edges port, int index) {
 312         return port.getName(index);
 313     }
 314 
 315     @Override
 316     public Object edgeType(Edges port, int index) {
 317         return ((InputEdges) port).getInputType(index);
 318     }
 319 
 320     @Override
 321     public Collection<? extends Node> edgeNodes(GraphInfo graph, Node node, Edges port, int i) {
 322         if (i < port.getDirectCount()) {
 323             Node single = Edges.getNode(node, port.getOffsets(), i);
 324             return Collections.singletonList(single);
 325         } else {
 326             return Edges.getNodeList(node, port.getOffsets(), i);
 327         }
 328     }
 329 
 330     @Override
 331     public Object enumClass(Object enumValue) {
 332         if (enumValue instanceof Enum) {
 333             return enumValue.getClass();



 334         }
 335         return null;
 336     }
 337 
 338     @Override
 339     public int enumOrdinal(Object obj) {
 340         if (obj instanceof Enum<?>) {
 341             return ((Enum<?>) obj).ordinal();






 342         }
 343         return -1;
 344     }
 345 
 346     @SuppressWarnings("unchecked")
 347     @Override
 348     public String[] enumTypeValues(Object clazz) {
 349         if (clazz instanceof Class<?>) {
 350             Class<? extends Enum<?>> enumClass = (Class<? extends Enum<?>>) clazz;
 351             Enum<?>[] constants = enumClass.getEnumConstants();
 352             if (constants != null) {
 353                 String[] names = new String[constants.length];
 354                 for (int i = 0; i < constants.length; i++) {
 355                     names[i] = constants[i].name();
 356                 }
 357                 return names;
 358             }



 359         }
 360         return null;

 361     }
 362 
 363     @Override
 364     public String typeName(Object obj) {
 365         if (obj instanceof Class<?>) {
 366             return ((Class<?>) obj).getName();
 367         }
 368         if (obj instanceof ResolvedJavaType) {
 369             return ((ResolvedJavaType) obj).getName();
 370         }
 371         return null;

 372     }
 373 
 374     @Override
 375     public byte[] methodCode(ResolvedJavaMethod method) {
 376         return method.getCode();
 377     }
 378 
 379     @Override
 380     public int methodModifiers(ResolvedJavaMethod method) {
 381         return method.getModifiers();





 382     }
 383 
 384     @Override
 385     public Signature methodSignature(ResolvedJavaMethod method) {
 386         return method.getSignature();
 387     }
 388 
 389     @Override
 390     public String methodName(ResolvedJavaMethod method) {
 391         return method.getName();
 392     }
 393 
 394     @Override
 395     public Object methodDeclaringClass(ResolvedJavaMethod method) {
 396         return method.getDeclaringClass();
 397     }
 398 
 399     @Override
 400     public int fieldModifiers(ResolvedJavaField field) {
 401         return field.getModifiers();
 402     }
 403 
 404     @Override
 405     public String fieldTypeName(ResolvedJavaField field) {
 406         return field.getType().getName();
 407     }
 408 
 409     @Override
 410     public String fieldName(ResolvedJavaField field) {
 411         return field.getName();
 412     }
 413 
 414     @Override
 415     public Object fieldDeclaringClass(ResolvedJavaField field) {
 416         return field.getDeclaringClass();
 417     }
 418 
 419     @Override
 420     public ResolvedJavaField field(Object object) {
 421         if (object instanceof ResolvedJavaField) {
 422             return (ResolvedJavaField) object;
 423         }
 424         return null;
 425     }
 426 
 427     @Override
 428     public Signature signature(Object object) {
 429         if (object instanceof Signature) {
 430             return (Signature) object;
 431         }
 432         return null;
 433     }
 434 
 435     @Override
 436     public int signatureParameterCount(Signature signature) {
 437         return signature.getParameterCount(false);
 438     }
 439 
 440     @Override
 441     public String signatureParameterTypeName(Signature signature, int index) {
 442         return signature.getParameterType(index, null).getName();
 443     }
 444 
 445     @Override
 446     public String signatureReturnTypeName(Signature signature) {
 447         return signature.getReturnType(null).getName();
 448     }
 449 
 450     @Override
 451     public NodeSourcePosition nodeSourcePosition(Object object) {
 452         if (object instanceof NodeSourcePosition) {
 453             return (NodeSourcePosition) object;
 454         }
 455         return null;
 456     }
 457 
 458     @Override
 459     public ResolvedJavaMethod nodeSourcePositionMethod(NodeSourcePosition pos) {
 460         return pos.getMethod();
 461     }
 462 
 463     @Override
 464     public NodeSourcePosition nodeSourcePositionCaller(NodeSourcePosition pos) {
 465         return pos.getCaller();
 466     }
 467 
 468     @Override
 469     public int nodeSourcePositionBCI(NodeSourcePosition pos) {
 470         return pos.getBCI();
 471     }
 472 
 473     @Override
 474     public StackTraceElement methodStackTraceElement(ResolvedJavaMethod method, int bci, NodeSourcePosition pos) {
 475         return method.asStackTraceElement(bci);
 476     }
 477 
 478     static final class GraphInfo {
 479         final DebugContext debug;
 480         final Graph graph;
 481         final ControlFlowGraph cfg;
 482         final BlockMap<List<Node>> blockToNodes;
 483         final NodeMap<Block> nodeToBlocks;
 484         final List<Block> blocks;
 485 
 486         private GraphInfo(DebugContext debug, Graph graph) {
 487             this.debug = debug;
 488             this.graph = graph;
 489             StructuredGraph.ScheduleResult scheduleResult = null;
 490             if (graph instanceof StructuredGraph) {
 491 
 492                 StructuredGraph structuredGraph = (StructuredGraph) graph;
 493                 scheduleResult = structuredGraph.getLastSchedule();
 494                 if (scheduleResult == null) {
 495 
 496                     // Also provide a schedule when an error occurs
 497                     if (DebugOptions.PrintGraphWithSchedule.getValue(graph.getOptions()) || debug.contextLookup(Throwable.class) != null) {
 498                         try {
 499                             SchedulePhase schedule = new SchedulePhase(graph.getOptions());
 500                             schedule.apply(structuredGraph);
 501                             scheduleResult = structuredGraph.getLastSchedule();
 502                         } catch (Throwable t) {
 503                         }
 504                     }
 505 
 506                 }
 507             }
 508             cfg = scheduleResult == null ? debug.contextLookup(ControlFlowGraph.class) : scheduleResult.getCFG();
 509             blockToNodes = scheduleResult == null ? null : scheduleResult.getBlockToNodesMap();
 510             nodeToBlocks = scheduleResult == null ? null : scheduleResult.getNodeToBlockMap();
 511             blocks = cfg == null ? null : Arrays.asList(cfg.getBlocks());
 512         }
 513     }
 514 
 515 }
< prev index next >