# HG changeset patch # User Gilles Duboscq # Date 1341836542 -7200 # Node ID 6a725f3c4bb0d4cce08482b986aeca77b6ae36b4 # Parent 506e762811450cc721fb116ec8cba9e4915208e8# Parent bc237d8b6f99f4b649675cec7bc18e2b525159d0 Merge diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java Mon Jul 09 14:22:22 2012 +0200 @@ -137,11 +137,13 @@ public static boolean DumpOnError = ____; // Ideal graph visualizer output settings + public static boolean PrintBinaryGraphs = ____; + public static boolean PrintCFG = true; public static int PlotLevel = 3; - public static int PrintIdealGraphLevel = 0; public static boolean PrintIdealGraphFile = ____; public static String PrintIdealGraphAddress = "127.0.0.1"; public static int PrintIdealGraphPort = 4444; + public static int PrintBinaryGraphPort = 4445; // Other printing settings public static boolean PrintQueue = ____; diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java Mon Jul 09 14:22:22 2012 +0200 @@ -27,6 +27,14 @@ import com.oracle.graal.graph.*; import com.oracle.graal.nodes.*; +/** + * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a specified fixed node.
+ * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode}, {@link MergeNode}...) and the {@link FixedWithNextNode#next() next} pointers + * of {@link FixedWithNextNode}.
+ * While iterating it maintains a user-defined state by calling the methods available in {@link MergeableState}. + * + * @param the type of {@link MergeableState} handled by this PostOrderNodeIterator + */ public abstract class PostOrderNodeIterator> { private final NodeBitMap visitedEnds; diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java Mon Jul 09 14:22:22 2012 +0200 @@ -22,6 +22,9 @@ */ package com.oracle.graal.compiler.phases; +import java.util.*; +import java.util.concurrent.*; + import com.oracle.graal.api.code.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.debug.*; @@ -51,6 +54,7 @@ private NodeWorkList workList; private Tool tool; + private List snapshotTemp; public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) { this(target, runtime, assumptions, null, 0, null); @@ -82,6 +86,7 @@ this.runtime = runtime; this.immutabilityPredicate = immutabilityPredicate; this.initWorkingSet = workingSet; + this.snapshotTemp = new ArrayList<>(); } @Override @@ -97,14 +102,6 @@ } tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate); processWorkSet(graph); - - while (graph.getUsagesDroppedNodesCount() > 0) { - for (Node n : graph.getAndCleanUsagesDroppedNodes()) { - if (!n.isDeleted() && n.usages().size() == 0 && GraphUtil.isFloatingNode().apply(n)) { - n.safeDelete(); - } - } - } } public interface IsImmutablePredicate { @@ -138,8 +135,19 @@ return; } int mark = graph.getMark(); - tryCanonicalize(node, graph, tool); - tryInferStamp(node, graph); + if (!tryKillUnused(node)) { + node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp); + if (!tryCanonicalize(node, graph, tool)) { + tryInferStamp(node, graph); + } else { + for (Node in : snapshotTemp) { + if (in.isAlive() && in.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(in); + } + } + } + snapshotTemp.clear(); + } for (Node newNode : graph.getNewNodes(mark)) { workList.add(newNode); @@ -147,6 +155,14 @@ } } + private static boolean tryKillUnused(Node node) { + if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(node); + return true; + } + return false; + } + public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) { if (node.getNodeClass().valueNumberable()) { Node newNode = graph.findDuplicate(node); @@ -162,11 +178,11 @@ return false; } - public static void tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) { + public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) { if (node instanceof Canonicalizable) { METRIC_CANONICALIZATION_CONSIDERED_NODES.increment(); - Debug.scope("CanonicalizeNode", node, new Runnable() { - public void run() { + return Debug.scope("CanonicalizeNode", node, new Callable(){ + public Boolean call() { ValueNode canonical = ((Canonicalizable) node).canonical(tool); // cases: original node: // |Floating|Fixed-unconnected|Fixed-connected| @@ -182,9 +198,9 @@ // X: must not happen (checked with assertions) if (canonical == node) { Debug.log("Canonicalizer: work on %s", node); + return false; } else { Debug.log("Canonicalizer: replacing %s with %s", node, canonical); - METRIC_CANONICALIZED_NODES.increment(); if (node instanceof FloatingNode) { if (canonical == null) { @@ -192,7 +208,7 @@ graph.removeFloating((FloatingNode) node); } else { // case 2 - assert !(canonical instanceof FixedNode) || canonical.predecessor() != null : node + " -> " + canonical + + assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical + " : replacement should be floating or fixed and connected"; graph.replaceFloating((FloatingNode) node, canonical); } @@ -218,6 +234,7 @@ } } } + return true; } } }); @@ -226,6 +243,7 @@ METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment(); ((Simplifiable) node).simplify(tool); } + return false; } /** diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java --- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java Mon Jul 09 14:22:22 2012 +0200 @@ -169,7 +169,7 @@ if (virtual.fieldsCount() > 0) { final BlockExitState startState = new BlockExitState(escapeFields, virtual); - final PostOrderNodeIterator iterator = new PostOrderNodeIterator(next, startState) { + new PostOrderNodeIterator(next, startState) { @Override protected void node(FixedNode curNode) { op.updateState(virtual, curNode, fields, state.fieldState); @@ -183,8 +183,7 @@ ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v); } } - }; - iterator.apply(); + }.apply(); } } } diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java Mon Jul 09 14:22:22 2012 +0200 @@ -47,7 +47,6 @@ private int deletedNodeCount; private GraphEventLog eventLog; - ArrayList usagesDropped = new ArrayList<>(); InputChangedListener inputChanged; private final HashMap cachedNodes = new HashMap<>(); @@ -149,16 +148,6 @@ return node; } - public int getUsagesDroppedNodesCount() { - return usagesDropped.size(); - } - - public List getAndCleanUsagesDroppedNodes() { - ArrayList result = usagesDropped; - usagesDropped = new ArrayList<>(); - return result; - } - public interface InputChangedListener { void inputChanged(Node node); } @@ -322,6 +311,11 @@ } return super.filter(clazz); } + + @Override + public int count() { + return getNodeCount(); + } }; } diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java Mon Jul 09 14:22:22 2012 +0200 @@ -279,9 +279,6 @@ private boolean removeThisFromUsages(Node n) { if (n.usages.remove(this)) { - if (n.usages.size() == 0) { - graph.usagesDropped.add(n); - } return true; } else { return false; @@ -492,6 +489,12 @@ } } + + @Deprecated + public int getId() { + return id; + } + @Override public void formatTo(Formatter formatter, int flags, int width, int precision) { if ((flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE) { diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java Mon Jul 09 14:22:22 2012 +0200 @@ -570,17 +570,6 @@ } else { assert false : "unhandled property type: " + type; } - } else { - value = unsafe.getObject(node, dataOffsets[i]); - if (type.isArray()) { - if (!type.getComponentType().isPrimitive()) { - value = Arrays.toString((Object[]) value); - } else if (type.getComponentType() == Integer.TYPE) { - value = Arrays.toString((int[]) value); - } else if (type.getComponentType() == Double.TYPE) { - value = Arrays.toString((double[]) value); - } - } } properties.put("data." + dataNames[i], value); } diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java Mon Jul 09 14:22:22 2012 +0200 @@ -55,7 +55,7 @@ this.nodes = new Node[elements.length]; for (int i = 0; i < elements.length; i++) { this.nodes[i] = elements[i]; - assert this.nodes[i] == null || !this.nodes[i].isDeleted(); + assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i]; } } } @@ -254,6 +254,13 @@ return (List) Arrays.asList(Arrays.copyOf(this.nodes, this.size)); } + @Override + public void snapshotTo(List to) { + for (int i = 0; i < size; i++) { + to.add(get(i)); + } + } + @SuppressWarnings("unchecked") public void setAll(NodeList values) { incModCount(); diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/AbstractNodeIterable.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/AbstractNodeIterable.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/AbstractNodeIterable.java Mon Jul 09 14:22:22 2012 +0200 @@ -65,6 +65,12 @@ return list; } @Override + public void snapshotTo(List to) { + for (T n : this) { + to.add(n); + } + } + @Override public T first() { Iterator iterator = iterator(); if (iterator.hasNext()) { diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java --- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java Mon Jul 09 14:22:22 2012 +0200 @@ -44,6 +44,8 @@ List snapshot(); + void snapshotTo(List to); + T first(); int count(); diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java --- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java Mon Jul 09 14:22:22 2012 +0200 @@ -64,13 +64,22 @@ if (logFilter != null || meterFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) { TTY.println(Thread.currentThread().getName() + ": " + toString()); } - - if (GraalOptions.PrintIdealGraphFile) { - dumpHandlers.add(new IdealGraphPrinterDumpHandler()); + if (GraalOptions.PrintBinaryGraphs) { + if (GraalOptions.PrintIdealGraphFile) { + dumpHandlers.add(new BinaryGraphPrinterDumpHandler()); + } else { + dumpHandlers.add(new BinaryGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintBinaryGraphPort)); + } } else { - dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort)); + if (GraalOptions.PrintIdealGraphFile) { + dumpHandlers.add(new IdealGraphPrinterDumpHandler()); + } else { + dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort)); + } } - dumpHandlers.add(new CFGPrinterObserver()); + if (GraalOptions.PrintCFG) { + dumpHandlers.add(new CFGPrinterObserver()); + } this.output = output; } diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java Mon Jul 09 14:22:22 2012 +0200 @@ -53,7 +53,6 @@ } public int getId() { - assert id >= 0; return id; } diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java --- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java Mon Jul 09 14:22:22 2012 +0200 @@ -25,6 +25,7 @@ public class CFGVerifier { public static boolean verify(ControlFlowGraph cfg) { for (Block block : cfg.getBlocks()) { + assert block.getId() >= 0; assert cfg.getBlocks()[block.getId()] == block; for (Block pred : block.getPredecessors()) { diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java Mon Jul 09 14:22:22 2012 +0200 @@ -130,12 +130,13 @@ AccessIndexedNode x = (AccessIndexedNode) current; if (GraphUtil.unProxify(x.array()) == node) { int index = ((AccessIndexedNode) current).index().asConstant().asInt(); + StructuredGraph graph = (StructuredGraph) x.graph(); if (current instanceof LoadIndexedNode) { x.replaceAtUsages(fieldState[index]); - ((StructuredGraph) x.graph()).removeFixed(x); + graph.removeFixed(x); } else if (current instanceof StoreIndexedNode) { fieldState[index] = ((StoreIndexedNode) x).value(); - ((StructuredGraph) x.graph()).removeFixed(x); + graph.removeFixed(x); return index; } } diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java --- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Mon Jul 09 14:22:22 2012 +0200 @@ -22,21 +22,24 @@ */ package com.oracle.graal.nodes.util; -import static com.oracle.graal.graph.iterators.NodePredicates.*; - import java.util.*; import com.oracle.graal.api.meta.*; import com.oracle.graal.graph.*; import com.oracle.graal.graph.iterators.*; -import com.oracle.graal.graph.iterators.NodePredicates.PositiveTypePredicate; import com.oracle.graal.nodes.*; import com.oracle.graal.nodes.calc.*; import com.oracle.graal.nodes.java.*; public class GraphUtil { - private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class); + private static final NodePredicate FLOATING = new NodePredicate() { + @Override + public final boolean apply(Node n) { + //isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class) + return n instanceof FloatingNode || n instanceof VirtualState || n instanceof CallTargetNode; + } + }; public static void killCFG(FixedNode node) { assert node.isAlive(); diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Mon Jul 09 14:22:22 2012 +0200 @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.printer; + +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.*; +import java.util.Map.Entry; + +import com.oracle.graal.api.meta.*; +import com.oracle.graal.compiler.schedule.*; +import com.oracle.graal.graph.*; +import com.oracle.graal.graph.Node.Verbosity; +import com.oracle.graal.graph.NodeClass.NodeClassIterator; +import com.oracle.graal.graph.NodeClass.Position; +import com.oracle.graal.lir.cfg.*; +import com.oracle.graal.nodes.*; + +public class BinaryGraphPrinter { + private static final int CONSTANT_POOL_MAX_SIZE = 2000; + + private static final int BEGIN_GROUP = 0x00; + private static final int BEGIN_GRAPH = 0x01; + private static final int CLOSE_GROUP = 0x02; + + private static final int POOL_NULL = -1; + private static final int POOL_NEW = 0x00; + private static final int POOL_STRING = 0x01; + private static final int POOL_ENUM = 0x02; + private static final int POOL_CLASS = 0x03; + private static final int POOL_METHOD = 0x04; + + private static final int PROPERTY_POOL = 0x00; + private static final int PROPERTY_INT = 0x01; + private static final int PROPERTY_LONG = 0x02; + private static final int PROPERTY_DOUBLE = 0x03; + private static final int PROPERTY_FLOAT = 0x04; + private static final int PROPERTY_TRUE = 0x05; + private static final int PROPERTY_FALSE = 0x06; + private static final int PROPERTY_ARRAY = 0x07; + + private static final int KLASS = 0x00; + private static final int ENUM_KLASS = 0x01; + + protected static class Edge { + final int from; + final char fromIndex; + final int to; + final char toIndex; + final String label; + + public Edge(int from, char fromIndex, int to, char toIndex, String label) { + this.from = from; + this.fromIndex = fromIndex; + this.to = to; + this.toIndex = toIndex; + this.label = label; + } + + @Override + public int hashCode() { + int h = from ^ to; + h = 3 * h + fromIndex; + h = 5 * h + toIndex; + if (label != null) { + h ^= label.hashCode(); + } + return h; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof Edge) { + Edge other = (Edge) obj; + return from == other.from + && fromIndex == other.fromIndex + && to == other.to + && toIndex == other.toIndex + && (label == other.label || (label != null && label.equals(other.label))); + } + return false; + } + } + + private static final class CosntantPool extends LinkedHashMap { + private final LinkedList availableIds; + private int nextId; + private static final long serialVersionUID = -2676889957907285681L; + public CosntantPool() { + super(50, 0.65f); + availableIds = new LinkedList<>(); + } + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + if (size() > CONSTANT_POOL_MAX_SIZE) { + availableIds.addFirst(eldest.getValue()); + return true; + } + return false; + } + + private Integer nextAvailableId() { + if (!availableIds.isEmpty()) { + return availableIds.removeFirst(); + } + return nextId++; + } + + public int add(Object obj) { + Integer id = nextAvailableId(); + put(obj, id); + return id; + } + } + + private final CosntantPool constantPool; + + + private final ByteBuffer buffer; + private final WritableByteChannel channel; + + + public BinaryGraphPrinter(WritableByteChannel channel) { + constantPool = new CosntantPool(); + buffer = ByteBuffer.allocateDirect(64 * 1024); + this.channel = channel; + } + + public void print(Graph graph, String title, SchedulePhase predefinedSchedule) throws IOException { + Set noBlockNodes = new HashSet<>(); + SchedulePhase schedule = predefinedSchedule; + if (schedule == null) { + try { + schedule = new SchedulePhase(); + schedule.apply((StructuredGraph) graph); + } catch (Throwable t) { + } + } + ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG(); + + BlockMap> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap(); + writeByte(BEGIN_GRAPH); + writePoolObject(title); + int edgeCount = writeNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes); + writeEdges(graph, edgeCount); + + + Block[] blocks = cfg == null ? null : cfg.getBlocks(); + writeBlocks(blocks, noBlockNodes, blockToNodes); + flush(); + } + + private void flush() throws IOException { + buffer.flip(); + channel.write(buffer); + buffer.compact(); + } + + private void ensureAvailable(int i) throws IOException { + while (buffer.remaining() < i) { + flush(); + } + } + + private void writeByte(int b) throws IOException { + ensureAvailable(1); + buffer.put((byte) b); + } + + private void writeInt(int b) throws IOException { + ensureAvailable(4); + buffer.putInt(b); + } + + private void writeLong(long b) throws IOException { + ensureAvailable(8); + buffer.putLong(b); + } + + private void writeDouble(double b) throws IOException { + ensureAvailable(8); + buffer.putDouble(b); + } + + private void writeFloat(float b) throws IOException { + ensureAvailable(4); + buffer.putFloat(b); + } + + private void writeShort(char b) throws IOException { + ensureAvailable(2); + buffer.putChar(b); + } + + private void writeString(String str) throws IOException { + writeInt(str.length()); + ensureAvailable(str.length() * 2); + for (int i = 0; i < str.length(); i++) { + buffer.putChar(str.charAt(i)); + } + } + + private void writeBytes(byte[] b) throws IOException { + if (b == null) { + writeInt(-1); + } else { + writeInt(b.length); + ensureAvailable(b.length); + buffer.put(b); + } + } + + private void writeInts(int[] b) throws IOException { + if (b == null) { + writeInt(-1); + } else { + writeInt(b.length); + ensureAvailable(b.length * 4); + for (int i = 0; i < b.length; i++) { + buffer.putInt(b[i]); + } + } + } + + private void writeDoubles(double[] b) throws IOException { + if (b == null) { + writeInt(-1); + } else { + writeInt(b.length); + ensureAvailable(b.length * 8); + for (int i = 0; i < b.length; i++) { + buffer.putDouble(b[i]); + } + } + } + + private void writePoolObject(Object object) throws IOException { + if (object == null) { + writeByte(POOL_NULL); + return; + } + Integer id = constantPool.get(object); + if (id == null) { + addPoolEntry(object); + } else { + if (object instanceof Enum) { + writeByte(POOL_ENUM); + } else if (object instanceof Class) { + writeByte(POOL_CLASS); + } else if (object instanceof ResolvedJavaMethod) { + writeByte(POOL_METHOD); + } else { + writeByte(POOL_STRING); + } + writeInt(id.intValue()); + } + } + + private void addPoolEntry(Object object) throws IOException { + int index = constantPool.add(object); + writeByte(POOL_NEW); + writeInt(index); + if (object instanceof Class) { + Class klass = (Class< ? >) object; + writeByte(POOL_CLASS); + writePoolObject(klass.getName()); + if (klass.isEnum()) { + writeByte(ENUM_KLASS); + Object[] enumConstants = object.getClass().getEnumConstants(); + writeInt(enumConstants.length); + for (Object o : enumConstants) { + writePoolObject(((Enum) o).name()); + } + } else { + writePoolObject(klass.getName()); + writeByte(KLASS); + } + } else if (object instanceof Enum) { + writeByte(POOL_ENUM); + writePoolObject(object.getClass()); + writeInt(((Enum) object).ordinal()); + } else if (object instanceof ResolvedJavaMethod) { + writeByte(POOL_METHOD); + writeBytes(((ResolvedJavaMethod) object).code()); + } else { + writeByte(POOL_STRING); + writeString(object.toString()); + } + } + + private void writePropertyObject(Object obj) throws IOException { + if (obj instanceof Integer) { + writeByte(PROPERTY_INT); + writeInt(((Integer) obj).intValue()); + } else if (obj instanceof Long) { + writeByte(PROPERTY_LONG); + writeLong(((Long) obj).longValue()); + } else if (obj instanceof Double) { + writeByte(PROPERTY_DOUBLE); + writeDouble(((Double) obj).doubleValue()); + } else if (obj instanceof Float) { + writeByte(PROPERTY_FLOAT); + writeFloat(((Float) obj).floatValue()); + } else if (obj instanceof Boolean) { + if (((Boolean) obj).booleanValue()) { + writeByte(PROPERTY_TRUE); + } else { + writeByte(PROPERTY_FALSE); + } + } else if (obj.getClass().isArray()) { + Class< ? > componentType = obj.getClass().getComponentType(); + if (componentType.isPrimitive()) { + if (componentType == Double.TYPE) { + writeByte(PROPERTY_ARRAY); + writeByte(PROPERTY_DOUBLE); + writeDoubles((double[]) obj); + } else if (componentType == Integer.TYPE) { + writeByte(PROPERTY_ARRAY); + writeByte(PROPERTY_DOUBLE); + writeInts((int[]) obj); + } else { + writeByte(PROPERTY_POOL); + writePoolObject(obj); + } + } else { + writeByte(PROPERTY_ARRAY); + writeByte(PROPERTY_POOL); + Object[] array = (Object[]) obj; + writeInt(array.length); + for (Object o : array) { + writePoolObject(o); + } + } + } else { + writeByte(PROPERTY_POOL); + writePoolObject(obj); + } + } + + @SuppressWarnings("deprecation") + private int writeNodes(Graph graph, NodeMap nodeToBlock, Set noBlockNodes) throws IOException { + int edges = 0; + Map props = new HashMap<>(); + writeInt(graph.getNodeCount()); + for (Node node : graph.getNodes()) { + node.getNodeClass().getDebugProperties(node, props); + String name = node.toString(Verbosity.Name); + + writeInt(node.getId()); + writePoolObject(name); + writePoolObject(node.getClass().getSimpleName()); + Block block = nodeToBlock == null ? null : nodeToBlock.get(node); + if (block != null) { + writeInt(block.getId()); + } else { + writeInt(-1); + noBlockNodes.add(node); + } + writeByte(node.predecessor() != null ? 1 : 0); + writeInt(props.size()); + for (Entry entry : props.entrySet()) { + String key = entry.getKey().toString(); + String value = entry.getValue() == null ? "null" : entry.getValue().toString(); + writePoolObject(key); + writePropertyObject(value); + } + edges += node.successors()/*.nonNull()*/.count(); + edges += node.inputs()/*.nonNull()*/.count(); + props.clear(); + } + + return edges; + } + + @SuppressWarnings("deprecation") + private void writeEdges(Graph graph, int edgeCount) throws IOException { + writeInt(edgeCount); + for (Node node : graph.getNodes()) { + // successors + char fromIndex = 0; + NodeClassIterator succIter = node.successors().iterator(); + while (succIter.hasNext()) { + Position position = succIter.nextPosition(); + Node successor = node.getNodeClass().get(node, position); + if (successor != null) { + writeShort(fromIndex); + writeInt(node.getId()); + writeShort((char) 0); + writeInt(successor.getId()); + writePoolObject(node.getNodeClass().getName(position)); + } + fromIndex++; + } + + // inputs + char toIndex = 1; + NodeClassIterator inputIter = node.inputs().iterator(); + while (inputIter.hasNext()) { + Position position = inputIter.nextPosition(); + Node input = node.getNodeClass().get(node, position); + if (input != null) { + writeShort((char) input.successors().count()); + writeInt(input.getId()); + writeShort(toIndex); + writeInt(node.getId()); + writePoolObject(node.getNodeClass().getName(position)); + } + toIndex++; + } + } + } + + @SuppressWarnings("deprecation") + private void writeBlocks(Block[] blocks, Set noBlockNodes, BlockMap> blockToNodes) throws IOException { + if (blocks != null) { + writeInt(blocks.length + (noBlockNodes.isEmpty() ? 0 : 1)); + int suxCount = 0; + for (Block block : blocks) { + List nodes = blockToNodes.get(block); + writeInt(block.getId()); + writeInt(nodes.size()); + for (Node node : nodes) { + writeInt(node.getId()); + } + suxCount += block.getSuccessors().size(); + } + if (!noBlockNodes.isEmpty()) { + writeInt(-1); + writeInt(noBlockNodes.size()); + for (Node node : noBlockNodes) { + writeInt(node.getId()); + } + } + writeInt(suxCount); + for (Block block : blocks) { + for (Block sux : block.getSuccessors()) { + writeInt(block.getId()); + writeInt(sux.getId()); + } + } + } else { + writeInt(0); + } + } + + public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci) throws IOException { + writeByte(BEGIN_GROUP); + writePoolObject(name); + writePoolObject(shortName); + writePoolObject(method); + writeInt(bci); + } + + public void endGroup() throws IOException { + writeByte(CLOSE_GROUP); + } +} diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinterDumpHandler.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinterDumpHandler.java Mon Jul 09 14:22:22 2012 +0200 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.graal.printer; + +import java.io.*; +import java.net.*; +import java.nio.channels.*; +import java.util.*; + +import com.oracle.max.criutils.*; +import com.oracle.graal.api.meta.*; +import com.oracle.graal.debug.*; +import com.oracle.graal.graph.*; + +/** + * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be + * inspected with the Ideal Graph Visualizer. + */ +public class BinaryGraphPrinterDumpHandler implements DebugDumpHandler { + + private static final String DEFAULT_FILE_NAME = "output.gvb"; + + private BinaryGraphPrinter printer; + private List previousInlineContext = new ArrayList<>(); + private String fileName; + private String host; + private int port; + private int failuresCount; + + /** + * Creates a new {@link BinaryGraphPrinterDumpHandler} that writes output to a file named after the compiled method. + */ + public BinaryGraphPrinterDumpHandler() { + this.fileName = DEFAULT_FILE_NAME; + } + + /** + * Creates a new {@link BinaryGraphPrinterDumpHandler} that sends output to a remote IdealGraphVisualizer instance. + */ + public BinaryGraphPrinterDumpHandler(String host, int port) { + this.host = host; + this.port = port; + } + + private void ensureInitialized() { + if (printer == null) { + if (failuresCount > 8) { + return; + } + previousInlineContext.clear(); + if (fileName != null) { + initializeFilePrinter(); + } else { + initializeNetworkPrinter(); + } + } + } + + private void initializeFilePrinter() { + try { + printer = new BinaryGraphPrinter(FileChannel.open(new File(fileName).toPath())); + } catch (IOException e) { + failuresCount++; + printer = null; + } + } + + private void initializeNetworkPrinter() { + try { + SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port)); + printer = new BinaryGraphPrinter(channel); + TTY.println("Connected to the IGV on port %d", port); + } catch (IOException e) { + TTY.println("Could not connect to the IGV on port %d: %s", port, e); + failuresCount++; + printer = null; + } + } + + @Override + public void dump(Object object, final String message) { + if (object instanceof Graph) { + ensureInitialized(); + if (printer == null) { + return; + } + final Graph graph = (Graph) object; + + if (printer != null) { + // Get all current RiResolvedMethod instances in the context. + List inlineContext = getInlineContext(); + + // Reverse list such that inner method comes after outer method. + Collections.reverse(inlineContext); + + // Check for method scopes that must be closed since the previous dump. + for (int i = 0; i < previousInlineContext.size(); ++i) { + if (i >= inlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) { + for (int j = previousInlineContext.size() - 1; j >= i; --j) { + closeScope(); + } + break; + } + } + + // Check for method scopes that must be opened since the previous dump. + for (int i = 0; i < inlineContext.size(); ++i) { + if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) { + for (int j = i; j < inlineContext.size(); ++j) { + openScope(inlineContext.get(j), j == 0); + } + break; + } + } + + // Save inline context for next dump. + previousInlineContext = inlineContext; + + Debug.sandbox("PrintingGraph", new Runnable() { + + @Override + public void run() { + // Finally, output the graph. + try { + printer.print(graph, message, null); + } catch (IOException e) { + failuresCount++; + printer = null; + } + } + }); + } + } + } + + private static List getInlineContext() { + List result = new ArrayList<>(); + for (Object o : Debug.context()) { + if (o instanceof ResolvedJavaMethod) { + ResolvedJavaMethod method = (ResolvedJavaMethod) o; + result.add(MetaUtil.format("%H::%n(%p)", method)); + } else if (o instanceof DebugDumpScope) { + DebugDumpScope debugDumpScope = (DebugDumpScope) o; + if (debugDumpScope.decorator && !result.isEmpty()) { + result.set(result.size() - 1, debugDumpScope.name + ":" + result.get(result.size() - 1)); + } else { + result.add(debugDumpScope.name); + } + } + } + return result; + } + + private void openScope(String name, boolean showThread) { + String prefix = showThread ? Thread.currentThread().getName() + ":" : ""; + try { + printer.beginGroup(prefix + name, name, Debug.contextLookup(ResolvedJavaMethod.class), -1); + } catch (IOException e) { + failuresCount++; + printer = null; + } + } + + private void closeScope() { + try { + printer.endGroup(); + } catch (IOException e) { + failuresCount++; + printer = null; + } + } +} diff -r 506e76281145 -r 6a725f3c4bb0 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java --- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Sat Jul 07 12:53:00 2012 +0200 +++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java Mon Jul 09 14:22:22 2012 +0200 @@ -79,12 +79,12 @@ schedule = new SchedulePhase(); schedule.apply((StructuredGraph) graph); } catch (Throwable t) { - schedule = null; } } + ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG(); beginNodes(); - List edges = printNodes(graph, schedule == null ? null : schedule.getCFG().getNodeToBlock(), noBlockNodes); + List edges = printNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes); endNodes(); beginEdges(); @@ -93,10 +93,10 @@ } endEdges(); - if (schedule != null) { + if (cfg != null && cfg.getBlocks() != null) { beginControlFlow(); - for (Block block : schedule.getCFG().getBlocks()) { - printBlock(graph, block, schedule.getCFG().getNodeToBlock()); + for (Block block : cfg.getBlocks()) { + printBlock(graph, block, cfg.getNodeToBlock()); } printNoBlock(noBlockNodes); endControlFlow(); diff -r 506e76281145 -r 6a725f3c4bb0 src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java --- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java Sat Jul 07 12:53:00 2012 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java Mon Jul 09 14:22:22 2012 +0200 @@ -23,6 +23,7 @@ */ package com.sun.hotspot.igv.coordinator; +import com.sun.hotspot.igv.connection.BinaryServer; import com.sun.hotspot.igv.connection.Server; import com.sun.hotspot.igv.coordinator.actions.*; import com.sun.hotspot.igv.data.GraphDocument; @@ -61,6 +62,7 @@ private GraphDocument document; private FolderNode root; private Server server; + private BinaryServer binaryServer; private OutlineTopComponent() { initComponents(); @@ -116,6 +118,7 @@ }; server = new Server(callback); + binaryServer = new BinaryServer(callback); } public void clear() { diff -r 506e76281145 -r 6a725f3c4bb0 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java --- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Sat Jul 07 12:53:00 2012 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java Mon Jul 09 14:22:22 2012 +0200 @@ -243,10 +243,7 @@ } public void addEdge(InputEdge c) { - // Be tolerant with duplicated edges. - if (!edges.contains(c)) { - edges.add(c); - } + edges.add(c); } public Group getGroup() { diff -r 506e76281145 -r 6a725f3c4bb0 src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java Mon Jul 09 14:22:22 2012 +0200 @@ -0,0 +1,447 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.sun.hotspot.igv.data.serialization; + +import com.sun.hotspot.igv.data.*; +import com.sun.hotspot.igv.data.services.GroupCallback; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ReadableByteChannel; +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import javax.swing.SwingUtilities; + +/** + * + * @author gd + */ +public class BinaryParser { + private static final int BEGIN_GROUP = 0x00; + private static final int BEGIN_GRAPH = 0x01; + private static final int CLOSE_GROUP = 0x02; + + private static final int POOL_NULL = -1; + private static final int POOL_NEW = 0x00; + private static final int POOL_STRING = 0x01; + private static final int POOL_ENUM = 0x02; + private static final int POOL_CLASS = 0x03; + private static final int POOL_METHOD = 0x04; + + private static final int KLASS = 0x00; + private static final int ENUM_KLASS = 0x01; + + private static final int PROPERTY_POOL = 0x00; + private static final int PROPERTY_INT = 0x01; + private static final int PROPERTY_LONG = 0x02; + private static final int PROPERTY_DOUBLE = 0x03; + private static final int PROPERTY_FLOAT = 0x04; + private static final int PROPERTY_TRUE = 0x05; + private static final int PROPERTY_FALSE = 0x06; + private static final int PROPERTY_ARRAY = 0x07; + + private static final String NO_BLOCK = "noBlock"; + + private GroupCallback callback; + private List constantPool; + private int maxConstant; + private final ByteBuffer buffer; + private final ReadableByteChannel channel; + private Deque folderStack; + + private static class Klass { + public String name; + public Klass(String name) { + this.name = name; + } + } + + private static class EnumKlass extends Klass { + public String[] values; + public EnumKlass(String name, String[] values) { + super(name); + this.values = values; + } + } + + private static class EnumValue { + public EnumKlass enumKlass; + public int ordinal; + public EnumValue(EnumKlass enumKlass, int ordinal) { + this.enumKlass = enumKlass; + this.ordinal = ordinal; + } + } + + public BinaryParser(GroupCallback callback, ReadableByteChannel channel) { + this.callback = callback; + constantPool = new ArrayList<>(); + buffer = ByteBuffer.allocateDirect(64 * 1024); + buffer.flip(); + this.channel = channel; + folderStack = new LinkedList<>(); + } + + private void fill() throws IOException { + buffer.compact(); + channel.read(buffer); + buffer.flip(); + } + + private void ensureAvailable(int i) throws IOException { + while (buffer.remaining() < i) { + fill(); + } + } + + private int readByte() throws IOException { + ensureAvailable(1); + return ((int)buffer.get()) & 0xff; + } + + private int readInt() throws IOException { + ensureAvailable(4); + return buffer.getInt(); + } + + private char readShort() throws IOException { + ensureAvailable(2); + return buffer.getChar(); + } + + private long readLong() throws IOException { + ensureAvailable(8); + return buffer.getLong(); + } + + private double readDouble() throws IOException { + ensureAvailable(8); + return buffer.getDouble(); + } + + private float readFloat() throws IOException { + ensureAvailable(4); + return buffer.getFloat(); + } + + private String readString() throws IOException { + int len = readInt(); + ensureAvailable(len * 2); + char[] chars = new char[len]; + for (int i = 0; i < len; i++) { + chars[i] = buffer.getChar(); + } + return new String(chars); + } + + private byte[] readBytes() throws IOException { + int len = readInt(); + if (len < 0) { + return null; + } + ensureAvailable(len); + byte[] data = new byte[len]; + buffer.get(data); + return data; + } + + private String readIntsToString() throws IOException { + int len = readInt(); + if (len < 0) { + return "null"; + } + ensureAvailable(len * 4); + StringBuilder sb = new StringBuilder().append('['); + for (int i = 0; i < len; i++) { + sb.append(buffer.getInt()); + if (i < len - 1) { + sb.append(", "); + } + } + sb.append(']'); + return sb.toString(); + } + + private String readDoublesToString() throws IOException { + int len = readInt(); + if (len < 0) { + return "null"; + } + ensureAvailable(len * 8); + StringBuilder sb = new StringBuilder().append('['); + for (int i = 0; i < len; i++) { + sb.append(buffer.getDouble()); + if (i < len - 1) { + sb.append(", "); + } + } + sb.append(']'); + return sb.toString(); + } + + private String readPoolObjectsToString() throws IOException { + int len = readInt(); + if (len < 0) { + return "null"; + } + StringBuilder sb = new StringBuilder().append('['); + for (int i = 0; i < len; i++) { + sb.append(readPoolObject(Object.class)); + if (i < len - 1) { + sb.append(", "); + } + } + sb.append(']'); + return sb.toString(); + } + + private T readPoolObject(Class klass) throws IOException { + int type = readByte(); + if (type == POOL_NULL) { + return null; + } + if (type == POOL_NEW) { + return (T) addPoolEntry(klass); + } + int index = readInt(); + if (index < 0 || index >= constantPool.size()) { + throw new IOException("Invalid constant pool index : " + index); + } + Object obj = constantPool.get(index); + return (T) obj; + } + + private boolean assertObjectType(Class klass, int type) { + switch(type) { + case POOL_CLASS: + return klass.isAssignableFrom(Klass.class); + case POOL_ENUM: + return klass.isAssignableFrom(EnumValue.class); + case POOL_METHOD: + return klass.isAssignableFrom(byte[].class); + case POOL_STRING: + return klass.isAssignableFrom(String.class); + case POOL_NULL: + return true; + default: + return false; + } + } + + private Object addPoolEntry(Class klass) throws IOException { + int index = readInt(); + int type = readByte(); + assert assertObjectType(klass, type) : "Wrong object type : " + klass + " != " + type; + Object obj; + switch(type) { + case POOL_CLASS: + String name = readString(); + int klasstype = readByte(); + if (klasstype == ENUM_KLASS) { + int len = readInt(); + String[] values = new String[len]; + for (int i = 0; i < len; i++) { + values[i] = readPoolObject(String.class); + } + obj = new EnumKlass(name, values); + } else if (klasstype == KLASS) { + obj = new Klass(name); + } else { + throw new IOException("unknown klass type"); + } + break; + case POOL_ENUM: + EnumKlass enumClass = readPoolObject(EnumKlass.class); + int ordinal = readInt(); + obj = new EnumValue(enumClass, ordinal); + break; + case POOL_METHOD: + obj = readBytes(); + break; + case POOL_STRING: + obj = readString(); + break; + default: + throw new IOException("unknown pool type"); + } + while (constantPool.size() <= index) { + constantPool.add(null); + } + constantPool.set(index, obj); + return obj; + } + + private Object readPropertyObject() throws IOException { + int type = readByte(); + switch (type) { + case PROPERTY_INT: + return readInt(); + case PROPERTY_LONG: + return readLong(); + case PROPERTY_FLOAT: + return readFloat(); + case PROPERTY_DOUBLE: + return readDouble(); + case PROPERTY_TRUE: + return Boolean.TRUE; + case PROPERTY_FALSE: + return Boolean.FALSE; + case PROPERTY_POOL: + return readPoolObject(Object.class); + case PROPERTY_ARRAY: + int subType = readByte(); + switch(subType) { + case PROPERTY_INT: + return readIntsToString(); + case PROPERTY_DOUBLE: + return readDoublesToString(); + case PROPERTY_POOL: + return readPoolObjectsToString(); + default: + throw new IOException("Unknown type"); + } + default: + throw new IOException("Unknown type"); + } + } + + public void parse() throws IOException { + folderStack.push(new GraphDocument()); + while(true) { + parseRoot(); + } + } + + private void parseRoot() throws IOException { + int type = readByte(); + switch(type) { + case BEGIN_GRAPH: { + final Folder parent = folderStack.peek(); + final InputGraph graph = parseGraph(); + SwingUtilities.invokeLater(new Runnable(){ + @Override + public void run() { + parent.addElement(graph); + } + }); + break; + } + case BEGIN_GROUP: { + final Folder parent = folderStack.peek(); + final Group group = parseGroup(parent); + if (callback == null || parent instanceof Group) { + SwingUtilities.invokeLater(new Runnable(){ + @Override + public void run() { + parent.addElement(group); + } + }); + } + folderStack.push(group); + if (callback != null && parent instanceof GraphDocument) { + callback.started(group); + } + break; + } + case CLOSE_GROUP: { + if (folderStack.isEmpty()) { + throw new IOException("Unbalanced groups"); + } + folderStack.pop(); + break; + } + default: + throw new IOException("unknown root : " + type); + } + } + + private Group parseGroup(Folder parent) throws IOException { + String name = readPoolObject(String.class); + String shortName = readPoolObject(String.class); + byte[] bytecodes = readPoolObject(byte[].class); + int bci = readInt(); + Group group = new Group(parent); + group.getProperties().setProperty("name", name); + final InputMethod method = new InputMethod(group, name, shortName, bci); + if (bytecodes != null) { + method.setBytecodes("TODO"); + } + group.setMethod(method); + return group; + } + + private InputGraph parseGraph() throws IOException { + String title = readPoolObject(String.class); + InputGraph graph = new InputGraph(title); + parseNodes(graph); + parseEdges(graph); + parseBlocks(graph); + graph.ensureNodesInBlocks(); + return graph; + } + + private void parseBlocks(InputGraph graph) throws IOException { + int blockCount = readInt(); + for (int i = 0; i < blockCount; i++) { + int id = readInt(); + String name = id >= 0 ? Integer.toString(id) : NO_BLOCK; + InputBlock block = graph.addBlock(name); + int nodeCount = readInt(); + for (int j = 0; j < nodeCount; j++) { + block.addNode(readInt()); + } + } + int edgeCount = readInt(); + for (int i = 0; i < edgeCount; i++) { + int from = readInt(); + int to = readInt(); + String fromName = from >= 0 ? Integer.toString(from) : NO_BLOCK; + String toName = to >= 0 ? Integer.toString(to) : NO_BLOCK; + graph.addBlockEdge(graph.getBlock(fromName), graph.getBlock(toName)); + } + } + + private void parseEdges(InputGraph graph) throws IOException { + int count = readInt(); + for (int i = 0; i < count; i++) { + char fromIndex = readShort(); + int from = readInt(); + char toIndex = readShort(); + int to = readInt(); + String label = readPoolObject(String.class); + graph.addEdge(new InputEdge(fromIndex, toIndex, from, to, label)); + } + } + + private void parseNodes(InputGraph graph) throws IOException { + int count = readInt(); + + for (int i = 0; i < count; i++) { + int id = readInt(); + InputNode node = new InputNode(id); + final Properties properties = node.getProperties(); + String name = readPoolObject(String.class); + String simpleName = readPoolObject(String.class); + int block = readInt(); + int preds = readByte(); + properties.setProperty("name", name); + properties.setProperty("class", simpleName); + properties.setProperty("predecessorCount", Integer.toString(preds)); + if (block > 0) { + properties.setProperty("block", Integer.toString(block)); + } else { + properties.setProperty("block", NO_BLOCK); + } + int propCount = readInt(); + for (int j = 0; j < propCount; j++) { + String key = readPoolObject(String.class); + Object value = readPropertyObject(); + properties.setProperty(key, value.toString()); + } + graph.addNode(node); + } + } +} diff -r 506e76281145 -r 6a725f3c4bb0 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryClient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryClient.java Mon Jul 09 14:22:22 2012 +0200 @@ -0,0 +1,64 @@ +/* + * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.hotspot.igv.connection; + +import com.sun.hotspot.igv.data.serialization.BinaryParser; +import com.sun.hotspot.igv.data.services.GroupCallback; +import java.io.IOException; +import java.nio.channels.SocketChannel; +import org.openide.util.Exceptions; + +/** + * + * @author Thomas Wuerthinger + */ +public class BinaryClient implements Runnable { + + private SocketChannel socket; + private GroupCallback callback; + + public BinaryClient(SocketChannel socket, GroupCallback callback) { + this.callback = callback; + this.socket = socket; + } + + @Override + public void run() { + + try { + final SocketChannel channel = socket; + channel.configureBlocking(true); + new BinaryParser(callback, channel).parse(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } finally { + try { + socket.close(); + } catch (IOException ex) { + Exceptions.printStackTrace(ex); + } + } + } +} \ No newline at end of file diff -r 506e76281145 -r 6a725f3c4bb0 src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryServer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryServer.java Mon Jul 09 14:22:22 2012 +0200 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.sun.hotspot.igv.connection; + +import com.sun.hotspot.igv.data.services.GroupCallback; +import com.sun.hotspot.igv.settings.Settings; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.prefs.PreferenceChangeEvent; +import java.util.prefs.PreferenceChangeListener; +import org.openide.DialogDisplayer; +import org.openide.NotifyDescriptor; +import org.openide.util.RequestProcessor; + +/** + * + * @author Thomas Wuerthinger + */ +public class BinaryServer implements PreferenceChangeListener { + + private ServerSocketChannel serverSocket; + private GroupCallback callback; + private int port; + private Runnable serverRunnable; + + public BinaryServer(GroupCallback callback) { + + this.callback = callback; + initializeNetwork(); + Settings.get().addPreferenceChangeListener(this); + } + + @Override + public void preferenceChange(PreferenceChangeEvent e) { + + int curPort = Integer.parseInt(Settings.get().get(Settings.PORT_BINARY, Settings.PORT_BINARY_DEFAULT)); + if (curPort != port) { + initializeNetwork(); + } + } + + private void initializeNetwork() { + + int curPort = Integer.parseInt(Settings.get().get(Settings.PORT_BINARY, Settings.PORT_BINARY_DEFAULT)); + this.port = curPort; + try { + serverSocket = ServerSocketChannel.open(); + serverSocket.bind(new InetSocketAddress(curPort)); + } catch (IOException ex) { + NotifyDescriptor message = new NotifyDescriptor.Message("Could not create server. Listening for incoming binary data is disabled.", NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notifyLater(message); + return; + } + + Runnable runnable = new Runnable() { + + @Override + public void run() { + while (true) { + try { + SocketChannel clientSocket = serverSocket.accept(); + if (serverRunnable != this) { + clientSocket.close(); + return; + } + RequestProcessor.getDefault().post(new BinaryClient(clientSocket, callback), 0, Thread.MAX_PRIORITY); + } catch (IOException ex) { + serverSocket = null; + NotifyDescriptor message = new NotifyDescriptor.Message("Error during listening for incoming connections. Listening for incoming binary data is disabled.", NotifyDescriptor.ERROR_MESSAGE); + DialogDisplayer.getDefault().notifyLater(message); + return; + } + } + } + }; + + serverRunnable = runnable; + + RequestProcessor.getDefault().post(runnable, 0, Thread.MAX_PRIORITY); + } +} diff -r 506e76281145 -r 6a725f3c4bb0 src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java --- a/src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java Sat Jul 07 12:53:00 2012 +0200 +++ b/src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java Mon Jul 09 14:22:22 2012 +0200 @@ -37,7 +37,9 @@ public final static String NODE_WIDTH = "nodeWidth"; public final static String NODE_WIDTH_DEFAULT = "100"; public final static String PORT = "port"; + public final static String PORT_BINARY = "portBinary"; public final static String PORT_DEFAULT = "4444"; + public final static String PORT_BINARY_DEFAULT = "4445"; public final static String DIRECTORY = "directory"; public final static String DIRECTORY_DEFAULT = System.getProperty("user.dir");