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 } |