BinaryGraphPrinter.java revision 13264:48566d838608
1/* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23package org.graalvm.compiler.printer; 24 25import static org.graalvm.compiler.graph.Edges.Type.Inputs; 26import static org.graalvm.compiler.graph.Edges.Type.Successors; 27 28import java.io.IOException; 29import java.nio.ByteBuffer; 30import java.nio.channels.WritableByteChannel; 31import java.nio.charset.Charset; 32import java.util.Arrays; 33import java.util.HashMap; 34import java.util.LinkedHashMap; 35import java.util.LinkedList; 36import java.util.List; 37import java.util.Map; 38import java.util.Map.Entry; 39 40import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; 41import org.graalvm.compiler.bytecode.Bytecode; 42import org.graalvm.compiler.core.common.cfg.BlockMap; 43import org.graalvm.compiler.debug.DebugContext; 44import org.graalvm.compiler.debug.DebugOptions; 45import org.graalvm.compiler.graph.CachedGraph; 46import org.graalvm.compiler.graph.Edges; 47import org.graalvm.compiler.graph.Graph; 48import org.graalvm.compiler.graph.InputEdges; 49import org.graalvm.compiler.graph.Node; 50import org.graalvm.compiler.graph.NodeClass; 51import org.graalvm.compiler.graph.NodeList; 52import org.graalvm.compiler.graph.NodeMap; 53import org.graalvm.compiler.nodes.AbstractBeginNode; 54import org.graalvm.compiler.nodes.AbstractEndNode; 55import org.graalvm.compiler.nodes.AbstractMergeNode; 56import org.graalvm.compiler.nodes.ConstantNode; 57import org.graalvm.compiler.nodes.ControlSinkNode; 58import org.graalvm.compiler.nodes.ControlSplitNode; 59import org.graalvm.compiler.nodes.FixedNode; 60import org.graalvm.compiler.nodes.PhiNode; 61import org.graalvm.compiler.nodes.ProxyNode; 62import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 63import org.graalvm.compiler.nodes.VirtualState; 64import org.graalvm.compiler.nodes.cfg.Block; 65import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 66 67import jdk.vm.ci.meta.JavaType; 68import jdk.vm.ci.meta.ResolvedJavaField; 69import jdk.vm.ci.meta.ResolvedJavaMethod; 70import jdk.vm.ci.meta.Signature; 71import org.graalvm.compiler.graph.NodeSourcePosition; 72 73public 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); 547 } 548 } 549 550 if (node instanceof ControlSinkNode) { 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} 697